audren_u.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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>(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. {0x0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
  129. {0x1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
  130. {0x2, nullptr, "GetAudioDeviceOutputVolume"},
  131. {0x3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
  132. {0x4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
  133. {0x5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
  134. {0x6, nullptr, "ListAudioDeviceNameAuto"},
  135. {0x7, nullptr, "SetAudioDeviceOutputVolumeAuto"},
  136. {0x8, nullptr, "GetAudioDeviceOutputVolumeAuto"},
  137. {0x10, nullptr, "GetActiveAudioDeviceNameAuto"},
  138. {0x11, nullptr, "QueryAudioDeviceInputEvent"},
  139. {0x12, nullptr, "QueryAudioDeviceOutputEvent"}};
  140. RegisterHandlers(functions);
  141. buffer_event =
  142. Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
  143. }
  144. private:
  145. void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
  146. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  147. IPC::RequestParser rp{ctx};
  148. const std::string audio_interface = "AudioInterface";
  149. ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
  150. IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
  151. rb.Push(RESULT_SUCCESS);
  152. rb.Push<u32>(1);
  153. }
  154. void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
  155. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  156. IPC::RequestParser rp{ctx};
  157. f32 volume = static_cast<f32>(rp.Pop<u32>());
  158. auto file_buffer = ctx.ReadBuffer();
  159. auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
  160. IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
  161. rb.Push(RESULT_SUCCESS);
  162. }
  163. void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
  164. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  165. IPC::RequestParser rp{ctx};
  166. const std::string audio_interface = "AudioDevice";
  167. ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
  168. IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
  169. rb.Push(RESULT_SUCCESS);
  170. rb.Push<u32>(1);
  171. }
  172. void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
  173. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  174. buffer_event->Signal();
  175. IPC::ResponseBuilder rb{ctx, 2, 1};
  176. rb.Push(RESULT_SUCCESS);
  177. rb.PushCopyObjects(buffer_event);
  178. }
  179. void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
  180. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  181. IPC::ResponseBuilder rb{ctx, 3};
  182. rb.Push(RESULT_SUCCESS);
  183. rb.Push<u32>(1);
  184. }
  185. Kernel::SharedPtr<Kernel::Event> buffer_event;
  186. }; // namespace Audio
  187. AudRenU::AudRenU() : ServiceFramework("audren:u") {
  188. static const FunctionInfo functions[] = {
  189. {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
  190. {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
  191. {2, &AudRenU::GetAudioDevice, "GetAudioDevice"},
  192. {3, nullptr, "OpenAudioRendererAuto"},
  193. {4, nullptr, "GetAudioDeviceServiceWithRevisionInfo"},
  194. };
  195. RegisterHandlers(functions);
  196. }
  197. void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
  198. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  199. rb.Push(RESULT_SUCCESS);
  200. rb.PushIpcInterface<Audio::IAudioRenderer>();
  201. NGLOG_DEBUG(Service_Audio, "called");
  202. }
  203. void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
  204. IPC::ResponseBuilder rb{ctx, 4};
  205. rb.Push(RESULT_SUCCESS);
  206. rb.Push<u64>(0x400);
  207. NGLOG_WARNING(Service_Audio, "(STUBBED) called");
  208. }
  209. void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
  210. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  211. rb.Push(RESULT_SUCCESS);
  212. rb.PushIpcInterface<Audio::IAudioDevice>();
  213. NGLOG_DEBUG(Service_Audio, "called");
  214. }
  215. } // namespace Service::Audio