summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Liam2024-02-20 00:46:35 -0500
committerGravatar Liam2024-02-20 22:15:37 -0500
commit62083fcafd11348e01cf0d99e2693cb608cca71b (patch)
treeeca4183bdc0d8b299c7ffdfa879d4e1acaffb773
parentaudio: move IFinalOutputRecorderManager{,ForApplet} (diff)
downloadyuzu-62083fcafd11348e01cf0d99e2693cb608cca71b.tar.gz
yuzu-62083fcafd11348e01cf0d99e2693cb608cca71b.tar.xz
yuzu-62083fcafd11348e01cf0d99e2693cb608cca71b.zip
audio: split IAudioDevice, IAudioRenderer, move IAudioRendererManager
-rw-r--r--src/core/CMakeLists.txt12
-rw-r--r--src/core/hle/service/audio/audio.cpp5
-rw-r--r--src/core/hle/service/audio/audio_device.cpp183
-rw-r--r--src/core/hle/service/audio/audio_device.h35
-rw-r--r--src/core/hle/service/audio/audio_renderer.cpp210
-rw-r--r--src/core/hle/service/audio/audio_renderer.h45
-rw-r--r--src/core/hle/service/audio/audio_renderer_manager.cpp143
-rw-r--r--src/core/hle/service/audio/audio_renderer_manager.h (renamed from src/core/hle/service/audio/audren_u.h)7
-rw-r--r--src/core/hle/service/audio/audren_u.cpp552
9 files changed, 630 insertions, 562 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 68b940af3..5a1fc83bd 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -489,6 +489,10 @@ add_library(core STATIC
489 hle/service/apm/apm_controller.h 489 hle/service/apm/apm_controller.h
490 hle/service/apm/apm_interface.cpp 490 hle/service/apm/apm_interface.cpp
491 hle/service/apm/apm_interface.h 491 hle/service/apm/apm_interface.h
492 hle/service/audio/audio_controller.cpp
493 hle/service/audio/audio_controller.h
494 hle/service/audio/audio_device.cpp
495 hle/service/audio/audio_device.h
492 hle/service/audio/audio_in_manager.cpp 496 hle/service/audio/audio_in_manager.cpp
493 hle/service/audio/audio_in_manager.h 497 hle/service/audio/audio_in_manager.h
494 hle/service/audio/audio_in.cpp 498 hle/service/audio/audio_in.cpp
@@ -497,12 +501,12 @@ add_library(core STATIC
497 hle/service/audio/audio_out_manager.h 501 hle/service/audio/audio_out_manager.h
498 hle/service/audio/audio_out.cpp 502 hle/service/audio/audio_out.cpp
499 hle/service/audio/audio_out.h 503 hle/service/audio/audio_out.h
504 hle/service/audio/audio_renderer_manager.cpp
505 hle/service/audio/audio_renderer_manager.h
506 hle/service/audio/audio_renderer.cpp
507 hle/service/audio/audio_renderer.h
500 hle/service/audio/audio.cpp 508 hle/service/audio/audio.cpp
501 hle/service/audio/audio.h 509 hle/service/audio/audio.h
502 hle/service/audio/audio_controller.cpp
503 hle/service/audio/audio_controller.h
504 hle/service/audio/audren_u.cpp
505 hle/service/audio/audren_u.h
506 hle/service/audio/errors.h 510 hle/service/audio/errors.h
507 hle/service/audio/final_output_recorder_manager_for_applet.cpp 511 hle/service/audio/final_output_recorder_manager_for_applet.cpp
508 hle/service/audio/final_output_recorder_manager_for_applet.h 512 hle/service/audio/final_output_recorder_manager_for_applet.h
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 02773aee5..82a2ae283 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -6,7 +6,7 @@
6#include "core/hle/service/audio/audio_controller.h" 6#include "core/hle/service/audio/audio_controller.h"
7#include "core/hle/service/audio/audio_in_manager.h" 7#include "core/hle/service/audio/audio_in_manager.h"
8#include "core/hle/service/audio/audio_out_manager.h" 8#include "core/hle/service/audio/audio_out_manager.h"
9#include "core/hle/service/audio/audren_u.h" 9#include "core/hle/service/audio/audio_renderer_manager.h"
10#include "core/hle/service/audio/final_output_recorder_manager.h" 10#include "core/hle/service/audio/final_output_recorder_manager.h"
11#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h" 11#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
12#include "core/hle/service/audio/hwopus.h" 12#include "core/hle/service/audio/hwopus.h"
@@ -25,7 +25,8 @@ void LoopProcess(Core::System& system) {
25 "audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system)); 25 "audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system));
26 server_manager->RegisterNamedService("audrec:u", 26 server_manager->RegisterNamedService("audrec:u",
27 std::make_shared<IFinalOutputRecorderManager>(system)); 27 std::make_shared<IFinalOutputRecorderManager>(system));
28 server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system)); 28 server_manager->RegisterNamedService("audren:u",
29 std::make_shared<IAudioRendererManager>(system));
29 server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system)); 30 server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system));
30 ServerManager::RunServer(std::move(server_manager)); 31 ServerManager::RunServer(std::move(server_manager));
31} 32}
diff --git a/src/core/hle/service/audio/audio_device.cpp b/src/core/hle/service/audio/audio_device.cpp
new file mode 100644
index 000000000..3608d08c7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.cpp
@@ -0,0 +1,183 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/audio_core.h"
5#include "common/string_util.h"
6#include "core/hle/service/audio/audio_device.h"
7#include "core/hle/service/ipc_helpers.h"
8
9namespace Service::Audio {
10using namespace AudioCore::Renderer;
11
12IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
13 u32 device_num)
14 : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
15 impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
16 event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
17 static const FunctionInfo functions[] = {
18 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
19 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
20 {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
21 {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
22 {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
23 {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
24 {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
25 {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
26 {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
27 {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
28 {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
29 {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
30 {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"},
31 {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"},
32 };
33 RegisterHandlers(functions);
34
35 event->Signal();
36}
37
38IAudioDevice::~IAudioDevice() {
39 service_context.CloseEvent(event);
40}
41
42void IAudioDevice::ListAudioDeviceName(HLERequestContext& ctx) {
43 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
44
45 std::vector<AudioDevice::AudioDeviceName> out_names{};
46
47 const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
48
49 std::string out{};
50 for (u32 i = 0; i < out_count; i++) {
51 std::string a{};
52 u32 j = 0;
53 while (out_names[i].name[j] != '\0') {
54 a += out_names[i].name[j];
55 j++;
56 }
57 out += "\n\t" + a;
58 }
59
60 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
61
62 IPC::ResponseBuilder rb{ctx, 3};
63
64 ctx.WriteBuffer(out_names);
65
66 rb.Push(ResultSuccess);
67 rb.Push(out_count);
68}
69
70void IAudioDevice::SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
71 IPC::RequestParser rp{ctx};
72 const f32 volume = rp.Pop<f32>();
73
74 const auto device_name_buffer = ctx.ReadBuffer();
75 const std::string name = Common::StringFromBuffer(device_name_buffer);
76
77 LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume);
78
79 if (name == "AudioTvOutput") {
80 impl->SetDeviceVolumes(volume);
81 }
82
83 IPC::ResponseBuilder rb{ctx, 2};
84 rb.Push(ResultSuccess);
85}
86
87void IAudioDevice::GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
88 const auto device_name_buffer = ctx.ReadBuffer();
89 const std::string name = Common::StringFromBuffer(device_name_buffer);
90
91 LOG_DEBUG(Service_Audio, "called. Name={}", name);
92
93 f32 volume{1.0f};
94 if (name == "AudioTvOutput") {
95 volume = impl->GetDeviceVolume(name);
96 }
97
98 IPC::ResponseBuilder rb{ctx, 3};
99 rb.Push(ResultSuccess);
100 rb.Push(volume);
101}
102
103void IAudioDevice::GetActiveAudioDeviceName(HLERequestContext& ctx) {
104 const auto write_size = ctx.GetWriteBufferSize();
105 std::string out_name{"AudioTvOutput"};
106
107 LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);
108
109 out_name.resize(write_size);
110
111 ctx.WriteBuffer(out_name);
112
113 IPC::ResponseBuilder rb{ctx, 2};
114 rb.Push(ResultSuccess);
115}
116
117void IAudioDevice::QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
118 LOG_DEBUG(Service_Audio, "(STUBBED) called");
119
120 event->Signal();
121
122 IPC::ResponseBuilder rb{ctx, 2, 1};
123 rb.Push(ResultSuccess);
124 rb.PushCopyObjects(event->GetReadableEvent());
125}
126
127void IAudioDevice::GetActiveChannelCount(HLERequestContext& ctx) {
128 const auto& sink{system.AudioCore().GetOutputSink()};
129 u32 channel_count{sink.GetSystemChannels()};
130
131 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);
132
133 IPC::ResponseBuilder rb{ctx, 3};
134
135 rb.Push(ResultSuccess);
136 rb.Push<u32>(channel_count);
137}
138
139void IAudioDevice::QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
140 LOG_DEBUG(Service_Audio, "(STUBBED) called");
141
142 IPC::ResponseBuilder rb{ctx, 2, 1};
143 rb.Push(ResultSuccess);
144 rb.PushCopyObjects(event->GetReadableEvent());
145}
146
147void IAudioDevice::QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
148 LOG_DEBUG(Service_Audio, "called");
149
150 IPC::ResponseBuilder rb{ctx, 2, 1};
151 rb.Push(ResultSuccess);
152 rb.PushCopyObjects(event->GetReadableEvent());
153}
154
155void IAudioDevice::ListAudioOutputDeviceName(HLERequestContext& ctx) {
156 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
157
158 std::vector<AudioDevice::AudioDeviceName> out_names{};
159
160 const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
161
162 std::string out{};
163 for (u32 i = 0; i < out_count; i++) {
164 std::string a{};
165 u32 j = 0;
166 while (out_names[i].name[j] != '\0') {
167 a += out_names[i].name[j];
168 j++;
169 }
170 out += "\n\t" + a;
171 }
172
173 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
174
175 IPC::ResponseBuilder rb{ctx, 3};
176
177 ctx.WriteBuffer(out_names);
178
179 rb.Push(ResultSuccess);
180 rb.Push(out_count);
181}
182
183} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_device.h b/src/core/hle/service/audio/audio_device.h
new file mode 100644
index 000000000..850c60051
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.h
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/audio_device.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IAudioDevice final : public ServiceFramework<IAudioDevice> {
13
14public:
15 explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
16 u32 device_num);
17 ~IAudioDevice() override;
18
19private:
20 void ListAudioDeviceName(HLERequestContext& ctx);
21 void SetAudioDeviceOutputVolume(HLERequestContext& ctx);
22 void GetAudioDeviceOutputVolume(HLERequestContext& ctx);
23 void GetActiveAudioDeviceName(HLERequestContext& ctx);
24 void QueryAudioDeviceSystemEvent(HLERequestContext& ctx);
25 void GetActiveChannelCount(HLERequestContext& ctx);
26 void QueryAudioDeviceInputEvent(HLERequestContext& ctx);
27 void QueryAudioDeviceOutputEvent(HLERequestContext& ctx);
28 void ListAudioOutputDeviceName(HLERequestContext& ctx);
29
30 KernelHelpers::ServiceContext service_context;
31 std::unique_ptr<AudioCore::Renderer::AudioDevice> impl;
32 Kernel::KEvent* event;
33};
34
35} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.cpp b/src/core/hle/service/audio/audio_renderer.cpp
new file mode 100644
index 000000000..68415eb8f
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.cpp
@@ -0,0 +1,210 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/audio_renderer.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::Audio {
8using namespace AudioCore::Renderer;
9
10IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_,
11 AudioCore::AudioRendererParameterInternal& params,
12 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
13 u32 process_handle, Kernel::KProcess& process_,
14 u64 applet_resource_user_id, s32 session_id)
15 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
16 rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
17 impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} {
18 // clang-format off
19 static const FunctionInfo functions[] = {
20 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
21 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
22 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
23 {3, &IAudioRenderer::GetState, "GetState"},
24 {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
25 {5, &IAudioRenderer::Start, "Start"},
26 {6, &IAudioRenderer::Stop, "Stop"},
27 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
28 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
29 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
30 {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"},
31 {11, nullptr, "ExecuteAudioRendererRendering"},
32 {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"},
33 {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"},
34 };
35 // clang-format on
36 RegisterHandlers(functions);
37
38 process.Open();
39 impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
40 applet_resource_user_id, session_id);
41}
42
43IAudioRenderer::~IAudioRenderer() {
44 impl->Finalize();
45 service_context.CloseEvent(rendered_event);
46 process.Close();
47}
48
49void IAudioRenderer::GetSampleRate(HLERequestContext& ctx) {
50 const auto sample_rate{impl->GetSystem().GetSampleRate()};
51
52 LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate);
53
54 IPC::ResponseBuilder rb{ctx, 3};
55 rb.Push(ResultSuccess);
56 rb.Push(sample_rate);
57}
58
59void IAudioRenderer::GetSampleCount(HLERequestContext& ctx) {
60 const auto sample_count{impl->GetSystem().GetSampleCount()};
61
62 LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count);
63
64 IPC::ResponseBuilder rb{ctx, 3};
65 rb.Push(ResultSuccess);
66 rb.Push(sample_count);
67}
68
69void IAudioRenderer::GetState(HLERequestContext& ctx) {
70 const u32 state{!impl->GetSystem().IsActive()};
71
72 LOG_DEBUG(Service_Audio, "called, state {}", state);
73
74 IPC::ResponseBuilder rb{ctx, 3};
75 rb.Push(ResultSuccess);
76 rb.Push(state);
77}
78
79void IAudioRenderer::GetMixBufferCount(HLERequestContext& ctx) {
80 LOG_DEBUG(Service_Audio, "called");
81
82 const auto buffer_count{impl->GetSystem().GetMixBufferCount()};
83
84 IPC::ResponseBuilder rb{ctx, 3};
85 rb.Push(ResultSuccess);
86 rb.Push(buffer_count);
87}
88
89void IAudioRenderer::RequestUpdate(HLERequestContext& ctx) {
90 LOG_TRACE(Service_Audio, "called");
91
92 const auto input{ctx.ReadBuffer(0)};
93
94 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
95 // checking size 0. Performance size is 0 for most games.
96
97 auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
98 if (is_buffer_b) {
99 const auto buffersB{ctx.BufferDescriptorB()};
100 output_buffer.resize_destructive(buffersB[0].Size());
101 performance_buffer.resize_destructive(buffersB[1].Size());
102 } else {
103 const auto buffersC{ctx.BufferDescriptorC()};
104 output_buffer.resize_destructive(buffersC[0].Size());
105 performance_buffer.resize_destructive(buffersC[1].Size());
106 }
107
108 auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
109
110 if (result.IsSuccess()) {
111 if (is_buffer_b) {
112 ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
113 ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
114 } else {
115 ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
116 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
117 }
118 } else {
119 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.GetDescription());
120 }
121
122 IPC::ResponseBuilder rb{ctx, 2};
123 rb.Push(result);
124}
125
126void IAudioRenderer::Start(HLERequestContext& ctx) {
127 LOG_DEBUG(Service_Audio, "called");
128
129 impl->Start();
130
131 IPC::ResponseBuilder rb{ctx, 2};
132 rb.Push(ResultSuccess);
133}
134
135void IAudioRenderer::Stop(HLERequestContext& ctx) {
136 LOG_DEBUG(Service_Audio, "called");
137
138 impl->Stop();
139
140 IPC::ResponseBuilder rb{ctx, 2};
141 rb.Push(ResultSuccess);
142}
143
144void IAudioRenderer::QuerySystemEvent(HLERequestContext& ctx) {
145 LOG_DEBUG(Service_Audio, "called");
146
147 if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) {
148 IPC::ResponseBuilder rb{ctx, 2};
149 rb.Push(Audio::ResultNotSupported);
150 return;
151 }
152
153 IPC::ResponseBuilder rb{ctx, 2, 1};
154 rb.Push(ResultSuccess);
155 rb.PushCopyObjects(rendered_event->GetReadableEvent());
156}
157
158void IAudioRenderer::SetRenderingTimeLimit(HLERequestContext& ctx) {
159 LOG_DEBUG(Service_Audio, "called");
160
161 IPC::RequestParser rp{ctx};
162 auto limit = rp.PopRaw<u32>();
163
164 auto& system_ = impl->GetSystem();
165 system_.SetRenderingTimeLimit(limit);
166
167 IPC::ResponseBuilder rb{ctx, 2};
168 rb.Push(ResultSuccess);
169}
170
171void IAudioRenderer::GetRenderingTimeLimit(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Audio, "called");
173
174 auto& system_ = impl->GetSystem();
175 auto time = system_.GetRenderingTimeLimit();
176
177 IPC::ResponseBuilder rb{ctx, 3};
178 rb.Push(ResultSuccess);
179 rb.Push(time);
180}
181
182void IAudioRenderer::ExecuteAudioRendererRendering(HLERequestContext& ctx) {
183 LOG_DEBUG(Service_Audio, "called");
184}
185
186void IAudioRenderer::SetVoiceDropParameter(HLERequestContext& ctx) {
187 LOG_DEBUG(Service_Audio, "called");
188
189 IPC::RequestParser rp{ctx};
190 auto voice_drop_param{rp.Pop<f32>()};
191
192 auto& system_ = impl->GetSystem();
193 system_.SetVoiceDropParameter(voice_drop_param);
194
195 IPC::ResponseBuilder rb{ctx, 2};
196 rb.Push(ResultSuccess);
197}
198
199void IAudioRenderer::GetVoiceDropParameter(HLERequestContext& ctx) {
200 LOG_DEBUG(Service_Audio, "called");
201
202 auto& system_ = impl->GetSystem();
203 auto voice_drop_param{system_.GetVoiceDropParameter()};
204
205 IPC::ResponseBuilder rb{ctx, 3};
206 rb.Push(ResultSuccess);
207 rb.Push(voice_drop_param);
208}
209
210} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.h b/src/core/hle/service/audio/audio_renderer.h
new file mode 100644
index 000000000..f8c48154b
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.h
@@ -0,0 +1,45 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/audio_renderer.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
13public:
14 explicit IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
15 AudioCore::AudioRendererParameterInternal& params,
16 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
17 u32 process_handle, Kernel::KProcess& process_,
18 u64 applet_resource_user_id, s32 session_id);
19 ~IAudioRenderer() override;
20
21private:
22 void GetSampleRate(HLERequestContext& ctx);
23 void GetSampleCount(HLERequestContext& ctx);
24 void GetState(HLERequestContext& ctx);
25 void GetMixBufferCount(HLERequestContext& ctx);
26 void RequestUpdate(HLERequestContext& ctx);
27 void Start(HLERequestContext& ctx);
28 void Stop(HLERequestContext& ctx);
29 void QuerySystemEvent(HLERequestContext& ctx);
30 void SetRenderingTimeLimit(HLERequestContext& ctx);
31 void GetRenderingTimeLimit(HLERequestContext& ctx);
32 void ExecuteAudioRendererRendering(HLERequestContext& ctx);
33 void SetVoiceDropParameter(HLERequestContext& ctx);
34 void GetVoiceDropParameter(HLERequestContext& ctx);
35
36 KernelHelpers::ServiceContext service_context;
37 Kernel::KEvent* rendered_event;
38 AudioCore::Renderer::Manager& manager;
39 std::unique_ptr<AudioCore::Renderer::Renderer> impl;
40 Kernel::KProcess& process;
41 Common::ScratchBuffer<u8> output_buffer;
42 Common::ScratchBuffer<u8> performance_buffer;
43};
44
45} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.cpp b/src/core/hle/service/audio/audio_renderer_manager.cpp
new file mode 100644
index 000000000..7baa9d8cf
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.cpp
@@ -0,0 +1,143 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/audio_render_manager.h"
5#include "audio_core/common/feature_support.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/k_transfer_memory.h"
8#include "core/hle/service/audio/audio_device.h"
9#include "core/hle/service/audio/audio_renderer.h"
10#include "core/hle/service/audio/audio_renderer_manager.h"
11#include "core/hle/service/ipc_helpers.h"
12
13namespace Service::Audio {
14
15using namespace AudioCore::Renderer;
16
17IAudioRendererManager::IAudioRendererManager(Core::System& system_)
18 : ServiceFramework{system_, "audren:u"}, service_context{system_, "audren:u"},
19 impl{std::make_unique<Manager>(system_)} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, &IAudioRendererManager::OpenAudioRenderer, "OpenAudioRenderer"},
23 {1, &IAudioRendererManager::GetWorkBufferSize, "GetWorkBufferSize"},
24 {2, &IAudioRendererManager::GetAudioDeviceService, "GetAudioDeviceService"},
25 {3, nullptr, "OpenAudioRendererForManualExecution"},
26 {4, &IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
27 };
28 // clang-format on
29
30 RegisterHandlers(functions);
31}
32
33IAudioRendererManager::~IAudioRendererManager() = default;
34
35void IAudioRendererManager::OpenAudioRenderer(HLERequestContext& ctx) {
36 IPC::RequestParser rp{ctx};
37
38 AudioCore::AudioRendererParameterInternal params;
39 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
40 rp.Skip(1, false);
41 auto transfer_memory_size = rp.Pop<u64>();
42 auto applet_resource_user_id = rp.Pop<u64>();
43 auto transfer_memory_handle = ctx.GetCopyHandle(0);
44 auto process_handle = ctx.GetCopyHandle(1);
45
46 if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
47 LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
48 IPC::ResponseBuilder rb{ctx, 2};
49 rb.Push(Audio::ResultOutOfSessions);
50 return;
51 }
52
53 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()};
54 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
55
56 const auto session_id{impl->GetSessionId()};
57 if (session_id == -1) {
58 LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(Audio::ResultOutOfSessions);
61 return;
62 }
63
64 LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
65 impl->GetSessionCount());
66
67 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
68 rb.Push(ResultSuccess);
69 rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(),
70 transfer_memory_size, process_handle, *process,
71 applet_resource_user_id, session_id);
72}
73
74void IAudioRendererManager::GetWorkBufferSize(HLERequestContext& ctx) {
75 AudioCore::AudioRendererParameterInternal params;
76
77 IPC::RequestParser rp{ctx};
78 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
79
80 u64 size{0};
81 auto result = impl->GetWorkBufferSize(params, size);
82
83 std::string output_info{};
84 output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
85 output_info +=
86 fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
87 output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
88 static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
89 output_info += fmt::format(
90 "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
91 "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
92 "Context {:04X}",
93 params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
94 params.splitter_destinations, params.voices, params.perf_frames,
95 params.external_context_size);
96
97 LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
98 output_info, size);
99
100 IPC::ResponseBuilder rb{ctx, 4};
101 rb.Push(result);
102 rb.Push<u64>(size);
103}
104
105void IAudioRendererManager::GetAudioDeviceService(HLERequestContext& ctx) {
106 IPC::RequestParser rp{ctx};
107
108 const auto applet_resource_user_id = rp.Pop<u64>();
109
110 LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id);
111
112 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
113
114 rb.Push(ResultSuccess);
115 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id,
116 ::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
117}
118
119void IAudioRendererManager::OpenAudioRendererForManualExecution(HLERequestContext& ctx) {
120 LOG_ERROR(Service_Audio, "called. Implement me!");
121}
122
123void IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) {
124 struct Parameters {
125 u32 revision;
126 u64 applet_resource_user_id;
127 };
128
129 IPC::RequestParser rp{ctx};
130
131 const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>();
132
133 LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}",
134 AudioCore::GetRevisionNum(revision), applet_resource_user_id);
135
136 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
137
138 rb.Push(ResultSuccess);
139 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision,
140 num_audio_devices++);
141}
142
143} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audio_renderer_manager.h
index 3d7993a16..3623f91c6 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audio_renderer_manager.h
@@ -4,7 +4,6 @@
4#pragma once 4#pragma once
5 5
6#include "audio_core/audio_render_manager.h" 6#include "audio_core/audio_render_manager.h"
7#include "common/scratch_buffer.h"
8#include "core/hle/service/kernel_helpers.h" 7#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
10 9
@@ -15,10 +14,10 @@ class System;
15namespace Service::Audio { 14namespace Service::Audio {
16class IAudioRenderer; 15class IAudioRenderer;
17 16
18class AudRenU final : public ServiceFramework<AudRenU> { 17class IAudioRendererManager final : public ServiceFramework<IAudioRendererManager> {
19public: 18public:
20 explicit AudRenU(Core::System& system_); 19 explicit IAudioRendererManager(Core::System& system_);
21 ~AudRenU() override; 20 ~IAudioRendererManager() override;
22 21
23private: 22private:
24 void OpenAudioRenderer(HLERequestContext& ctx); 23 void OpenAudioRenderer(HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
deleted file mode 100644
index 10108abc0..000000000
--- a/src/core/hle/service/audio/audren_u.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <memory>
6
7#include "audio_core/audio_core.h"
8#include "audio_core/common/audio_renderer_parameter.h"
9#include "audio_core/common/feature_support.h"
10#include "audio_core/renderer/audio_device.h"
11#include "audio_core/renderer/audio_renderer.h"
12#include "audio_core/renderer/voice/voice_info.h"
13#include "common/alignment.h"
14#include "common/bit_util.h"
15#include "common/common_funcs.h"
16#include "common/logging/log.h"
17#include "common/polyfill_ranges.h"
18#include "common/scratch_buffer.h"
19#include "common/string_util.h"
20#include "core/core.h"
21#include "core/hle/kernel/k_event.h"
22#include "core/hle/kernel/k_process.h"
23#include "core/hle/kernel/k_transfer_memory.h"
24#include "core/hle/service/audio/audren_u.h"
25#include "core/hle/service/audio/errors.h"
26#include "core/hle/service/ipc_helpers.h"
27#include "core/memory.h"
28
29using namespace AudioCore::Renderer;
30
31namespace Service::Audio {
32
33class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
34public:
35 explicit IAudioRenderer(Core::System& system_, Manager& manager_,
36 AudioCore::AudioRendererParameterInternal& params,
37 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
38 u32 process_handle, Kernel::KProcess& process_,
39 u64 applet_resource_user_id, s32 session_id)
40 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
41 rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
42 impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} {
43 // clang-format off
44 static const FunctionInfo functions[] = {
45 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
46 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
47 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
48 {3, &IAudioRenderer::GetState, "GetState"},
49 {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
50 {5, &IAudioRenderer::Start, "Start"},
51 {6, &IAudioRenderer::Stop, "Stop"},
52 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
53 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
54 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
55 {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"},
56 {11, nullptr, "ExecuteAudioRendererRendering"},
57 {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"},
58 {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"},
59 };
60 // clang-format on
61 RegisterHandlers(functions);
62
63 process.Open();
64 impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
65 applet_resource_user_id, session_id);
66 }
67
68 ~IAudioRenderer() override {
69 impl->Finalize();
70 service_context.CloseEvent(rendered_event);
71 process.Close();
72 }
73
74private:
75 void GetSampleRate(HLERequestContext& ctx) {
76 const auto sample_rate{impl->GetSystem().GetSampleRate()};
77
78 LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate);
79
80 IPC::ResponseBuilder rb{ctx, 3};
81 rb.Push(ResultSuccess);
82 rb.Push(sample_rate);
83 }
84
85 void GetSampleCount(HLERequestContext& ctx) {
86 const auto sample_count{impl->GetSystem().GetSampleCount()};
87
88 LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count);
89
90 IPC::ResponseBuilder rb{ctx, 3};
91 rb.Push(ResultSuccess);
92 rb.Push(sample_count);
93 }
94
95 void GetState(HLERequestContext& ctx) {
96 const u32 state{!impl->GetSystem().IsActive()};
97
98 LOG_DEBUG(Service_Audio, "called, state {}", state);
99
100 IPC::ResponseBuilder rb{ctx, 3};
101 rb.Push(ResultSuccess);
102 rb.Push(state);
103 }
104
105 void GetMixBufferCount(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_Audio, "called");
107
108 const auto buffer_count{impl->GetSystem().GetMixBufferCount()};
109
110 IPC::ResponseBuilder rb{ctx, 3};
111 rb.Push(ResultSuccess);
112 rb.Push(buffer_count);
113 }
114
115 void RequestUpdate(HLERequestContext& ctx) {
116 LOG_TRACE(Service_Audio, "called");
117
118 const auto input{ctx.ReadBuffer(0)};
119
120 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
121 // checking size 0. Performance size is 0 for most games.
122
123 auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
124 if (is_buffer_b) {
125 const auto buffersB{ctx.BufferDescriptorB()};
126 output_buffer.resize_destructive(buffersB[0].Size());
127 performance_buffer.resize_destructive(buffersB[1].Size());
128 } else {
129 const auto buffersC{ctx.BufferDescriptorC()};
130 output_buffer.resize_destructive(buffersC[0].Size());
131 performance_buffer.resize_destructive(buffersC[1].Size());
132 }
133
134 auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
135
136 if (result.IsSuccess()) {
137 if (is_buffer_b) {
138 ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
139 ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
140 } else {
141 ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
142 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
143 }
144 } else {
145 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!",
146 result.GetDescription());
147 }
148
149 IPC::ResponseBuilder rb{ctx, 2};
150 rb.Push(result);
151 }
152
153 void Start(HLERequestContext& ctx) {
154 LOG_DEBUG(Service_Audio, "called");
155
156 impl->Start();
157
158 IPC::ResponseBuilder rb{ctx, 2};
159 rb.Push(ResultSuccess);
160 }
161
162 void Stop(HLERequestContext& ctx) {
163 LOG_DEBUG(Service_Audio, "called");
164
165 impl->Stop();
166
167 IPC::ResponseBuilder rb{ctx, 2};
168 rb.Push(ResultSuccess);
169 }
170
171 void QuerySystemEvent(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Audio, "called");
173
174 if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) {
175 IPC::ResponseBuilder rb{ctx, 2};
176 rb.Push(Audio::ResultNotSupported);
177 return;
178 }
179
180 IPC::ResponseBuilder rb{ctx, 2, 1};
181 rb.Push(ResultSuccess);
182 rb.PushCopyObjects(rendered_event->GetReadableEvent());
183 }
184
185 void SetRenderingTimeLimit(HLERequestContext& ctx) {
186 LOG_DEBUG(Service_Audio, "called");
187
188 IPC::RequestParser rp{ctx};
189 auto limit = rp.PopRaw<u32>();
190
191 auto& system_ = impl->GetSystem();
192 system_.SetRenderingTimeLimit(limit);
193
194 IPC::ResponseBuilder rb{ctx, 2};
195 rb.Push(ResultSuccess);
196 }
197
198 void GetRenderingTimeLimit(HLERequestContext& ctx) {
199 LOG_DEBUG(Service_Audio, "called");
200
201 auto& system_ = impl->GetSystem();
202 auto time = system_.GetRenderingTimeLimit();
203
204 IPC::ResponseBuilder rb{ctx, 3};
205 rb.Push(ResultSuccess);
206 rb.Push(time);
207 }
208
209 void ExecuteAudioRendererRendering(HLERequestContext& ctx) {
210 LOG_DEBUG(Service_Audio, "called");
211 }
212
213 void SetVoiceDropParameter(HLERequestContext& ctx) {
214 LOG_DEBUG(Service_Audio, "called");
215
216 IPC::RequestParser rp{ctx};
217 auto voice_drop_param{rp.Pop<f32>()};
218
219 auto& system_ = impl->GetSystem();
220 system_.SetVoiceDropParameter(voice_drop_param);
221
222 IPC::ResponseBuilder rb{ctx, 2};
223 rb.Push(ResultSuccess);
224 }
225
226 void GetVoiceDropParameter(HLERequestContext& ctx) {
227 LOG_DEBUG(Service_Audio, "called");
228
229 auto& system_ = impl->GetSystem();
230 auto voice_drop_param{system_.GetVoiceDropParameter()};
231
232 IPC::ResponseBuilder rb{ctx, 3};
233 rb.Push(ResultSuccess);
234 rb.Push(voice_drop_param);
235 }
236
237 KernelHelpers::ServiceContext service_context;
238 Kernel::KEvent* rendered_event;
239 Manager& manager;
240 std::unique_ptr<Renderer> impl;
241 Kernel::KProcess& process;
242 Common::ScratchBuffer<u8> output_buffer;
243 Common::ScratchBuffer<u8> performance_buffer;
244};
245
246class IAudioDevice final : public ServiceFramework<IAudioDevice> {
247
248public:
249 explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
250 u32 device_num)
251 : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
252 impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
253 event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
254 static const FunctionInfo functions[] = {
255 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
256 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
257 {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
258 {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
259 {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
260 {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
261 {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
262 {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
263 {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
264 {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
265 {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
266 {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
267 {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"},
268 {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"},
269 };
270 RegisterHandlers(functions);
271
272 event->Signal();
273 }
274
275 ~IAudioDevice() override {
276 service_context.CloseEvent(event);
277 }
278
279private:
280 void ListAudioDeviceName(HLERequestContext& ctx) {
281 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
282
283 std::vector<AudioDevice::AudioDeviceName> out_names{};
284
285 const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
286
287 std::string out{};
288 for (u32 i = 0; i < out_count; i++) {
289 std::string a{};
290 u32 j = 0;
291 while (out_names[i].name[j] != '\0') {
292 a += out_names[i].name[j];
293 j++;
294 }
295 out += "\n\t" + a;
296 }
297
298 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
299
300 IPC::ResponseBuilder rb{ctx, 3};
301
302 ctx.WriteBuffer(out_names);
303
304 rb.Push(ResultSuccess);
305 rb.Push(out_count);
306 }
307
308 void SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
309 IPC::RequestParser rp{ctx};
310 const f32 volume = rp.Pop<f32>();
311
312 const auto device_name_buffer = ctx.ReadBuffer();
313 const std::string name = Common::StringFromBuffer(device_name_buffer);
314
315 LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume);
316
317 if (name == "AudioTvOutput") {
318 impl->SetDeviceVolumes(volume);
319 }
320
321 IPC::ResponseBuilder rb{ctx, 2};
322 rb.Push(ResultSuccess);
323 }
324
325 void GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
326 const auto device_name_buffer = ctx.ReadBuffer();
327 const std::string name = Common::StringFromBuffer(device_name_buffer);
328
329 LOG_DEBUG(Service_Audio, "called. Name={}", name);
330
331 f32 volume{1.0f};
332 if (name == "AudioTvOutput") {
333 volume = impl->GetDeviceVolume(name);
334 }
335
336 IPC::ResponseBuilder rb{ctx, 3};
337 rb.Push(ResultSuccess);
338 rb.Push(volume);
339 }
340
341 void GetActiveAudioDeviceName(HLERequestContext& ctx) {
342 const auto write_size = ctx.GetWriteBufferSize();
343 std::string out_name{"AudioTvOutput"};
344
345 LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);
346
347 out_name.resize(write_size);
348
349 ctx.WriteBuffer(out_name);
350
351 IPC::ResponseBuilder rb{ctx, 2};
352 rb.Push(ResultSuccess);
353 }
354
355 void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
356 LOG_DEBUG(Service_Audio, "(STUBBED) called");
357
358 event->Signal();
359
360 IPC::ResponseBuilder rb{ctx, 2, 1};
361 rb.Push(ResultSuccess);
362 rb.PushCopyObjects(event->GetReadableEvent());
363 }
364
365 void GetActiveChannelCount(HLERequestContext& ctx) {
366 const auto& sink{system.AudioCore().GetOutputSink()};
367 u32 channel_count{sink.GetSystemChannels()};
368
369 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);
370
371 IPC::ResponseBuilder rb{ctx, 3};
372
373 rb.Push(ResultSuccess);
374 rb.Push<u32>(channel_count);
375 }
376
377 void QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
378 LOG_DEBUG(Service_Audio, "(STUBBED) called");
379
380 IPC::ResponseBuilder rb{ctx, 2, 1};
381 rb.Push(ResultSuccess);
382 rb.PushCopyObjects(event->GetReadableEvent());
383 }
384
385 void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
386 LOG_DEBUG(Service_Audio, "called");
387
388 IPC::ResponseBuilder rb{ctx, 2, 1};
389 rb.Push(ResultSuccess);
390 rb.PushCopyObjects(event->GetReadableEvent());
391 }
392
393 void ListAudioOutputDeviceName(HLERequestContext& ctx) {
394 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
395
396 std::vector<AudioDevice::AudioDeviceName> out_names{};
397
398 const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
399
400 std::string out{};
401 for (u32 i = 0; i < out_count; i++) {
402 std::string a{};
403 u32 j = 0;
404 while (out_names[i].name[j] != '\0') {
405 a += out_names[i].name[j];
406 j++;
407 }
408 out += "\n\t" + a;
409 }
410
411 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
412
413 IPC::ResponseBuilder rb{ctx, 3};
414
415 ctx.WriteBuffer(out_names);
416
417 rb.Push(ResultSuccess);
418 rb.Push(out_count);
419 }
420
421 KernelHelpers::ServiceContext service_context;
422 std::unique_ptr<AudioDevice> impl;
423 Kernel::KEvent* event;
424};
425
426AudRenU::AudRenU(Core::System& system_)
427 : ServiceFramework{system_, "audren:u"},
428 service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
429 // clang-format off
430 static const FunctionInfo functions[] = {
431 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
432 {1, &AudRenU::GetWorkBufferSize, "GetWorkBufferSize"},
433 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
434 {3, nullptr, "OpenAudioRendererForManualExecution"},
435 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
436 };
437 // clang-format on
438
439 RegisterHandlers(functions);
440}
441
442AudRenU::~AudRenU() = default;
443
444void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
445 IPC::RequestParser rp{ctx};
446
447 AudioCore::AudioRendererParameterInternal params;
448 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
449 rp.Skip(1, false);
450 auto transfer_memory_size = rp.Pop<u64>();
451 auto applet_resource_user_id = rp.Pop<u64>();
452 auto transfer_memory_handle = ctx.GetCopyHandle(0);
453 auto process_handle = ctx.GetCopyHandle(1);
454
455 if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
456 LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
457 IPC::ResponseBuilder rb{ctx, 2};
458 rb.Push(Audio::ResultOutOfSessions);
459 return;
460 }
461
462 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()};
463 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
464
465 const auto session_id{impl->GetSessionId()};
466 if (session_id == -1) {
467 LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
468 IPC::ResponseBuilder rb{ctx, 2};
469 rb.Push(Audio::ResultOutOfSessions);
470 return;
471 }
472
473 LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
474 impl->GetSessionCount());
475
476 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
477 rb.Push(ResultSuccess);
478 rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(),
479 transfer_memory_size, process_handle, *process,
480 applet_resource_user_id, session_id);
481}
482
483void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) {
484 AudioCore::AudioRendererParameterInternal params;
485
486 IPC::RequestParser rp{ctx};
487 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
488
489 u64 size{0};
490 auto result = impl->GetWorkBufferSize(params, size);
491
492 std::string output_info{};
493 output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
494 output_info +=
495 fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
496 output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
497 static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
498 output_info += fmt::format(
499 "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
500 "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
501 "Context {:04X}",
502 params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
503 params.splitter_destinations, params.voices, params.perf_frames,
504 params.external_context_size);
505
506 LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
507 output_info, size);
508
509 IPC::ResponseBuilder rb{ctx, 4};
510 rb.Push(result);
511 rb.Push<u64>(size);
512}
513
514void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) {
515 IPC::RequestParser rp{ctx};
516
517 const auto applet_resource_user_id = rp.Pop<u64>();
518
519 LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id);
520
521 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
522
523 rb.Push(ResultSuccess);
524 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id,
525 ::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
526}
527
528void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) {
529 LOG_ERROR(Service_Audio, "called. Implement me!");
530}
531
532void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) {
533 struct Parameters {
534 u32 revision;
535 u64 applet_resource_user_id;
536 };
537
538 IPC::RequestParser rp{ctx};
539
540 const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>();
541
542 LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}",
543 AudioCore::GetRevisionNum(revision), applet_resource_user_id);
544
545 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
546
547 rb.Push(ResultSuccess);
548 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision,
549 num_audio_devices++);
550}
551
552} // namespace Service::Audio