// 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/ipc_helpers.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(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::~IAudioDevice() { service_context.CloseEvent(event); } void IAudioDevice::ListAudioDeviceName(HLERequestContext& ctx) { const size_t in_count = ctx.GetWriteBufferNumElements(); std::vector 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 IAudioDevice::SetAudioDeviceOutputVolume(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const f32 volume = rp.Pop(); 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 IAudioDevice::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 IAudioDevice::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 IAudioDevice::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 IAudioDevice::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(channel_count); } void IAudioDevice::QueryAudioDeviceInputEvent(HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); rb.PushCopyObjects(event->GetReadableEvent()); } void IAudioDevice::QueryAudioDeviceOutputEvent(HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); rb.PushCopyObjects(event->GetReadableEvent()); } void IAudioDevice::ListAudioOutputDeviceName(HLERequestContext& ctx) { const size_t in_count = ctx.GetWriteBufferNumElements(); std::vector 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); } } // namespace Service::Audio