audren_u.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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/alignment.h"
  5. #include "common/logging/log.h"
  6. #include "core/core_timing.h"
  7. #include "core/hle/ipc_helpers.h"
  8. #include "core/hle/kernel/event.h"
  9. #include "core/hle/kernel/hle_ipc.h"
  10. #include "core/hle/service/audio/audren_u.h"
  11. namespace Service::Audio {
  12. /// TODO(bunnei): Find a proper value for the audio_ticks
  13. constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
  14. class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
  15. public:
  16. IAudioRenderer(AudioRendererParameter audren_params)
  17. : ServiceFramework("IAudioRenderer"), worker_params(audren_params) {
  18. static const FunctionInfo functions[] = {
  19. {0, nullptr, "GetAudioRendererSampleRate"},
  20. {1, nullptr, "GetAudioRendererSampleCount"},
  21. {2, nullptr, "GetAudioRendererMixBufferCount"},
  22. {3, nullptr, "GetAudioRendererState"},
  23. {4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
  24. {5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
  25. {6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"},
  26. {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
  27. {8, nullptr, "SetAudioRendererRenderingTimeLimit"},
  28. {9, nullptr, "GetAudioRendererRenderingTimeLimit"},
  29. {10, nullptr, "RequestUpdateAudioRendererAuto"},
  30. {11, nullptr, "ExecuteAudioRendererRendering"},
  31. };
  32. RegisterHandlers(functions);
  33. system_event =
  34. Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioRenderer:SystemEvent");
  35. // Register event callback to update the Audio Buffer
  36. audio_event = CoreTiming::RegisterEvent(
  37. "IAudioRenderer::UpdateAudioCallback", [this](u64 userdata, int cycles_late) {
  38. UpdateAudioCallback();
  39. CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
  40. });
  41. // Start the audio event
  42. CoreTiming::ScheduleEvent(audio_ticks, audio_event);
  43. voice_status_list.resize(worker_params.voice_count);
  44. }
  45. ~IAudioRenderer() {
  46. CoreTiming::UnscheduleEvent(audio_event, 0);
  47. }
  48. private:
  49. void UpdateAudioCallback() {
  50. system_event->Signal();
  51. }
  52. void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
  53. UpdateDataHeader config{};
  54. auto buf = ctx.ReadBuffer();
  55. std::memcpy(&config, buf.data(), sizeof(UpdateDataHeader));
  56. u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
  57. std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
  58. std::memcpy(mem_pool_info.data(),
  59. buf.data() + sizeof(UpdateDataHeader) + config.behavior_size,
  60. memory_pool_count * sizeof(MemoryPoolInfo));
  61. std::vector<VoiceInfo> voice_info(worker_params.voice_count);
  62. std::memcpy(voice_info.data(),
  63. buf.data() + sizeof(UpdateDataHeader) + config.behavior_size +
  64. config.memory_pools_size + config.voice_resource_size,
  65. worker_params.voice_count * sizeof(VoiceInfo));
  66. UpdateDataHeader response_data{worker_params};
  67. ASSERT(ctx.GetWriteBufferSize() == response_data.total_size);
  68. std::vector<u8> output(response_data.total_size);
  69. std::memcpy(output.data(), &response_data, sizeof(UpdateDataHeader));
  70. std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
  71. for (unsigned i = 0; i < memory_pool.size(); i++) {
  72. if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestAttach)
  73. memory_pool[i].state = MemoryPoolStates::Attached;
  74. else if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestDetach)
  75. memory_pool[i].state = MemoryPoolStates::Detached;
  76. }
  77. std::memcpy(output.data() + sizeof(UpdateDataHeader), memory_pool.data(),
  78. response_data.memory_pools_size);
  79. for (unsigned i = 0; i < voice_info.size(); i++) {
  80. if (voice_info[i].is_new) {
  81. voice_status_list[i].played_sample_count = 0;
  82. voice_status_list[i].wave_buffer_consumed = 0;
  83. } else if (voice_info[i].play_state == (u8)PlayStates::Started) {
  84. for (u32 buff_idx = 0; buff_idx < voice_info[i].wave_buffer_count; buff_idx++) {
  85. voice_status_list[i].played_sample_count +=
  86. (voice_info[i].wave_buffer[buff_idx].end_sample_offset -
  87. voice_info[i].wave_buffer[buff_idx].start_sample_offset) /
  88. 2;
  89. voice_status_list[i].wave_buffer_consumed++;
  90. }
  91. }
  92. }
  93. std::memcpy(output.data() + sizeof(UpdateDataHeader) + response_data.memory_pools_size,
  94. voice_status_list.data(), response_data.voices_size);
  95. ctx.WriteBuffer(output);
  96. IPC::ResponseBuilder rb{ctx, 2};
  97. rb.Push(RESULT_SUCCESS);
  98. LOG_WARNING(Service_Audio, "(STUBBED) called");
  99. }
  100. void StartAudioRenderer(Kernel::HLERequestContext& ctx) {
  101. IPC::ResponseBuilder rb{ctx, 2};
  102. rb.Push(RESULT_SUCCESS);
  103. LOG_WARNING(Service_Audio, "(STUBBED) called");
  104. }
  105. void StopAudioRenderer(Kernel::HLERequestContext& ctx) {
  106. IPC::ResponseBuilder rb{ctx, 2};
  107. rb.Push(RESULT_SUCCESS);
  108. LOG_WARNING(Service_Audio, "(STUBBED) called");
  109. }
  110. void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
  111. // system_event->Signal();
  112. IPC::ResponseBuilder rb{ctx, 2, 1};
  113. rb.Push(RESULT_SUCCESS);
  114. rb.PushCopyObjects(system_event);
  115. LOG_WARNING(Service_Audio, "(STUBBED) called");
  116. }
  117. enum class MemoryPoolStates : u32 { // Should be LE
  118. Invalid = 0x0,
  119. Unknown = 0x1,
  120. RequestDetach = 0x2,
  121. Detached = 0x3,
  122. RequestAttach = 0x4,
  123. Attached = 0x5,
  124. Released = 0x6,
  125. };
  126. enum class PlayStates : u8 {
  127. Started = 0,
  128. Stopped = 1,
  129. };
  130. struct MemoryPoolEntry {
  131. MemoryPoolStates state;
  132. u32_le unknown_4;
  133. u32_le unknown_8;
  134. u32_le unknown_c;
  135. };
  136. static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
  137. struct MemoryPoolInfo {
  138. u64_le pool_address;
  139. u64_le pool_size;
  140. MemoryPoolStates pool_state;
  141. INSERT_PADDING_WORDS(3); // Unknown
  142. };
  143. static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
  144. struct UpdateDataHeader {
  145. UpdateDataHeader() {}
  146. UpdateDataHeader(const AudioRendererParameter& config) {
  147. revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
  148. behavior_size = 0xb0;
  149. memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
  150. voices_size = config.voice_count * 0x10;
  151. voice_resource_size = 0x0;
  152. effects_size = config.effect_count * 0x10;
  153. mixes_size = 0x0;
  154. sinks_size = config.sink_count * 0x20;
  155. performance_manager_size = 0x10;
  156. total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size +
  157. voices_size + effects_size + sinks_size + performance_manager_size;
  158. }
  159. u32_le revision;
  160. u32_le behavior_size;
  161. u32_le memory_pools_size;
  162. u32_le voices_size;
  163. u32_le voice_resource_size;
  164. u32_le effects_size;
  165. u32_le mixes_size;
  166. u32_le sinks_size;
  167. u32_le performance_manager_size;
  168. INSERT_PADDING_WORDS(6);
  169. u32_le total_size;
  170. };
  171. static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
  172. struct BiquadFilter {
  173. u8 enable;
  174. INSERT_PADDING_BYTES(1);
  175. s16_le numerator[3];
  176. s16_le denominator[2];
  177. };
  178. static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
  179. struct WaveBuffer {
  180. u64_le buffer_addr;
  181. u64_le buffer_sz;
  182. s32_le start_sample_offset;
  183. s32_le end_sample_offset;
  184. u8 loop;
  185. u8 end_of_stream;
  186. u8 sent_to_server;
  187. INSERT_PADDING_BYTES(5);
  188. u64 context_addr;
  189. u64 context_sz;
  190. INSERT_PADDING_BYTES(8);
  191. };
  192. static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
  193. struct VoiceInfo {
  194. u32_le id;
  195. u32_le node_id;
  196. u8 is_new;
  197. u8 is_in_use;
  198. u8 play_state;
  199. u8 sample_format;
  200. u32_le sample_rate;
  201. u32_le priority;
  202. u32_le sorting_order;
  203. u32_le channel_count;
  204. float_le pitch;
  205. float_le volume;
  206. BiquadFilter biquad_filter[2];
  207. u32_le wave_buffer_count;
  208. u16_le wave_buffer_head;
  209. INSERT_PADDING_BYTES(6);
  210. u64_le additional_params_addr;
  211. u64_le additional_params_sz;
  212. u32_le mix_id;
  213. u32_le splitter_info_id;
  214. WaveBuffer wave_buffer[4];
  215. u32_le voice_channel_resource_ids[6];
  216. INSERT_PADDING_BYTES(24);
  217. };
  218. static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
  219. struct VoiceOutStatus {
  220. u64_le played_sample_count;
  221. u32_le wave_buffer_consumed;
  222. INSERT_PADDING_WORDS(1);
  223. };
  224. static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
  225. /// This is used to trigger the audio event callback.
  226. CoreTiming::EventType* audio_event;
  227. Kernel::SharedPtr<Kernel::Event> system_event;
  228. AudioRendererParameter worker_params;
  229. std::vector<VoiceOutStatus> voice_status_list;
  230. };
  231. class IAudioDevice final : public ServiceFramework<IAudioDevice> {
  232. public:
  233. IAudioDevice() : ServiceFramework("IAudioDevice") {
  234. static const FunctionInfo functions[] = {
  235. {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
  236. {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
  237. {2, nullptr, "GetAudioDeviceOutputVolume"},
  238. {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
  239. {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
  240. {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
  241. {6, &IAudioDevice::ListAudioDeviceName,
  242. "ListAudioDeviceNameAuto"}, // TODO(ogniK): Confirm if autos are identical to non auto
  243. {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
  244. {8, nullptr, "GetAudioDeviceOutputVolumeAuto"},
  245. {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
  246. {11, nullptr, "QueryAudioDeviceInputEvent"},
  247. {12, nullptr, "QueryAudioDeviceOutputEvent"},
  248. };
  249. RegisterHandlers(functions);
  250. buffer_event =
  251. Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
  252. }
  253. private:
  254. void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
  255. LOG_WARNING(Service_Audio, "(STUBBED) called");
  256. IPC::RequestParser rp{ctx};
  257. const std::string audio_interface = "AudioInterface";
  258. ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
  259. IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
  260. rb.Push(RESULT_SUCCESS);
  261. rb.Push<u32>(1);
  262. }
  263. void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
  264. LOG_WARNING(Service_Audio, "(STUBBED) called");
  265. IPC::RequestParser rp{ctx};
  266. f32 volume = static_cast<f32>(rp.Pop<u32>());
  267. auto file_buffer = ctx.ReadBuffer();
  268. auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0');
  269. IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
  270. rb.Push(RESULT_SUCCESS);
  271. }
  272. void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
  273. LOG_WARNING(Service_Audio, "(STUBBED) called");
  274. IPC::RequestParser rp{ctx};
  275. const std::string audio_interface = "AudioDevice";
  276. ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size());
  277. IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
  278. rb.Push(RESULT_SUCCESS);
  279. rb.Push<u32>(1);
  280. }
  281. void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
  282. LOG_WARNING(Service_Audio, "(STUBBED) called");
  283. buffer_event->Signal();
  284. IPC::ResponseBuilder rb{ctx, 2, 1};
  285. rb.Push(RESULT_SUCCESS);
  286. rb.PushCopyObjects(buffer_event);
  287. }
  288. void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
  289. LOG_WARNING(Service_Audio, "(STUBBED) called");
  290. IPC::ResponseBuilder rb{ctx, 3};
  291. rb.Push(RESULT_SUCCESS);
  292. rb.Push<u32>(1);
  293. }
  294. Kernel::SharedPtr<Kernel::Event> buffer_event;
  295. }; // namespace Audio
  296. AudRenU::AudRenU() : ServiceFramework("audren:u") {
  297. static const FunctionInfo functions[] = {
  298. {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
  299. {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
  300. {2, &AudRenU::GetAudioDevice, "GetAudioDevice"},
  301. {3, nullptr, "OpenAudioRendererAuto"},
  302. {4, nullptr, "GetAudioDeviceServiceWithRevisionInfo"},
  303. };
  304. RegisterHandlers(functions);
  305. }
  306. void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
  307. IPC::RequestParser rp{ctx};
  308. auto params = rp.PopRaw<AudioRendererParameter>();
  309. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  310. rb.Push(RESULT_SUCCESS);
  311. rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
  312. LOG_DEBUG(Service_Audio, "called");
  313. }
  314. void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
  315. IPC::RequestParser rp{ctx};
  316. auto params = rp.PopRaw<AudioRendererParameter>();
  317. u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40);
  318. buffer_sz += params.unknown_c * 1024;
  319. buffer_sz += 0x940 * (params.unknown_c + 1);
  320. buffer_sz += 0x3F0 * params.voice_count;
  321. buffer_sz += Common::AlignUp(8 * (params.unknown_c + 1), 0x10);
  322. buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10);
  323. buffer_sz +=
  324. Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) *
  325. (params.unknown_8 + 6),
  326. 0x40);
  327. if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
  328. u32 count = params.unknown_c + 1;
  329. u64 node_count = Common::AlignUp(count, 0x40);
  330. u64 node_state_buffer_sz =
  331. 4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8);
  332. u64 edge_matrix_buffer_sz = 0;
  333. node_count = Common::AlignUp(count * count, 0x40);
  334. if (node_count >> 31 != 0) {
  335. edge_matrix_buffer_sz = (node_count | 7) / 8;
  336. } else {
  337. edge_matrix_buffer_sz = node_count / 8;
  338. }
  339. buffer_sz += Common::AlignUp(node_state_buffer_sz + edge_matrix_buffer_sz, 0x10);
  340. }
  341. buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50;
  342. if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
  343. buffer_sz += 0xE0 * params.unknown_2c;
  344. buffer_sz += 0x20 * params.splitter_count;
  345. buffer_sz += Common::AlignUp(4 * params.unknown_2c, 0x10);
  346. }
  347. buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count;
  348. u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count +
  349. ((params.voice_count * 256) | 0x40);
  350. if (params.unknown_1c >= 1) {
  351. output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count +
  352. 16 * params.voice_count + 16) +
  353. 0x658) *
  354. (params.unknown_1c + 1) +
  355. 0xc0,
  356. 0x40) +
  357. output_sz;
  358. }
  359. output_sz = Common::AlignUp(output_sz + 0x1807e, 0x1000);
  360. IPC::ResponseBuilder rb{ctx, 4};
  361. rb.Push(RESULT_SUCCESS);
  362. rb.Push<u64>(output_sz);
  363. LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz);
  364. }
  365. void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
  366. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  367. rb.Push(RESULT_SUCCESS);
  368. rb.PushIpcInterface<Audio::IAudioDevice>();
  369. LOG_DEBUG(Service_Audio, "called");
  370. }
  371. bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
  372. u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap
  373. switch (feature) {
  374. case AudioFeatures::Splitter:
  375. return version_num >= 2u;
  376. default:
  377. return false;
  378. }
  379. }
  380. } // namespace Service::Audio