mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	Merge pull request #13100 from liamwhite/audio-ipc
audio: move to new ipc
This commit is contained in:
		@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user