mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-10-31 14:56:40 +08:00 
			
		
		
		
	Merge pull request #13100 from liamwhite/audio-ipc
audio: move to new ipc
This commit is contained in:
		
						commit
						215e887be0
					
				| @ -121,6 +121,7 @@ else() | ||||
|         -Wno-attributes | ||||
|         -Wno-invalid-offsetof | ||||
|         -Wno-unused-parameter | ||||
|         -Wno-missing-field-initializers | ||||
|     ) | ||||
| 
 | ||||
|     if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang | ||||
|  | ||||
| @ -73,16 +73,15 @@ void Manager::BufferReleaseAndRegister() { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, | ||||
|                             [[maybe_unused]] const u32 max_count, | ||||
| u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, | ||||
|                             [[maybe_unused]] const bool filter) { | ||||
|     std::scoped_lock l{mutex}; | ||||
| 
 | ||||
|     LinkToManager(); | ||||
| 
 | ||||
|     auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)}; | ||||
|     if (input_devices.size() > 1) { | ||||
|         names.emplace_back("Uac"); | ||||
|     if (!input_devices.empty() && !names.empty()) { | ||||
|         names[0] = Renderer::AudioDevice::AudioDeviceName("Uac"); | ||||
|         return 1; | ||||
|     } | ||||
|     return 0; | ||||
|  | ||||
| @ -60,13 +60,11 @@ public: | ||||
|      * Get a list of audio in device names. | ||||
|      * | ||||
|      * @param names     - Output container to write names to. | ||||
|      * @param max_count - Maximum number of device names to write. Unused | ||||
|      * @param filter    - Should the list be filtered? Unused. | ||||
|      * | ||||
|      * @return Number of names written. | ||||
|      */ | ||||
|     u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count, | ||||
|                        bool filter); | ||||
|     u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter); | ||||
| 
 | ||||
|     /// Core system
 | ||||
|     Core::System& system; | ||||
|  | ||||
| @ -146,7 +146,11 @@ public: | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             tags[released++] = tag; | ||||
|             if (released < tags.size()) { | ||||
|                 tags[released] = tag; | ||||
|             } | ||||
| 
 | ||||
|             released++; | ||||
| 
 | ||||
|             if (released >= tags.size()) { | ||||
|                 break; | ||||
|  | ||||
| @ -28,8 +28,8 @@ OpusDecoder::~OpusDecoder() { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, | ||||
|                                u64 transfer_memory_size) { | ||||
| Result OpusDecoder::Initialize(const OpusParametersEx& params, | ||||
|                                Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { | ||||
|     auto frame_size{params.use_large_frame_size ? 5760 : 1920}; | ||||
|     shared_buffer_size = transfer_memory_size; | ||||
|     shared_buffer = std::make_unique<u8[]>(shared_buffer_size); | ||||
| @ -59,7 +59,7 @@ Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params, | ||||
| Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params, | ||||
|                                Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { | ||||
|     auto frame_size{params.use_large_frame_size ? 5760 : 1920}; | ||||
|     shared_buffer_size = transfer_memory_size; | ||||
|  | ||||
| @ -22,10 +22,10 @@ public: | ||||
|     explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_); | ||||
|     ~OpusDecoder(); | ||||
| 
 | ||||
|     Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, | ||||
|                       u64 transfer_memory_size); | ||||
|     Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory, | ||||
|     Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, | ||||
|                       u64 transfer_memory_size); | ||||
|     Result Initialize(const OpusMultiStreamParametersEx& params, | ||||
|                       Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size); | ||||
|     Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count, | ||||
|                              std::span<const u8> input_data, std::span<u8> output_data, bool reset); | ||||
|     Result SetContext([[maybe_unused]] std::span<const u8> context); | ||||
|  | ||||
| @ -38,7 +38,7 @@ OpusDecoderManager::OpusDecoderManager(Core::System& system_) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) { | ||||
| Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) { | ||||
|     OpusParametersEx ex{ | ||||
|         .sample_rate = params.sample_rate, | ||||
|         .channel_count = params.channel_count, | ||||
| @ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_si | ||||
|     R_RETURN(GetWorkBufferSizeExEx(ex, out_size)); | ||||
| } | ||||
| 
 | ||||
| Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) { | ||||
| Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) { | ||||
|     R_RETURN(GetWorkBufferSizeExEx(params, out_size)); | ||||
| } | ||||
| 
 | ||||
| Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) { | ||||
| Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) { | ||||
|     R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount); | ||||
|     R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); | ||||
| 
 | ||||
| @ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, | ||||
|                                                            u64& out_size) { | ||||
| Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, | ||||
|                                                            u32& out_size) { | ||||
|     OpusMultiStreamParametersEx ex{ | ||||
|         .sample_rate = params.sample_rate, | ||||
|         .channel_count = params.channel_count, | ||||
| @ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParame | ||||
|     R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size)); | ||||
| } | ||||
| 
 | ||||
| Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, | ||||
|                                                              u64& out_size) { | ||||
| Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx( | ||||
|     const OpusMultiStreamParametersEx& params, u32& out_size) { | ||||
|     R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size)); | ||||
| } | ||||
| 
 | ||||
| Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, | ||||
|                                                                u64& out_size) { | ||||
| Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx( | ||||
|     const OpusMultiStreamParametersEx& params, u32& out_size) { | ||||
|     R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount); | ||||
|     R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); | ||||
|     R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count, | ||||
|  | ||||
| @ -22,17 +22,19 @@ public: | ||||
|         return hardware_opus; | ||||
|     } | ||||
| 
 | ||||
|     Result GetWorkBufferSize(OpusParameters& params, u64& out_size); | ||||
|     Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size); | ||||
|     Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size); | ||||
|     Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size); | ||||
|     Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size); | ||||
|     Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size); | ||||
|     Result GetWorkBufferSize(const OpusParameters& params, u32& out_size); | ||||
|     Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size); | ||||
|     Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size); | ||||
|     Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size); | ||||
|     Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params, | ||||
|                                              u32& out_size); | ||||
|     Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params, | ||||
|                                                u32& out_size); | ||||
| 
 | ||||
| private: | ||||
|     Core::System& system; | ||||
|     HardwareOpus hardware_opus; | ||||
|     std::array<u64, MaxChannels> required_workbuffer_sizes{}; | ||||
|     std::array<u32, MaxChannels> required_workbuffer_sizes{}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace AudioCore::OpusDecoder
 | ||||
|  | ||||
| @ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_) | ||||
|     opus_decoder.SetSharedMemory(shared_memory); | ||||
| } | ||||
| 
 | ||||
| u64 HardwareOpus::GetWorkBufferSize(u32 channel) { | ||||
| u32 HardwareOpus::GetWorkBufferSize(u32 channel) { | ||||
|     if (!opus_decoder.IsRunning()) { | ||||
|         return 0; | ||||
|     } | ||||
| @ -55,10 +55,10 @@ u64 HardwareOpus::GetWorkBufferSize(u32 channel) { | ||||
|                   ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg); | ||||
|         return 0; | ||||
|     } | ||||
|     return shared_memory.dsp_return_data[0]; | ||||
|     return static_cast<u32>(shared_memory.dsp_return_data[0]); | ||||
| } | ||||
| 
 | ||||
| u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { | ||||
| u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { | ||||
|     std::scoped_lock l{mutex}; | ||||
|     shared_memory.host_send_data[0] = total_stream_count; | ||||
|     shared_memory.host_send_data[1] = stereo_stream_count; | ||||
| @ -70,7 +70,7 @@ u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st | ||||
|                   ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg); | ||||
|         return 0; | ||||
|     } | ||||
|     return shared_memory.dsp_return_data[0]; | ||||
|     return static_cast<u32>(shared_memory.dsp_return_data[0]); | ||||
| } | ||||
| 
 | ||||
| Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, | ||||
| @ -94,8 +94,9 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, | ||||
| 
 | ||||
| Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, | ||||
|                                                        u32 total_stream_count, | ||||
|                                                        u32 stereo_stream_count, void* mappings, | ||||
|                                                        void* buffer, u64 buffer_size) { | ||||
|                                                        u32 stereo_stream_count, | ||||
|                                                        const void* mappings, void* buffer, | ||||
|                                                        u64 buffer_size) { | ||||
|     std::scoped_lock l{mutex}; | ||||
|     shared_memory.host_send_data[0] = (u64)buffer; | ||||
|     shared_memory.host_send_data[1] = buffer_size; | ||||
|  | ||||
| @ -16,14 +16,14 @@ class HardwareOpus { | ||||
| public: | ||||
|     HardwareOpus(Core::System& system); | ||||
| 
 | ||||
|     u64 GetWorkBufferSize(u32 channel); | ||||
|     u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count); | ||||
|     u32 GetWorkBufferSize(u32 channel); | ||||
|     u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count); | ||||
| 
 | ||||
|     Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, | ||||
|                                   u64 buffer_size); | ||||
|     Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, | ||||
|                                              u32 totaL_stream_count, u32 stereo_stream_count, | ||||
|                                              void* mappings, void* buffer, u64 buffer_size); | ||||
|                                              const void* mappings, void* buffer, u64 buffer_size); | ||||
|     Result ShutdownDecodeObject(void* buffer, u64 buffer_size); | ||||
|     Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size); | ||||
|     Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size, | ||||
|  | ||||
| @ -20,7 +20,7 @@ struct OpusParametersEx { | ||||
|     /* 0x00 */ u32 sample_rate; | ||||
|     /* 0x04 */ u32 channel_count; | ||||
|     /* 0x08 */ bool use_large_frame_size; | ||||
|     /* 0x09 */ INSERT_PADDING_BYTES(7); | ||||
|     /* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7); | ||||
| }; // size = 0x10
 | ||||
| static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!"); | ||||
| 
 | ||||
| @ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx { | ||||
|     /* 0x08 */ u32 total_stream_count; | ||||
|     /* 0x0C */ u32 stereo_stream_count; | ||||
|     /* 0x10 */ bool use_large_frame_size; | ||||
|     /* 0x11 */ INSERT_PADDING_BYTES(7); | ||||
|     /* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7); | ||||
|     /* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings; | ||||
| }; // size = 0x118
 | ||||
| static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118, | ||||
|  | ||||
| @ -36,8 +36,7 @@ AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id | ||||
|     : output_sink{system.AudioCore().GetOutputSink()}, | ||||
|       applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {} | ||||
| 
 | ||||
| u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, | ||||
|                                      const size_t max_count) const { | ||||
| u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const { | ||||
|     std::span<const AudioDeviceName> names{}; | ||||
| 
 | ||||
|     if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) { | ||||
| @ -46,19 +45,18 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, | ||||
|         names = device_names; | ||||
|     } | ||||
| 
 | ||||
|     const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))}; | ||||
|     const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))}; | ||||
|     for (u32 i = 0; i < out_count; i++) { | ||||
|         out_buffer.push_back(names[i]); | ||||
|         out_buffer[i] = names[i]; | ||||
|     } | ||||
|     return out_count; | ||||
| } | ||||
| 
 | ||||
| u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, | ||||
|                                            const size_t max_count) const { | ||||
|     const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))}; | ||||
| u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const { | ||||
|     const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))}; | ||||
| 
 | ||||
|     for (u32 i = 0; i < out_count; i++) { | ||||
|         out_buffer.push_back(output_device_names[i]); | ||||
|         out_buffer[i] = output_device_names[i]; | ||||
|     } | ||||
|     return out_count; | ||||
| } | ||||
|  | ||||
| @ -36,20 +36,18 @@ public: | ||||
|      * Get a list of the available output devices. | ||||
|      * | ||||
|      * @param out_buffer - Output buffer to write the available device names. | ||||
|      * @param max_count  - Maximum number of devices to write (count of out_buffer). | ||||
|      * @return Number of device names written. | ||||
|      */ | ||||
|     u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const; | ||||
|     u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Get a list of the available output devices. | ||||
|      * Different to above somehow... | ||||
|      * | ||||
|      * @param out_buffer - Output buffer to write the available device names. | ||||
|      * @param max_count  - Maximum number of devices to write (count of out_buffer). | ||||
|      * @return Number of device names written. | ||||
|      */ | ||||
|     u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const; | ||||
|     u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Set the volume of all streams in the backend sink. | ||||
|  | ||||
| @ -17,9 +17,8 @@ Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* ren | ||||
| 
 | ||||
| Result Renderer::Initialize(const AudioRendererParameterInternal& params, | ||||
|                             Kernel::KTransferMemory* transfer_memory, | ||||
|                             const u64 transfer_memory_size, const u32 process_handle, | ||||
|                             Kernel::KProcess& process, const u64 applet_resource_user_id, | ||||
|                             const s32 session_id) { | ||||
|                             const u64 transfer_memory_size, Kernel::KProcess* process_handle, | ||||
|                             const u64 applet_resource_user_id, const s32 session_id) { | ||||
|     if (params.execution_mode == ExecutionMode::Auto) { | ||||
|         if (!manager.AddSystem(system)) { | ||||
|             LOG_ERROR(Service_Audio, | ||||
| @ -30,7 +29,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params, | ||||
|     } | ||||
| 
 | ||||
|     initialized = true; | ||||
|     system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process, | ||||
|     system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, | ||||
|                       applet_resource_user_id, session_id); | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
|  | ||||
| @ -38,14 +38,14 @@ public: | ||||
|      * @param params                  - Input parameters to initialize the system with. | ||||
|      * @param transfer_memory         - Game-supplied memory for all workbuffers. Unused. | ||||
|      * @param transfer_memory_size    - Size of the transfer memory. Unused. | ||||
|      * @param process_handle          - Process handle, also used for memory. Unused. | ||||
|      * @param process_handle          - Process handle, also used for memory. | ||||
|      * @param applet_resource_user_id - Applet id for this renderer. Unused. | ||||
|      * @param session_id              - Session id of this renderer. | ||||
|      * @return Result code. | ||||
|      */ | ||||
|     Result Initialize(const AudioRendererParameterInternal& params, | ||||
|                       Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, | ||||
|                       u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id, | ||||
|                       Kernel::KProcess* process_handle, u64 applet_resource_user_id, | ||||
|                       s32 session_id); | ||||
| 
 | ||||
|     /**
 | ||||
|  | ||||
| @ -18,7 +18,7 @@ | ||||
| namespace AudioCore::Renderer { | ||||
| 
 | ||||
| InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_, | ||||
|                          const u32 process_handle_, BehaviorInfo& behaviour_) | ||||
|                          Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_) | ||||
|     : input{input_.data() + sizeof(UpdateDataHeader)}, | ||||
|       input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)}, | ||||
|       output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>( | ||||
|  | ||||
| @ -8,6 +8,10 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/service/audio/errors.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KProcess; | ||||
| } | ||||
| 
 | ||||
| namespace AudioCore::Renderer { | ||||
| class BehaviorInfo; | ||||
| class VoiceContext; | ||||
| @ -39,8 +43,8 @@ class InfoUpdater { | ||||
|     static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!"); | ||||
| 
 | ||||
| public: | ||||
|     explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle, | ||||
|                          BehaviorInfo& behaviour); | ||||
|     explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, | ||||
|                          Kernel::KProcess* process_handle, BehaviorInfo& behaviour); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Update the voice channel resources. | ||||
| @ -197,7 +201,7 @@ private: | ||||
|     /// Expected output size, see CheckConsumedSize
 | ||||
|     u64 expected_output_size; | ||||
|     /// Unused
 | ||||
|     u32 process_handle; | ||||
|     Kernel::KProcess* process_handle; | ||||
|     /// Behaviour
 | ||||
|     BehaviorInfo& behaviour; | ||||
| }; | ||||
|  | ||||
| @ -8,11 +8,11 @@ | ||||
| 
 | ||||
| namespace AudioCore::Renderer { | ||||
| 
 | ||||
| PoolMapper::PoolMapper(u32 process_handle_, bool force_map_) | ||||
| PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_) | ||||
|     : process_handle{process_handle_}, force_map{force_map_} {} | ||||
| 
 | ||||
| PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_, | ||||
|                        bool force_map_) | ||||
| PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_, | ||||
|                        u32 pool_count_, bool force_map_) | ||||
|     : process_handle{process_handle_}, pool_infos{pool_infos_.data()}, | ||||
|       pool_count{pool_count_}, force_map{force_map_} {} | ||||
| 
 | ||||
| @ -106,15 +106,17 @@ bool PoolMapper::IsForceMapEnabled() const { | ||||
|     return force_map; | ||||
| } | ||||
| 
 | ||||
| u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const { | ||||
| Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const { | ||||
|     switch (pool->GetLocation()) { | ||||
|     case MemoryPoolInfo::Location::CPU: | ||||
|         return process_handle; | ||||
|     case MemoryPoolInfo::Location::DSP: | ||||
|         return Kernel::Svc::CurrentProcess; | ||||
|         // return Kernel::Svc::CurrentProcess;
 | ||||
|         return nullptr; | ||||
|     } | ||||
|     LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!"); | ||||
|     return Kernel::Svc::CurrentProcess; | ||||
|     // return Kernel::Svc::CurrentProcess;
 | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr, | ||||
| @ -147,14 +149,14 @@ bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const | ||||
| } | ||||
| 
 | ||||
| bool PoolMapper::Unmap(MemoryPoolInfo& pool) const { | ||||
|     [[maybe_unused]] u32 handle{0}; | ||||
|     [[maybe_unused]] Kernel::KProcess* handle{}; | ||||
| 
 | ||||
|     switch (pool.GetLocation()) { | ||||
|     case MemoryPoolInfo::Location::CPU: | ||||
|         handle = process_handle; | ||||
|         break; | ||||
|     case MemoryPoolInfo::Location::DSP: | ||||
|         handle = Kernel::Svc::CurrentProcess; | ||||
|         // handle = Kernel::Svc::CurrentProcess;
 | ||||
|         break; | ||||
|     } | ||||
|     // nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);
 | ||||
|  | ||||
| @ -10,6 +10,10 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/service/audio/errors.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KProcess; | ||||
| } | ||||
| 
 | ||||
| namespace AudioCore::Renderer { | ||||
| class AddressInfo; | ||||
| 
 | ||||
| @ -18,9 +22,9 @@ class AddressInfo; | ||||
|  */ | ||||
| class PoolMapper { | ||||
| public: | ||||
|     explicit PoolMapper(u32 process_handle, bool force_map); | ||||
|     explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count, | ||||
|                         bool force_map); | ||||
|     explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map); | ||||
|     explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos, | ||||
|                         u32 pool_count, bool force_map); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Clear the usage state for all given pools. | ||||
| @ -98,7 +102,7 @@ public: | ||||
|      * @return CurrentProcessHandle if location == DSP, | ||||
|      *         the PoolMapper's process_handle if location == CPU | ||||
|      */ | ||||
|     u32 GetProcessHandle(const MemoryPoolInfo* pool) const; | ||||
|     Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Map the given region with the given handle. This is a no-op. | ||||
| @ -167,7 +171,7 @@ public: | ||||
| 
 | ||||
| private: | ||||
|     /// Process handle for this mapper, used when location == CPU
 | ||||
|     u32 process_handle; | ||||
|     Kernel::KProcess* process_handle{}; | ||||
|     /// List of memory pools assigned to this mapper
 | ||||
|     MemoryPoolInfo* pool_infos{}; | ||||
|     /// The number of pools
 | ||||
|  | ||||
| @ -102,8 +102,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_) | ||||
| 
 | ||||
