summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar st4rk2018-01-24 19:17:54 -0800
committerGravatar bunnei2018-01-24 22:17:54 -0500
commit44eb8402322a47a52f0401f9ef7473bea719e2bf (patch)
treef2bd30601610b3a7650bacb176dda0e0a03cd9f0 /src
parentMerge pull request #140 from gdkchan/time_fix (diff)
downloadyuzu-44eb8402322a47a52f0401f9ef7473bea719e2bf.tar.gz
yuzu-44eb8402322a47a52f0401f9ef7473bea719e2bf.tar.xz
yuzu-44eb8402322a47a52f0401f9ef7473bea719e2bf.zip
audout:u OpenAudioOut and IAudioOut (#138)
* Updated the audout:u and IAudioOut, now it might work with RetroArch without trigger an assert, however it's not the ideal implementation * Updated the audout:u and IAudioOut, now it might work with RetroArch without trigger an assert, however it's not the ideal implementation * audout:u OpenAudioOut implementation and IAudioOut cmd 1,2,3,4,5 implementation * using an enum for audio_out_state as well as changing its initialize to member initializer list * Minor fixes, added Service_Audio for LOG_*, changed PcmFormat enum to EnumClass * Minor fixes, added Service_Audio for LOG_*, changed PcmFormat enum to EnumClass * added missing Audio loggin subclass, minor fixes, clang comment breakline * Solving backend logging conflict * minor fix * Fixed duplicated Service NVDRV in backend.cpp, my bad
Diffstat (limited to 'src')
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/core/hle/service/audio/audout_u.cpp166
-rw-r--r--src/core/hle/service/audio/audout_u.h14
4 files changed, 168 insertions, 14 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 2bd0a6be9..be53be407 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -39,6 +39,7 @@ namespace Log {
39 SUB(Service, DSP) \ 39 SUB(Service, DSP) \
40 SUB(Service, HID) \ 40 SUB(Service, HID) \
41 SUB(Service, NVDRV) \ 41 SUB(Service, NVDRV) \
42 SUB(Service, Audio) \
42 CLS(HW) \ 43 CLS(HW) \
43 SUB(HW, Memory) \ 44 SUB(HW, Memory) \
44 SUB(HW, LCD) \ 45 SUB(HW, LCD) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 3144a0349..09ea7a2c7 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -56,6 +56,7 @@ enum class Class : ClassType {
56 Service_DSP, ///< The DSP (DSP control) service 56 Service_DSP, ///< The DSP (DSP control) service
57 Service_HID, ///< The HID (Human interface device) service 57 Service_HID, ///< The HID (Human interface device) service
58 Service_NVDRV, ///< The NVDRV (Nvidia driver) service 58 Service_NVDRV, ///< The NVDRV (Nvidia driver) service
59 Service_Audio, ///< The Audio (Audio control) service
59 HW, ///< Low-level hardware emulation 60 HW, ///< Low-level hardware emulation
60 HW_Memory, ///< Memory-map and address translation 61 HW_Memory, ///< Memory-map and address translation
61 HW_LCD, ///< LCD register emulation 62 HW_LCD, ///< LCD register emulation
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 8a436bf97..df04d636e 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -2,35 +2,163 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <vector>
5#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core_timing.h"
6#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h"
7#include "core/hle/kernel/hle_ipc.h" 10#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/audio/audout_u.h" 11#include "core/hle/service/audio/audout_u.h"
9 12
10namespace Service { 13namespace Service {
11namespace Audio { 14namespace Audio {
12 15
16/// Switch sample rate frequency
17constexpr u32 sample_rate{48000};
18/// TODO(st4rk): dynamic number of channels, as I think Switch has support
19/// to more audio channels (probably when Docked I guess)
20constexpr u32 audio_channels{2};
21/// TODO(st4rk): find a proper value for the audio_ticks
22constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 500)};
23
13class IAudioOut final : public ServiceFramework<IAudioOut> { 24class IAudioOut final : public ServiceFramework<IAudioOut> {
14public: 25public:
15 IAudioOut() : ServiceFramework("IAudioOut") { 26 IAudioOut() : ServiceFramework("IAudioOut"), audio_out_state(Stopped) {
16 static const FunctionInfo functions[] = { 27 static const FunctionInfo functions[] = {
17 {0x0, nullptr, "GetAudioOutState"}, 28 {0x0, nullptr, "GetAudioOutState"},
18 {0x1, nullptr, "StartAudioOut"}, 29 {0x1, &IAudioOut::StartAudioOut, "StartAudioOut"},
19 {0x2, nullptr, "StopAudioOut"}, 30 {0x2, &IAudioOut::StopAudioOut, "StopAudioOut"},
20 {0x3, nullptr, "AppendAudioOutBuffer_1"}, 31 {0x3, &IAudioOut::AppendAudioOutBuffer_1, "AppendAudioOutBuffer_1"},
21 {0x4, nullptr, "RegisterBufferEvent"}, 32 {0x4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
22 {0x5, nullptr, "GetReleasedAudioOutBuffer_1"}, 33 {0x5, &IAudioOut::GetReleasedAudioOutBuffer_1, "GetReleasedAudioOutBuffer_1"},
23 {0x6, nullptr, "ContainsAudioOutBuffer"}, 34 {0x6, nullptr, "ContainsAudioOutBuffer"},
24 {0x7, nullptr, "AppendAudioOutBuffer_2"}, 35 {0x7, nullptr, "AppendAudioOutBuffer_2"},
25 {0x8, nullptr, "GetReleasedAudioOutBuffer_2"}, 36 {0x8, nullptr, "GetReleasedAudioOutBuffer_2"},
26 }; 37 };
27 RegisterHandlers(functions); 38 RegisterHandlers(functions);
39
40 // This is the event handle used to check if the audio buffer was released
41 buffer_event =
42 Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
43
44 // Register event callback to update the Audio Buffer
45 audio_event = CoreTiming::RegisterEvent(
46 "IAudioOut::UpdateAudioBuffersCallback", [this](u64 userdata, int cycles_late) {
47 UpdateAudioBuffersCallback();
48 CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
49 });
50
51 // Start the audio event
52 CoreTiming::ScheduleEvent(audio_ticks, audio_event);
28 } 53 }
54
29 ~IAudioOut() = default; 55 ~IAudioOut() = default;
56
57private:
58 void StartAudioOut(Kernel::HLERequestContext& ctx) {
59 LOG_WARNING(Service_Audio, "(STUBBED) called");
60
61 // start audio
62 audio_out_state = Started;
63
64 IPC::RequestBuilder rb{ctx, 2};
65 rb.Push(RESULT_SUCCESS);
66 }
67
68 void StopAudioOut(Kernel::HLERequestContext& ctx) {
69 LOG_WARNING(Service_Audio, "(STUBBED) called");
70
71 // stop audio
72 audio_out_state = Stopped;
73
74 queue_keys.clear();
75
76 IPC::RequestBuilder rb{ctx, 2};
77 rb.Push(RESULT_SUCCESS);
78 }
79
80 void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
81 LOG_WARNING(Service_Audio, "(STUBBED) called");
82
83 IPC::RequestBuilder rb{ctx, 2, 1};
84 rb.Push(RESULT_SUCCESS);
85 rb.PushCopyObjects(buffer_event);
86 }
87
88 void AppendAudioOutBuffer_1(Kernel::HLERequestContext& ctx) {
89 LOG_WARNING(Service_Audio, "(STUBBED) called");
90 IPC::RequestParser rp{ctx};
91
92 u64 key = rp.Pop<u64>();
93
94 queue_keys.insert(queue_keys.begin(), key);
95
96 IPC::RequestBuilder rb{ctx, 2};
97 rb.Push(RESULT_SUCCESS);
98 }
99
100 void GetReleasedAudioOutBuffer_1(Kernel::HLERequestContext& ctx) {
101 LOG_WARNING(Service_Audio, "(STUBBED) called");
102
103 const auto& buffer = ctx.BufferDescriptorB()[0];
104
105 // TODO(st4rk): this is how libtransistor currently implements the
106 // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the APP and this address
107 // is used to know which buffer should be filled with data and send again to the service
108 // through AppendAudioOutBuffer. Check if this is the proper way to do it.
109
110 u64 key{0};
111
112 if (queue_keys.size()) {
113 key = queue_keys.back();
114 queue_keys.pop_back();
115 }
116
117 Memory::WriteBlock(buffer.Address(), &key, sizeof(u64));
118
119 IPC::RequestBuilder rb{ctx, 3};
120 rb.Push(RESULT_SUCCESS);
121 // TODO(st4rk): This might be the total of released buffers, needs to be verified on
122 // hardware
123 rb.Push<u32>(static_cast<u32>(queue_keys.size()));
124 }
125
126 void UpdateAudioBuffersCallback() {
127
128 if (audio_out_state != Started) {
129 return;
130 }
131
132 if (queue_keys.empty()) {
133 return;
134 }
135
136 buffer_event->Signal();
137 }
138
139 enum AudioState : u32 {
140 Started,
141 Stopped,
142 };
143
144 /// This is used to trigger the audio event callback that is going to read the samples from the
145 /// audio_buffer list and enqueue the samples using the sink (audio_core).
146 CoreTiming::EventType* audio_event;
147
148 /// This is the evend handle used to check if the audio buffer was released
149 Kernel::SharedPtr<Kernel::Event> buffer_event;
150
151 /// (st4rk): this is just a temporary workaround for the future implementation. Libtransistor
152 /// uses the key as an address in the App, so we need to return when the
153 /// GetReleasedAudioOutBuffer_1 is called, otherwise we'll run in problems, because
154 /// libtransistor uses the key returned as an pointer;
155 std::vector<u64> queue_keys;
156
157 AudioState audio_out_state;
30}; 158};
31 159
32void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { 160void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
33 LOG_WARNING(Service, "(STUBBED) called"); 161 LOG_WARNING(Service_Audio, "(STUBBED) called");
34 IPC::RequestParser rp{ctx}; 162 IPC::RequestParser rp{ctx};
35 163
36 auto& buffer = ctx.BufferDescriptorB()[0]; 164 auto& buffer = ctx.BufferDescriptorB()[0];
@@ -50,16 +178,26 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
50} 178}
51 179
52void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) { 180void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) {
53 LOG_WARNING(Service, "(STUBBED) called"); 181 LOG_WARNING(Service_Audio, "(STUBBED) called");
182
183 if (!audio_out_interface) {
184 audio_out_interface = std::make_shared<IAudioOut>();
185 }
54 186
55 IPC::RequestBuilder rb{ctx, 6}; 187 auto sessions = Kernel::ServerSession::CreateSessionPair(audio_out_interface->GetServiceName());
188 auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions);
189 auto client = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions);
190 audio_out_interface->ClientConnected(server);
191 LOG_DEBUG(Service, "called, initialized IAudioOut -> session=%u", client->GetObjectId());
192 IPC::RequestBuilder rb{ctx, 6, 0, 1};
56 193
57 rb.Push(RESULT_SUCCESS); 194 rb.Push(RESULT_SUCCESS);
58 rb.Push<u32>(48000); // Sample Rate 195 rb.Push<u32>(sample_rate);
59 rb.Push<u32>(2); // Channels 196 rb.Push<u32>(audio_channels);
60 rb.Push<u32>(2); // PCM Format (INT16) 197 rb.Push<u32>(static_cast<u32>(PcmFormat::Int16));
61 rb.Push<u32>(0); // Unknown 198 // this field is unknown
62 rb.PushIpcInterface<Audio::IAudioOut>(); 199 rb.Push<u32>(0);
200 rb.PushMoveObjects(std::move(client));
63} 201}
64 202
65AudOutU::AudOutU() : ServiceFramework("audout:u") { 203AudOutU::AudOutU() : ServiceFramework("audout:u") {
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index 69626cc58..7fbce2225 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -13,14 +13,28 @@ class HLERequestContext;
13namespace Service { 13namespace Service {
14namespace Audio { 14namespace Audio {
15 15
16class IAudioOut;
17
16class AudOutU final : public ServiceFramework<AudOutU> { 18class AudOutU final : public ServiceFramework<AudOutU> {
17public: 19public:
18 AudOutU(); 20 AudOutU();
19 ~AudOutU() = default; 21 ~AudOutU() = default;
20 22
21private: 23private:
24 std::shared_ptr<IAudioOut> audio_out_interface;
25
22 void ListAudioOuts(Kernel::HLERequestContext& ctx); 26 void ListAudioOuts(Kernel::HLERequestContext& ctx);
23 void OpenAudioOut(Kernel::HLERequestContext& ctx); 27 void OpenAudioOut(Kernel::HLERequestContext& ctx);
28
29 enum class PcmFormat : u32 {
30 Invalid = 0,
31 Int8 = 1,
32 Int16 = 2,
33 Int24 = 3,
34 Int32 = 4,
35 PcmFloat = 5,
36 Adpcm = 6,
37 };
24}; 38};
25 39
26} // namespace Audio 40} // namespace Audio