diff options
| author | Maufeat <sahyno1996@gmail.com> | 2025-11-27 19:46:41 +0100 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2025-11-27 19:46:41 +0100 |
| commit | f58097e814ebb000f23acbe26f096c8c4368da73 (patch) | |
| tree | 815402cc40eb6ce1f69cd977d411257c49f347ce /src/core/hle/service/audio/audio_controller.cpp | |
| parent | 1efef853529074adc4c7c1b43bcd3288e4b43004 (diff) | |
[hle,display,overlay,starter,hid] add overlay functions, starter applet (initially), HID handheld for system applets and fw21 stubs (#3080)
Adds fully functional overlay display.
- Enable Overlay Applet via "View" -> "Enable Overlay Display Applet"
- Open the overlay by pressing the home button for over 1s
- Can adjust volume
- Can toggle airplane mode (if on WiFi, maybe if overlay is enabled pretend to be on WiFi?)
- Future TODO(?): Adjust Brightness implementation for host system
- Inputs are properly registered. e.g. if overlay open, application does not register inputs.
You can control volume and airplane mode outside of the emulator window
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3080
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Co-committed-by: Maufeat <sahyno1996@gmail.com>
Diffstat (limited to 'src/core/hle/service/audio/audio_controller.cpp')
| -rw-r--r-- | src/core/hle/service/audio/audio_controller.cpp | 167 |
1 files changed, 161 insertions, 6 deletions
diff --git a/src/core/hle/service/audio/audio_controller.cpp b/src/core/hle/service/audio/audio_controller.cpp index 4456869d35..10b60618e5 100644 --- a/src/core/hle/service/audio/audio_controller.cpp +++ b/src/core/hle/service/audio/audio_controller.cpp @@ -1,15 +1,22 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/logging/log.h" +#include "audio_core/audio_core.h" #include "core/hle/service/audio/audio_controller.h" +#include "core/hle/service/audio/audio_out_manager.h" +#include "core/core.h" #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/set/system_settings_server.h" #include "core/hle/service/sm/sm.h" +#include "common/settings.h" +#include <algorithm> namespace Service::Audio { @@ -17,12 +24,12 @@ IAudioController::IAudioController(Core::System& system_) : ServiceFramework{system_, "audctl"}, service_context{system, "audctl"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetTargetVolume"}, - {1, nullptr, "SetTargetVolume"}, + {0, D<&IAudioController::GetTargetVolume>, "GetTargetVolume"}, + {1, D<&IAudioController::SetTargetVolume>, "SetTargetVolume"}, {2, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"}, {3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"}, - {4, nullptr, "IsTargetMute"}, - {5, nullptr, "SetTargetMute"}, + {4, D<&IAudioController::IsTargetMute>, "IsTargetMute"}, + {5, D<&IAudioController::SetTargetMute>, "SetTargetMute"}, {6, nullptr, "IsTargetConnected"}, {7, nullptr, "SetDefaultTarget"}, {8, nullptr, "GetDefaultTarget"}, @@ -49,7 +56,7 @@ IAudioController::IAudioController(Core::System& system_) {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, {30, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"}, {31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"}, - {32, nullptr, "GetActiveOutputTarget"}, + {32, D<&IAudioController::GetActiveOutputTarget>, "GetActiveOutputTarget"}, {33, nullptr, "GetTargetDeviceInfo"}, {34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"}, {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, @@ -84,6 +91,38 @@ IAudioController::IAudioController(Core::System& system_) m_set_sys = system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); notification_event = service_context.CreateEvent("IAudioController:NotificationEvent"); + + // Probably shouldn't do this in constructor? + try { + const int ui_volume = Settings::values.volume.GetValue(); + const int mapped = static_cast<int>(std::lround((static_cast<double>(ui_volume) / 100.0) * 15.0)); + const auto active_idx = static_cast<size_t>(m_active_target); + if (active_idx < m_target_volumes.size()) { + m_target_volumes[active_idx] = std::clamp(mapped, 0, 15); + } + + const bool muted = Settings::values.audio_muted.GetValue(); + for (auto& m : m_target_muted) { + m = muted; + } + + if (!muted && active_idx < m_target_volumes.size()) { + const float vol_f = static_cast<float>(m_target_volumes[active_idx]) / 15.0f; + try { + auto& sink = system.AudioCore().GetOutputSink(); + sink.SetSystemVolume(vol_f); + sink.SetDeviceVolume(vol_f); + } catch (...) { + LOG_WARNING(Audio, "Failed to apply initial sink volume from settings"); + } + + if (auto audout_mgr = system.ServiceManager().GetService<Service::Audio::IAudioOutManager>("audout:u")) { + audout_mgr->SetAllAudioOutVolume(static_cast<float>(m_target_volumes[active_idx]) / 15.0f); + } + } + } catch (...) { + // Catch if something fails, since this is constructor + } } IAudioController::~IAudioController() { @@ -191,4 +230,120 @@ Result IAudioController::Unknown5000(Out<SharedPointer<IAudioController>> out_au R_SUCCEED(); } + +Result IAudioController::GetTargetVolume(Out<s32> out_target_volume, Set::AudioOutputModeTarget target) { + LOG_DEBUG(Audio, "GetTargetVolume called, target={}", target); + + const auto idx = static_cast<size_t>(target); + if (idx >= m_target_volumes.size()) { + LOG_ERROR(Audio, "GetTargetVolume invalid target {}", idx); + R_THROW(ResultInvalidArgument); + } + + *out_target_volume = m_target_volumes[idx]; + R_SUCCEED(); +} + +Result IAudioController::SetTargetVolume(Set::AudioOutputModeTarget target, s32 target_volume) { + LOG_INFO(Audio, "SetTargetVolume called, target={}, volume={}", target, target_volume); + + const auto idx = static_cast<size_t>(target); + if (idx >= m_target_volumes.size()) { + LOG_ERROR(Audio, "SetTargetVolume invalid target {}", idx); + R_THROW(ResultInvalidArgument); + } + + if (target_volume < 0) { + target_volume = 0; + } else if (target_volume > 15) { + target_volume = 15; + } + + m_target_volumes[idx] = target_volume; + + if (m_active_target == target && !m_target_muted[idx]) { + const float vol = static_cast<float>(target_volume) / 15.0f; + // try catch this, as we don't know how it handles it when no output is set. + // we already have audio issues when no output is set, so catch. + try { + auto& sink = system.AudioCore().GetOutputSink(); + sink.SetSystemVolume(vol); + sink.SetDeviceVolume(vol); + } catch (...) { + LOG_WARNING(Audio, "Failed to set sink system volume"); + } + + if (auto audout_mgr = system.ServiceManager().GetService<IAudioOutManager>("audout:u")) { + audout_mgr->SetAllAudioOutVolume(vol); + } + } + + if (m_active_target == target) { + const int ui_volume = static_cast<int>(std::lround((static_cast<double>(target_volume) / 15.0) * 100.0)); + Settings::values.volume.SetValue(static_cast<u8>(std::clamp(ui_volume, 0, 100))); + } + + R_SUCCEED(); +} + +Result IAudioController::IsTargetMute(Out<bool> out_is_target_muted, Set::AudioOutputModeTarget target) { + LOG_DEBUG(Audio, "called, target={}", target); + + const auto idx = static_cast<size_t>(target); + if (idx >= m_target_muted.size()) { + LOG_ERROR(Audio, "invalid target {}", idx); + R_THROW(ResultInvalidArgument); + } + + *out_is_target_muted = m_target_muted[idx]; + R_SUCCEED(); +} + +Result IAudioController::SetTargetMute(bool is_muted, Set::AudioOutputModeTarget target) { + LOG_INFO(Audio, "called, target={}, muted={}", target, is_muted); + + const auto idx = static_cast<size_t>(target); + if (idx >= m_target_muted.size()) { + LOG_ERROR(Audio, "invalid target {}", idx); + R_THROW(ResultInvalidArgument); + } + + m_target_muted[idx] = is_muted; + + if (m_active_target == target) { + try { + auto& sink = system.AudioCore().GetOutputSink(); + if (is_muted) { + sink.SetSystemVolume(0.0f); + sink.SetDeviceVolume(0.0f); + } else { + const float vol = static_cast<float>(m_target_volumes[idx]) / 15.0f; + sink.SetSystemVolume(vol); + sink.SetDeviceVolume(vol); + } + } catch (...) { + LOG_WARNING(Audio, "Failed to set sink system volume on mute change"); + } + + // Also update any open audout sessions via the audout:u service. + if (auto audout_mgr = system.ServiceManager().GetService<IAudioOutManager>("audout:u")) { + if (is_muted) { + audout_mgr->SetAllAudioOutVolume(0.0f); + } else { + const float vol = static_cast<float>(m_target_volumes[idx]) / 15.0f; + audout_mgr->SetAllAudioOutVolume(vol); + } + } + } + + Settings::values.audio_muted.SetValue(is_muted); + + R_SUCCEED(); +} + +Result IAudioController::GetActiveOutputTarget(Out<Set::AudioOutputModeTarget> out_active_target) { + LOG_DEBUG(Audio, "GetActiveOutputTarget called"); + *out_active_target = m_active_target; + R_SUCCEED(); +} } // namespace Service::Audio |
