decoder.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "audio_core/opus/decoder.h"
  4. #include "audio_core/opus/hardware_opus.h"
  5. #include "audio_core/opus/parameters.h"
  6. #include "common/alignment.h"
  7. #include "common/swap.h"
  8. #include "core/core.h"
  9. namespace AudioCore::OpusDecoder {
  10. using namespace Service::Audio;
  11. namespace {
  12. OpusPacketHeader ReverseHeader(OpusPacketHeader header) {
  13. OpusPacketHeader out;
  14. out.size = Common::swap32(header.size);
  15. out.final_range = Common::swap32(header.final_range);
  16. return out;
  17. }
  18. } // namespace
  19. OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_)
  20. : system{system_}, hardware_opus{hardware_opus_} {}
  21. OpusDecoder::~OpusDecoder() {
  22. if (decode_object_initialized) {
  23. hardware_opus.ShutdownDecodeObject(shared_buffer.get(), shared_buffer_size);
  24. }
  25. }
  26. Result OpusDecoder::Initialize(const OpusParametersEx& params,
  27. Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
  28. auto frame_size{params.use_large_frame_size ? 5760 : 1920};
  29. shared_buffer_size = transfer_memory_size;
  30. shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
  31. shared_memory_mapped = true;
  32. buffer_size =
  33. Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16);
  34. out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size};
  35. size_t in_data_size{0x600u};
  36. in_data = {out_data.data() - in_data_size, in_data_size};
  37. ON_RESULT_FAILURE {
  38. if (shared_memory_mapped) {
  39. shared_memory_mapped = false;
  40. ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size)));
  41. }
  42. };
  43. R_TRY(hardware_opus.InitializeDecodeObject(params.sample_rate, params.channel_count,
  44. shared_buffer.get(), shared_buffer_size));
  45. sample_rate = params.sample_rate;
  46. channel_count = params.channel_count;
  47. use_large_frame_size = params.use_large_frame_size;
  48. decode_object_initialized = true;
  49. R_SUCCEED();
  50. }
  51. Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
  52. Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
  53. auto frame_size{params.use_large_frame_size ? 5760 : 1920};
  54. shared_buffer_size = transfer_memory_size;
  55. shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
  56. shared_memory_mapped = true;
  57. buffer_size =
  58. Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16);
  59. out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size};
  60. size_t in_data_size{Common::AlignUp(1500ull * params.total_stream_count, 64u)};
  61. in_data = {out_data.data() - in_data_size, in_data_size};
  62. ON_RESULT_FAILURE {
  63. if (shared_memory_mapped) {
  64. shared_memory_mapped = false;
  65. ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size)));
  66. }
  67. };
  68. R_TRY(hardware_opus.InitializeMultiStreamDecodeObject(
  69. params.sample_rate, params.channel_count, params.total_stream_count,
  70. params.stereo_stream_count, params.mappings.data(), shared_buffer.get(),
  71. shared_buffer_size));
  72. sample_rate = params.sample_rate;
  73. channel_count = params.channel_count;
  74. total_stream_count = params.total_stream_count;
  75. stereo_stream_count = params.stereo_stream_count;
  76. use_large_frame_size = params.use_large_frame_size;
  77. decode_object_initialized = true;
  78. R_SUCCEED();
  79. }
  80. Result OpusDecoder::DecodeInterleaved(u32* out_data_size, u64* out_time_taken,
  81. u32* out_sample_count, std::span<const u8> input_data,
  82. std::span<u8> output_data, bool reset) {
  83. u32 out_samples;
  84. u64 time_taken{};
  85. R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall);
  86. auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
  87. OpusPacketHeader header{ReverseHeader(*header_p)};
  88. R_UNLESS(in_data.size_bytes() >= header.size &&
  89. header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(),
  90. ResultBufferTooSmall);
  91. if (!shared_memory_mapped) {
  92. R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
  93. shared_memory_mapped = true;
  94. }
  95. std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size);
  96. R_TRY(hardware_opus.DecodeInterleaved(out_samples, out_data.data(), out_data.size_bytes(),
  97. channel_count, in_data.data(), header.size,
  98. shared_buffer.get(), time_taken, reset));
  99. std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16));
  100. *out_data_size = header.size + sizeof(OpusPacketHeader);
  101. *out_sample_count = out_samples;
  102. if (out_time_taken) {
  103. *out_time_taken = time_taken / 1000;
  104. }
  105. R_SUCCEED();
  106. }
  107. Result OpusDecoder::SetContext([[maybe_unused]] std::span<const u8> context) {
  108. R_SUCCEED_IF(shared_memory_mapped);
  109. shared_memory_mapped = true;
  110. R_RETURN(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
  111. }
  112. Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken,
  113. u32* out_sample_count,
  114. std::span<const u8> input_data,
  115. std::span<u8> output_data, bool reset) {
  116. u32 out_samples;
  117. u64 time_taken{};
  118. R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall);
  119. auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
  120. OpusPacketHeader header{ReverseHeader(*header_p)};
  121. LOG_TRACE(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
  122. header.size, input_data.size_bytes(), in_data.size_bytes());
  123. R_UNLESS(in_data.size_bytes() >= header.size &&
  124. header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(),
  125. ResultBufferTooSmall);
  126. if (!shared_memory_mapped) {
  127. R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
  128. shared_memory_mapped = true;
  129. }
  130. std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size);
  131. R_TRY(hardware_opus.DecodeInterleavedForMultiStream(
  132. out_samples, out_data.data(), out_data.size_bytes(), channel_count, in_data.data(),
  133. header.size, shared_buffer.get(), time_taken, reset));
  134. std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16));
  135. *out_data_size = header.size + sizeof(OpusPacketHeader);
  136. *out_sample_count = out_samples;
  137. if (out_time_taken) {
  138. *out_time_taken = time_taken / 1000;
  139. }
  140. R_SUCCEED();
  141. }
  142. } // namespace AudioCore::OpusDecoder