From 6ecbc6c557e49d2531892b6d40c298c7d4a6f63c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 19 Jul 2019 00:13:57 -0400 Subject: [PATCH 1/5] service/audren_u: Report proper device names AudioDevice and AudioInterface aren't valid device names on the Switch. We should also be returning consistent names in GetActiveAudioDeviceName(). While we're at it, we can also handle proper name output in ListAudioDeviceName, by returning all the available devices on the Switch. --- src/core/hle/service/audio/audren_u.cpp | 35 ++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 679299f683..8b12b82017 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "audio_core/audio_renderer.h" #include "common/alignment.h" @@ -160,7 +161,7 @@ private: class IAudioDevice final : public ServiceFramework { public: - IAudioDevice() : ServiceFramework("IAudioDevice") { + explicit IAudioDevice() : ServiceFramework("IAudioDevice") { static const FunctionInfo functions[] = { {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, @@ -189,15 +190,32 @@ public: } private: + using AudioDeviceName = std::array; + static constexpr std::array audio_device_names{{ + "AudioStereoJackOutput", + "AudioBuiltInSpeakerOutput", + "AudioTvOutput", + "AudioUsbDeviceOutput", + }}; + void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_Audio, "(STUBBED) called"); - constexpr std::array audio_interface{{"AudioInterface"}}; - ctx.WriteBuffer(audio_interface); + const std::size_t num_names_requested = ctx.GetWriteBufferSize() / sizeof(AudioDeviceName); + const std::size_t num_to_copy = std::min(num_names_requested, audio_device_names.size()); + std::vector name_buffer(num_to_copy); + + for (std::size_t i = 0; i < num_to_copy; i++) { + const auto& device_name = audio_device_names[i]; + + device_name.copy(name_buffer[i].data(), device_name.size()); + } + + ctx.WriteBuffer(name_buffer); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(1); + rb.Push(static_cast(num_to_copy)); } void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { @@ -216,8 +234,13 @@ private: void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_Audio, "(STUBBED) called"); - constexpr std::array audio_interface{{"AudioDevice"}}; - ctx.WriteBuffer(audio_interface); + // Currently set to always be TV audio output. + const auto& device_name = audio_device_names[2]; + + AudioDeviceName out_device_name{}; + device_name.copy(out_device_name.data(), device_name.size()); + + ctx.WriteBuffer(out_device_name); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); From 7653e4babc98da1e4c50301263e627b35b7bd2ba Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 19 Jul 2019 02:45:02 -0400 Subject: [PATCH 2/5] service/audren_u: Remove unnecessary return value from GetActiveAudioDeviceName() This service function only ever returns a result and nothing more. --- src/core/hle/service/audio/audren_u.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 8b12b82017..9460c283dd 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -242,9 +242,8 @@ private: ctx.WriteBuffer(out_device_name); - IPC::ResponseBuilder rb{ctx, 3}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - rb.Push(1); } void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { From ed0485c5993cca8c544ca5a641357034519730a5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 19 Jul 2019 03:22:57 -0400 Subject: [PATCH 3/5] service/audio: Remove global system accessors Trims out the lingering reliance on global state out of the audio code. --- src/core/hle/service/audio/audio.cpp | 6 ++--- src/core/hle/service/audio/audio.h | 6 ++++- src/core/hle/service/audio/audout_u.cpp | 36 ++++++++++++++----------- src/core/hle/service/audio/audout_u.h | 12 ++++++--- src/core/hle/service/audio/audren_u.cpp | 18 ++++++------- src/core/hle/service/audio/audren_u.h | 8 +++++- src/core/hle/service/service.cpp | 2 +- 7 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 128df7db5a..1781bec835 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp @@ -19,16 +19,16 @@ namespace Service::Audio { -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); - std::make_shared()->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); - std::make_shared()->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h index f5bd3bf5fb..b6d13912e7 100644 --- a/src/core/hle/service/audio/audio.h +++ b/src/core/hle/service/audio/audio.h @@ -4,6 +4,10 @@ #pragma once +namespace Core { +class System; +} + namespace Service::SM { class ServiceManager; } @@ -11,6 +15,6 @@ class ServiceManager; namespace Service::Audio { /// Registers all Audio services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 7db6eb08d1..fb84a8f139 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -40,8 +40,8 @@ enum class AudioState : u32 { class IAudioOut final : public ServiceFramework { public: - IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name, - std::string&& unique_name) + IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core, + std::string&& device_name, std::string&& unique_name) : ServiceFramework("IAudioOut"), audio_core(audio_core), device_name(std::move(device_name)), audio_params(audio_params) { // clang-format off @@ -65,7 +65,6 @@ public: RegisterHandlers(functions); // This is the event handle used to check if the audio buffer was released - auto& system = Core::System::GetInstance(); buffer_event = Kernel::WritableEvent::CreateEventPair( system.Kernel(), Kernel::ResetType::Manual, "IAudioOutBufferReleased"); @@ -212,6 +211,22 @@ private: Kernel::EventPair buffer_event; }; +AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"}, + {1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"}, + {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"}, + {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}, + }; + // clang-format on + + RegisterHandlers(functions); + audio_core = std::make_unique(); +} + +AudOutU::~AudOutU() = default; + void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); @@ -248,7 +263,7 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())}; auto audio_out_interface = std::make_shared( - params, *audio_core, std::move(device_name), std::move(unique_name)); + system, params, *audio_core, std::move(device_name), std::move(unique_name)); IPC::ResponseBuilder rb{ctx, 6, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -256,20 +271,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { rb.Push(params.channel_count); rb.Push(static_cast(AudioCore::Codec::PcmFormat::Int16)); rb.Push(static_cast(AudioState::Stopped)); - rb.PushIpcInterface(audio_out_interface); + rb.PushIpcInterface(audio_out_interface); audio_out_interfaces.push_back(std::move(audio_out_interface)); } -AudOutU::AudOutU() : ServiceFramework("audout:u") { - static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"}, - {1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"}, - {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"}, - {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}}; - RegisterHandlers(functions); - audio_core = std::make_unique(); -} - -AudOutU::~AudOutU() = default; - } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index aed4c43b27..c9f532ccd6 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h @@ -11,6 +11,10 @@ namespace AudioCore { class AudioOut; } +namespace Core { +class System; +} + namespace Kernel { class HLERequestContext; } @@ -21,15 +25,17 @@ class IAudioOut; class AudOutU final : public ServiceFramework { public: - AudOutU(); + explicit AudOutU(Core::System& system_); ~AudOutU() override; private: + void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); + void OpenAudioOutImpl(Kernel::HLERequestContext& ctx); + std::vector> audio_out_interfaces; std::unique_ptr audio_core; - void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); - void OpenAudioOutImpl(Kernel::HLERequestContext& ctx); + Core::System& system; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 9460c283dd..6e9f6584f5 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -26,7 +26,7 @@ namespace Service::Audio { class IAudioRenderer final : public ServiceFramework { public: - explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params, + explicit IAudioRenderer(Core::System& system, AudioCore::AudioRendererParameter audren_params, const std::size_t instance_number) : ServiceFramework("IAudioRenderer") { // clang-format off @@ -47,7 +47,6 @@ public: // clang-format on RegisterHandlers(functions); - auto& system = Core::System::GetInstance(); system_event = Kernel::WritableEvent::CreateEventPair( system.Kernel(), Kernel::ResetType::Manual, "IAudioRenderer:SystemEvent"); renderer = std::make_unique( @@ -161,7 +160,7 @@ private: class IAudioDevice final : public ServiceFramework { public: - explicit IAudioDevice() : ServiceFramework("IAudioDevice") { + explicit IAudioDevice(Core::System& system) : ServiceFramework("IAudioDevice") { static const FunctionInfo functions[] = { {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, @@ -179,7 +178,7 @@ public: }; RegisterHandlers(functions); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, "IAudioOutBufferReleasedEvent"); @@ -277,7 +276,7 @@ private: }; // namespace Audio -AudRenU::AudRenU() : ServiceFramework("audren:u") { +AudRenU::AudRenU(Core::System& system_) : ServiceFramework("audren:u"), system{system_} { // clang-format off static const FunctionInfo functions[] = { {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, @@ -605,7 +604,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(system); } void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { @@ -619,9 +618,10 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + // TODO(ogniK): Figure out what is different based on the current revision + rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); // TODO(ogniK): Figure out what is different - // based on the current revision + rb.PushIpcInterface(system); } void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { @@ -630,7 +630,7 @@ void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(params, audren_instance_count++); + rb.PushIpcInterface(system, params, audren_instance_count++); } bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 49f2733cfd..6e17489cea 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -6,6 +6,10 @@ #include "core/hle/service/service.h" +namespace Core { +class System; +} + namespace Kernel { class HLERequestContext; } @@ -14,7 +18,7 @@ namespace Service::Audio { class AudRenU final : public ServiceFramework { public: - explicit AudRenU(); + explicit AudRenU(Core::System& system_); ~AudRenU() override; private: @@ -33,7 +37,9 @@ private: }; bool IsFeatureSupported(AudioFeatures feature, u32_le revision) const; + std::size_t audren_instance_count = 0; + Core::System& system; }; } // namespace Service::Audio diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 7eefd733f2..d343392fde 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -206,7 +206,7 @@ void Init(std::shared_ptr& sm, Core::System& system) { AM::InstallInterfaces(*sm, nv_flinger, system); AOC::InstallInterfaces(*sm); APM::InstallInterfaces(system); - Audio::InstallInterfaces(*sm); + Audio::InstallInterfaces(*sm, system); BCAT::InstallInterfaces(*sm); BPC::InstallInterfaces(*sm); BtDrv::InstallInterfaces(*sm); From b9ebab71beaf9afc74788368846086a9c4648f4b Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 19 Jul 2019 03:44:00 -0400 Subject: [PATCH 4/5] service/audren_u: Move revision testing code out of AudRenU The revision querying facilities are used by more than just audren. e.g. audio devices can use this to test whether or not USB audio output is supported. This will be used within the following change. --- src/core/hle/service/audio/audren_u.cpp | 108 ++++++++++++------------ src/core/hle/service/audio/audren_u.h | 18 ++-- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 6e9f6584f5..8a7bf8a790 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -349,7 +349,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the portion of the size related to the mix data (and the sorting thereof). - const auto calculate_mix_info_size = [this](const AudioCore::AudioRendererParameter& params) { + const auto calculate_mix_info_size = [](const AudioCore::AudioRendererParameter& params) { // The size of the mixing info data structure. constexpr u64 mix_info_size = 0x940; @@ -421,7 +421,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { // Calculates the part of the size related to the splitter context. const auto calculate_splitter_context_size = - [this](const AudioCore::AudioRendererParameter& params) -> u64 { + [](const AudioCore::AudioRendererParameter& params) -> u64 { if (!IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { return 0; } @@ -468,7 +468,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the part of the size related to performance statistics. - const auto calculate_perf_size = [this](const AudioCore::AudioRendererParameter& params) { + const auto calculate_perf_size = [](const AudioCore::AudioRendererParameter& params) { // Extra size value appended to the end of the calculation. constexpr u64 appended = 128; @@ -495,78 +495,76 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { }; // Calculates the part of the size that relates to the audio command buffer. - const auto calculate_command_buffer_size = - [this](const AudioCore::AudioRendererParameter& params) { - constexpr u64 alignment = (buffer_alignment_size - 1) * 2; + const auto calculate_command_buffer_size = [](const AudioCore::AudioRendererParameter& params) { + constexpr u64 alignment = (buffer_alignment_size - 1) * 2; - if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) { - constexpr u64 command_buffer_size = 0x18000; + if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) { + constexpr u64 command_buffer_size = 0x18000; - return command_buffer_size + alignment; - } + return command_buffer_size + alignment; + } - // When the variadic command buffer is supported, this means - // the command generator for the audio renderer can issue commands - // that are (as one would expect), variable in size. So what we need to do - // is determine the maximum possible size for a few command data structures - // then multiply them by the amount of present commands indicated by the given - // respective audio parameters. + // When the variadic command buffer is supported, this means + // the command generator for the audio renderer can issue commands + // that are (as one would expect), variable in size. So what we need to do + // is determine the maximum possible size for a few command data structures + // then multiply them by the amount of present commands indicated by the given + // respective audio parameters. - constexpr u64 max_biquad_filters = 2; - constexpr u64 max_mix_buffers = 24; + constexpr u64 max_biquad_filters = 2; + constexpr u64 max_mix_buffers = 24; - constexpr u64 biquad_filter_command_size = 0x2C; + constexpr u64 biquad_filter_command_size = 0x2C; - constexpr u64 depop_mix_command_size = 0x24; - constexpr u64 depop_setup_command_size = 0x50; + constexpr u64 depop_mix_command_size = 0x24; + constexpr u64 depop_setup_command_size = 0x50; - constexpr u64 effect_command_max_size = 0x540; + constexpr u64 effect_command_max_size = 0x540; - constexpr u64 mix_command_size = 0x1C; - constexpr u64 mix_ramp_command_size = 0x24; - constexpr u64 mix_ramp_grouped_command_size = 0x13C; + constexpr u64 mix_command_size = 0x1C; + constexpr u64 mix_ramp_command_size = 0x24; + constexpr u64 mix_ramp_grouped_command_size = 0x13C; - constexpr u64 perf_command_size = 0x28; + constexpr u64 perf_command_size = 0x28; - constexpr u64 sink_command_size = 0x130; + constexpr u64 sink_command_size = 0x130; - constexpr u64 submix_command_max_size = - depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers; + constexpr u64 submix_command_max_size = + depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers; - constexpr u64 volume_command_size = 0x1C; - constexpr u64 volume_ramp_command_size = 0x20; + constexpr u64 volume_command_size = 0x1C; + constexpr u64 volume_ramp_command_size = 0x20; - constexpr u64 voice_biquad_filter_command_size = - biquad_filter_command_size * max_biquad_filters; - constexpr u64 voice_data_command_size = 0x9C; - const u64 voice_command_max_size = - (params.splitter_count * depop_setup_command_size) + - (voice_data_command_size + voice_biquad_filter_command_size + - volume_ramp_command_size + mix_ramp_grouped_command_size); + constexpr u64 voice_biquad_filter_command_size = + biquad_filter_command_size * max_biquad_filters; + constexpr u64 voice_data_command_size = 0x9C; + const u64 voice_command_max_size = + (params.splitter_count * depop_setup_command_size) + + (voice_data_command_size + voice_biquad_filter_command_size + volume_ramp_command_size + + mix_ramp_grouped_command_size); - // Now calculate the individual elements that comprise the size and add them together. - const u64 effect_commands_size = params.effect_count * effect_command_max_size; + // Now calculate the individual elements that comprise the size and add them together. + const u64 effect_commands_size = params.effect_count * effect_command_max_size; - const u64 final_mix_commands_size = - depop_mix_command_size + volume_command_size * max_mix_buffers; + const u64 final_mix_commands_size = + depop_mix_command_size + volume_command_size * max_mix_buffers; - const u64 perf_commands_size = - perf_command_size * - (CalculateNumPerformanceEntries(params) + max_perf_detail_entries); + const u64 perf_commands_size = + perf_command_size * (CalculateNumPerformanceEntries(params) + max_perf_detail_entries); - const u64 sink_commands_size = params.sink_count * sink_command_size; + const u64 sink_commands_size = params.sink_count * sink_command_size; - const u64 splitter_commands_size = - params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size; + const u64 splitter_commands_size = + params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size; - const u64 submix_commands_size = params.submix_count * submix_command_max_size; + const u64 submix_commands_size = params.submix_count * submix_command_max_size; - const u64 voice_commands_size = params.voice_count * voice_command_max_size; + const u64 voice_commands_size = params.voice_count * voice_command_max_size; - return effect_commands_size + final_mix_commands_size + perf_commands_size + - sink_commands_size + splitter_commands_size + submix_commands_size + - voice_commands_size + alignment; - }; + return effect_commands_size + final_mix_commands_size + perf_commands_size + + sink_commands_size + splitter_commands_size + submix_commands_size + + voice_commands_size + alignment; + }; IPC::RequestParser rp{ctx}; const auto params = rp.PopRaw(); @@ -633,7 +631,7 @@ void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { rb.PushIpcInterface(system, params, audren_instance_count++); } -bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { +bool IsFeatureSupported(AudioFeatures feature, u32_le revision) { // Byte swap const u32_be version_num = revision - Common::MakeMagic('R', 'E', 'V', '0'); diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 6e17489cea..0f3aad5018 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -30,16 +30,18 @@ private: void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); - enum class AudioFeatures : u32 { - Splitter, - PerformanceMetricsVersion2, - VariadicCommandBuffer, - }; - - bool IsFeatureSupported(AudioFeatures feature, u32_le revision) const; - std::size_t audren_instance_count = 0; Core::System& system; }; +// Describes a particular audio feature that may be supported in a particular revision. +enum class AudioFeatures : u32 { + Splitter, + PerformanceMetricsVersion2, + VariadicCommandBuffer, +}; + +// Tests if a particular audio feature is supported with a given audio revision. +bool IsFeatureSupported(AudioFeatures feature, u32_le revision); + } // namespace Service::Audio From 16730c4c4351133c9a27d0b34c5aeb54ac65e9a6 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 19 Jul 2019 03:56:21 -0400 Subject: [PATCH 5/5] service/audren_u: Handle audio USB output revision queries in ListAudioDeviceName() Audio devices use the supplied revision information in order to determine if USB audio output is able to be supported. In this case, we can only really handle using this revision information in ListAudioDeviceName(), where it checks if USB audio output is supported before supplying it as a device name. A few other scenarios exist where the revision info is checked, such as: - Early exiting from SetAudioDeviceOutputVolume if USB audio is attempted to be set when that device is unsupported. - Early exiting and returning 0.0f in GetAudioDeviceOutputVolume when USB output volume is queried and it's an unsupported device. - Falling back to AHUB headphones in GetActiveAudioDeviceName when the device type is USB output, but is unsupported based off the revision info. In order for these changes to also be implemented, a few other changes to the interface need to be made. Given we now properly handle everything about ListAudioDeviceName(), we no longer need to describe it as a stubbed function. --- src/core/hle/service/audio/audren_u.cpp | 62 ++++++++++++++++++------- src/core/hle/service/audio/audren_u.h | 1 + 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 8a7bf8a790..5b0b7f17e3 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -160,7 +160,8 @@ private: class IAudioDevice final : public ServiceFramework { public: - explicit IAudioDevice(Core::System& system) : ServiceFramework("IAudioDevice") { + explicit IAudioDevice(Core::System& system, u32_le revision_num) + : ServiceFramework("IAudioDevice"), revision{revision_num} { static const FunctionInfo functions[] = { {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, @@ -196,25 +197,40 @@ private: "AudioTvOutput", "AudioUsbDeviceOutput", }}; + enum class DeviceType { + AHUBHeadphones, + AHUBSpeakers, + HDA, + USBOutput, + }; void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + LOG_DEBUG(Service_Audio, "called"); - const std::size_t num_names_requested = ctx.GetWriteBufferSize() / sizeof(AudioDeviceName); - const std::size_t num_to_copy = std::min(num_names_requested, audio_device_names.size()); - std::vector name_buffer(num_to_copy); + const bool usb_output_supported = + IsFeatureSupported(AudioFeatures::AudioUSBDeviceOutput, revision); + const std::size_t count = ctx.GetWriteBufferSize() / sizeof(AudioDeviceName); + + std::vector name_buffer; + name_buffer.reserve(audio_device_names.size()); + + for (std::size_t i = 0; i < count && i < audio_device_names.size(); i++) { + const auto type = static_cast(i); + + if (!usb_output_supported && type == DeviceType::USBOutput) { + continue; + } - for (std::size_t i = 0; i < num_to_copy; i++) { const auto& device_name = audio_device_names[i]; - - device_name.copy(name_buffer[i].data(), device_name.size()); + auto& entry = name_buffer.emplace_back(); + device_name.copy(entry.data(), device_name.size()); } ctx.WriteBuffer(name_buffer); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast(num_to_copy)); + rb.Push(static_cast(name_buffer.size())); } void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { @@ -271,6 +287,7 @@ private: rb.PushCopyObjects(audio_output_device_switch_event.readable); } + u32_le revision = 0; Kernel::EventPair buffer_event; Kernel::EventPair audio_output_device_switch_event; @@ -597,12 +614,16 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { } void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Audio, "called"); + IPC::RequestParser rp{ctx}; + const u64 aruid = rp.Pop(); + LOG_DEBUG(Service_Audio, "called. aruid={:016X}", aruid); + + // Revisionless variant of GetAudioDeviceServiceWithRevisionInfo that + // always assumes the initial release revision (REV1). IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, Common::MakeMagic('R', 'E', 'V', '1')); } void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { @@ -612,14 +633,19 @@ void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { } void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + struct Parameters { + u32 revision; + u64 aruid; + }; + + IPC::RequestParser rp{ctx}; + const auto [revision, aruid] = rp.PopRaw(); + + LOG_DEBUG(Service_Audio, "called. revision={:08X}, aruid={:016X}", revision, aruid); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - // TODO(ogniK): Figure out what is different based on the current revision - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, revision); } void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { @@ -636,6 +662,8 @@ bool IsFeatureSupported(AudioFeatures feature, u32_le revision) { const u32_be version_num = revision - Common::MakeMagic('R', 'E', 'V', '0'); switch (feature) { + case AudioFeatures::AudioUSBDeviceOutput: + return version_num >= 4U; case AudioFeatures::Splitter: return version_num >= 2U; case AudioFeatures::PerformanceMetricsVersion2: diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 0f3aad5018..4e0ccc792c 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -36,6 +36,7 @@ private: // Describes a particular audio feature that may be supported in a particular revision. enum class AudioFeatures : u32 { + AudioUSBDeviceOutput, Splitter, PerformanceMetricsVersion2, VariadicCommandBuffer,