| Result System::Initialize(const AudioRendererParameterInternal& params, | ||||
|                           Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, | ||||
|                           u32 process_handle_, Kernel::KProcess& process_, | ||||
|                           u64 applet_resource_user_id_, s32 session_id_) { | ||||
|                           Kernel::KProcess* process_handle_, u64 applet_resource_user_id_, | ||||
|                           s32 session_id_) { | ||||
|     if (!CheckValidRevision(params.revision)) { | ||||
|         return Service::Audio::ResultInvalidRevision; | ||||
|     } | ||||
| @ -119,7 +119,6 @@ Result System::Initialize(const AudioRendererParameterInternal& params, | ||||
|     behavior.SetUserLibRevision(params.revision); | ||||
| 
 | ||||
|     process_handle = process_handle_; | ||||
|     process = &process_; | ||||
|     applet_resource_user_id = applet_resource_user_id_; | ||||
|     session_id = session_id_; | ||||
| 
 | ||||
| @ -132,7 +131,8 @@ Result System::Initialize(const AudioRendererParameterInternal& params, | ||||
|     render_device = params.rendering_device; | ||||
|     execution_mode = params.execution_mode; | ||||
| 
 | ||||
|     process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size); | ||||
|     process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), | ||||
|                                           transfer_memory_size); | ||||
| 
 | ||||
|     // Note: We're not actually using the transfer memory because it's a pain to code for.
 | ||||
|     // Allocate the memory normally instead and hope the game doesn't try to read anything back
 | ||||
| @ -616,7 +616,7 @@ void System::SendCommandToDsp() { | ||||
|                 static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 * | ||||
|                                  (static_cast<f32>(render_time_limit_percent) / 100.0f))}; | ||||
|             audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit, | ||||
|                                             applet_resource_user_id, process, | ||||
|                                             applet_resource_user_id, process_handle, | ||||
|                                             reset_command_buffers); | ||||
|             reset_command_buffers = false; | ||||
|             command_buffer_size = command_size; | ||||
|  | ||||
| @ -74,14 +74,14 @@ public: | ||||
|      * @param params                  - Input parameters to initialize the system with. | ||||
|      * @param transfer_memory         - Game-supplied memory for all workbuffers. Unused. | ||||
|      * @param transfer_memory_size    - Size of the transfer memory. Unused. | ||||
|      * @param process_handle          - Process handle, also used for memory. Unused. | ||||
|      * @param process_handle          - Process handle, also used for memory. | ||||
|      * @param applet_resource_user_id - Applet id for this renderer. Unused. | ||||
|      * @param session_id              - Session id of this renderer. | ||||
|      * @return Result code. | ||||
|      */ | ||||
|     Result Initialize(const AudioRendererParameterInternal& params, | ||||
|                       Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, | ||||
|                       u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id, | ||||
|                       Kernel::KProcess* process_handle, u64 applet_resource_user_id, | ||||
|                       s32 session_id); | ||||
| 
 | ||||
