audren_u.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/logging/log.h"
  5. #include "core/core_timing.h"
  6. #include "core/hle/ipc_helpers.h"
  7. #include "core/hle/kernel/event.h"
  8. #include "core/hle/kernel/hle_ipc.h"
  9. #include "core/hle/service/audio/audren_u.h"
  10. namespace Service::Audio {
  11. /// TODO(bunnei): Find a proper value for the audio_ticks
  12. constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
  13. class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
  14. public:
  15. IAudioRenderer() : ServiceFramework("IAudioRenderer") {
  16. static const FunctionInfo functions[] = {
  17. {0, nullptr, "GetAudioRendererSampleRate"},
  18. {1, nullptr, "GetAudioRendererSampleCount"},
  19. {2, nullptr, "GetAudioRendererMixBufferCount"},
  20. {3, nullptr, "GetAudioRendererState"},
  21. {4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
  22. {5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
  23. {6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"},
  24. {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
  25. {8, nullptr, "SetAudioRendererRenderingTimeLimit"},
  26. {9, nullptr, "GetAudioRendererRenderingTimeLimit"},
  27. {10, nullptr, "RequestUpdateAudioRendererAuto"},
  28. {11, nullptr, "ExecuteAudioRendererRendering"},
  29. };
  30. RegisterHandlers(functions);
  31. system_event =
  32. Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioRenderer:SystemEvent");
  33. // Register event callback to update the Audio Buffer
  34. audio_event = CoreTiming::RegisterEvent(
  35. "IAudioRenderer::UpdateAudioCallback", [this](u64 userdata, int cycles_late) {
  36. UpdateAudioCallback();
  37. CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
  38. });
  39. // Start the audio event
  40. CoreTiming::ScheduleEvent(audio_ticks, audio_event);
  41. }
  42. ~IAudioRenderer() {
  43. CoreTiming::UnscheduleEvent(audio_event, 0);
  44. }
  45. private:
  46. void UpdateAudioCallback() {
  47. system_event->Signal();
  48. }
  49. void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
  50. NGLOG_DEBUG(Service_Audio, "{}", ctx.Description());
  51. AudioRendererResponseData response_data{};
  52. response_data.section_0_size =
  53. static_cast<u32>(response_data.state_entries.size() * sizeof(AudioRendererStateEntry));
  54. response_data.section_1_size = static_cast<u32>(response_data.section_1.size());
  55. response_data.section_2_size = static_cast<u32>(response_data.section_2.size());
  56. response_data.section_3_size = static_cast<u32>(response_data.section_3.size());
  57. response_data.section_4_size = static_cast<u32>(response_data.section_4.size());
  58. response_data.section_5_size = static_cast<u32>(response_data.section_5.size());
  59. response_data.total_size = sizeof(AudioRendererResponseData);
  60. for (unsigned i = 0; i < response_data.state_entries.size(); i++) {
  61. // 4 = Busy and 5 = Ready?
  62. response_data.state_entries[i].state = 5;
  63. }
  64. ctx.WriteBuffer(&response_data, response_data.total_size);
  65. IPC::ResponseBuilder rb{ctx, 2};
  66. rb.Push(RESULT_SUCCESS);
  67. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  68. }
  69. void StartAudioRenderer(Kernel::HLERequestContext& ctx) {
  70. IPC::ResponseBuilder rb{ctx, 2};
  71. rb.Push(RESULT_SUCCESS);
  72. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  73. }
  74. void StopAudioRenderer(Kernel::HLERequestContext& ctx) {
  75. IPC::ResponseBuilder rb{ctx, 2};
  76. rb.Push(RESULT_SUCCESS);
  77. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  78. }
  79. void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
  80. // system_event->Signal();
  81. IPC::ResponseBuilder rb{ctx, 2, 1};
  82. rb.Push(RESULT_SUCCESS);
  83. rb.PushCopyObjects(system_event);
  84. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  85. }
  86. struct AudioRendererStateEntry {
  87. u32_le state;
  88. u32_le unknown_4;
  89. u32_le unknown_8;
  90. u32_le unknown_c;
  91. };
  92. static_assert(sizeof(AudioRendererStateEntry) == 0x10,
  93. "AudioRendererStateEntry has wrong size");
  94. struct AudioRendererResponseData {
  95. u32_le unknown_0;
  96. u32_le section_5_size;
  97. u32_le section_0_size;
  98. u32_le section_1_size;
  99. u32_le unknown_10;
  100. u32_le section_2_size;
  101. u32_le unknown_18;
  102. u32_le section_3_size;
  103. u32_le section_4_size;
  104. u32_le unknown_24;
  105. u32_le unknown_28;
  106. u32_le unknown_2c;
  107. u32_le unknown_30;
  108. u32_le unknown_34;
  109. u32_le unknown_38;
  110. u32_le total_size;
  111. std::array<AudioRendererStateEntry, 0x18e> state_entries;
  112. std::array<u8, 0x600> section_1;
  113. std::array<u8, 0xe0> section_2;
  114. std::array<u8, 0x20> section_3;
  115. std::array<u8, 0x10> section_4;
  116. std::array<u8, 0xb0> section_5;
  117. };
  118. static_assert(sizeof(AudioRendererResponseData) == 0x20e0,
  119. "AudioRendererResponseData has wrong size");
  120. /// This is used to trigger the audio event callback.
  121. CoreTiming::EventType* audio_event;
  122. Kernel::SharedPtr<Kernel::Event> system_event;
  123. };
  124. class IAudioDevice final : public ServiceFramework<IAudioDevice> {
  125. public:
  126. IAudioDevice() : ServiceFramework("IAudioDevice") {
  127. static const FunctionInfo functions[] = {
  128. {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
  129. {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
  130. {2, nullptr, "GetAudioDeviceOutputVolume"},
  131. {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
  132. {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
  133. {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
  134. {6, &IAudioDevice::ListAudioDeviceName,
  135. "ListAudioDeviceNameAuto"}, // TODO(ogniK): Confirm if autos are identical to non auto
  136. {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
  137. {8, nullptr, "GetAudioDeviceOutputVolumeAuto"},
  138. {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
  139. {11, nullptr, "QueryAudioDeviceInputEvent"},
  140. {12, nullptr, "QueryAudioDeviceOutputEvent"},
  141. };
  142. RegisterHandlers(functions);
  143. buffer_event =
  144. Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
  145. }
  146. private:
  147. void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
  148. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  149. IPC::RequestParser rp{ctx};
  150. const std::string audio_interface = "AudioInterface";
  151. ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
  152. IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
  153. rb.Push(RESULT_SUCCESS);
  154. rb.Push<u32>(1);
  155. }
  156. void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
  157. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  158. IPC::RequestParser rp{ctx};
  159. f32 volume = static_cast<f32>(rp.Pop<u32>());
  160. auto file_buffer = ctx.ReadBuffer();
  161. auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
  162. IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
  163. rb.Push(RESULT_SUCCESS);
  164. }
  165. void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
  166. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  167. IPC::RequestParser rp{ctx};
  168. const std::string audio_interface = "AudioDevice";
  169. ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
  170. IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
  171. rb.Push(RESULT_SUCCESS);
  172. rb.Push<u32>(1);
  173. }
  174. void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
  175. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  176. buffer_event->Signal();
  177. IPC::ResponseBuilder rb{ctx, 2, 1};
  178. rb.Push(RESULT_SUCCESS);
  179. rb.PushCopyObjects(buffer_event);
  180. }
  181. void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
  182. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  183. IPC::ResponseBuilder rb{ctx, 3};
  184. rb.Push(RESULT_SUCCESS);
  185. rb.Push<u32>(1);
  186. }
  187. Kernel::SharedPtr<Kernel::Event> buffer_event;
  188. }; // namespace Audio
  189. AudRenU::AudRenU() : ServiceFramework("audren:u") {
  190. static const FunctionInfo functions[] = {
  191. {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
  192. {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
  193. {2, &AudRenU::GetAudioDevice, "GetAudioDevice"},
  194. {3, nullptr, "OpenAudioRendererAuto"},
  195. {4, nullptr, "GetAudioDeviceServiceWithRevisionInfo"},
  196. };
  197. RegisterHandlers(functions);
  198. }
  199. void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
  200. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  201. rb.Push(RESULT_SUCCESS);
  202. rb.PushIpcInterface<Audio::IAudioRenderer>();
  203. NGLOG_DEBUG(Service_Audio, "called");
  204. }
  205. void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
  206. IPC::ResponseBuilder rb{ctx, 4};
  207. rb.Push(RESULT_SUCCESS);
  208. rb.Push<u64>(0x4000);
  209. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  210. }
  211. void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
  212. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  213. rb.Push(RESULT_SUCCESS);
  214. rb.PushIpcInterface<Audio::IAudioDevice>();
  215. NGLOG_DEBUG(Service_Audio, "called");
  216. }
  217. } // namespace Service::Audio