hardware_opus.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <array>
  4. #include "audio_core/audio_core.h"
  5. #include "audio_core/opus/hardware_opus.h"
  6. #include "core/core.h"
  7. namespace AudioCore::OpusDecoder {
  8. namespace {
  9. using namespace Service::Audio;
  10. static constexpr Result ResultCodeFromLibOpusErrorCode(u64 error_code) {
  11. s32 error{static_cast<s32>(error_code)};
  12. ASSERT(error <= OPUS_OK);
  13. switch (error) {
  14. case OPUS_ALLOC_FAIL:
  15. R_THROW(ResultLibOpusAllocFail);
  16. case OPUS_INVALID_STATE:
  17. R_THROW(ResultLibOpusInvalidState);
  18. case OPUS_UNIMPLEMENTED:
  19. R_THROW(ResultLibOpusUnimplemented);
  20. case OPUS_INVALID_PACKET:
  21. R_THROW(ResultLibOpusInvalidPacket);
  22. case OPUS_INTERNAL_ERROR:
  23. R_THROW(ResultLibOpusInternalError);
  24. case OPUS_BUFFER_TOO_SMALL:
  25. R_THROW(ResultBufferTooSmall);
  26. case OPUS_BAD_ARG:
  27. R_THROW(ResultLibOpusBadArg);
  28. case OPUS_OK:
  29. R_RETURN(ResultSuccess);
  30. }
  31. UNREACHABLE();
  32. }
  33. } // namespace
  34. HardwareOpus::HardwareOpus(Core::System& system_)
  35. : system{system_}, opus_decoder{system.AudioCore().ADSP().OpusDecoder()} {
  36. opus_decoder.SetSharedMemory(shared_memory);
  37. }
  38. u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
  39. if (!opus_decoder.IsRunning()) {
  40. return 0;
  41. }
  42. std::scoped_lock l{mutex};
  43. shared_memory.host_send_data[0] = channel;
  44. opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::GetWorkBufferSize);
  45. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  46. if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeOK) {
  47. LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
  48. ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
  49. return 0;
  50. }
  51. return static_cast<u32>(shared_memory.dsp_return_data[0]);
  52. }
  53. u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
  54. std::scoped_lock l{mutex};
  55. shared_memory.host_send_data[0] = total_stream_count;
  56. shared_memory.host_send_data[1] = stereo_stream_count;
  57. opus_decoder.Send(ADSP::Direction::DSP,
  58. ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStream);
  59. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  60. if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK) {
  61. LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
  62. ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
  63. return 0;
  64. }
  65. return static_cast<u32>(shared_memory.dsp_return_data[0]);
  66. }
  67. Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
  68. u64 buffer_size) {
  69. std::scoped_lock l{mutex};
  70. shared_memory.host_send_data[0] = (u64)buffer;
  71. shared_memory.host_send_data[1] = buffer_size;
  72. shared_memory.host_send_data[2] = sample_rate;
  73. shared_memory.host_send_data[3] = channel_count;
  74. opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::InitializeDecodeObject);
  75. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  76. if (msg != ADSP::OpusDecoder::Message::InitializeDecodeObjectOK) {
  77. LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
  78. ADSP::OpusDecoder::Message::InitializeDecodeObjectOK, msg);
  79. R_THROW(ResultInvalidOpusDSPReturnCode);
  80. }
  81. R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
  82. }
  83. Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
  84. u32 total_stream_count,
  85. u32 stereo_stream_count,
  86. const void* mappings, void* buffer,
  87. u64 buffer_size) {
  88. std::scoped_lock l{mutex};
  89. shared_memory.host_send_data[0] = (u64)buffer;
  90. shared_memory.host_send_data[1] = buffer_size;
  91. shared_memory.host_send_data[2] = sample_rate;
  92. shared_memory.host_send_data[3] = channel_count;
  93. shared_memory.host_send_data[4] = total_stream_count;
  94. shared_memory.host_send_data[5] = stereo_stream_count;
  95. ASSERT(channel_count <= MaxChannels);
  96. std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8));
  97. opus_decoder.Send(ADSP::Direction::DSP,
  98. ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObject);
  99. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  100. if (msg != ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK) {
  101. LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
  102. ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK, msg);
  103. R_THROW(ResultInvalidOpusDSPReturnCode);
  104. }
  105. R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
  106. }
  107. Result HardwareOpus::ShutdownDecodeObject(void* buffer, u64 buffer_size) {
  108. std::scoped_lock l{mutex};
  109. shared_memory.host_send_data[0] = (u64)buffer;
  110. shared_memory.host_send_data[1] = buffer_size;
  111. opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::ShutdownDecodeObject);
  112. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  113. ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK,
  114. "Expected Opus shutdown code {}, got {}",
  115. ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK, msg);
  116. R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
  117. }
  118. Result HardwareOpus::ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size) {
  119. std::scoped_lock l{mutex};
  120. shared_memory.host_send_data[0] = (u64)buffer;
  121. shared_memory.host_send_data[1] = buffer_size;
  122. opus_decoder.Send(ADSP::Direction::DSP,
  123. ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObject);
  124. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  125. ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK,
  126. "Expected Opus shutdown code {}, got {}",
  127. ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK, msg);
  128. R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0]));
  129. }
  130. Result HardwareOpus::DecodeInterleaved(u32& out_sample_count, void* output_data,
  131. u64 output_data_size, u32 channel_count, void* input_data,
  132. u64 input_data_size, void* buffer, u64& out_time_taken,
  133. bool reset) {
  134. std::scoped_lock l{mutex};
  135. shared_memory.host_send_data[0] = (u64)buffer;
  136. shared_memory.host_send_data[1] = (u64)input_data;
  137. shared_memory.host_send_data[2] = input_data_size;
  138. shared_memory.host_send_data[3] = (u64)output_data;
  139. shared_memory.host_send_data[4] = output_data_size;
  140. shared_memory.host_send_data[5] = 0;
  141. shared_memory.host_send_data[6] = reset;
  142. opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::DecodeInterleaved);
  143. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  144. if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedOK) {
  145. LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
  146. ADSP::OpusDecoder::Message::DecodeInterleavedOK, msg);
  147. R_THROW(ResultInvalidOpusDSPReturnCode);
  148. }
  149. auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])};
  150. if (error_code == OPUS_OK) {
  151. out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]);
  152. out_time_taken = 1000 * shared_memory.dsp_return_data[2];
  153. }
  154. R_RETURN(ResultCodeFromLibOpusErrorCode(error_code));
  155. }
  156. Result HardwareOpus::DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data,
  157. u64 output_data_size, u32 channel_count,
  158. void* input_data, u64 input_data_size,
  159. void* buffer, u64& out_time_taken,
  160. bool reset) {
  161. std::scoped_lock l{mutex};
  162. shared_memory.host_send_data[0] = (u64)buffer;
  163. shared_memory.host_send_data[1] = (u64)input_data;
  164. shared_memory.host_send_data[2] = input_data_size;
  165. shared_memory.host_send_data[3] = (u64)output_data;
  166. shared_memory.host_send_data[4] = output_data_size;
  167. shared_memory.host_send_data[5] = 0;
  168. shared_memory.host_send_data[6] = reset;
  169. opus_decoder.Send(ADSP::Direction::DSP,
  170. ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStream);
  171. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  172. if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK) {
  173. LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
  174. ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK, msg);
  175. R_THROW(ResultInvalidOpusDSPReturnCode);
  176. }
  177. auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])};
  178. if (error_code == OPUS_OK) {
  179. out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]);
  180. out_time_taken = 1000 * shared_memory.dsp_return_data[2];
  181. }
  182. R_RETURN(ResultCodeFromLibOpusErrorCode(error_code));
  183. }
  184. Result HardwareOpus::MapMemory(void* buffer, u64 buffer_size) {
  185. std::scoped_lock l{mutex};
  186. shared_memory.host_send_data[0] = (u64)buffer;
  187. shared_memory.host_send_data[1] = buffer_size;
  188. opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::MapMemory);
  189. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  190. if (msg != ADSP::OpusDecoder::Message::MapMemoryOK) {
  191. LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
  192. ADSP::OpusDecoder::Message::MapMemoryOK, msg);
  193. R_THROW(ResultInvalidOpusDSPReturnCode);
  194. }
  195. R_SUCCEED();
  196. }
  197. Result HardwareOpus::UnmapMemory(void* buffer, u64 buffer_size) {
  198. std::scoped_lock l{mutex};
  199. shared_memory.host_send_data[0] = (u64)buffer;
  200. shared_memory.host_send_data[1] = buffer_size;
  201. opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::UnmapMemory);
  202. auto msg = opus_decoder.Receive(ADSP::Direction::Host);
  203. if (msg != ADSP::OpusDecoder::Message::UnmapMemoryOK) {
  204. LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}",
  205. ADSP::OpusDecoder::Message::UnmapMemoryOK, msg);
  206. R_THROW(ResultInvalidOpusDSPReturnCode);
  207. }
  208. R_SUCCEED();
  209. }
  210. } // namespace AudioCore::OpusDecoder