audren_u.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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 {
  11. namespace Audio {
  12. /// TODO(bunnei): Find a proper value for the audio_ticks
  13. constexpr u64 audio_ticks{static_cast<u64>(BASE_CLOCK_RATE / 200)};
  14. class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
  15. public:
  16. IAudioRenderer() : ServiceFramework("IAudioRenderer") {
  17. static const FunctionInfo functions[] = {
  18. {0x0, nullptr, "GetAudioRendererSampleRate"},
  19. {0x1, nullptr, "GetAudioRendererSampleCount"},
  20. {0x2, nullptr, "GetAudioRendererMixBufferCount"},
  21. {0x3, nullptr, "GetAudioRendererState"},
  22. {0x4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
  23. {0x5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
  24. {0x6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"},
  25. {0x7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
  26. {0x8, nullptr, "SetAudioRendererRenderingTimeLimit"},
  27. {0x9, nullptr, "GetAudioRendererRenderingTimeLimit"},
  28. };
  29. RegisterHandlers(functions);
  30. system_event =
  31. Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioRenderer:SystemEvent");
  32. // Register event callback to update the Audio Buffer
  33. audio_event = CoreTiming::RegisterEvent(
  34. "IAudioRenderer::UpdateAudioCallback", [this](u64 userdata, int cycles_late) {
  35. UpdateAudioCallback();
  36. CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
  37. });
  38. // Start the audio event
  39. CoreTiming::ScheduleEvent(audio_ticks, audio_event);
  40. }
  41. ~IAudioRenderer() {
  42. CoreTiming::UnscheduleEvent(audio_event, 0);
  43. }
  44. private:
  45. void UpdateAudioCallback() {
  46. system_event->Signal();
  47. }
  48. void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
  49. LOG_DEBUG(Service_Audio, "%s", ctx.Description().c_str());
  50. AudioRendererResponseData response_data{};
  51. response_data.section_0_size =
  52. response_data.state_entries.size() * sizeof(AudioRendererStateEntry);
  53. response_data.section_1_size = response_data.section_1.size();
  54. response_data.section_2_size = response_data.section_2.size();
  55. response_data.section_3_size = response_data.section_3.size();
  56. response_data.section_4_size = response_data.section_4.size();
  57. response_data.section_5_size = response_data.section_5.size();
  58. response_data.total_size = sizeof(AudioRendererResponseData);
  59. for (unsigned i = 0; i < response_data.state_entries.size(); i++) {
  60. // 4 = Busy and 5 = Ready?
  61. response_data.state_entries[i].state = 5;
  62. }
  63. ctx.WriteBuffer(&response_data, response_data.total_size);
  64. IPC::ResponseBuilder rb{ctx, 2};
  65. rb.Push(RESULT_SUCCESS);
  66. LOG_WARNING(Service_Audio, "(STUBBED) called");
  67. }
  68. void StartAudioRenderer(Kernel::HLERequestContext& ctx) {
  69. IPC::ResponseBuilder rb{ctx, 2};
  70. rb.Push(RESULT_SUCCESS);
  71. LOG_WARNING(Service_Audio, "(STUBBED) called");
  72. }
  73. void StopAudioRenderer(Kernel::HLERequestContext& ctx) {
  74. IPC::ResponseBuilder rb{ctx, 2};
  75. rb.Push(RESULT_SUCCESS);
  76. LOG_WARNING(Service_Audio, "(STUBBED) called");
  77. }
  78. void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
  79. // system_event->Signal();
  80. IPC::ResponseBuilder rb{ctx, 2, 1};
  81. rb.Push(RESULT_SUCCESS);
  82. rb.PushCopyObjects(system_event);
  83. LOG_WARNING(Service_Audio, "(STUBBED) called");
  84. }
  85. struct AudioRendererStateEntry {
  86. u32_le state;
  87. u32_le unknown_4;
  88. u32_le unknown_8;
  89. u32_le unknown_c;
  90. };
  91. static_assert(sizeof(AudioRendererStateEntry) == 0x10,
  92. "AudioRendererStateEntry has wrong size");
  93. struct AudioRendererResponseData {
  94. u32_le unknown_0;
  95. u32_le section_5_size;
  96. u32_le section_0_size;
  97. u32_le section_1_size;
  98. u32_le unknown_10;
  99. u32_le section_2_size;
  100. u32_le unknown_18;
  101. u32_le section_3_size;
  102. u32_le section_4_size;
  103. u32_le unknown_24;
  104. u32_le unknown_28;
  105. u32_le unknown_2c;
  106. u32_le unknown_30;
  107. u32_le unknown_34;
  108. u32_le unknown_38;
  109. u32_le total_size;
  110. std::array<AudioRendererStateEntry, 0x18e> state_entries;
  111. std::array<u8, 0x600> section_1;
  112. std::array<u8, 0xe0> section_2;
  113. std::array<u8, 0x20> section_3;
  114. std::array<u8, 0x10> section_4;
  115. std::array<u8, 0xb0> section_5;
  116. };
  117. static_assert(sizeof(AudioRendererResponseData) == 0x20e0,
  118. "AudioRendererResponseData has wrong size");
  119. /// This is used to trigger the audio event callback.
  120. CoreTiming::EventType* audio_event;
  121. Kernel::SharedPtr<Kernel::Event> system_event;
  122. };
  123. class IAudioDevice final : public ServiceFramework<IAudioDevice> {
  124. public:
  125. IAudioDevice() : ServiceFramework("IAudioDevice") {
  126. static const FunctionInfo functions[] = {
  127. {0x0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
  128. {0x1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}};
  129. RegisterHandlers(functions);
  130. buffer_event =
  131. Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
  132. }
  133. private:
  134. void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
  135. LOG_WARNING(Service_Audio, "(STUBBED) called");
  136. IPC::RequestParser rp{ctx};
  137. const std::string audio_interface = "AudioInterface";
  138. ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
  139. IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
  140. rb.Push(RESULT_SUCCESS);
  141. rb.Push<u32>(1);
  142. }
  143. void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
  144. LOG_WARNING(Service_Audio, "(STUBBED) called");
  145. IPC::RequestParser rp{ctx};
  146. f32 volume = static_cast<f32>(rp.Pop<u32>());
  147. auto file_buffer = ctx.ReadBuffer();
  148. auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
  149. IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
  150. rb.Push(RESULT_SUCCESS);
  151. }
  152. Kernel::SharedPtr<Kernel::Event> buffer_event;
  153. };
  154. AudRenU::AudRenU() : ServiceFramework("audren:u") {
  155. static const FunctionInfo functions[] = {
  156. {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
  157. {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
  158. {2, &AudRenU::GetAudioDevice, "GetAudioDevice"},
  159. };
  160. RegisterHandlers(functions);
  161. }
  162. void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
  163. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  164. rb.Push(RESULT_SUCCESS);
  165. rb.PushIpcInterface<Audio::IAudioRenderer>();
  166. LOG_DEBUG(Service_Audio, "called");
  167. }
  168. void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
  169. IPC::ResponseBuilder rb{ctx, 4};
  170. rb.Push(RESULT_SUCCESS);
  171. rb.Push<u64>(0x400);
  172. LOG_WARNING(Service_Audio, "(STUBBED) called");
  173. }
  174. void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
  175. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  176. rb.Push(RESULT_SUCCESS);
  177. rb.PushIpcInterface<Audio::IAudioDevice>();
  178. LOG_DEBUG(Service_Audio, "called");
  179. }
  180. } // namespace Audio
  181. } // namespace Service