|     /**
 | ||||
| @ -278,9 +278,7 @@ private: | ||||
|     /// Does what locks do
 | ||||
|     std::mutex lock{}; | ||||
|     /// Process this audio render is operating within, used for memory reads/writes.
 | ||||
|     Kernel::KProcess* process{}; | ||||
|     /// Handle for the process for this system, unused
 | ||||
|     u32 process_handle{}; | ||||
|     Kernel::KProcess* process_handle{}; | ||||
|     /// Applet resource id for this system, unused
 | ||||
|     u64 applet_resource_user_id{}; | ||||
|     /// Controls performance input and output
 | ||||
|  | ||||
| @ -67,9 +67,13 @@ public: | ||||
|         oboe::AudioStreamBuilder builder; | ||||
| 
 | ||||
|         const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream); | ||||
|         ASSERT(result == oboe::Result::OK); | ||||
|         if (result == oboe::Result::OK) { | ||||
|             return temp_stream->getChannelCount() >= 6 ? 6 : 2; | ||||
|         } | ||||
| 
 | ||||
|         return temp_stream->getChannelCount() >= 6 ? 6 : 2; | ||||
|         LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2", | ||||
|                   direction == oboe::Direction::Output ? "output" : "input"); | ||||
|         return 2; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|  | ||||
| @ -38,6 +38,10 @@ std::string StringFromBuffer(std::span<const u8> data) { | ||||
|     return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); | ||||
| } | ||||
| 
 | ||||
| std::string StringFromBuffer(std::span<const char> data) { | ||||
|     return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); | ||||
| } | ||||
| 
 | ||||
| // Turns "  hej " into "hej". Also handles tabs.
 | ||||
| std::string StripSpaces(const std::string& str) { | ||||
|     const std::size_t s = str.find_first_not_of(" \t\r\n"); | ||||
|  | ||||
| @ -19,6 +19,7 @@ namespace Common { | ||||
| [[nodiscard]] std::string ToUpper(std::string str); | ||||
| 
 | ||||
| [[nodiscard]] std::string StringFromBuffer(std::span<const u8> data); | ||||
| [[nodiscard]] std::string StringFromBuffer(std::span<const char> data); | ||||
| 
 | ||||
| [[nodiscard]] std::string StripSpaces(const std::string& s); | ||||
| [[nodiscard]] std::string StripQuotes(const std::string& s); | ||||
|  | ||||
| @ -494,23 +494,33 @@ add_library(core STATIC | ||||
|     hle/service/apm/apm_controller.h | ||||
|     hle/service/apm/apm_interface.cpp | ||||
|     hle/service/apm/apm_interface.h | ||||
|     hle/service/audio/audin_u.cpp | ||||
|     hle/service/audio/audin_u.h | ||||
|     hle/service/audio/audio.cpp | ||||
|     hle/service/audio/audio.h | ||||
|     hle/service/audio/audio_controller.cpp | ||||
|     hle/service/audio/audio_controller.h | ||||
|     hle/service/audio/audout_u.cpp | ||||
|     hle/service/audio/audout_u.h | ||||
|     hle/service/audio/audrec_a.cpp | ||||
|     hle/service/audio/audrec_a.h | ||||
|     hle/service/audio/audrec_u.cpp | ||||
|     hle/service/audio/audrec_u.h | ||||
|     hle/service/audio/audren_u.cpp | ||||
|     hle/service/audio/audren_u.h | ||||
|     hle/service/audio/audio_device.cpp | ||||
|     hle/service/audio/audio_device.h | ||||
|     hle/service/audio/audio_in_manager.cpp | ||||
|     hle/service/audio/audio_in_manager.h | ||||
|     hle/service/audio/audio_in.cpp | ||||
|     hle/service/audio/audio_in.h | ||||
|     hle/service/audio/audio_out_manager.cpp | ||||
|     hle/service/audio/audio_out_manager.h | ||||
|     hle/service/audio/audio_out.cpp | ||||
|     hle/service/audio/audio_out.h | ||||
|     hle/service/audio/audio_renderer_manager.cpp | ||||
|     hle/service/audio/audio_renderer_manager.h | ||||
|     hle/service/audio/audio_renderer.cpp | ||||
|     hle/service/audio/audio_renderer.h | ||||
|     hle/service/audio/audio.cpp | ||||
|     hle/service/audio/audio.h | ||||
|     hle/service/audio/errors.h | ||||
|     hle/service/audio/hwopus.cpp | ||||
|     hle/service/audio/hwopus.h | ||||
|     hle/service/audio/final_output_recorder_manager_for_applet.cpp | ||||
|     hle/service/audio/final_output_recorder_manager_for_applet.h | ||||
|     hle/service/audio/final_output_recorder_manager.cpp | ||||
|     hle/service/audio/final_output_recorder_manager.h | ||||
|     hle/service/audio/hardware_opus_decoder_manager.cpp | ||||
|     hle/service/audio/hardware_opus_decoder_manager.h | ||||
|     hle/service/audio/hardware_opus_decoder.cpp | ||||
|     hle/service/audio/hardware_opus_decoder.h | ||||
|     hle/service/bcat/backend/backend.cpp | ||||
|     hle/service/bcat/backend/backend.h | ||||
|     hle/service/bcat/bcat.cpp | ||||
|  | ||||
| @ -1,393 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "audio_core/in/audio_in_system.h" | ||||
| #include "audio_core/renderer/audio_device.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/scratch_buffer.h" | ||||
| #include "common/string_util.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/k_event.h" | ||||
| #include "core/hle/service/audio/audin_u.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::AudioIn; | ||||
| 
 | ||||
| class IAudioIn final : public ServiceFramework<IAudioIn> { | ||||
| public: | ||||
|     explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, | ||||
|                       const std::string& device_name, const AudioInParameter& in_params, | ||||
|                       Kernel::KProcess* handle, u64 applet_resource_user_id) | ||||
|         : ServiceFramework{system_, "IAudioIn"}, | ||||
|           service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, | ||||
|           process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IAudioIn::GetAudioInState, "GetAudioInState"}, | ||||
|             {1, &IAudioIn::Start, "Start"}, | ||||
|             {2, &IAudioIn::Stop, "Stop"}, | ||||
|             {3, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBuffer"}, | ||||
|             {4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"}, | ||||
|             {5, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffer"}, | ||||
|             {6, &IAudioIn::ContainsAudioInBuffer, "ContainsAudioInBuffer"}, | ||||
|             {7, &IAudioIn::AppendAudioInBuffer, "AppendUacInBuffer"}, | ||||
|             {8, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBufferAuto"}, | ||||
|             {9, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffersAuto"}, | ||||
|             {10, &IAudioIn::AppendAudioInBuffer, "AppendUacInBufferAuto"}, | ||||
|             {11, &IAudioIn::GetAudioInBufferCount, "GetAudioInBufferCount"}, | ||||
|             {12, &IAudioIn::SetDeviceGain, "SetDeviceGain"}, | ||||
|             {13, &IAudioIn::GetDeviceGain, "GetDeviceGain"}, | ||||
|             {14, &IAudioIn::FlushAudioInBuffers, "FlushAudioInBuffers"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         process->Open(); | ||||
| 
 | ||||
|         if (impl->GetSystem() | ||||
|                 .Initialize(device_name, in_params, handle, applet_resource_user_id) | ||||
|                 .IsError()) { | ||||
|             LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ~IAudioIn() override { | ||||
|         impl->Free(); | ||||
|         service_context.CloseEvent(event); | ||||
|         process->Close(); | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] std::shared_ptr<In> GetImpl() { | ||||
|         return impl; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void GetAudioInState(HLERequestContext& ctx) { | ||||
|         const auto state = static_cast<u32>(impl->GetState()); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. State={}", state); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(state); | ||||
|     } | ||||
| 
 | ||||
|     void Start(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto result = impl->StartSystem(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void Stop(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto result = impl->StopSystem(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void AppendAudioInBuffer(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         u64 tag = rp.PopRaw<u64>(); | ||||
| 
 | ||||
|         const auto in_buffer_size{ctx.GetReadBufferSize()}; | ||||
|         if (in_buffer_size < sizeof(AudioInBuffer)) { | ||||
|             LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!"); | ||||
|         } | ||||
| 
 | ||||
|         const auto& in_buffer = ctx.ReadBuffer(); | ||||
|         AudioInBuffer buffer{}; | ||||
|         std::memcpy(&buffer, in_buffer.data(), sizeof(AudioInBuffer)); | ||||
| 
 | ||||
|         [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()}; | ||||
|         LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag); | ||||
| 
 | ||||
|         auto result = impl->AppendBuffer(buffer, tag); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void RegisterBufferEvent(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto& buffer_event = impl->GetBufferEvent(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.PushCopyObjects(buffer_event); | ||||
|     } | ||||
| 
 | ||||
|     void GetReleasedAudioInBuffer(HLERequestContext& ctx) { | ||||
|         const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); | ||||
|         released_buffer.resize_destructive(write_buffer_size); | ||||
|         released_buffer[0] = 0; | ||||
| 
 | ||||
|         const auto count = impl->GetReleasedBuffers(released_buffer); | ||||
| 
 | ||||
|         LOG_TRACE(Service_Audio, "called. Session {} released {} buffers", | ||||
|                   impl->GetSystem().GetSessionId(), count); | ||||
| 
 | ||||
|         ctx.WriteBuffer(released_buffer); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(count); | ||||
|     } | ||||
| 
 | ||||
|     void ContainsAudioInBuffer(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         const u64 tag{rp.Pop<u64>()}; | ||||
|         const auto buffer_queued{impl->ContainsAudioBuffer(tag)}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(buffer_queued); | ||||
|     } | ||||
| 
 | ||||
|     void GetAudioInBufferCount(HLERequestContext& ctx) { | ||||
|         const auto buffer_count = impl->GetBufferCount(); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(buffer_count); | ||||
|     } | ||||
| 
 | ||||
|     void SetDeviceGain(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         const auto volume{rp.Pop<f32>()}; | ||||
|         LOG_DEBUG(Service_Audio, "called. Gain {}", volume); | ||||
| 
 | ||||
|         impl->SetVolume(volume); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| 
 | ||||
|     void GetDeviceGain(HLERequestContext& ctx) { | ||||
|         auto volume{impl->GetVolume()}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Gain {}", volume); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(volume); | ||||
|     } | ||||
| 
 | ||||
|     void FlushAudioInBuffers(HLERequestContext& ctx) { | ||||
|         bool flushed{impl->FlushAudioInBuffers()}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(flushed); | ||||
|     } | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     Kernel::KEvent* event; | ||||
|     Kernel::KProcess* process; | ||||
|     std::shared_ptr<AudioCore::AudioIn::In> impl; | ||||
|     Common::ScratchBuffer<u64> released_buffer; | ||||
| }; | ||||
| 
 | ||||
| AudInU::AudInU(Core::System& system_) | ||||
|     : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"}, | ||||
|       impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &AudInU::ListAudioIns, "ListAudioIns"}, | ||||
|         {1, &AudInU::OpenAudioIn, "OpenAudioIn"}, | ||||
|         {2, &AudInU::ListAudioIns, "ListAudioInsAuto"}, | ||||
|         {3, &AudInU::OpenAudioIn, "OpenAudioInAuto"}, | ||||
|         {4, &AudInU::ListAudioInsAutoFiltered, "ListAudioInsAutoFiltered"}, | ||||
|         {5, &AudInU::OpenAudioInProtocolSpecified, "OpenAudioInProtocolSpecified"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| AudInU::~AudInU() = default; | ||||
| 
 | ||||
| void AudInU::ListAudioIns(HLERequestContext& ctx) { | ||||
|     using namespace AudioCore::Renderer; | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|     const auto write_count = | ||||
|         static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); | ||||
|     std::vector<AudioDevice::AudioDeviceName> device_names{}; | ||||
| 
 | ||||
|     u32 out_count{0}; | ||||
|     if (write_count > 0) { | ||||
|         out_count = impl->GetDeviceNames(device_names, write_count, false); | ||||
|         ctx.WriteBuffer(device_names); | ||||
|     } | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.Push(out_count); | ||||
| } | ||||
| 
 | ||||
| void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) { | ||||
|     using namespace AudioCore::Renderer; | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|     const auto write_count = | ||||
|         static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); | ||||
|     std::vector<AudioDevice::AudioDeviceName> device_names{}; | ||||
| 
 | ||||
|     u32 out_count{0}; | ||||
|     if (write_count > 0) { | ||||
|         out_count = impl->GetDeviceNames(device_names, write_count, true); | ||||
|         ctx.WriteBuffer(device_names); | ||||
|     } | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.Push(out_count); | ||||
| } | ||||
| 
 | ||||
| void AudInU::OpenAudioIn(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     auto in_params{rp.PopRaw<AudioInParameter>()}; | ||||
|     auto applet_resource_user_id{rp.PopRaw<u64>()}; | ||||
|     const auto device_name_data{ctx.ReadBuffer()}; | ||||
|     auto device_name = Common::StringFromBuffer(device_name_data); | ||||
|     auto handle{ctx.GetCopyHandle(0)}; | ||||
| 
 | ||||
|     auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||||
|     if (process.IsNull()) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultUnknown); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     std::scoped_lock l{impl->mutex}; | ||||
|     auto link{impl->LinkToManager()}; | ||||
|     if (link.IsError()) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(link); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     size_t new_session_id{}; | ||||
|     auto result{impl->AcquireSessionId(new_session_id)}; | ||||
|     if (result.IsError()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, | ||||
|               impl->num_free_sessions); | ||||
| 
 | ||||
|     auto audio_in = | ||||
|         std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, | ||||
|                                    process.GetPointerUnsafe(), applet_resource_user_id); | ||||
|     impl->sessions[new_session_id] = audio_in->GetImpl(); | ||||
|     impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; | ||||
| 
 | ||||
|     auto& out_system = impl->sessions[new_session_id]->GetSystem(); | ||||
|     AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(), | ||||
|                                         .channel_count = out_system.GetChannelCount(), | ||||
|                                         .sample_format = | ||||
|                                             static_cast<u32>(out_system.GetSampleFormat()), | ||||
|                                         .state = static_cast<u32>(out_system.GetState())}; | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 6, 0, 1}; | ||||
| 
 | ||||
|     std::string out_name{out_system.GetName()}; | ||||
|     ctx.WriteBuffer(out_name); | ||||
| 
 | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushRaw<AudioInParameterInternal>(out_params); | ||||
|     rb.PushIpcInterface<IAudioIn>(audio_in); | ||||
| } | ||||
| 
 | ||||
| void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     auto protocol_specified{rp.PopRaw<u64>()}; | ||||
|     auto in_params{rp.PopRaw<AudioInParameter>()}; | ||||
|     auto applet_resource_user_id{rp.PopRaw<u64>()}; | ||||
|     const auto device_name_data{ctx.ReadBuffer()}; | ||||
|     auto device_name = Common::StringFromBuffer(device_name_data); | ||||
|     auto handle{ctx.GetCopyHandle(0)}; | ||||
| 
 | ||||
|     auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||||
|     if (process.IsNull()) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultUnknown); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     std::scoped_lock l{impl->mutex}; | ||||
|     auto link{impl->LinkToManager()}; | ||||
|     if (link.IsError()) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(link); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     size_t new_session_id{}; | ||||
|     auto result{impl->AcquireSessionId(new_session_id)}; | ||||
|     if (result.IsError()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, | ||||
|               impl->num_free_sessions); | ||||
| 
 | ||||
|     auto audio_in = | ||||
|         std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, | ||||
|                                    process.GetPointerUnsafe(), applet_resource_user_id); | ||||
|     impl->sessions[new_session_id] = audio_in->GetImpl(); | ||||
|     impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; | ||||
| 
 | ||||
|     auto& out_system = impl->sessions[new_session_id]->GetSystem(); | ||||
|     AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(), | ||||
|                                         .channel_count = out_system.GetChannelCount(), | ||||
|                                         .sample_format = | ||||
|                                             static_cast<u32>(out_system.GetSampleFormat()), | ||||
|                                         .state = static_cast<u32>(out_system.GetState())}; | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 6, 0, 1}; | ||||
| 
 | ||||
|     std::string out_name{out_system.GetName()}; | ||||
|     if (protocol_specified == 0) { | ||||
|         if (out_system.IsUac()) { | ||||
|             out_name = "UacIn"; | ||||
|         } else { | ||||
|             out_name = "DeviceIn"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ctx.WriteBuffer(out_name); | ||||
| 
 | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushRaw<AudioInParameterInternal>(out_params); | ||||
|     rb.PushIpcInterface<IAudioIn>(audio_in); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,38 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/audio_in_manager.h" | ||||
| #include "audio_core/in/audio_in.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| class System; | ||||
| } | ||||
| 
 | ||||
| namespace AudioCore::AudioOut { | ||||
| class Manager; | ||||
| class In; | ||||
| } // namespace AudioCore::AudioOut
 | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class AudInU final : public ServiceFramework<AudInU> { | ||||
| public: | ||||
|     explicit AudInU(Core::System& system_); | ||||
|     ~AudInU() override; | ||||
| 
 | ||||
| private: | ||||
|     void ListAudioIns(HLERequestContext& ctx); | ||||
|     void ListAudioInsAutoFiltered(HLERequestContext& ctx); | ||||
|     void OpenInOutImpl(HLERequestContext& ctx); | ||||
|     void OpenAudioIn(HLERequestContext& ctx); | ||||
|     void OpenAudioInProtocolSpecified(HLERequestContext& ctx); | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     std::unique_ptr<AudioCore::AudioIn::Manager> impl; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -2,14 +2,14 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/core.h" | ||||
| #include "core/hle/service/audio/audin_u.h" | ||||
| #include "core/hle/service/audio/audio.h" | ||||
| #include "core/hle/service/audio/audio_controller.h" | ||||
| #include "core/hle/service/audio/audout_u.h" | ||||
| #include "core/hle/service/audio/audrec_a.h" | ||||
| #include "core/hle/service/audio/audrec_u.h" | ||||
| #include "core/hle/service/audio/audren_u.h" | ||||
| #include "core/hle/service/audio/hwopus.h" | ||||
| #include "core/hle/service/audio/audio_in_manager.h" | ||||
| #include "core/hle/service/audio/audio_out_manager.h" | ||||
| #include "core/hle/service/audio/audio_renderer_manager.h" | ||||
| #include "core/hle/service/audio/final_output_recorder_manager.h" | ||||
| #include "core/hle/service/audio/final_output_recorder_manager_for_applet.h" | ||||
| #include "core/hle/service/audio/hardware_opus_decoder_manager.h" | ||||
| #include "core/hle/service/server_manager.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| @ -19,12 +19,16 @@ void LoopProcess(Core::System& system) { | ||||
|     auto server_manager = std::make_unique<ServerManager>(system); | ||||
| 
 | ||||
|     server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system)); | ||||
|     server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system)); | ||||
|     server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system)); | ||||
|     server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system)); | ||||
|     server_manager->RegisterNamedService("audrec:u", std::make_shared<AudRecU>(system)); | ||||
|     server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system)); | ||||
|     server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system)); | ||||
|     server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system)); | ||||
|     server_manager->RegisterNamedService("audout:u", std::make_shared<IAudioOutManager>(system)); | ||||
|     server_manager->RegisterNamedService( | ||||
|         "audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system)); | ||||
|     server_manager->RegisterNamedService("audrec:u", | ||||
|                                          std::make_shared<IFinalOutputRecorderManager>(system)); | ||||
|     server_manager->RegisterNamedService("audren:u", | ||||
|                                          std::make_shared<IAudioRendererManager>(system)); | ||||
|     server_manager->RegisterNamedService("hwopus", | ||||
|                                          std::make_shared<IHardwareOpusDecoderManager>(system)); | ||||
|     ServerManager::RunServer(std::move(server_manager)); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -16,27 +16,27 @@ IAudioController::IAudioController(Core::System& system_) | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, nullptr, "GetTargetVolume"}, | ||||
|         {1, nullptr, "SetTargetVolume"}, | ||||
|         {2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"}, | ||||
|         {3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"}, | ||||
|         {2, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"}, | ||||
|         {3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"}, | ||||
|         {4, nullptr, "IsTargetMute"}, | ||||
|         {5, nullptr, "SetTargetMute"}, | ||||
|         {6, nullptr, "IsTargetConnected"}, | ||||
|         {7, nullptr, "SetDefaultTarget"}, | ||||
|         {8, nullptr, "GetDefaultTarget"}, | ||||
|         {9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"}, | ||||
|         {10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"}, | ||||
|         {9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"}, | ||||
|         {10, D<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"}, | ||||
|         {11, nullptr, "SetForceMutePolicy"}, | ||||
|         {12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"}, | ||||
|         {13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"}, | ||||
|         {14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"}, | ||||
|         {12, D<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"}, | ||||
|         {13, D<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"}, | ||||
|         {14, D<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"}, | ||||
|         {15, nullptr, "SetOutputTarget"}, | ||||
|         {16, nullptr, "SetInputTargetForceEnabled"}, | ||||
|         {17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"}, | ||||
|         {18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"}, | ||||
|         {17, D<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"}, | ||||
|         {18, D<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"}, | ||||
|         {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"}, | ||||
|         {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"}, | ||||
|         {21, nullptr, "GetAudioOutputTargetForPlayReport"}, | ||||
|         {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"}, | ||||
|         {22, D<&IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent>, "NotifyHeadphoneVolumeWarningDisplayedEvent"}, | ||||
|         {23, nullptr, "SetSystemOutputMasterVolume"}, | ||||
|         {24, nullptr, "GetSystemOutputMasterVolume"}, | ||||
|         {25, nullptr, "GetAudioVolumeDataForPlayReport"}, | ||||
| @ -44,11 +44,11 @@ IAudioController::IAudioController(Core::System& system_) | ||||
|         {27, nullptr, "SetVolumeMappingTableForDev"}, | ||||
|         {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, | ||||
|         {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, | ||||
|         {30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"}, | ||||
|         {31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"}, | ||||
|         {30, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"}, | ||||
|         {31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"}, | ||||
|         {32, nullptr, "GetActiveOutputTarget"}, | ||||
|         {33, nullptr, "GetTargetDeviceInfo"}, | ||||
|         {34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"}, | ||||
|         {34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"}, | ||||
|         {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, | ||||
|         {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, | ||||
|         {37, nullptr, "SetHearingProtectionSafeguardEnabled"}, | ||||
| @ -150,6 +150,11 @@ Result IAudioController::GetHeadphoneOutputLevelMode( | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent() { | ||||
|     LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) { | ||||
|     LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled); | ||||
| 
 | ||||
|  | ||||
| @ -45,6 +45,7 @@ private: | ||||
|                                 Set::AudioOutputMode output_mode); | ||||
|     Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode); | ||||
|     Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode); | ||||
|     Result NotifyHeadphoneVolumeWarningDisplayedEvent(); | ||||
|     Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled); | ||||
|     Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled); | ||||
|     Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event); | ||||
|  | ||||
							
								
								
									
										163
									
								
								src/core/hle/service/audio/audio_device.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/core/hle/service/audio/audio_device.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,163 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "audio_core/audio_core.h" | ||||
| #include "common/string_util.h" | ||||
| #include "core/hle/service/audio/audio_device.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::Renderer; | ||||
| 
 | ||||
| IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision, | ||||
|                            u32 device_num) | ||||
|     : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"}, | ||||
|       impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)}, | ||||
|       event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} { | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"}, | ||||
|         {1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"}, | ||||
|         {2, D<&IAudioDevice::GetAudioDeviceOutputVolume>, "GetAudioDeviceOutputVolume"}, | ||||
|         {3, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioDeviceName"}, | ||||
|         {4, D<&IAudioDevice::QueryAudioDeviceSystemEvent>, "QueryAudioDeviceSystemEvent"}, | ||||
|         {5, D<&IAudioDevice::GetActiveChannelCount>, "GetActiveChannelCount"}, | ||||
|         {6, D<&IAudioDevice::ListAudioDeviceNameAuto>, "ListAudioDeviceNameAuto"}, | ||||
|         {7, D<&IAudioDevice::SetAudioDeviceOutputVolumeAuto>, "SetAudioDeviceOutputVolumeAuto"}, | ||||
|         {8, D<&IAudioDevice::GetAudioDeviceOutputVolumeAuto>, "GetAudioDeviceOutputVolumeAuto"}, | ||||
|         {10, D<&IAudioDevice::GetActiveAudioDeviceNameAuto>, "GetActiveAudioDeviceNameAuto"}, | ||||
|         {11, D<&IAudioDevice::QueryAudioDeviceInputEvent>, "QueryAudioDeviceInputEvent"}, | ||||
|         {12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"}, | ||||
|         {13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"}, | ||||
|         {14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"}, | ||||
|     }; | ||||
|     RegisterHandlers(functions); | ||||
| 
 | ||||
|     event->Signal(); | ||||
| } | ||||
| 
 | ||||
| IAudioDevice::~IAudioDevice() { | ||||
|     service_context.CloseEvent(event); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::ListAudioDeviceName( | ||||
|     OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) { | ||||
|     R_RETURN(this->ListAudioDeviceNameAuto(out_names, out_count)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::SetAudioDeviceOutputVolume( | ||||
|     InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume) { | ||||
|     R_RETURN(this->SetAudioDeviceOutputVolumeAuto(name, volume)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::GetAudioDeviceOutputVolume( | ||||
|     Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name) { | ||||
|     R_RETURN(this->GetAudioDeviceOutputVolumeAuto(out_volume, name)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::GetActiveAudioDeviceName( | ||||
|     OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name) { | ||||
|     R_RETURN(this->GetActiveAudioDeviceNameAuto(out_name)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::ListAudioDeviceNameAuto( | ||||
|     OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names, | ||||
|     Out<s32> out_count) { | ||||
|     *out_count = impl->ListAudioDeviceName(out_names); | ||||
| 
 | ||||
|     std::string out{}; | ||||
|     for (s32 i = 0; i < *out_count; i++) { | ||||
|         std::string a{}; | ||||
|         u32 j = 0; | ||||
|         while (out_names[i].name[j] != '\0') { | ||||
|             a += out_names[i].name[j]; | ||||
|             j++; | ||||
|         } | ||||
|         out += "\n\t" + a; | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called.\nNames={}", out); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::SetAudioDeviceOutputVolumeAuto( | ||||
|     InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume) { | ||||
|     R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer); | ||||
| 
 | ||||
|     const std::string device_name = Common::StringFromBuffer(name[0].name); | ||||
|     LOG_DEBUG(Service_Audio, "called. name={}, volume={}", device_name, volume); | ||||
| 
 | ||||
|     if (device_name == "AudioTvOutput") { | ||||
|         impl->SetDeviceVolumes(volume); | ||||
|     } | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::GetAudioDeviceOutputVolumeAuto( | ||||
|     Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name) { | ||||
|     R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer); | ||||
| 
 | ||||
|     const std::string device_name = Common::StringFromBuffer(name[0].name); | ||||
|     LOG_DEBUG(Service_Audio, "called. Name={}", device_name); | ||||
| 
 | ||||
|     *out_volume = 1.0f; | ||||
|     if (device_name == "AudioTvOutput") { | ||||
|         *out_volume = impl->GetDeviceVolume(device_name); | ||||
|     } | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::GetActiveAudioDeviceNameAuto( | ||||
|     OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name) { | ||||
|     R_UNLESS(!out_name.empty(), Audio::ResultInsufficientBuffer); | ||||
|     out_name[0] = AudioDevice::AudioDeviceName("AudioTvOutput"); | ||||
|     LOG_DEBUG(Service_Audio, "(STUBBED) called"); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||||
|     LOG_DEBUG(Service_Audio, "(STUBBED) called"); | ||||
|     event->Signal(); | ||||
|     *out_event = &event->GetReadableEvent(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||||
|     LOG_DEBUG(Service_Audio, "(STUBBED) called"); | ||||
|     *out_event = &event->GetReadableEvent(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     *out_event = &event->GetReadableEvent(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::GetActiveChannelCount(Out<u32> out_active_channel_count) { | ||||
|     *out_active_channel_count = system.AudioCore().GetOutputSink().GetSystemChannels(); | ||||
|     LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", *out_active_channel_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioDevice::ListAudioOutputDeviceName( | ||||
|     OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) { | ||||
|     *out_count = impl->ListAudioOutputDeviceName(out_names); | ||||
| 
 | ||||
|     std::string out{}; | ||||
|     for (s32 i = 0; i < *out_count; i++) { | ||||
|         std::string a{}; | ||||
|         u32 j = 0; | ||||
|         while (out_names[i].name[j] != '\0') { | ||||
|             a += out_names[i].name[j]; | ||||
|             j++; | ||||
|         } | ||||
|         out += "\n\t" + a; | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called.\nNames={}", out); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										58
									
								
								src/core/hle/service/audio/audio_device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/core/hle/service/audio/audio_device.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/renderer/audio_device.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KReadableEvent; | ||||
| } | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| using AudioCore::Renderer::AudioDevice; | ||||
| 
 | ||||
| class IAudioDevice final : public ServiceFramework<IAudioDevice> { | ||||
| 
 | ||||
| public: | ||||
|     explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision, | ||||
|                           u32 device_num); | ||||
|     ~IAudioDevice() override; | ||||
| 
 | ||||
| private: | ||||
|     Result ListAudioDeviceName( | ||||
|         OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, | ||||
|         Out<s32> out_count); | ||||
|     Result SetAudioDeviceOutputVolume( | ||||
|         InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume); | ||||
|     Result GetAudioDeviceOutputVolume( | ||||
|         Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name); | ||||
|     Result GetActiveAudioDeviceName( | ||||
|         OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name); | ||||
|     Result ListAudioDeviceNameAuto( | ||||
|         OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names, | ||||
|         Out<s32> out_count); | ||||
|     Result SetAudioDeviceOutputVolumeAuto( | ||||
|         InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume); | ||||
|     Result GetAudioDeviceOutputVolumeAuto( | ||||
|         Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name); | ||||
|     Result GetActiveAudioDeviceNameAuto( | ||||
|         OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name); | ||||
|     Result QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||||
|     Result QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||||
|     Result QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||||
|     Result GetActiveChannelCount(Out<u32> out_active_channel_count); | ||||
|     Result ListAudioOutputDeviceName( | ||||
|         OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, | ||||
|         Out<s32> out_count); | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     std::unique_ptr<AudioCore::Renderer::AudioDevice> impl; | ||||
|     Kernel::KEvent* event; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										146
									
								
								src/core/hle/service/audio/audio_in.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/core/hle/service/audio/audio_in.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,146 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/hle/service/audio/audio_in.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::AudioIn; | ||||
| 
 | ||||
| IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id, | ||||
|                    const std::string& device_name, const AudioInParameter& in_params, | ||||
|                    Kernel::KProcess* handle, u64 applet_resource_user_id) | ||||
|     : ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"}, | ||||
|       event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_, | ||||
|                                                                                     manager, event, | ||||
|                                                                                     session_id)} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IAudioIn::GetAudioInState>, "GetAudioInState"}, | ||||
|         {1, D<&IAudioIn::Start>, "Start"}, | ||||
|         {2, D<&IAudioIn::Stop>, "Stop"}, | ||||
|         {3, D<&IAudioIn::AppendAudioInBuffer>, "AppendAudioInBuffer"}, | ||||
|         {4, D<&IAudioIn::RegisterBufferEvent>, "RegisterBufferEvent"}, | ||||
|         {5, D<&IAudioIn::GetReleasedAudioInBuffers>, "GetReleasedAudioInBuffers"}, | ||||
|         {6, D<&IAudioIn::ContainsAudioInBuffer>, "ContainsAudioInBuffer"}, | ||||
|         {7, D<&IAudioIn::AppendAudioInBuffer>, "AppendUacInBuffer"}, | ||||
|         {8, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendAudioInBufferAuto"}, | ||||
|         {9, D<&IAudioIn::GetReleasedAudioInBuffersAuto>, "GetReleasedAudioInBuffersAuto"}, | ||||
|         {10, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendUacInBufferAuto"}, | ||||
|         {11, D<&IAudioIn::GetAudioInBufferCount>, "GetAudioInBufferCount"}, | ||||
|         {12, D<&IAudioIn::SetDeviceGain>, "SetDeviceGain"}, | ||||
|         {13, D<&IAudioIn::GetDeviceGain>, "GetDeviceGain"}, | ||||
|         {14, D<&IAudioIn::FlushAudioInBuffers>, "FlushAudioInBuffers"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     RegisterHandlers(functions); | ||||
| 
 | ||||
|     process->Open(); | ||||
| 
 | ||||
|     if (impl->GetSystem() | ||||
|             .Initialize(device_name, in_params, handle, applet_resource_user_id) | ||||
|             .IsError()) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| IAudioIn::~IAudioIn() { | ||||
|     impl->Free(); | ||||
|     service_context.CloseEvent(event); | ||||
|     process->Close(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::GetAudioInState(Out<u32> out_state) { | ||||
|     *out_state = static_cast<u32>(impl->GetState()); | ||||
|     LOG_DEBUG(Service_Audio, "called. state={}", *out_state); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::Start() { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(impl->StartSystem()); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::Stop() { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(impl->StopSystem()); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer, | ||||
|                                      u64 buffer_client_ptr) { | ||||
|     R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer, | ||||
|                                          u64 buffer_client_ptr) { | ||||
|     if (buffer.empty()) { | ||||
|         LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!"); | ||||
|         R_THROW(Audio::ResultInsufficientBuffer); | ||||
|     } | ||||
| 
 | ||||
|     [[maybe_unused]] const auto session_id{impl->GetSystem().GetSessionId()}; | ||||
|     LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", session_id, | ||||
|               buffer_client_ptr); | ||||
| 
 | ||||
|     R_RETURN(impl->AppendBuffer(buffer[0], buffer_client_ptr)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     *out_event = &impl->GetBufferEvent(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, | ||||
|                                            Out<u32> out_count) { | ||||
|     R_RETURN(this->GetReleasedAudioInBuffersAuto(out_audio_buffer, out_count)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::GetReleasedAudioInBuffersAuto( | ||||
|     OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) { | ||||
| 
 | ||||
|     if (!out_audio_buffer.empty()) { | ||||
|         out_audio_buffer[0] = 0; | ||||
|     } | ||||
|     *out_count = impl->GetReleasedBuffers(out_audio_buffer); | ||||
| 
 | ||||
|     LOG_TRACE(Service_Audio, "called. Session {} released {} buffers", | ||||
|               impl->GetSystem().GetSessionId(), *out_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) { | ||||
|     *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr, | ||||
|               *out_contains_buffer); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::GetAudioInBufferCount(Out<u32> out_buffer_count) { | ||||
|     *out_buffer_count = impl->GetBufferCount(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::SetDeviceGain(f32 device_gain) { | ||||
|     impl->SetVolume(device_gain); | ||||
|     LOG_DEBUG(Service_Audio, "called. Gain {}", device_gain); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::GetDeviceGain(Out<f32> out_device_gain) { | ||||
|     *out_device_gain = impl->GetVolume(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Gain {}", *out_device_gain); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioIn::FlushAudioInBuffers(Out<bool> out_flushed) { | ||||
|     *out_flushed = impl->FlushAudioInBuffers(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										53
									
								
								src/core/hle/service/audio/audio_in.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/core/hle/service/audio/audio_in.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/in/audio_in.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class IAudioIn final : public ServiceFramework<IAudioIn> { | ||||
| public: | ||||
|     explicit IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager, | ||||
|                       size_t session_id, const std::string& device_name, | ||||
|                       const AudioCore::AudioIn::AudioInParameter& in_params, | ||||
|                       Kernel::KProcess* handle, u64 applet_resource_user_id); | ||||
|     ~IAudioIn() override; | ||||
| 
 | ||||
|     std::shared_ptr<AudioCore::AudioIn::In> GetImpl() { | ||||
|         return impl; | ||||
|     } | ||||
| 
 | ||||
|     Result GetAudioInState(Out<u32> out_state); | ||||
|     Result Start(); | ||||
|     Result Stop(); | ||||
|     Result AppendAudioInBuffer( | ||||
|         InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer, | ||||
|         u64 buffer_client_ptr); | ||||
|     Result AppendAudioInBufferAuto( | ||||
|         InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer, | ||||
|         u64 buffer_client_ptr); | ||||
|     Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||||
|     Result GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, | ||||
|                                      Out<u32> out_count); | ||||
|     Result GetReleasedAudioInBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, | ||||
|                                          Out<u32> out_count); | ||||
|     Result ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr); | ||||
|     Result GetAudioInBufferCount(Out<u32> out_buffer_count); | ||||
|     Result SetDeviceGain(f32 device_gain); | ||||
|     Result GetDeviceGain(Out<f32> out_device_gain); | ||||
|     Result FlushAudioInBuffers(Out<bool> out_flushed); | ||||
| 
 | ||||
| private: | ||||
|     Kernel::KProcess* process; | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     Kernel::KEvent* event; | ||||
|     std::shared_ptr<AudioCore::AudioIn::In> impl; | ||||
|     Common::ScratchBuffer<u64> released_buffer; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										125
									
								
								src/core/hle/service/audio/audio_in_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								src/core/hle/service/audio/audio_in_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "common/string_util.h" | ||||
| #include "core/hle/service/audio/audio_in.h" | ||||
| #include "core/hle/service/audio/audio_in_manager.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::AudioIn; | ||||
| 
 | ||||
| IAudioInManager::IAudioInManager(Core::System& system_) | ||||
|     : ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>( | ||||
|                                                 system_)} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IAudioInManager::ListAudioIns>, "ListAudioIns"}, | ||||
|         {1, D<&IAudioInManager::OpenAudioIn>, "OpenAudioIn"}, | ||||
|         {2, D<&IAudioInManager::ListAudioIns>, "ListAudioInsAuto"}, | ||||
|         {3, D<&IAudioInManager::OpenAudioIn>, "OpenAudioInAuto"}, | ||||
|         {4, D<&IAudioInManager::ListAudioInsAutoFiltered>, "ListAudioInsAutoFiltered"}, | ||||
|         {5, D<&IAudioInManager::OpenAudioInProtocolSpecified>, "OpenAudioInProtocolSpecified"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| IAudioInManager::~IAudioInManager() = default; | ||||
| 
 | ||||
| Result IAudioInManager::ListAudioIns( | ||||
|     OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, Out<u32> out_count) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal, | ||||
|                                     Out<SharedPointer<IAudioIn>> out_audio_in, | ||||
|                                     OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, | ||||
|                                     InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, | ||||
|                                     AudioInParameter parameter, | ||||
|                                     InCopyHandle<Kernel::KProcess> process_handle, | ||||
|                                     ClientAppletResourceUserId aruid) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name, | ||||
|                                                 name, {}, parameter, process_handle, aruid)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioInManager::ListAudioInsAuto( | ||||
|     OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioInManager::OpenAudioInAuto( | ||||
|     Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in, | ||||
|     OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, | ||||
|     InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter, | ||||
|     InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name, | ||||
|                                                 name, {}, parameter, process_handle, aruid)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioInManager::ListAudioInsAutoFiltered( | ||||
|     OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     *out_count = impl->GetDeviceNames(out_audio_ins, true); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioInManager::OpenAudioInProtocolSpecified( | ||||
|     Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in, | ||||
|     OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, | ||||
|     InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol, | ||||
|     AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle, | ||||
|     ClientAppletResourceUserId aruid) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|     if (!process_handle) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||||
|         R_THROW(ResultUnknown); | ||||
|     } | ||||
|     if (name.empty() || out_name.empty()) { | ||||
|         LOG_ERROR(Service_Audio, "Invalid buffers"); | ||||
|         R_THROW(ResultUnknown); | ||||
|     } | ||||
| 
 | ||||
|     std::scoped_lock l{impl->mutex}; | ||||
| 
 | ||||
|     size_t new_session_id{}; | ||||
| 
 | ||||
|     R_TRY(impl->LinkToManager()); | ||||
|     R_TRY(impl->AcquireSessionId(new_session_id)); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id, | ||||
|               impl->num_free_sessions); | ||||
| 
 | ||||
|     const auto device_name = Common::StringFromBuffer(name[0].name); | ||||
|     *out_audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, | ||||
|                                                parameter, process_handle.Get(), aruid.pid); | ||||
|     impl->sessions[new_session_id] = (*out_audio_in)->GetImpl(); | ||||
|     impl->applet_resource_user_ids[new_session_id] = aruid.pid; | ||||
| 
 | ||||
|     auto& out_system = impl->sessions[new_session_id]->GetSystem(); | ||||
|     *out_parameter_internal = | ||||
|         AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(), | ||||
|                                  .channel_count = out_system.GetChannelCount(), | ||||
|                                  .sample_format = static_cast<u32>(out_system.GetSampleFormat()), | ||||
|                                  .state = static_cast<u32>(out_system.GetState())}; | ||||
| 
 | ||||
|     out_name[0] = AudioDeviceName(out_system.GetName()); | ||||
| 
 | ||||
|     if (protocol == Protocol{}) { | ||||
|         if (out_system.IsUac()) { | ||||
|             out_name[0] = AudioDeviceName("UacIn"); | ||||
|         } else { | ||||
|             out_name[0] = AudioDeviceName("DeviceIn"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										57
									
								
								src/core/hle/service/audio/audio_in_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/core/hle/service/audio/audio_in_manager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/audio_in_manager.h" | ||||
| #include "audio_core/in/audio_in_system.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName; | ||||
| using Protocol = std::array<u32, 2>; | ||||
| 
 | ||||
| class IAudioIn; | ||||
| 
 | ||||
| class IAudioInManager final : public ServiceFramework<IAudioInManager> { | ||||
| public: | ||||
|     explicit IAudioInManager(Core::System& system_); | ||||
|     ~IAudioInManager() override; | ||||
| 
 | ||||
| private: | ||||
|     Result ListAudioIns(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, | ||||
|                         Out<u32> out_count); | ||||
|     Result OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, | ||||
|                        Out<SharedPointer<IAudioIn>> out_audio_in, | ||||
|                        OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, | ||||
|                        InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, | ||||
|                        AudioCore::AudioIn::AudioInParameter parameter, | ||||
|                        InCopyHandle<Kernel::KProcess> process_handle, | ||||
|                        ClientAppletResourceUserId aruid); | ||||
| 
 | ||||
|     Result ListAudioInsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, | ||||
|                             Out<u32> out_count); | ||||
|     Result OpenAudioInAuto(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, | ||||
|                            Out<SharedPointer<IAudioIn>> out_audio_in, | ||||
|                            OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, | ||||
|                            InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, | ||||
|                            AudioCore::AudioIn::AudioInParameter parameter, | ||||
|                            InCopyHandle<Kernel::KProcess> process_handle, | ||||
|                            ClientAppletResourceUserId aruid); | ||||
| 
 | ||||
|     Result ListAudioInsAutoFiltered( | ||||
|         OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count); | ||||
|     Result OpenAudioInProtocolSpecified( | ||||
|         Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, | ||||
|         Out<SharedPointer<IAudioIn>> out_audio_in, | ||||
|         OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, | ||||
|         InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol, | ||||
|         AudioCore::AudioIn::AudioInParameter parameter, | ||||
|         InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid); | ||||
| 
 | ||||
|     std::unique_ptr<AudioCore::AudioIn::Manager> impl; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										146
									
								
								src/core/hle/service/audio/audio_out.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/core/hle/service/audio/audio_out.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,146 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "audio_core/out/audio_out.h" | ||||
| #include "audio_core/out/audio_out_system.h" | ||||
| #include "core/hle/kernel/k_process.h" | ||||
| #include "core/hle/service/audio/audio_out.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::AudioOut; | ||||
| 
 | ||||
| IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id, | ||||
|                      const std::string& device_name, const AudioOutParameter& in_params, | ||||
|                      Kernel::KProcess* handle, u64 applet_resource_user_id) | ||||
|     : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, | ||||
|       event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, | ||||
|       impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { | ||||
| 
 | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IAudioOut::GetAudioOutState>, "GetAudioOutState"}, | ||||
|         {1, D<&IAudioOut::Start>, "Start"}, | ||||
|         {2, D<&IAudioOut::Stop>, "Stop"}, | ||||
|         {3, D<&IAudioOut::AppendAudioOutBuffer>, "AppendAudioOutBuffer"}, | ||||
|         {4, D<&IAudioOut::RegisterBufferEvent>, "RegisterBufferEvent"}, | ||||
|         {5, D<&IAudioOut::GetReleasedAudioOutBuffers>, "GetReleasedAudioOutBuffers"}, | ||||
|         {6, D<&IAudioOut::ContainsAudioOutBuffer>, "ContainsAudioOutBuffer"}, | ||||
|         {7, D<&IAudioOut::AppendAudioOutBufferAuto>, "AppendAudioOutBufferAuto"}, | ||||
|         {8, D<&IAudioOut::GetReleasedAudioOutBuffersAuto>, "GetReleasedAudioOutBuffersAuto"}, | ||||
|         {9, D<&IAudioOut::GetAudioOutBufferCount>, "GetAudioOutBufferCount"}, | ||||
|         {10, D<&IAudioOut::GetAudioOutPlayedSampleCount>, "GetAudioOutPlayedSampleCount"}, | ||||
|         {11, D<&IAudioOut::FlushAudioOutBuffers>, "FlushAudioOutBuffers"}, | ||||
|         {12, D<&IAudioOut::SetAudioOutVolume>, "SetAudioOutVolume"}, | ||||
|         {13, D<&IAudioOut::GetAudioOutVolume>, "GetAudioOutVolume"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
|     RegisterHandlers(functions); | ||||
| 
 | ||||
|     process->Open(); | ||||
| } | ||||
| 
 | ||||
| IAudioOut::~IAudioOut() { | ||||
|     impl->Free(); | ||||
|     service_context.CloseEvent(event); | ||||
|     process->Close(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::GetAudioOutState(Out<u32> out_state) { | ||||
|     *out_state = static_cast<u32>(impl->GetState()); | ||||
|     LOG_DEBUG(Service_Audio, "called. state={}", *out_state); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::Start() { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(impl->StartSystem()); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::Stop() { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(impl->StopSystem()); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::AppendAudioOutBuffer( | ||||
|     InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) { | ||||
|     R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::AppendAudioOutBufferAuto( | ||||
|     InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) { | ||||
|     if (audio_out_buffer.empty()) { | ||||
|         LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!"); | ||||
|         R_THROW(Audio::ResultInsufficientBuffer); | ||||
|     } | ||||
| 
 | ||||
|     LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", | ||||
|               impl->GetSystem().GetSessionId(), buffer_client_ptr); | ||||
|     R_RETURN(impl->AppendBuffer(audio_out_buffer[0], buffer_client_ptr)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     *out_event = &impl->GetBufferEvent(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::GetReleasedAudioOutBuffers( | ||||
|     OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, Out<u32> out_count) { | ||||
|     R_RETURN(this->GetReleasedAudioOutBuffersAuto(out_audio_buffer, out_count)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::GetReleasedAudioOutBuffersAuto( | ||||
|     OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) { | ||||
| 
 | ||||
|     if (!out_audio_buffer.empty()) { | ||||
|         out_audio_buffer[0] = 0; | ||||
|     } | ||||
|     *out_count = impl->GetReleasedBuffers(out_audio_buffer); | ||||
| 
 | ||||
|     LOG_TRACE(Service_Audio, "called. Session {} released {} buffers", | ||||
|               impl->GetSystem().GetSessionId(), *out_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) { | ||||
|     *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr, | ||||
|               *out_contains_buffer); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::GetAudioOutBufferCount(Out<u32> out_buffer_count) { | ||||
|     *out_buffer_count = impl->GetBufferCount(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count) { | ||||
|     *out_played_sample_count = impl->GetPlayedSampleCount(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Played samples={}", *out_played_sample_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::FlushAudioOutBuffers(Out<bool> out_flushed) { | ||||
|     *out_flushed = impl->FlushAudioOutBuffers(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::SetAudioOutVolume(f32 volume) { | ||||
|     LOG_DEBUG(Service_Audio, "called. Volume={}", volume); | ||||
|     impl->SetVolume(volume); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOut::GetAudioOutVolume(Out<f32> out_volume) { | ||||
|     *out_volume = impl->GetVolume(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Volume={}", *out_volume); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										58
									
								
								src/core/hle/service/audio/audio_out.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/core/hle/service/audio/audio_out.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/audio_out_manager.h" | ||||
| #include "audio_core/out/audio_out_system.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KReadableEvent; | ||||
| } | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class IAudioOut : public ServiceFramework<IAudioOut> { | ||||
| public: | ||||
|     explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, | ||||
|                        size_t session_id, const std::string& device_name, | ||||
|                        const AudioCore::AudioOut::AudioOutParameter& in_params, | ||||
|                        Kernel::KProcess* handle, u64 applet_resource_user_id); | ||||
|     ~IAudioOut() override; | ||||
| 
 | ||||
|     std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { | ||||
|         return impl; | ||||
|     } | ||||
| 
 | ||||
|     Result GetAudioOutState(Out<u32> out_state); | ||||
|     Result Start(); | ||||
|     Result Stop(); | ||||
|     Result AppendAudioOutBuffer( | ||||
|         InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, | ||||
|         u64 buffer_client_ptr); | ||||
|     Result AppendAudioOutBufferAuto( | ||||
|         InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, | ||||
|         u64 buffer_client_ptr); | ||||
|     Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||||
|     Result GetReleasedAudioOutBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, | ||||
|                                       Out<u32> out_count); | ||||
|     Result GetReleasedAudioOutBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, | ||||
|                                           Out<u32> out_count); | ||||
|     Result ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr); | ||||
|     Result GetAudioOutBufferCount(Out<u32> out_buffer_count); | ||||
|     Result GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count); | ||||
|     Result FlushAudioOutBuffers(Out<bool> out_flushed); | ||||
|     Result SetAudioOutVolume(f32 volume); | ||||
|     Result GetAudioOutVolume(Out<f32> out_volume); | ||||
| 
 | ||||
| private: | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     Kernel::KEvent* event; | ||||
|     Kernel::KProcess* process; | ||||
|     std::shared_ptr<AudioCore::AudioOut::Out> impl; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										101
									
								
								src/core/hle/service/audio/audio_out_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/core/hle/service/audio/audio_out_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "common/string_util.h" | ||||
| #include "core/hle/service/audio/audio_out.h" | ||||
| #include "core/hle/service/audio/audio_out_manager.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| #include "core/memory.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::AudioOut; | ||||
| 
 | ||||
| IAudioOutManager::IAudioOutManager(Core::System& system_) | ||||
|     : ServiceFramework{system_, "audout:u"}, impl{std::make_unique<Manager>(system_)} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"}, | ||||
|         {1, D<&IAudioOutManager::OpenAudioOut>, "OpenAudioOut"}, | ||||
|         {2, D<&IAudioOutManager::ListAudioOutsAuto>, "ListAudioOutsAuto"}, | ||||
|         {3, D<&IAudioOutManager::OpenAudioOutAuto>, "OpenAudioOutAuto"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| IAudioOutManager::~IAudioOutManager() = default; | ||||
| 
 | ||||
| Result IAudioOutManager::ListAudioOuts( | ||||
|     OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, Out<u32> out_count) { | ||||
|     R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal, | ||||
|                                       Out<SharedPointer<IAudioOut>> out_audio_out, | ||||
|                                       OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, | ||||
|                                       InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, | ||||
|                                       AudioOutParameter parameter, | ||||
|                                       InCopyHandle<Kernel::KProcess> process_handle, | ||||
|                                       ClientAppletResourceUserId aruid) { | ||||
|     R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name, | ||||
|                                     parameter, process_handle, aruid)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOutManager::ListAudioOutsAuto( | ||||
|     OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, Out<u32> out_count) { | ||||
|     if (!out_audio_outs.empty()) { | ||||
|         out_audio_outs[0] = AudioDeviceName("DeviceOut"); | ||||
|         *out_count = 1; | ||||
|         LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut"); | ||||
|     } else { | ||||
|         *out_count = 0; | ||||
|         LOG_DEBUG(Service_Audio, "called. Empty buffer passed in."); | ||||
|     } | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioOutManager::OpenAudioOutAuto( | ||||
|     Out<AudioOutParameterInternal> out_parameter_internal, | ||||
|     Out<SharedPointer<IAudioOut>> out_audio_out, | ||||
|     OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, | ||||
|     InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter, | ||||
|     InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) { | ||||
|     if (!process_handle) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||||
|         R_THROW(ResultUnknown); | ||||
|     } | ||||
|     if (name.empty() || out_name.empty()) { | ||||
|         LOG_ERROR(Service_Audio, "Invalid buffers"); | ||||
|         R_THROW(ResultUnknown); | ||||
|     } | ||||
| 
 | ||||
|     size_t new_session_id{}; | ||||
|     R_TRY(impl->LinkToManager()); | ||||
|     R_TRY(impl->AcquireSessionId(new_session_id)); | ||||
| 
 | ||||
|     const auto device_name = Common::StringFromBuffer(name[0].name); | ||||
|     LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, | ||||
|               impl->num_free_sessions); | ||||
| 
 | ||||
|     auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, | ||||
|                                                  parameter, process_handle.Get(), aruid.pid); | ||||
|     R_TRY(audio_out->GetImpl()->GetSystem().Initialize(device_name, parameter, process_handle.Get(), | ||||
|                                                        aruid.pid)); | ||||
| 
 | ||||
|     *out_audio_out = audio_out; | ||||
|     impl->sessions[new_session_id] = audio_out->GetImpl(); | ||||
|     impl->applet_resource_user_ids[new_session_id] = aruid.pid; | ||||
| 
 | ||||
|     auto& out_system = impl->sessions[new_session_id]->GetSystem(); | ||||
|     *out_parameter_internal = | ||||
|         AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(), | ||||
|                                   .channel_count = out_system.GetChannelCount(), | ||||
|                                   .sample_format = static_cast<u32>(out_system.GetSampleFormat()), | ||||
|                                   .state = static_cast<u32>(out_system.GetState())}; | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										44
									
								
								src/core/hle/service/audio/audio_out_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/core/hle/service/audio/audio_out_manager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/audio_out_manager.h" | ||||
| #include "audio_core/out/audio_out.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName; | ||||
| class IAudioOut; | ||||
| 
 | ||||
| class IAudioOutManager final : public ServiceFramework<IAudioOutManager> { | ||||
| public: | ||||
|     explicit IAudioOutManager(Core::System& system_); | ||||
|     ~IAudioOutManager() override; | ||||
| 
 | ||||
| private: | ||||
|     Result ListAudioOuts(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, | ||||
|                          Out<u32> out_count); | ||||
|     Result OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal, | ||||
|                         Out<SharedPointer<IAudioOut>> out_audio_out, | ||||
|                         OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, | ||||
|                         InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, | ||||
|                         AudioCore::AudioOut::AudioOutParameter parameter, | ||||
|                         InCopyHandle<Kernel::KProcess> process_handle, | ||||
|                         ClientAppletResourceUserId aruid); | ||||
|     Result ListAudioOutsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, | ||||
|                              Out<u32> out_count); | ||||
|     Result OpenAudioOutAuto( | ||||
|         Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal, | ||||
|         Out<SharedPointer<IAudioOut>> out_audio_out, | ||||
|         OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, | ||||
|         InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, | ||||
|         AudioCore::AudioOut::AudioOutParameter parameter, | ||||
|         InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid); | ||||
| 
 | ||||
|     std::unique_ptr<AudioCore::AudioOut::Manager> impl; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										139
									
								
								src/core/hle/service/audio/audio_renderer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/core/hle/service/audio/audio_renderer.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,139 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/hle/service/audio/audio_renderer.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::Renderer; | ||||
| 
 | ||||
| IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_, | ||||
|                                AudioCore::AudioRendererParameterInternal& params, | ||||
|                                Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, | ||||
|                                Kernel::KProcess* process_handle_, u64 applet_resource_user_id, | ||||
|                                s32 session_id) | ||||
|     : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, | ||||
|       rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, | ||||
|       impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{ | ||||
|                                                                               process_handle_} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"}, | ||||
|         {1, D<&IAudioRenderer::GetSampleCount>, "GetSampleCount"}, | ||||
|         {2, D<&IAudioRenderer::GetMixBufferCount>, "GetMixBufferCount"}, | ||||
|         {3, D<&IAudioRenderer::GetState>, "GetState"}, | ||||
|         {4, D<&IAudioRenderer::RequestUpdate>, "RequestUpdate"}, | ||||
|         {5, D<&IAudioRenderer::Start>, "Start"}, | ||||
|         {6, D<&IAudioRenderer::Stop>, "Stop"}, | ||||
|         {7, D<&IAudioRenderer::QuerySystemEvent>, "QuerySystemEvent"}, | ||||
|         {8, D<&IAudioRenderer::SetRenderingTimeLimit>, "SetRenderingTimeLimit"}, | ||||
|         {9, D<&IAudioRenderer::GetRenderingTimeLimit>, "GetRenderingTimeLimit"}, | ||||
|         {10, D<&IAudioRenderer::RequestUpdateAuto>, "RequestUpdateAuto"}, | ||||
|         {11, nullptr, "ExecuteAudioRendererRendering"}, | ||||
|         {12, D<&IAudioRenderer::SetVoiceDropParameter>, "SetVoiceDropParameter"}, | ||||
|         {13, D<&IAudioRenderer::GetVoiceDropParameter>, "GetVoiceDropParameter"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
|     RegisterHandlers(functions); | ||||
| 
 | ||||
|     process_handle->Open(); | ||||
|     impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, | ||||
|                      applet_resource_user_id, session_id); | ||||
| } | ||||
| 
 | ||||
| IAudioRenderer::~IAudioRenderer() { | ||||
|     impl->Finalize(); | ||||
|     service_context.CloseEvent(rendered_event); | ||||
|     process_handle->Close(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::GetSampleRate(Out<u32> out_sample_rate) { | ||||
|     *out_sample_rate = impl->GetSystem().GetSampleRate(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Sample rate {}", *out_sample_rate); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::GetSampleCount(Out<u32> out_sample_count) { | ||||
|     *out_sample_count = impl->GetSystem().GetSampleCount(); | ||||
|     LOG_DEBUG(Service_Audio, "called. Sample count {}", *out_sample_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::GetState(Out<u32> out_state) { | ||||
|     *out_state = !impl->GetSystem().IsActive(); | ||||
|     LOG_DEBUG(Service_Audio, "called, state {}", *out_state); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::GetMixBufferCount(Out<u32> out_mix_buffer_count) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     *out_mix_buffer_count = impl->GetSystem().GetMixBufferCount(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer, | ||||
|                                      OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer, | ||||
|                                      InBuffer<BufferAttr_HipcMapAlias> input) { | ||||
|     R_RETURN(this->RequestUpdateAuto(out_buffer, out_performance_buffer, input)); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::RequestUpdateAuto( | ||||
|     OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, | ||||
|     OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer, | ||||
|     InBuffer<BufferAttr_HipcAutoSelect> input) { | ||||
|     LOG_TRACE(Service_Audio, "called"); | ||||
| 
 | ||||
|     const auto result = impl->RequestUpdate(input, out_performance_buffer, out_buffer); | ||||
|     if (result.IsFailure()) { | ||||
|         LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.GetDescription()); | ||||
|     } | ||||
| 
 | ||||
|     R_RETURN(result); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::Start() { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     impl->Start(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::Stop() { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     impl->Stop(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_UNLESS(impl->GetSystem().GetExecutionMode() != AudioCore::ExecutionMode::Manual, | ||||
|              Audio::ResultNotSupported); | ||||
|     *out_event = &rendered_event->GetReadableEvent(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::SetRenderingTimeLimit(u32 rendering_time_limit) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     impl->GetSystem().SetRenderingTimeLimit(rendering_time_limit); | ||||
|     ; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::GetRenderingTimeLimit(Out<u32> out_rendering_time_limit) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     *out_rendering_time_limit = impl->GetSystem().GetRenderingTimeLimit(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::SetVoiceDropParameter(f32 voice_drop_parameter) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     impl->GetSystem().SetVoiceDropParameter(voice_drop_parameter); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRenderer::GetVoiceDropParameter(Out<f32> out_voice_drop_parameter) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     *out_voice_drop_parameter = impl->GetSystem().GetVoiceDropParameter(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										54
									
								
								src/core/hle/service/audio/audio_renderer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/core/hle/service/audio/audio_renderer.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/renderer/audio_renderer.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KReadableEvent; | ||||
| } | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { | ||||
| public: | ||||
|     explicit IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_, | ||||
|                             AudioCore::AudioRendererParameterInternal& params, | ||||
|                             Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, | ||||
|                             Kernel::KProcess* process_handle_, u64 applet_resource_user_id, | ||||
|                             s32 session_id); | ||||
|     ~IAudioRenderer() override; | ||||
| 
 | ||||
| private: | ||||
|     Result GetSampleRate(Out<u32> out_sample_rate); | ||||
|     Result GetSampleCount(Out<u32> out_sample_count); | ||||
|     Result GetState(Out<u32> out_state); | ||||
|     Result GetMixBufferCount(Out<u32> out_mix_buffer_count); | ||||
|     Result RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer, | ||||
|                          OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer, | ||||
|                          InBuffer<BufferAttr_HipcMapAlias> input); | ||||
|     Result RequestUpdateAuto(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, | ||||
|                              OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer, | ||||
|                              InBuffer<BufferAttr_HipcAutoSelect> input); | ||||
|     Result Start(); | ||||
|     Result Stop(); | ||||
|     Result QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||||
|     Result SetRenderingTimeLimit(u32 rendering_time_limit); | ||||
|     Result GetRenderingTimeLimit(Out<u32> out_rendering_time_limit); | ||||
|     Result SetVoiceDropParameter(f32 voice_drop_parameter); | ||||
|     Result GetVoiceDropParameter(Out<f32> out_voice_drop_parameter); | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     Kernel::KEvent* rendered_event; | ||||
|     AudioCore::Renderer::Manager& manager; | ||||
|     std::unique_ptr<AudioCore::Renderer::Renderer> impl; | ||||
|     Kernel::KProcess* process_handle; | ||||
|     Common::ScratchBuffer<u8> output_buffer; | ||||
|     Common::ScratchBuffer<u8> performance_buffer; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										104
									
								
								src/core/hle/service/audio/audio_renderer_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/core/hle/service/audio/audio_renderer_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "audio_core/audio_render_manager.h" | ||||
| #include "audio_core/common/feature_support.h" | ||||
| #include "core/hle/kernel/k_process.h" | ||||
| #include "core/hle/kernel/k_transfer_memory.h" | ||||
| #include "core/hle/service/audio/audio_device.h" | ||||
| #include "core/hle/service/audio/audio_renderer.h" | ||||
| #include "core/hle/service/audio/audio_renderer_manager.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| using namespace AudioCore::Renderer; | ||||
| 
 | ||||
| IAudioRendererManager::IAudioRendererManager(Core::System& system_) | ||||
|     : ServiceFramework{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"}, | ||||
|         {1, D<&IAudioRendererManager::GetWorkBufferSize>, "GetWorkBufferSize"}, | ||||
|         {2, D<&IAudioRendererManager::GetAudioDeviceService>, "GetAudioDeviceService"}, | ||||
|         {3, nullptr, "OpenAudioRendererForManualExecution"}, | ||||
|         {4, D<&IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo>, "GetAudioDeviceServiceWithRevisionInfo"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| IAudioRendererManager::~IAudioRendererManager() = default; | ||||
| 
 | ||||
| Result IAudioRendererManager::OpenAudioRenderer( | ||||
|     Out<SharedPointer<IAudioRenderer>> out_audio_renderer, | ||||
|     AudioCore::AudioRendererParameterInternal parameter, | ||||
|     InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size, | ||||
|     InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|     if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) { | ||||
|         LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!"); | ||||
|         R_THROW(Audio::ResultOutOfSessions); | ||||
|     } | ||||
| 
 | ||||
|     const auto session_id{impl->GetSessionId()}; | ||||
|     if (session_id == -1) { | ||||
|         LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!"); | ||||
|         R_THROW(Audio::ResultOutOfSessions); | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id, | ||||
|               impl->GetSessionCount()); | ||||
| 
 | ||||
|     *out_audio_renderer = | ||||
|         std::make_shared<IAudioRenderer>(system, *impl, parameter, tmem_handle.Get(), tmem_size, | ||||
|                                          process_handle.Get(), aruid.pid, session_id); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRendererManager::GetWorkBufferSize(Out<u64> out_size, | ||||
|                                                 AudioCore::AudioRendererParameterInternal params) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|     R_TRY(impl->GetWorkBufferSize(params, *out_size)) | ||||
| 
 | ||||
|     std::string output_info{}; | ||||
|     output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision)); | ||||
|     output_info += | ||||
|         fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count); | ||||
|     output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}", | ||||
|                                static_cast<u32>(params.execution_mode), params.voice_drop_enabled); | ||||
|     output_info += fmt::format( | ||||
|         "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos " | ||||
|         "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External " | ||||
|         "Context {:04X}", | ||||
|         params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos, | ||||
|         params.splitter_destinations, params.voices, params.perf_frames, | ||||
|         params.external_context_size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}", | ||||
|               output_info, *out_size); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRendererManager::GetAudioDeviceService( | ||||
|     Out<SharedPointer<IAudioDevice>> out_audio_device, ClientAppletResourceUserId aruid) { | ||||
|     LOG_DEBUG(Service_Audio, "called, aruid={:#x}", aruid.pid); | ||||
|     *out_audio_device = std::make_shared<IAudioDevice>( | ||||
|         system, aruid.pid, Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo( | ||||
|     Out<SharedPointer<IAudioDevice>> out_audio_device, u32 revision, | ||||
|     ClientAppletResourceUserId aruid) { | ||||
|     LOG_DEBUG(Service_Audio, "called, revision={} aruid={:#x}", AudioCore::GetRevisionNum(revision), | ||||
|               aruid.pid); | ||||
|     *out_audio_device = | ||||
|         std::make_shared<IAudioDevice>(system, aruid.pid, revision, num_audio_devices++); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										37
									
								
								src/core/hle/service/audio/audio_renderer_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/core/hle/service/audio/audio_renderer_manager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/audio_render_manager.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class IAudioDevice; | ||||
| class IAudioRenderer; | ||||
| 
 | ||||
| class IAudioRendererManager final : public ServiceFramework<IAudioRendererManager> { | ||||
| public: | ||||
|     explicit IAudioRendererManager(Core::System& system_); | ||||
|     ~IAudioRendererManager() override; | ||||
| 
 | ||||
| private: | ||||
|     Result OpenAudioRenderer(Out<SharedPointer<IAudioRenderer>> out_audio_renderer, | ||||
|                              AudioCore::AudioRendererParameterInternal parameter, | ||||
|                              InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size, | ||||
|                              InCopyHandle<Kernel::KProcess> process_handle, | ||||
|                              ClientAppletResourceUserId aruid); | ||||
|     Result GetWorkBufferSize(Out<u64> out_size, | ||||
|                              AudioCore::AudioRendererParameterInternal parameter); | ||||
|     Result GetAudioDeviceService(Out<SharedPointer<IAudioDevice>> out_audio_device, | ||||
|                                  ClientAppletResourceUserId aruid); | ||||
|     Result GetAudioDeviceServiceWithRevisionInfo(Out<SharedPointer<IAudioDevice>> out_audio_device, | ||||
|                                                  u32 revision, ClientAppletResourceUserId aruid); | ||||
| 
 | ||||
|     std::unique_ptr<AudioCore::Renderer::Manager> impl; | ||||
|     u32 num_audio_devices{0}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,323 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include <array> | ||||
| #include <cstring> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "audio_core/out/audio_out_system.h" | ||||
| #include "audio_core/renderer/audio_device.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/scratch_buffer.h" | ||||
| #include "common/string_util.h" | ||||
| #include "common/swap.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/k_event.h" | ||||
| #include "core/hle/service/audio/audout_u.h" | ||||
| #include "core/hle/service/audio/errors.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| #include "core/memory.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::AudioOut; | ||||
| 
 | ||||
| class IAudioOut final : public ServiceFramework<IAudioOut> { | ||||
| public: | ||||
|     explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, | ||||
|                        size_t session_id, const std::string& device_name, | ||||
|                        const AudioOutParameter& in_params, Kernel::KProcess* handle, | ||||
|                        u64 applet_resource_user_id) | ||||
|         : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, | ||||
|           event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, | ||||
|           impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { | ||||
| 
 | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, | ||||
|             {1, &IAudioOut::Start, "Start"}, | ||||
|             {2, &IAudioOut::Stop, "Stop"}, | ||||
|             {3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"}, | ||||
|             {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, | ||||
|             {5, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffers"}, | ||||
|             {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"}, | ||||
|             {7, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBufferAuto"}, | ||||
|             {8, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffersAuto"}, | ||||
|             {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"}, | ||||
|             {10, &IAudioOut::GetAudioOutPlayedSampleCount, "GetAudioOutPlayedSampleCount"}, | ||||
|             {11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"}, | ||||
|             {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"}, | ||||
|             {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         process->Open(); | ||||
|     } | ||||
| 
 | ||||
|     ~IAudioOut() override { | ||||
|         impl->Free(); | ||||
|         service_context.CloseEvent(event); | ||||
|         process->Close(); | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { | ||||
|         return impl; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void GetAudioOutState(HLERequestContext& ctx) { | ||||
|         const auto state = static_cast<u32>(impl->GetState()); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. State={}", state); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(state); | ||||
|     } | ||||
| 
 | ||||
|     void Start(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto result = impl->StartSystem(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void Stop(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto result = impl->StopSystem(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void AppendAudioOutBuffer(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         u64 tag = rp.PopRaw<u64>(); | ||||
| 
 | ||||
|         const auto in_buffer_size{ctx.GetReadBufferSize()}; | ||||
|         if (in_buffer_size < sizeof(AudioOutBuffer)) { | ||||
|             LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!"); | ||||
|         } | ||||
| 
 | ||||
|         const auto& in_buffer = ctx.ReadBuffer(); | ||||
|         AudioOutBuffer buffer{}; | ||||
|         std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer)); | ||||
| 
 | ||||
|         LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", | ||||
|                   impl->GetSystem().GetSessionId(), tag); | ||||
| 
 | ||||
|         auto result = impl->AppendBuffer(buffer, tag); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void RegisterBufferEvent(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto& buffer_event = impl->GetBufferEvent(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.PushCopyObjects(buffer_event); | ||||
|     } | ||||
| 
 | ||||
|     void GetReleasedAudioOutBuffers(HLERequestContext& ctx) { | ||||
|         const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); | ||||
|         released_buffer.resize_destructive(write_buffer_size); | ||||
|         released_buffer[0] = 0; | ||||
| 
 | ||||
|         const auto count = impl->GetReleasedBuffers(released_buffer); | ||||
| 
 | ||||
|         ctx.WriteBuffer(released_buffer); | ||||
| 
 | ||||
|         LOG_TRACE(Service_Audio, "called. Session {} released {} buffers", | ||||
|                   impl->GetSystem().GetSessionId(), count); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(count); | ||||
|     } | ||||
| 
 | ||||
|     void ContainsAudioOutBuffer(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         const u64 tag{rp.Pop<u64>()}; | ||||
|         const auto buffer_queued{impl->ContainsAudioBuffer(tag)}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(buffer_queued); | ||||
|     } | ||||
| 
 | ||||
|     void GetAudioOutBufferCount(HLERequestContext& ctx) { | ||||
|         const auto buffer_count = impl->GetBufferCount(); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(buffer_count); | ||||
|     } | ||||
| 
 | ||||
|     void GetAudioOutPlayedSampleCount(HLERequestContext& ctx) { | ||||
|         const auto samples_played = impl->GetPlayedSampleCount(); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 4}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(samples_played); | ||||
|     } | ||||
| 
 | ||||
|     void FlushAudioOutBuffers(HLERequestContext& ctx) { | ||||
|         bool flushed{impl->FlushAudioOutBuffers()}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(flushed); | ||||
|     } | ||||
| 
 | ||||
|     void SetAudioOutVolume(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         const auto volume = rp.Pop<f32>(); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Volume={}", volume); | ||||
| 
 | ||||
|         impl->SetVolume(volume); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| 
 | ||||
|     void GetAudioOutVolume(HLERequestContext& ctx) { | ||||
|         const auto volume = impl->GetVolume(); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Volume={}", volume); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(volume); | ||||
|     } | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     Kernel::KEvent* event; | ||||
|     Kernel::KProcess* process; | ||||
|     std::shared_ptr<AudioCore::AudioOut::Out> impl; | ||||
|     Common::ScratchBuffer<u64> released_buffer; | ||||
| }; | ||||
| 
 | ||||
| AudOutU::AudOutU(Core::System& system_) | ||||
|     : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"}, | ||||
|       impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &AudOutU::ListAudioOuts, "ListAudioOuts"}, | ||||
|         {1, &AudOutU::OpenAudioOut, "OpenAudioOut"}, | ||||
|         {2, &AudOutU::ListAudioOuts, "ListAudioOutsAuto"}, | ||||
|         {3, &AudOutU::OpenAudioOut, "OpenAudioOutAuto"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| AudOutU::~AudOutU() = default; | ||||
| 
 | ||||
| void AudOutU::ListAudioOuts(HLERequestContext& ctx) { | ||||
|     using namespace AudioCore::Renderer; | ||||
| 
 | ||||
|     std::scoped_lock l{impl->mutex}; | ||||
| 
 | ||||
|     const auto write_count = | ||||
|         static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); | ||||
|     std::vector<AudioDevice::AudioDeviceName> device_names{}; | ||||
|     if (write_count > 0) { | ||||
|         device_names.emplace_back("DeviceOut"); | ||||
|         LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut"); | ||||
|     } else { | ||||
|         LOG_DEBUG(Service_Audio, "called. Empty buffer passed in."); | ||||
|     } | ||||
| 
 | ||||
|     ctx.WriteBuffer(device_names); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.Push<u32>(static_cast<u32>(device_names.size())); | ||||
| } | ||||
| 
 | ||||
| void AudOutU::OpenAudioOut(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     auto in_params{rp.PopRaw<AudioOutParameter>()}; | ||||
|     auto applet_resource_user_id{rp.PopRaw<u64>()}; | ||||
|     const auto device_name_data{ctx.ReadBuffer()}; | ||||
|     auto device_name = Common::StringFromBuffer(device_name_data); | ||||
|     auto handle{ctx.GetCopyHandle(0)}; | ||||
| 
 | ||||
|     auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||||
|     if (process.IsNull()) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultUnknown); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto link{impl->LinkToManager()}; | ||||
|     if (link.IsError()) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(link); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     size_t new_session_id{}; | ||||
|     auto result{impl->AcquireSessionId(new_session_id)}; | ||||
|     if (result.IsError()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, | ||||
|               impl->num_free_sessions); | ||||
| 
 | ||||
|     auto audio_out = | ||||
|         std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params, | ||||
|                                     process.GetPointerUnsafe(), applet_resource_user_id); | ||||
|     result = audio_out->GetImpl()->GetSystem().Initialize( | ||||
|         device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id); | ||||
|     if (result.IsError()) { | ||||
|         LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     impl->sessions[new_session_id] = audio_out->GetImpl(); | ||||
|     impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; | ||||
| 
 | ||||
|     auto& out_system = impl->sessions[new_session_id]->GetSystem(); | ||||
|     AudioOutParameterInternal out_params{.sample_rate = out_system.GetSampleRate(), | ||||
|                                          .channel_count = out_system.GetChannelCount(), | ||||
|                                          .sample_format = | ||||
|                                              static_cast<u32>(out_system.GetSampleFormat()), | ||||
|                                          .state = static_cast<u32>(out_system.GetState())}; | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 6, 0, 1}; | ||||
| 
 | ||||
|     ctx.WriteBuffer(out_system.GetName()); | ||||
| 
 | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushRaw<AudioOutParameterInternal>(out_params); | ||||
|     rb.PushIpcInterface<IAudioOut>(audio_out); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,37 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/audio_out_manager.h" | ||||
| #include "audio_core/out/audio_out.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| class System; | ||||
| } | ||||
| 
 | ||||
| namespace AudioCore::AudioOut { | ||||
| class Manager; | ||||
| class Out; | ||||
| } // namespace AudioCore::AudioOut
 | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class IAudioOut; | ||||
| 
 | ||||
| class AudOutU final : public ServiceFramework<AudOutU> { | ||||
| public: | ||||
|     explicit AudOutU(Core::System& system_); | ||||
|     ~AudOutU() override; | ||||
| 
 | ||||
| private: | ||||
|     void ListAudioOuts(HLERequestContext& ctx); | ||||
|     void OpenAudioOut(HLERequestContext& ctx); | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     std::unique_ptr<AudioCore::AudioOut::Manager> impl; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,552 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include <array> | ||||
| #include <memory> | ||||
| 
 | ||||
| #include "audio_core/audio_core.h" | ||||
| #include "audio_core/common/audio_renderer_parameter.h" | ||||
| #include "audio_core/common/feature_support.h" | ||||
| #include "audio_core/renderer/audio_device.h" | ||||
| #include "audio_core/renderer/audio_renderer.h" | ||||
| #include "audio_core/renderer/voice/voice_info.h" | ||||
| #include "common/alignment.h" | ||||
| #include "common/bit_util.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/polyfill_ranges.h" | ||||
| #include "common/scratch_buffer.h" | ||||
| #include "common/string_util.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/k_event.h" | ||||
| #include "core/hle/kernel/k_process.h" | ||||
| #include "core/hle/kernel/k_transfer_memory.h" | ||||
| #include "core/hle/service/audio/audren_u.h" | ||||
| #include "core/hle/service/audio/errors.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| #include "core/memory.h" | ||||
| 
 | ||||
| using namespace AudioCore::Renderer; | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { | ||||
| public: | ||||
|     explicit IAudioRenderer(Core::System& system_, Manager& manager_, | ||||
|                             AudioCore::AudioRendererParameterInternal& params, | ||||
|                             Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, | ||||
|                             u32 process_handle, Kernel::KProcess& process_, | ||||
|                             u64 applet_resource_user_id, s32 session_id) | ||||
|         : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, | ||||
|           rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, | ||||
|           impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, | ||||
|             {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"}, | ||||
|             {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"}, | ||||
|             {3, &IAudioRenderer::GetState, "GetState"}, | ||||
|             {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"}, | ||||
|             {5, &IAudioRenderer::Start, "Start"}, | ||||
|             {6, &IAudioRenderer::Stop, "Stop"}, | ||||
|             {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, | ||||
|             {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"}, | ||||
|             {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"}, | ||||
|             {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"}, | ||||
|             {11, nullptr, "ExecuteAudioRendererRendering"}, | ||||
|             {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"}, | ||||
|             {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         process.Open(); | ||||
|         impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process, | ||||
|                          applet_resource_user_id, session_id); | ||||
|     } | ||||
| 
 | ||||
|     ~IAudioRenderer() override { | ||||
|         impl->Finalize(); | ||||
|         service_context.CloseEvent(rendered_event); | ||||
|         process.Close(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void GetSampleRate(HLERequestContext& ctx) { | ||||
|         const auto sample_rate{impl->GetSystem().GetSampleRate()}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(sample_rate); | ||||
|     } | ||||
| 
 | ||||
|     void GetSampleCount(HLERequestContext& ctx) { | ||||
|         const auto sample_count{impl->GetSystem().GetSampleCount()}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(sample_count); | ||||
|     } | ||||
| 
 | ||||
|     void GetState(HLERequestContext& ctx) { | ||||
|         const u32 state{!impl->GetSystem().IsActive()}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called, state {}", state); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(state); | ||||
|     } | ||||
| 
 | ||||
|     void GetMixBufferCount(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         const auto buffer_count{impl->GetSystem().GetMixBufferCount()}; | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(buffer_count); | ||||
|     } | ||||
| 
 | ||||
|     void RequestUpdate(HLERequestContext& ctx) { | ||||
|         LOG_TRACE(Service_Audio, "called"); | ||||
| 
 | ||||
|         const auto input{ctx.ReadBuffer(0)}; | ||||
| 
 | ||||
|         // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
 | ||||
|         // checking size 0. Performance size is 0 for most games.
 | ||||
| 
 | ||||
|         auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0}; | ||||
|         if (is_buffer_b) { | ||||
|             const auto buffersB{ctx.BufferDescriptorB()}; | ||||
|             output_buffer.resize_destructive(buffersB[0].Size()); | ||||
|             performance_buffer.resize_destructive(buffersB[1].Size()); | ||||
|         } else { | ||||
|             const auto buffersC{ctx.BufferDescriptorC()}; | ||||
|             output_buffer.resize_destructive(buffersC[0].Size()); | ||||
|             performance_buffer.resize_destructive(buffersC[1].Size()); | ||||
|         } | ||||
| 
 | ||||
|         auto result = impl->RequestUpdate(input, performance_buffer, output_buffer); | ||||
| 
 | ||||
|         if (result.IsSuccess()) { | ||||
|             if (is_buffer_b) { | ||||
|                 ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0); | ||||
|                 ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1); | ||||
|             } else { | ||||
|                 ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0); | ||||
|                 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1); | ||||
|             } | ||||
|         } else { | ||||
|             LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", | ||||
|                       result.GetDescription()); | ||||
|         } | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void Start(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         impl->Start(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| 
 | ||||
|     void Stop(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         impl->Stop(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| 
 | ||||
|     void QuerySystemEvent(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) { | ||||
|             IPC::ResponseBuilder rb{ctx, 2}; | ||||
|             rb.Push(Audio::ResultNotSupported); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.PushCopyObjects(rendered_event->GetReadableEvent()); | ||||
|     } | ||||
| 
 | ||||
|     void SetRenderingTimeLimit(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         auto limit = rp.PopRaw<u32>(); | ||||
| 
 | ||||
|         auto& system_ = impl->GetSystem(); | ||||
|         system_.SetRenderingTimeLimit(limit); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| 
 | ||||
|     void GetRenderingTimeLimit(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto& system_ = impl->GetSystem(); | ||||
|         auto time = system_.GetRenderingTimeLimit(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(time); | ||||
|     } | ||||
| 
 | ||||
|     void ExecuteAudioRendererRendering(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
|     } | ||||
| 
 | ||||
|     void SetVoiceDropParameter(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         auto voice_drop_param{rp.Pop<f32>()}; | ||||
| 
 | ||||
|         auto& system_ = impl->GetSystem(); | ||||
|         system_.SetVoiceDropParameter(voice_drop_param); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| 
 | ||||
|     void GetVoiceDropParameter(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto& system_ = impl->GetSystem(); | ||||
|         auto voice_drop_param{system_.GetVoiceDropParameter()}; | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(voice_drop_param); | ||||
|     } | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     Kernel::KEvent* rendered_event; | ||||
|     Manager& manager; | ||||
|     std::unique_ptr<Renderer> impl; | ||||
|     Kernel::KProcess& process; | ||||
|     Common::ScratchBuffer<u8> output_buffer; | ||||
|     Common::ScratchBuffer<u8> performance_buffer; | ||||
| }; | ||||
| 
 | ||||
| class IAudioDevice final : public ServiceFramework<IAudioDevice> { | ||||
| 
 | ||||
| public: | ||||
|     explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision, | ||||
|                           u32 device_num) | ||||
|         : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"}, | ||||
|           impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)}, | ||||
|           event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, | ||||
|             {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, | ||||
|             {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"}, | ||||
|             {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"}, | ||||
|             {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"}, | ||||
|             {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"}, | ||||
|             {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"}, | ||||
|             {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"}, | ||||
|             {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"}, | ||||
|             {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"}, | ||||
|             {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"}, | ||||
|             {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"}, | ||||
|             {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"}, | ||||
|             {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"}, | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
| 
 | ||||
|         event->Signal(); | ||||
|     } | ||||
| 
 | ||||
|     ~IAudioDevice() override { | ||||
|         service_context.CloseEvent(event); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void ListAudioDeviceName(HLERequestContext& ctx) { | ||||
|         const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>(); | ||||
| 
 | ||||
|         std::vector<AudioDevice::AudioDeviceName> out_names{}; | ||||
| 
 | ||||
|         const u32 out_count = impl->ListAudioDeviceName(out_names, in_count); | ||||
| 
 | ||||
|         std::string out{}; | ||||
|         for (u32 i = 0; i < out_count; i++) { | ||||
|             std::string a{}; | ||||
|             u32 j = 0; | ||||
|             while (out_names[i].name[j] != '\0') { | ||||
|                 a += out_names[i].name[j]; | ||||
|                 j++; | ||||
|             } | ||||
|             out += "\n\t" + a; | ||||
|         } | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called.\nNames={}", out); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
| 
 | ||||
|         ctx.WriteBuffer(out_names); | ||||
| 
 | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(out_count); | ||||
|     } | ||||
| 
 | ||||
|     void SetAudioDeviceOutputVolume(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         const f32 volume = rp.Pop<f32>(); | ||||
| 
 | ||||
|         const auto device_name_buffer = ctx.ReadBuffer(); | ||||
|         const std::string name = Common::StringFromBuffer(device_name_buffer); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume); | ||||
| 
 | ||||
|         if (name == "AudioTvOutput") { | ||||
|             impl->SetDeviceVolumes(volume); | ||||
|         } | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| 
 | ||||
|     void GetAudioDeviceOutputVolume(HLERequestContext& ctx) { | ||||
|         const auto device_name_buffer = ctx.ReadBuffer(); | ||||
|         const std::string name = Common::StringFromBuffer(device_name_buffer); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called. Name={}", name); | ||||
| 
 | ||||
|         f32 volume{1.0f}; | ||||
|         if (name == "AudioTvOutput") { | ||||
|             volume = impl->GetDeviceVolume(name); | ||||
|         } | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(volume); | ||||
|     } | ||||
| 
 | ||||
|     void GetActiveAudioDeviceName(HLERequestContext& ctx) { | ||||
|         const auto write_size = ctx.GetWriteBufferSize(); | ||||
|         std::string out_name{"AudioTvOutput"}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name); | ||||
| 
 | ||||
|         out_name.resize(write_size); | ||||
| 
 | ||||
|         ctx.WriteBuffer(out_name); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(ResultSuccess); | ||||
|     } | ||||
| 
 | ||||
|     void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "(STUBBED) called"); | ||||
| 
 | ||||
|         event->Signal(); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.PushCopyObjects(event->GetReadableEvent()); | ||||
|     } | ||||
| 
 | ||||
|     void GetActiveChannelCount(HLERequestContext& ctx) { | ||||
|         const auto& sink{system.AudioCore().GetOutputSink()}; | ||||
|         u32 channel_count{sink.GetSystemChannels()}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
| 
 | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push<u32>(channel_count); | ||||
|     } | ||||
| 
 | ||||
|     void QueryAudioDeviceInputEvent(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "(STUBBED) called"); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.PushCopyObjects(event->GetReadableEvent()); | ||||
|     } | ||||
| 
 | ||||
|     void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.PushCopyObjects(event->GetReadableEvent()); | ||||
|     } | ||||
| 
 | ||||
|     void ListAudioOutputDeviceName(HLERequestContext& ctx) { | ||||
|         const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>(); | ||||
| 
 | ||||
|         std::vector<AudioDevice::AudioDeviceName> out_names{}; | ||||
| 
 | ||||
|         const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count); | ||||
| 
 | ||||
|         std::string out{}; | ||||
|         for (u32 i = 0; i < out_count; i++) { | ||||
|             std::string a{}; | ||||
|             u32 j = 0; | ||||
|             while (out_names[i].name[j] != '\0') { | ||||
|                 a += out_names[i].name[j]; | ||||
|                 j++; | ||||
|             } | ||||
|             out += "\n\t" + a; | ||||
|         } | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called.\nNames={}", out); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
| 
 | ||||
|         ctx.WriteBuffer(out_names); | ||||
| 
 | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push(out_count); | ||||
|     } | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     std::unique_ptr<AudioDevice> impl; | ||||
|     Kernel::KEvent* event; | ||||
| }; | ||||
| 
 | ||||
| AudRenU::AudRenU(Core::System& system_) | ||||
|     : ServiceFramework{system_, "audren:u"}, | ||||
|       service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, | ||||
|         {1, &AudRenU::GetWorkBufferSize, "GetWorkBufferSize"}, | ||||
|         {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"}, | ||||
|         {3, nullptr, "OpenAudioRendererForManualExecution"}, | ||||
|         {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| AudRenU::~AudRenU() = default; | ||||
| 
 | ||||
| void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     AudioCore::AudioRendererParameterInternal params; | ||||
|     rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params); | ||||
|     rp.Skip(1, false); | ||||
|     auto transfer_memory_size = rp.Pop<u64>(); | ||||
|     auto applet_resource_user_id = rp.Pop<u64>(); | ||||
|     auto transfer_memory_handle = ctx.GetCopyHandle(0); | ||||
|     auto process_handle = ctx.GetCopyHandle(1); | ||||
| 
 | ||||
|     if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) { | ||||
|         LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(Audio::ResultOutOfSessions); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()}; | ||||
|     auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; | ||||
| 
 | ||||
|     const auto session_id{impl->GetSessionId()}; | ||||
|     if (session_id == -1) { | ||||
|         LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(Audio::ResultOutOfSessions); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id, | ||||
|               impl->GetSessionCount()); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(), | ||||
|                                         transfer_memory_size, process_handle, *process, | ||||
|                                         applet_resource_user_id, session_id); | ||||
| } | ||||
| 
 | ||||
| void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) { | ||||
|     AudioCore::AudioRendererParameterInternal params; | ||||
| 
 | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params); | ||||
| 
 | ||||
|     u64 size{0}; | ||||
|     auto result = impl->GetWorkBufferSize(params, size); | ||||
| 
 | ||||
|     std::string output_info{}; | ||||
|     output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision)); | ||||
|     output_info += | ||||
|         fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count); | ||||
|     output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}", | ||||
|                                static_cast<u32>(params.execution_mode), params.voice_drop_enabled); | ||||
|     output_info += fmt::format( | ||||
|         "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos " | ||||
|         "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External " | ||||
|         "Context {:04X}", | ||||
|         params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos, | ||||
|         params.splitter_destinations, params.voices, params.perf_frames, | ||||
|         params.external_context_size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}", | ||||
|               output_info, size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(result); | ||||
|     rb.Push<u64>(size); | ||||
| } | ||||
| 
 | ||||
| void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     const auto applet_resource_user_id = rp.Pop<u64>(); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
| 
 | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, | ||||
|                                       ::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++); | ||||
| } | ||||
| 
 | ||||
| void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) { | ||||
|     LOG_ERROR(Service_Audio, "called. Implement me!"); | ||||
| } | ||||
| 
 | ||||
| void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) { | ||||
|     struct Parameters { | ||||
|         u32 revision; | ||||
|         u64 applet_resource_user_id; | ||||
|     }; | ||||
| 
 | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>(); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}", | ||||
|               AudioCore::GetRevisionNum(revision), applet_resource_user_id); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
| 
 | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision, | ||||
|                                       num_audio_devices++); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,35 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/audio_render_manager.h" | ||||
| #include "common/scratch_buffer.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| class System; | ||||
| } | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| class IAudioRenderer; | ||||
| 
 | ||||
| class AudRenU final : public ServiceFramework<AudRenU> { | ||||
| public: | ||||
|     explicit AudRenU(Core::System& system_); | ||||
|     ~AudRenU() override; | ||||
| 
 | ||||
| private: | ||||
|     void OpenAudioRenderer(HLERequestContext& ctx); | ||||
|     void GetWorkBufferSize(HLERequestContext& ctx); | ||||
|     void GetAudioDeviceService(HLERequestContext& ctx); | ||||
|     void OpenAudioRendererForManualExecution(HLERequestContext& ctx); | ||||
|     void GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx); | ||||
| 
 | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     std::unique_ptr<AudioCore::Renderer::Manager> impl; | ||||
|     u32 num_audio_devices{0}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,7 +1,7 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/hle/service/audio/audrec_u.h" | ||||
| #include "core/hle/service/audio/final_output_recorder_manager.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| @ -30,13 +30,14 @@ public: | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} { | ||||
| IFinalOutputRecorderManager::IFinalOutputRecorderManager(Core::System& system_) | ||||
|     : ServiceFramework{system_, "audrec:u"} { | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, nullptr, "OpenFinalOutputRecorder"}, | ||||
|     }; | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| AudRecU::~AudRecU() = default; | ||||
| IFinalOutputRecorderManager::~IFinalOutputRecorderManager() = default; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -11,10 +11,10 @@ class System; | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class AudRecA final : public ServiceFramework<AudRecA> { | ||||
| class IFinalOutputRecorderManager final : public ServiceFramework<IFinalOutputRecorderManager> { | ||||
| public: | ||||
|     explicit AudRecA(Core::System& system_); | ||||
|     ~AudRecA() override; | ||||
|     explicit IFinalOutputRecorderManager(Core::System& system_); | ||||
|     ~IFinalOutputRecorderManager() override; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,11 +1,12 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/hle/service/audio/audrec_a.h" | ||||
| #include "core/hle/service/audio/final_output_recorder_manager_for_applet.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} { | ||||
| IFinalOutputRecorderManagerForApplet::IFinalOutputRecorderManagerForApplet(Core::System& system_) | ||||
|     : ServiceFramework{system_, "audrec:a"} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, nullptr, "RequestSuspend"}, | ||||
| @ -16,6 +17,6 @@ AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| AudRecA::~AudRecA() = default; | ||||
| IFinalOutputRecorderManagerForApplet::~IFinalOutputRecorderManagerForApplet() = default; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -11,10 +11,11 @@ class System; | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class AudRecU final : public ServiceFramework<AudRecU> { | ||||
| class IFinalOutputRecorderManagerForApplet final | ||||
|     : public ServiceFramework<IFinalOutputRecorderManagerForApplet> { | ||||
| public: | ||||
|     explicit AudRecU(Core::System& system_); | ||||
|     ~AudRecU() override; | ||||
|     explicit IFinalOutputRecorderManagerForApplet(Core::System& system_); | ||||
|     ~IFinalOutputRecorderManagerForApplet() override; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										145
									
								
								src/core/hle/service/audio/hardware_opus_decoder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								src/core/hle/service/audio/hardware_opus_decoder.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,145 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/hle/service/audio/hardware_opus_decoder.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| using namespace AudioCore::OpusDecoder; | ||||
| 
 | ||||
| IHardwareOpusDecoder::IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus) | ||||
|     : ServiceFramework{system_, "IHardwareOpusDecoder"}, | ||||
|       impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IHardwareOpusDecoder::DecodeInterleavedOld>, "DecodeInterleavedOld"}, | ||||
|         {1, D<&IHardwareOpusDecoder::SetContext>, "SetContext"}, | ||||
|         {2, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld>, "DecodeInterleavedForMultiStreamOld"}, | ||||
|         {3, D<&IHardwareOpusDecoder::SetContextForMultiStream>, "SetContextForMultiStream"}, | ||||
|         {4, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfOld>, "DecodeInterleavedWithPerfOld"}, | ||||
|         {5, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld>, "DecodeInterleavedForMultiStreamWithPerfOld"}, | ||||
|         {6, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld>, "DecodeInterleavedWithPerfAndResetOld"}, | ||||
|         {7, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld>, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"}, | ||||
|         {8, D<&IHardwareOpusDecoder::DecodeInterleaved>, "DecodeInterleaved"}, | ||||
|         {9, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStream>, "DecodeInterleavedForMultiStream"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| IHardwareOpusDecoder::~IHardwareOpusDecoder() = default; | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::Initialize(const OpusParametersEx& params, | ||||
|                                         Kernel::KTransferMemory* transfer_memory, | ||||
|                                         u64 transfer_memory_size) { | ||||
|     return impl->Initialize(params, transfer_memory, transfer_memory_size); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::Initialize(const OpusMultiStreamParametersEx& params, | ||||
|                                         Kernel::KTransferMemory* transfer_memory, | ||||
|                                         u64 transfer_memory_size) { | ||||
|     return impl->Initialize(params, transfer_memory, transfer_memory_size); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, | ||||
|                                                   Out<u32> out_data_size, Out<u32> out_sample_count, | ||||
|                                                   InBuffer<BufferAttr_HipcMapAlias> opus_data) { | ||||
|     R_TRY(impl->DecodeInterleaved(out_data_size, nullptr, out_sample_count, opus_data, out_pcm_data, | ||||
|                                   false)); | ||||
|     LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size, | ||||
|               *out_sample_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(impl->SetContext(decoder_context)); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld( | ||||
|     OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, Out<u32> out_data_size, | ||||
|     Out<u32> out_sample_count, InBuffer<BufferAttr_HipcMapAlias> opus_data) { | ||||
|     R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, nullptr, out_sample_count, opus_data, | ||||
|                                                 out_pcm_data, false)); | ||||
|     LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size, | ||||
|               *out_sample_count); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::SetContextForMultiStream( | ||||
|     InBuffer<BufferAttr_HipcMapAlias> decoder_context) { | ||||
|     LOG_DEBUG(Service_Audio, "called"); | ||||
|     R_RETURN(impl->SetContext(decoder_context)); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::DecodeInterleavedWithPerfOld( | ||||
|     OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|     Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|     InBuffer<BufferAttr_HipcMapAlias> opus_data) { | ||||
|     R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data, | ||||
|                                   out_pcm_data, false)); | ||||
|     LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size, | ||||
|               *out_sample_count, *out_time_taken); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld( | ||||
|     OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|     Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|     InBuffer<BufferAttr_HipcMapAlias> opus_data) { | ||||
|     R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count, | ||||
|                                                 opus_data, out_pcm_data, false)); | ||||
|     LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size, | ||||
|               *out_sample_count, *out_time_taken); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld( | ||||
|     OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|     Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|     InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) { | ||||
|     R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data, | ||||
|                                   out_pcm_data, reset)); | ||||
|     LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset, | ||||
|               *out_data_size, *out_sample_count, *out_time_taken); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld( | ||||
|     OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|     Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|     InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) { | ||||
|     R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count, | ||||
|                                                 opus_data, out_pcm_data, reset)); | ||||
|     LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset, | ||||
|               *out_data_size, *out_sample_count, *out_time_taken); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::DecodeInterleaved( | ||||
|     OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|     Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|     InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data, | ||||
|     bool reset) { | ||||
|     R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data, | ||||
|                                   out_pcm_data, reset)); | ||||
|     LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset, | ||||
|               *out_data_size, *out_sample_count, *out_time_taken); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoder::DecodeInterleavedForMultiStream( | ||||
|     OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|     Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|     InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data, | ||||
|     bool reset) { | ||||
|     R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count, | ||||
|                                                 opus_data, out_pcm_data, reset)); | ||||
|     LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset, | ||||
|               *out_data_size, *out_sample_count, *out_time_taken); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										63
									
								
								src/core/hle/service/audio/hardware_opus_decoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/core/hle/service/audio/hardware_opus_decoder.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/opus/decoder.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> { | ||||
| public: | ||||
|     explicit IHardwareOpusDecoder(Core::System& system_, | ||||
|                                   AudioCore::OpusDecoder::HardwareOpus& hardware_opus); | ||||
|     ~IHardwareOpusDecoder() override; | ||||
| 
 | ||||
|     Result Initialize(const AudioCore::OpusDecoder::OpusParametersEx& params, | ||||
|                       Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size); | ||||
|     Result Initialize(const AudioCore::OpusDecoder::OpusMultiStreamParametersEx& params, | ||||
|                       Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size); | ||||
| 
 | ||||
| private: | ||||
|     Result DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, | ||||
|                                 Out<u32> out_data_size, Out<u32> out_sample_count, | ||||
|                                 InBuffer<BufferAttr_HipcMapAlias> opus_data); | ||||
|     Result SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context); | ||||
|     Result DecodeInterleavedForMultiStreamOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, | ||||
|                                               Out<u32> out_data_size, Out<u32> out_sample_count, | ||||
|                                               InBuffer<BufferAttr_HipcMapAlias> opus_data); | ||||
|     Result SetContextForMultiStream(InBuffer<BufferAttr_HipcMapAlias> decoder_context); | ||||
|     Result DecodeInterleavedWithPerfOld( | ||||
|         OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|         Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|         InBuffer<BufferAttr_HipcMapAlias> opus_data); | ||||
|     Result DecodeInterleavedForMultiStreamWithPerfOld( | ||||
|         OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|         Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|         InBuffer<BufferAttr_HipcMapAlias> opus_data); | ||||
|     Result DecodeInterleavedWithPerfAndResetOld( | ||||
|         OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|         Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|         InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset); | ||||
|     Result DecodeInterleavedForMultiStreamWithPerfAndResetOld( | ||||
|         OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|         Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|         InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset); | ||||
|     Result DecodeInterleaved( | ||||
|         OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|         Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|         InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data, | ||||
|         bool reset); | ||||
|     Result DecodeInterleavedForMultiStream( | ||||
|         OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, | ||||
|         Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, | ||||
|         InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data, | ||||
|         bool reset); | ||||
| 
 | ||||
|     std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl; | ||||
|     Common::ScratchBuffer<u8> output_data; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										156
									
								
								src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,156 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "core/hle/service/audio/hardware_opus_decoder.h" | ||||
| #include "core/hle/service/audio/hardware_opus_decoder_manager.h" | ||||
| #include "core/hle/service/cmif_serialization.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| using namespace AudioCore::OpusDecoder; | ||||
| 
 | ||||
| IHardwareOpusDecoderManager::IHardwareOpusDecoderManager(Core::System& system_) | ||||
|     : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} { | ||||
|     // clang-format off
 | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoder>, "OpenHardwareOpusDecoder"}, | ||||
|         {1, D<&IHardwareOpusDecoderManager::GetWorkBufferSize>, "GetWorkBufferSize"}, | ||||
|         {2, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream>, "OpenOpusDecoderForMultiStream"}, | ||||
|         {3, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream>, "GetWorkBufferSizeForMultiStream"}, | ||||
|         {4, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx>, "OpenHardwareOpusDecoderEx"}, | ||||
|         {5, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeEx>, "GetWorkBufferSizeEx"}, | ||||
|         {6, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx>, "OpenHardwareOpusDecoderForMultiStreamEx"}, | ||||
|         {7, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx>, "GetWorkBufferSizeForMultiStreamEx"}, | ||||
|         {8, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeExEx>, "GetWorkBufferSizeExEx"}, | ||||
|         {9, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx>, "GetWorkBufferSizeForMultiStreamExEx"}, | ||||
|     }; | ||||
|     // clang-format on
 | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| IHardwareOpusDecoderManager::~IHardwareOpusDecoderManager() = default; | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoder( | ||||
|     Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParameters params, u32 tmem_size, | ||||
|     InCopyHandle<Kernel::KTransferMemory> tmem_handle) { | ||||
|     LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}", | ||||
|               params.sample_rate, params.channel_count, tmem_size); | ||||
| 
 | ||||
|     auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; | ||||
|     OpusParametersEx ex{ | ||||
|         .sample_rate = params.sample_rate, | ||||
|         .channel_count = params.channel_count, | ||||
|         .use_large_frame_size = false, | ||||
|     }; | ||||
|     R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size)); | ||||
| 
 | ||||
|     *out_decoder = decoder; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::GetWorkBufferSize(Out<u32> out_size, OpusParameters params) { | ||||
|     R_TRY(impl.GetWorkBufferSize(params, *out_size)); | ||||
|     LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size {:#x}", | ||||
|               params.sample_rate, params.channel_count, *out_size); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream( | ||||
|     Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, | ||||
|     InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size, | ||||
|     InCopyHandle<Kernel::KTransferMemory> tmem_handle) { | ||||
|     LOG_DEBUG(Service_Audio, | ||||
|               "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " | ||||
|               "transfer_memory_size {:#x}", | ||||
|               params->sample_rate, params->channel_count, params->total_stream_count, | ||||
|               params->stereo_stream_count, tmem_size); | ||||
| 
 | ||||
|     auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; | ||||
| 
 | ||||
|     OpusMultiStreamParametersEx ex{ | ||||
|         .sample_rate = params->sample_rate, | ||||
|         .channel_count = params->channel_count, | ||||
|         .total_stream_count = params->total_stream_count, | ||||
|         .stereo_stream_count = params->stereo_stream_count, | ||||
|         .use_large_frame_size = false, | ||||
|         .mappings{}, | ||||
|     }; | ||||
|     std::memcpy(ex.mappings.data(), params->mappings.data(), sizeof(params->mappings)); | ||||
|     R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size)); | ||||
| 
 | ||||
|     *out_decoder = decoder; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream( | ||||
|     Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params) { | ||||
|     R_TRY(impl.GetWorkBufferSizeForMultiStream(*params, *out_size)); | ||||
|     LOG_DEBUG(Service_Audio, "size {:#x}", *out_size); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx( | ||||
|     Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParametersEx params, u32 tmem_size, | ||||
|     InCopyHandle<Kernel::KTransferMemory> tmem_handle) { | ||||
|     LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}", | ||||
|               params.sample_rate, params.channel_count, tmem_size); | ||||
| 
 | ||||
|     auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; | ||||
|     R_TRY(decoder->Initialize(params, tmem_handle.Get(), tmem_size)); | ||||
| 
 | ||||
|     *out_decoder = decoder; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(Out<u32> out_size, | ||||
|                                                         OpusParametersEx params) { | ||||
|     R_TRY(impl.GetWorkBufferSizeEx(params, *out_size)); | ||||
|     LOG_DEBUG(Service_Audio, "size {:#x}", *out_size); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx( | ||||
|     Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, | ||||
|     InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size, | ||||
|     InCopyHandle<Kernel::KTransferMemory> tmem_handle) { | ||||
|     LOG_DEBUG(Service_Audio, | ||||
|               "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " | ||||
|               "use_large_frame_size {}" | ||||
|               "transfer_memory_size {:#x}", | ||||
|               params->sample_rate, params->channel_count, params->total_stream_count, | ||||
|               params->stereo_stream_count, params->use_large_frame_size, tmem_size); | ||||
| 
 | ||||
|     auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; | ||||
| 
 | ||||
|     R_TRY(decoder->Initialize(*params, tmem_handle.Get(), tmem_size)); | ||||
| 
 | ||||
|     *out_decoder = decoder; | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx( | ||||
|     Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) { | ||||
|     R_TRY(impl.GetWorkBufferSizeForMultiStreamEx(*params, *out_size)); | ||||
|     LOG_DEBUG(Service_Audio, | ||||
|               "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " | ||||
|               "use_large_frame_size {} -- returned size {:#x}", | ||||
|               params->sample_rate, params->channel_count, params->total_stream_count, | ||||
|               params->stereo_stream_count, params->use_large_frame_size, *out_size); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::GetWorkBufferSizeExEx(Out<u32> out_size, | ||||
|                                                           OpusParametersEx params) { | ||||
|     R_TRY(impl.GetWorkBufferSizeExEx(params, *out_size)); | ||||
|     LOG_DEBUG(Service_Audio, "size {:#x}", *out_size); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx( | ||||
|     Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) { | ||||
|     R_TRY(impl.GetWorkBufferSizeForMultiStreamExEx(*params, *out_size)); | ||||
|     LOG_DEBUG(Service_Audio, "size {:#x}", *out_size); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
							
								
								
									
										53
									
								
								src/core/hle/service/audio/hardware_opus_decoder_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/core/hle/service/audio/hardware_opus_decoder_manager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/opus/decoder_manager.h" | ||||
| #include "core/hle/service/cmif_types.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class IHardwareOpusDecoder; | ||||
| 
 | ||||
| using AudioCore::OpusDecoder::OpusMultiStreamParameters; | ||||
| using AudioCore::OpusDecoder::OpusMultiStreamParametersEx; | ||||
| using AudioCore::OpusDecoder::OpusParameters; | ||||
| using AudioCore::OpusDecoder::OpusParametersEx; | ||||
| 
 | ||||
| class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { | ||||
| public: | ||||
|     explicit IHardwareOpusDecoderManager(Core::System& system_); | ||||
|     ~IHardwareOpusDecoderManager() override; | ||||
| 
 | ||||
| private: | ||||
|     Result OpenHardwareOpusDecoder(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, | ||||
|                                    OpusParameters params, u32 tmem_size, | ||||
|                                    InCopyHandle<Kernel::KTransferMemory> tmem_handle); | ||||
|     Result GetWorkBufferSize(Out<u32> out_size, OpusParameters params); | ||||
|     Result OpenHardwareOpusDecoderForMultiStream( | ||||
|         Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, | ||||
|         InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size, | ||||
|         InCopyHandle<Kernel::KTransferMemory> tmem_handle); | ||||
|     Result GetWorkBufferSizeForMultiStream( | ||||
|         Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params); | ||||
|     Result OpenHardwareOpusDecoderEx(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, | ||||
|                                      OpusParametersEx params, u32 tmem_size, | ||||
|                                      InCopyHandle<Kernel::KTransferMemory> tmem_handle); | ||||
|     Result GetWorkBufferSizeEx(Out<u32> out_size, OpusParametersEx params); | ||||
|     Result OpenHardwareOpusDecoderForMultiStreamEx( | ||||
|         Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, | ||||
|         InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size, | ||||
|         InCopyHandle<Kernel::KTransferMemory> tmem_handle); | ||||
|     Result GetWorkBufferSizeForMultiStreamEx( | ||||
|         Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params); | ||||
|     Result GetWorkBufferSizeExEx(Out<u32> out_size, OpusParametersEx params); | ||||
|     Result GetWorkBufferSizeForMultiStreamExEx( | ||||
|         Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params); | ||||
| 
 | ||||
|     Core::System& system; | ||||
|     AudioCore::OpusDecoder::OpusDecoderManager impl; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,502 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "audio_core/opus/decoder.h" | ||||
| #include "audio_core/opus/parameters.h" | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/scratch_buffer.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/service/audio/hwopus.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| using namespace AudioCore::OpusDecoder; | ||||
| 
 | ||||
| class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> { | ||||
| public: | ||||
|     explicit IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus) | ||||
|         : ServiceFramework{system_, "IHardwareOpusDecoder"}, | ||||
|           impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IHardwareOpusDecoder::DecodeInterleavedOld, "DecodeInterleavedOld"}, | ||||
|             {1, &IHardwareOpusDecoder::SetContext, "SetContext"}, | ||||
|             {2, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld, "DecodeInterleavedForMultiStreamOld"}, | ||||
|             {3, &IHardwareOpusDecoder::SetContextForMultiStream, "SetContextForMultiStream"}, | ||||
|             {4, &IHardwareOpusDecoder::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"}, | ||||
|             {5, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld, "DecodeInterleavedForMultiStreamWithPerfOld"}, | ||||
|             {6, &IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld, "DecodeInterleavedWithPerfAndResetOld"}, | ||||
|             {7, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"}, | ||||
|             {8, &IHardwareOpusDecoder::DecodeInterleaved, "DecodeInterleaved"}, | ||||
|             {9, &IHardwareOpusDecoder::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
| 
 | ||||
|     Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, | ||||
|                       u64 transfer_memory_size) { | ||||
|         return impl->Initialize(params, transfer_memory, transfer_memory_size); | ||||
|     } | ||||
| 
 | ||||
|     Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory, | ||||
|                       u64 transfer_memory_size) { | ||||
|         return impl->Initialize(params, transfer_memory, transfer_memory_size); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void DecodeInterleavedOld(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         output_data.resize_destructive(ctx.GetWriteBufferSize()); | ||||
| 
 | ||||
|         u32 size{}; | ||||
|         u32 sample_count{}; | ||||
|         auto result = | ||||
|             impl->DecodeInterleaved(&size, nullptr, &sample_count, input_data, output_data, false); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count); | ||||
| 
 | ||||
|         ctx.WriteBuffer(output_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 4}; | ||||
|         rb.Push(result); | ||||
|         rb.Push(size); | ||||
|         rb.Push(sample_count); | ||||
|     } | ||||
| 
 | ||||
|     void SetContext(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         auto result = impl->SetContext(input_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void DecodeInterleavedForMultiStreamOld(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         output_data.resize_destructive(ctx.GetWriteBufferSize()); | ||||
| 
 | ||||
|         u32 size{}; | ||||
|         u32 sample_count{}; | ||||
|         auto result = impl->DecodeInterleavedForMultiStream(&size, nullptr, &sample_count, | ||||
|                                                             input_data, output_data, false); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count); | ||||
| 
 | ||||
|         ctx.WriteBuffer(output_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 4}; | ||||
|         rb.Push(result); | ||||
|         rb.Push(size); | ||||
|         rb.Push(sample_count); | ||||
|     } | ||||
| 
 | ||||
|     void SetContextForMultiStream(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "called"); | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         auto result = impl->SetContext(input_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(result); | ||||
|     } | ||||
| 
 | ||||
|     void DecodeInterleavedWithPerfOld(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         output_data.resize_destructive(ctx.GetWriteBufferSize()); | ||||
| 
 | ||||
|         u32 size{}; | ||||
|         u32 sample_count{}; | ||||
|         u64 time_taken{}; | ||||
|         auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data, | ||||
|                                               output_data, false); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size, | ||||
|                   sample_count, time_taken); | ||||
| 
 | ||||
|         ctx.WriteBuffer(output_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 6}; | ||||
|         rb.Push(result); | ||||
|         rb.Push(size); | ||||
|         rb.Push(sample_count); | ||||
|         rb.Push(time_taken); | ||||
|     } | ||||
| 
 | ||||
|     void DecodeInterleavedForMultiStreamWithPerfOld(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         output_data.resize_destructive(ctx.GetWriteBufferSize()); | ||||
| 
 | ||||
|         u32 size{}; | ||||
|         u32 sample_count{}; | ||||
|         u64 time_taken{}; | ||||
|         auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count, | ||||
|                                                             input_data, output_data, false); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size, | ||||
|                   sample_count, time_taken); | ||||
| 
 | ||||
|         ctx.WriteBuffer(output_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 6}; | ||||
|         rb.Push(result); | ||||
|         rb.Push(size); | ||||
|         rb.Push(sample_count); | ||||
|         rb.Push(time_taken); | ||||
|     } | ||||
| 
 | ||||
|     void DecodeInterleavedWithPerfAndResetOld(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         auto reset{rp.Pop<bool>()}; | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         output_data.resize_destructive(ctx.GetWriteBufferSize()); | ||||
| 
 | ||||
|         u32 size{}; | ||||
|         u32 sample_count{}; | ||||
|         u64 time_taken{}; | ||||
|         auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data, | ||||
|                                               output_data, reset); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}", | ||||
|                   reset, size, sample_count, time_taken); | ||||
| 
 | ||||
|         ctx.WriteBuffer(output_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 6}; | ||||
|         rb.Push(result); | ||||
|         rb.Push(size); | ||||
|         rb.Push(sample_count); | ||||
|         rb.Push(time_taken); | ||||
|     } | ||||
| 
 | ||||
|     void DecodeInterleavedForMultiStreamWithPerfAndResetOld(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         auto reset{rp.Pop<bool>()}; | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         output_data.resize_destructive(ctx.GetWriteBufferSize()); | ||||
| 
 | ||||
|         u32 size{}; | ||||
|         u32 sample_count{}; | ||||
|         u64 time_taken{}; | ||||
|         auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count, | ||||
|                                                             input_data, output_data, reset); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}", | ||||
|                   reset, size, sample_count, time_taken); | ||||
| 
 | ||||
|         ctx.WriteBuffer(output_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 6}; | ||||
|         rb.Push(result); | ||||
|         rb.Push(size); | ||||
|         rb.Push(sample_count); | ||||
|         rb.Push(time_taken); | ||||
|     } | ||||
| 
 | ||||
|     void DecodeInterleaved(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         auto reset{rp.Pop<bool>()}; | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         output_data.resize_destructive(ctx.GetWriteBufferSize()); | ||||
| 
 | ||||
|         u32 size{}; | ||||
|         u32 sample_count{}; | ||||
|         u64 time_taken{}; | ||||
|         auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data, | ||||
|                                               output_data, reset); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}", | ||||
|                   reset, size, sample_count, time_taken); | ||||
| 
 | ||||
|         ctx.WriteBuffer(output_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 6}; | ||||
|         rb.Push(result); | ||||
|         rb.Push(size); | ||||
|         rb.Push(sample_count); | ||||
|         rb.Push(time_taken); | ||||
|     } | ||||
| 
 | ||||
|     void DecodeInterleavedForMultiStream(HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|         auto reset{rp.Pop<bool>()}; | ||||
| 
 | ||||
|         auto input_data{ctx.ReadBuffer(0)}; | ||||
|         output_data.resize_destructive(ctx.GetWriteBufferSize()); | ||||
| 
 | ||||
|         u32 size{}; | ||||
|         u32 sample_count{}; | ||||
|         u64 time_taken{}; | ||||
|         auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count, | ||||
|                                                             input_data, output_data, reset); | ||||
| 
 | ||||
|         LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}", | ||||
|                   reset, size, sample_count, time_taken); | ||||
| 
 | ||||
|         ctx.WriteBuffer(output_data); | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 6}; | ||||
|         rb.Push(result); | ||||
|         rb.Push(size); | ||||
|         rb.Push(sample_count); | ||||
|         rb.Push(time_taken); | ||||
|     } | ||||
| 
 | ||||
|     std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl; | ||||
|     Common::ScratchBuffer<u8> output_data; | ||||
| }; | ||||
| 
 | ||||
| void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     auto params = rp.PopRaw<OpusParameters>(); | ||||
|     auto transfer_memory_size{rp.Pop<u32>()}; | ||||
|     auto transfer_memory_handle{ctx.GetCopyHandle(0)}; | ||||
|     auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", | ||||
|               params.sample_rate, params.channel_count, transfer_memory_size); | ||||
| 
 | ||||
|     auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; | ||||
| 
 | ||||
|     OpusParametersEx ex{ | ||||
|         .sample_rate = params.sample_rate, | ||||
|         .channel_count = params.channel_count, | ||||
|         .use_large_frame_size = false, | ||||
|     }; | ||||
|     auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(result); | ||||
|     rb.PushIpcInterface(decoder); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::GetWorkBufferSize(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     auto params = rp.PopRaw<OpusParameters>(); | ||||
| 
 | ||||
|     u64 size{}; | ||||
|     auto result = impl.GetWorkBufferSize(params, size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size 0x{:X}", | ||||
|               params.sample_rate, params.channel_count, size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(result); | ||||
|     rb.Push(size); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     auto input{ctx.ReadBuffer()}; | ||||
|     OpusMultiStreamParameters params; | ||||
|     std::memcpy(¶ms, input.data(), sizeof(OpusMultiStreamParameters)); | ||||
| 
 | ||||
|     auto transfer_memory_size{rp.Pop<u32>()}; | ||||
|     auto transfer_memory_handle{ctx.GetCopyHandle(0)}; | ||||
|     auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, | ||||
|               "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " | ||||
|               "transfer_memory_size 0x{:X}", | ||||
|               params.sample_rate, params.channel_count, params.total_stream_count, | ||||
|               params.stereo_stream_count, transfer_memory_size); | ||||
| 
 | ||||
|     auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; | ||||
| 
 | ||||
|     OpusMultiStreamParametersEx ex{ | ||||
|         .sample_rate = params.sample_rate, | ||||
|         .channel_count = params.channel_count, | ||||
|         .total_stream_count = params.total_stream_count, | ||||
|         .stereo_stream_count = params.stereo_stream_count, | ||||
|         .use_large_frame_size = false, | ||||
|         .mappings{}, | ||||
|     }; | ||||
|     std::memcpy(ex.mappings.data(), params.mappings.data(), sizeof(params.mappings)); | ||||
|     auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(result); | ||||
|     rb.PushIpcInterface(decoder); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::GetWorkBufferSizeForMultiStream(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     auto input{ctx.ReadBuffer()}; | ||||
|     OpusMultiStreamParameters params; | ||||
|     std::memcpy(¶ms, input.data(), sizeof(OpusMultiStreamParameters)); | ||||
| 
 | ||||
|     u64 size{}; | ||||
|     auto result = impl.GetWorkBufferSizeForMultiStream(params, size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "size 0x{:X}", size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(result); | ||||
|     rb.Push(size); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     auto params = rp.PopRaw<OpusParametersEx>(); | ||||
|     auto transfer_memory_size{rp.Pop<u32>()}; | ||||
|     auto transfer_memory_handle{ctx.GetCopyHandle(0)}; | ||||
|     auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", | ||||
|               params.sample_rate, params.channel_count, transfer_memory_size); | ||||
| 
 | ||||
|     auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; | ||||
| 
 | ||||
|     auto result = | ||||
|         decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(result); | ||||
|     rb.PushIpcInterface(decoder); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::GetWorkBufferSizeEx(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     auto params = rp.PopRaw<OpusParametersEx>(); | ||||
| 
 | ||||
|     u64 size{}; | ||||
|     auto result = impl.GetWorkBufferSizeEx(params, size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "size 0x{:X}", size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(result); | ||||
|     rb.Push(size); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     auto input{ctx.ReadBuffer()}; | ||||
|     OpusMultiStreamParametersEx params; | ||||
|     std::memcpy(¶ms, input.data(), sizeof(OpusMultiStreamParametersEx)); | ||||
| 
 | ||||
|     auto transfer_memory_size{rp.Pop<u32>()}; | ||||
|     auto transfer_memory_handle{ctx.GetCopyHandle(0)}; | ||||
|     auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, | ||||
|               "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " | ||||
|               "use_large_frame_size {}" | ||||
|               "transfer_memory_size 0x{:X}", | ||||
|               params.sample_rate, params.channel_count, params.total_stream_count, | ||||
|               params.stereo_stream_count, params.use_large_frame_size, transfer_memory_size); | ||||
| 
 | ||||
|     auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; | ||||
| 
 | ||||
|     auto result = | ||||
|         decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(result); | ||||
|     rb.PushIpcInterface(decoder); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     auto input{ctx.ReadBuffer()}; | ||||
|     OpusMultiStreamParametersEx params; | ||||
|     std::memcpy(¶ms, input.data(), sizeof(OpusMultiStreamParametersEx)); | ||||
| 
 | ||||
|     u64 size{}; | ||||
|     auto result = impl.GetWorkBufferSizeForMultiStreamEx(params, size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, | ||||
|               "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " | ||||
|               "use_large_frame_size {} -- returned size 0x{:X}", | ||||
|               params.sample_rate, params.channel_count, params.total_stream_count, | ||||
|               params.stereo_stream_count, params.use_large_frame_size, size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(result); | ||||
|     rb.Push(size); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::GetWorkBufferSizeExEx(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     auto params = rp.PopRaw<OpusParametersEx>(); | ||||
| 
 | ||||
|     u64 size{}; | ||||
|     auto result = impl.GetWorkBufferSizeExEx(params, size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "size 0x{:X}", size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(result); | ||||
|     rb.Push(size); | ||||
| } | ||||
| 
 | ||||
| void HwOpus::GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
| 
 | ||||
|     auto input{ctx.ReadBuffer()}; | ||||
|     OpusMultiStreamParametersEx params; | ||||
|     std::memcpy(¶ms, input.data(), sizeof(OpusMultiStreamParametersEx)); | ||||
| 
 | ||||
|     u64 size{}; | ||||
|     auto result = impl.GetWorkBufferSizeForMultiStreamExEx(params, size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_Audio, "size 0x{:X}", size); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(result); | ||||
|     rb.Push(size); | ||||
| } | ||||
| 
 | ||||
| HwOpus::HwOpus(Core::System& system_) | ||||
|     : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} { | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"}, | ||||
|         {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, | ||||
|         {2, &HwOpus::OpenHardwareOpusDecoderForMultiStream, "OpenOpusDecoderForMultiStream"}, | ||||
|         {3, &HwOpus::GetWorkBufferSizeForMultiStream, "GetWorkBufferSizeForMultiStream"}, | ||||
|         {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"}, | ||||
|         {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"}, | ||||
|         {6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx, | ||||
|          "OpenHardwareOpusDecoderForMultiStreamEx"}, | ||||
|         {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"}, | ||||
|         {8, &HwOpus::GetWorkBufferSizeExEx, "GetWorkBufferSizeExEx"}, | ||||
|         {9, &HwOpus::GetWorkBufferSizeForMultiStreamExEx, "GetWorkBufferSizeForMultiStreamExEx"}, | ||||
|     }; | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
| 
 | ||||
| HwOpus::~HwOpus() = default; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -1,36 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "audio_core/opus/decoder_manager.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| class System; | ||||
| } | ||||
| 
 | ||||
| namespace Service::Audio { | ||||
| 
 | ||||
| class HwOpus final : public ServiceFramework<HwOpus> { | ||||
| public: | ||||
|     explicit HwOpus(Core::System& system_); | ||||
|     ~HwOpus() override; | ||||
| 
 | ||||
| private: | ||||
|     void OpenHardwareOpusDecoder(HLERequestContext& ctx); | ||||
|     void GetWorkBufferSize(HLERequestContext& ctx); | ||||
|     void OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx); | ||||
|     void GetWorkBufferSizeForMultiStream(HLERequestContext& ctx); | ||||
|     void OpenHardwareOpusDecoderEx(HLERequestContext& ctx); | ||||
|     void GetWorkBufferSizeEx(HLERequestContext& ctx); | ||||
|     void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx); | ||||
|     void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx); | ||||
|     void GetWorkBufferSizeExEx(HLERequestContext& ctx); | ||||
|     void GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx); | ||||
| 
 | ||||
|     Core::System& system; | ||||
|     AudioCore::OpusDecoder::OpusDecoderManager impl; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::Audio
 | ||||
| @ -415,7 +415,7 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ | ||||
|             auto& buffer = temp[OutBufferIndex]; | ||||
|             const size_t size = buffer.size(); | ||||
| 
 | ||||
|             if (ctx.CanWriteBuffer(OutBufferIndex)) { | ||||
|             if (size > 0 && ctx.CanWriteBuffer(OutBufferIndex)) { | ||||
|                 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { | ||||
|                     ctx.WriteBuffer(buffer.data(), size, OutBufferIndex); | ||||
|                 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user