aboutsummaryrefslogtreecommitdiff
path: root/src/audio_core
diff options
context:
space:
mode:
authorlizzie <lizzie@eden-emu.dev>2026-07-09 19:02:26 +0200
committercrueter <crueter@eden-emu.dev>2026-07-09 19:02:26 +0200
commit3fd6eeaf9fb42c942ffbc2a60a50dd8ebfd8dfee (patch)
tree374fbcafa21b93faca67f5e9a9d58e6c183f61e0 /src/audio_core
parent372bdfccbc06aead40fc4d14620df6c292728656 (diff)
Revert #3970 #4177 (#4187)
3970 revert fixes crash caused by scheduler 4177 fix mario galaxy and metroid prime 4 not booting Co-authored-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4187 Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Diffstat (limited to 'src/audio_core')
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp181
-rw-r--r--src/audio_core/adsp/apps/audio_renderer/audio_renderer.h5
-rw-r--r--src/audio_core/adsp/apps/opus/opus_decoder.cpp371
-rw-r--r--src/audio_core/adsp/apps/opus/opus_decoder.h4
4 files changed, 287 insertions, 274 deletions
diff --git a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp
index af37fb4685..45a69eca03 100644
--- a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp
+++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.cpp
@@ -29,96 +29,8 @@ void AudioRenderer::Start() {
CreateSinkStreams();
mailbox.Initialize(AppMailboxId::AudioRenderer);
- // Main AudioRenderer thread, responsible for processing the command lists.
- main_thread = std::jthread([this](std::stop_token stop_token) {
- Common::SetCurrentThreadName("DSP_AudioRenderer_Main");
- Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
- // TODO: Create buffer map/unmap thread + mailbox
- // TODO: Create gMix devices, initialize them here
-
- if (mailbox.Receive(Direction::DSP) != Message::InitializeOK) {
- LOG_ERROR(Service_Audio, "ADSP Audio Renderer -- Failed to receive initialize message from host!");
- return;
- }
-
- mailbox.Send(Direction::Host, Message::InitializeOK);
-
- // 0.12 seconds (2,304,000 / 19,200,000)
- constexpr u64 max_process_time{2'304'000ULL};
- while (!stop_token.stop_requested()) {
- auto msg{mailbox.Receive(Direction::DSP)};
- switch (msg) {
- case Message::Shutdown:
- mailbox.Send(Direction::Host, Message::Shutdown);
- return;
-
- case Message::Render: {
- if (system.IsShuttingDown()) {
- std::this_thread::sleep_for(std::chrono::milliseconds(200));
- mailbox.Send(Direction::Host, Message::RenderResponse);
- continue;
- }
- std::array<bool, MaxRendererSessions> buffers_reset{};
- std::array<u64, MaxRendererSessions> render_times_taken{};
- const auto start_time{system.CoreTiming().GetGlobalTimeUs().count()};
-
- for (u32 index = 0; index < MaxRendererSessions; index++) {
- auto& command_buffer{command_buffers[index]};
- auto& command_list_processor{command_list_processors[index]};
-
- // Check this buffer is valid, as it may not be used.
- if (command_buffer.buffer != 0) {
- // If there are no remaining commands (from the previous list),
- // this is a new command list, initialize it.
- if (command_buffer.remaining_command_count == 0) {
- command_list_processor.Initialize(system, *command_buffer.process,
- command_buffer.buffer,
- command_buffer.size, streams[index]);
- }
-
- if (command_buffer.reset_buffer && !buffers_reset[index]) {
- streams[index]->ClearQueue();
- buffers_reset[index] = true;
- }
-
- u64 max_time{max_process_time};
- if (index == 1 && command_buffer.applet_resource_user_id ==
- command_buffers[0].applet_resource_user_id) {
- max_time = max_process_time - render_times_taken[0];
- if (render_times_taken[0] > max_process_time) {
- max_time = 0;
- }
- }
-
- max_time = (std::min)(command_buffer.time_limit, max_time);
- command_list_processor.SetProcessTimeMax(max_time);
-
- if (index == 0) {
- streams[index]->WaitFreeSpace(stop_token);
- }
-
- // Process the command list
- {
- render_times_taken[index] =
- command_list_processor.Process(index) - start_time;
- }
-
- const auto end_time{system.CoreTiming().GetGlobalTimeUs().count()};
-
- command_buffer.remaining_command_count =
- command_list_processor.GetRemainingCommandCount();
- command_buffer.render_time_taken_us = end_time - start_time;
- }
- }
- mailbox.Send(Direction::Host, Message::RenderResponse);
- } break;
- default:
- LOG_WARNING(Service_Audio, "ADSP AudioRenderer received an invalid message, msg={:02X}!", msg);
- break;
- }
- }
- });
+ main_thread = std::jthread([this](std::stop_token stop_token) { Main(stop_token); });
mailbox.Send(Direction::DSP, Message::InitializeOK);
if (mailbox.Receive(Direction::Host) != Message::InitializeOK) {
@@ -217,4 +129,95 @@ void AudioRenderer::CreateSinkStreams() {
}
}
+void AudioRenderer::Main(std::stop_token stop_token) {
+ Common::SetCurrentThreadName("DSP_AudioRenderer_Main");
+ Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
+
+ // TODO: Create buffer map/unmap thread + mailbox
+ // TODO: Create gMix devices, initialize them here
+
+ if (mailbox.Receive(Direction::DSP) != Message::InitializeOK) {
+ LOG_ERROR(Service_Audio, "ADSP Audio Renderer -- Failed to receive initialize message from host!");
+ return;
+ }
+
+ mailbox.Send(Direction::Host, Message::InitializeOK);
+
+ // 0.12 seconds (2,304,000 / 19,200,000)
+ constexpr u64 max_process_time{2'304'000ULL};
+
+ while (!stop_token.stop_requested()) {
+ auto msg{mailbox.Receive(Direction::DSP)};
+ switch (msg) {
+ case Message::Shutdown:
+ mailbox.Send(Direction::Host, Message::Shutdown);
+ return;
+
+ case Message::Render: {
+ if (system.IsShuttingDown()) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+ mailbox.Send(Direction::Host, Message::RenderResponse);
+ continue;
+ }
+ std::array<bool, MaxRendererSessions> buffers_reset{};
+ std::array<u64, MaxRendererSessions> render_times_taken{};
+ const auto start_time{system.CoreTiming().GetGlobalTimeUs().count()};
+
+ for (u32 index = 0; index < MaxRendererSessions; index++) {
+ auto& command_buffer{command_buffers[index]};
+ auto& command_list_processor{command_list_processors[index]};
+
+ // Check this buffer is valid, as it may not be used.
+ if (command_buffer.buffer != 0) {
+ // If there are no remaining commands (from the previous list),
+ // this is a new command list, initialize it.
+ if (command_buffer.remaining_command_count == 0) {
+ command_list_processor.Initialize(system, *command_buffer.process,
+ command_buffer.buffer,
+ command_buffer.size, streams[index]);
+ }
+
+ if (command_buffer.reset_buffer && !buffers_reset[index]) {
+ streams[index]->ClearQueue();
+ buffers_reset[index] = true;
+ }
+
+ u64 max_time{max_process_time};
+ if (index == 1 && command_buffer.applet_resource_user_id ==
+ command_buffers[0].applet_resource_user_id) {
+ max_time = max_process_time - render_times_taken[0];
+ if (render_times_taken[0] > max_process_time) {
+ max_time = 0;
+ }
+ }
+
+ max_time = (std::min)(command_buffer.time_limit, max_time);
+ command_list_processor.SetProcessTimeMax(max_time);
+
+ if (index == 0) {
+ streams[index]->WaitFreeSpace(stop_token);
+ }
+
+ // Process the command list
+ {
+ render_times_taken[index] =
+ command_list_processor.Process(index) - start_time;
+ }
+
+ const auto end_time{system.CoreTiming().GetGlobalTimeUs().count()};
+
+ command_buffer.remaining_command_count =
+ command_list_processor.GetRemainingCommandCount();
+ command_buffer.render_time_taken_us = end_time - start_time;
+ }
+ }
+ mailbox.Send(Direction::Host, Message::RenderResponse);
+ } break;
+ default:
+ LOG_WARNING(Service_Audio, "ADSP AudioRenderer received an invalid message, msg={:02X}!", msg);
+ break;
+ }
+ }
+}
+
} // namespace AudioCore::ADSP::AudioRenderer
diff --git a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h
index a7a21e76af..4e128187a7 100644
--- a/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h
+++ b/src/audio_core/adsp/apps/audio_renderer/audio_renderer.h
@@ -83,6 +83,11 @@ public:
private:
/**
+ * Main AudioRenderer thread, responsible for processing the command lists.
+ */
+ void Main(std::stop_token stop_token);
+
+ /**
* Creates the streams which will receive the processed samples.
*/
void CreateSinkStreams();
diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.cpp b/src/audio_core/adsp/apps/opus/opus_decoder.cpp
index 1ce81d287a..8a009c04c7 100644
--- a/src/audio_core/adsp/apps/opus/opus_decoder.cpp
+++ b/src/audio_core/adsp/apps/opus/opus_decoder.cpp
@@ -37,9 +37,7 @@ bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 stereo_stream_co
} // namespace
OpusDecoder::OpusDecoder(Core::System& system_) : system{system_} {
- init_thread = std::jthread([this](std::stop_token stop_token) {
- Init(stop_token);
- });
+ init_thread = std::jthread([this](std::stop_token stop_token) { Init(stop_token); });
}
OpusDecoder::~OpusDecoder() {
@@ -66,203 +64,206 @@ u32 OpusDecoder::Receive(Direction dir, std::stop_token stop_token) {
return mailbox.Receive(dir, stop_token);
}
-void OpusDecoder::Init(std::stop_token rc_stop_token) {
+void OpusDecoder::Init(std::stop_token stop_token) {
Common::SetCurrentThreadName("DSP_OpusDecoder_Init");
- if (Receive(Direction::DSP, rc_stop_token) != Message::Start) {
- LOG_ERROR(Service_Audio, "DSP OpusDecoder failed to receive Start message. Opus initialization failed.");
+ if (Receive(Direction::DSP, stop_token) != Message::Start) {
+ LOG_ERROR(Service_Audio,
+ "DSP OpusDecoder failed to receive Start message. Opus initialization failed.");
return;
}
- // Main OpusDecoder thread, responsible for processing the incoming Opus packets.
- main_thread = std::jthread([this](std::stop_token stop_token) {
- Common::SetCurrentThreadName("DSP_OpusDecoder_Main");
- while (!stop_token.stop_requested()) {
- auto msg = Receive(Direction::DSP, stop_token);
- switch (msg) {
- case Shutdown:
- Send(Direction::Host, Message::ShutdownOK);
- return;
-
- case GetWorkBufferSize: {
- auto channel_count = static_cast<s32>(shared_memory->host_send_data[0]);
-
- ASSERT(IsValidChannelCount(channel_count));
-
- shared_memory->dsp_return_data[0] = OpusDecodeObject::GetWorkBufferSize(channel_count);
- Send(Direction::Host, Message::GetWorkBufferSizeOK);
- } break;
-
- case InitializeDecodeObject: {
- auto buffer = shared_memory->host_send_data[0];
- auto buffer_size = shared_memory->host_send_data[1];
- auto sample_rate = static_cast<s32>(shared_memory->host_send_data[2]);
- auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
-
- ASSERT(sample_rate >= 0);
- ASSERT(IsValidChannelCount(channel_count));
- ASSERT(buffer_size >= OpusDecodeObject::GetWorkBufferSize(channel_count));
-
- auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
- shared_memory->dsp_return_data[0] =
- decoder_object.InitializeDecoder(sample_rate, channel_count);
-
- Send(Direction::Host, Message::InitializeDecodeObjectOK);
- } break;
-
- case ShutdownDecodeObject: {
- auto buffer = shared_memory->host_send_data[0];
- [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
-
- auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
- shared_memory->dsp_return_data[0] = decoder_object.Shutdown();
-
- Send(Direction::Host, Message::ShutdownDecodeObjectOK);
- } break;
-
- case DecodeInterleaved: {
- auto start_time = system.CoreTiming().GetGlobalTimeUs();
-
- auto buffer = shared_memory->host_send_data[0];
- auto input_data = shared_memory->host_send_data[1];
- auto input_data_size = shared_memory->host_send_data[2];
- auto output_data = shared_memory->host_send_data[3];
- auto output_data_size = shared_memory->host_send_data[4];
- auto final_range = static_cast<u32>(shared_memory->host_send_data[5]);
- auto reset_requested = shared_memory->host_send_data[6];
-
- u32 decoded_samples{0};
-
- auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
- s32 error_code{OPUS_OK};
- if (reset_requested) {
- error_code = decoder_object.ResetDecoder();
- }
+ main_thread = std::jthread([this](std::stop_token st) { Main(st); });
+ running = true;
+ Send(Direction::Host, Message::StartOK);
+}
- if (error_code == OPUS_OK) {
- error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size,
- input_data, input_data_size);
- }
+void OpusDecoder::Main(std::stop_token stop_token) {
+ Common::SetCurrentThreadName("DSP_OpusDecoder_Main");
- if (error_code == OPUS_OK) {
- if (final_range && decoder_object.GetFinalRange() != final_range) {
- error_code = OPUS_INVALID_PACKET;
- }
- }
+ while (!stop_token.stop_requested()) {
+ auto msg = Receive(Direction::DSP, stop_token);
+ switch (msg) {
+ case Shutdown:
+ Send(Direction::Host, Message::ShutdownOK);
+ return;
- auto end_time = system.CoreTiming().GetGlobalTimeUs();
- shared_memory->dsp_return_data[0] = error_code;
- shared_memory->dsp_return_data[1] = decoded_samples;
- shared_memory->dsp_return_data[2] = (end_time - start_time).count();
-
- Send(Direction::Host, Message::DecodeInterleavedOK);
- } break;
-
- case MapMemory: {
- [[maybe_unused]] auto buffer = shared_memory->host_send_data[0];
- [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
- Send(Direction::Host, Message::MapMemoryOK);
- } break;
-
- case UnmapMemory: {
- [[maybe_unused]] auto buffer = shared_memory->host_send_data[0];
- [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
- Send(Direction::Host, Message::UnmapMemoryOK);
- } break;
-
- case GetWorkBufferSizeForMultiStream: {
- auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[0]);
- auto stereo_stream_count = static_cast<s32>(shared_memory->host_send_data[1]);
-
- ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count));
-
- shared_memory->dsp_return_data[0] = OpusMultiStreamDecodeObject::GetWorkBufferSize(
- total_stream_count, stereo_stream_count);
- Send(Direction::Host, Message::GetWorkBufferSizeForMultiStreamOK);
- } break;
-
- case InitializeMultiStreamDecodeObject: {
- auto buffer = shared_memory->host_send_data[0];
- auto buffer_size = shared_memory->host_send_data[1];
- auto sample_rate = static_cast<s32>(shared_memory->host_send_data[2]);
- auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
- auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[4]);
- auto stereo_stream_count = static_cast<s32>(shared_memory->host_send_data[5]);
- // Nintendo seem to have a bug here, they try to use &host_send_data[6] for the channel
- // mappings, but [6] is never set, and there is not enough room in the argument data for
- // more than 40 channels, when 255 are possible.
- // It also means the mapping values are undefined, though likely always 0,
- // and the mappings given by the game are ignored. The mappings are copied to this
- // dedicated buffer host side, so let's do as intended.
- auto mappings = shared_memory->channel_mapping.data();
-
- ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count));
- ASSERT(sample_rate >= 0);
- ASSERT(buffer_size >= OpusMultiStreamDecodeObject::GetWorkBufferSize(
- total_stream_count, stereo_stream_count));
-
- auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
- shared_memory->dsp_return_data[0] = decoder_object.InitializeDecoder(
- sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings);
-
- Send(Direction::Host, Message::InitializeMultiStreamDecodeObjectOK);
- } break;
-
- case ShutdownMultiStreamDecodeObject: {
- auto buffer = shared_memory->host_send_data[0];
- [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
-
- auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
- shared_memory->dsp_return_data[0] = decoder_object.Shutdown();
-
- Send(Direction::Host, Message::ShutdownMultiStreamDecodeObjectOK);
- } break;
-
- case DecodeInterleavedForMultiStream: {
- auto start_time = system.CoreTiming().GetGlobalTimeUs();
-
- auto buffer = shared_memory->host_send_data[0];
- auto input_data = shared_memory->host_send_data[1];
- auto input_data_size = shared_memory->host_send_data[2];
- auto output_data = shared_memory->host_send_data[3];
- auto output_data_size = shared_memory->host_send_data[4];
- auto final_range = static_cast<u32>(shared_memory->host_send_data[5]);
- auto reset_requested = shared_memory->host_send_data[6];
-
- u32 decoded_samples{0};
-
- auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
- s32 error_code{OPUS_OK};
- if (reset_requested) {
- error_code = decoder_object.ResetDecoder();
- }
+ case GetWorkBufferSize: {
+ auto channel_count = static_cast<s32>(shared_memory->host_send_data[0]);
- if (error_code == OPUS_OK) {
- error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size,
- input_data, input_data_size);
- }
+ ASSERT(IsValidChannelCount(channel_count));
+
+ shared_memory->dsp_return_data[0] = OpusDecodeObject::GetWorkBufferSize(channel_count);
+ Send(Direction::Host, Message::GetWorkBufferSizeOK);
+ } break;
+
+ case InitializeDecodeObject: {
+ auto buffer = shared_memory->host_send_data[0];
+ auto buffer_size = shared_memory->host_send_data[1];
+ auto sample_rate = static_cast<s32>(shared_memory->host_send_data[2]);
+ auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
+
+ ASSERT(sample_rate >= 0);
+ ASSERT(IsValidChannelCount(channel_count));
+ ASSERT(buffer_size >= OpusDecodeObject::GetWorkBufferSize(channel_count));
+
+ auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
+ shared_memory->dsp_return_data[0] =
+ decoder_object.InitializeDecoder(sample_rate, channel_count);
+
+ Send(Direction::Host, Message::InitializeDecodeObjectOK);
+ } break;
+
+ case ShutdownDecodeObject: {
+ auto buffer = shared_memory->host_send_data[0];
+ [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
+
+ auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
+ shared_memory->dsp_return_data[0] = decoder_object.Shutdown();
+
+ Send(Direction::Host, Message::ShutdownDecodeObjectOK);
+ } break;
+
+ case DecodeInterleaved: {
+ auto start_time = system.CoreTiming().GetGlobalTimeUs();
- if (error_code == OPUS_OK) {
- if (final_range && decoder_object.GetFinalRange() != final_range) {
- error_code = OPUS_INVALID_PACKET;
- }
+ auto buffer = shared_memory->host_send_data[0];
+ auto input_data = shared_memory->host_send_data[1];
+ auto input_data_size = shared_memory->host_send_data[2];
+ auto output_data = shared_memory->host_send_data[3];
+ auto output_data_size = shared_memory->host_send_data[4];
+ auto final_range = static_cast<u32>(shared_memory->host_send_data[5]);
+ auto reset_requested = shared_memory->host_send_data[6];
+
+ u32 decoded_samples{0};
+
+ auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
+ s32 error_code{OPUS_OK};
+ if (reset_requested) {
+ error_code = decoder_object.ResetDecoder();
+ }
+
+ if (error_code == OPUS_OK) {
+ error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size,
+ input_data, input_data_size);
+ }
+
+ if (error_code == OPUS_OK) {
+ if (final_range && decoder_object.GetFinalRange() != final_range) {
+ error_code = OPUS_INVALID_PACKET;
}
+ }
- auto end_time = system.CoreTiming().GetGlobalTimeUs();
- shared_memory->dsp_return_data[0] = error_code;
- shared_memory->dsp_return_data[1] = decoded_samples;
- shared_memory->dsp_return_data[2] = (end_time - start_time).count();
+ auto end_time = system.CoreTiming().GetGlobalTimeUs();
+ shared_memory->dsp_return_data[0] = error_code;
+ shared_memory->dsp_return_data[1] = decoded_samples;
+ shared_memory->dsp_return_data[2] = (end_time - start_time).count();
+
+ Send(Direction::Host, Message::DecodeInterleavedOK);
+ } break;
+
+ case MapMemory: {
+ [[maybe_unused]] auto buffer = shared_memory->host_send_data[0];
+ [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
+ Send(Direction::Host, Message::MapMemoryOK);
+ } break;
+
+ case UnmapMemory: {
+ [[maybe_unused]] auto buffer = shared_memory->host_send_data[0];
+ [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
+ Send(Direction::Host, Message::UnmapMemoryOK);
+ } break;
+
+ case GetWorkBufferSizeForMultiStream: {
+ auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[0]);
+ auto stereo_stream_count = static_cast<s32>(shared_memory->host_send_data[1]);
+
+ ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count));
+
+ shared_memory->dsp_return_data[0] = OpusMultiStreamDecodeObject::GetWorkBufferSize(
+ total_stream_count, stereo_stream_count);
+ Send(Direction::Host, Message::GetWorkBufferSizeForMultiStreamOK);
+ } break;
+
+ case InitializeMultiStreamDecodeObject: {
+ auto buffer = shared_memory->host_send_data[0];
+ auto buffer_size = shared_memory->host_send_data[1];
+ auto sample_rate = static_cast<s32>(shared_memory->host_send_data[2]);
+ auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
+ auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[4]);
+ auto stereo_stream_count = static_cast<s32>(shared_memory->host_send_data[5]);
+ // Nintendo seem to have a bug here, they try to use &host_send_data[6] for the channel
+ // mappings, but [6] is never set, and there is not enough room in the argument data for
+ // more than 40 channels, when 255 are possible.
+ // It also means the mapping values are undefined, though likely always 0,
+ // and the mappings given by the game are ignored. The mappings are copied to this
+ // dedicated buffer host side, so let's do as intended.
+ auto mappings = shared_memory->channel_mapping.data();
+
+ ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count));
+ ASSERT(sample_rate >= 0);
+ ASSERT(buffer_size >= OpusMultiStreamDecodeObject::GetWorkBufferSize(
+ total_stream_count, stereo_stream_count));
+
+ auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
+ shared_memory->dsp_return_data[0] = decoder_object.InitializeDecoder(
+ sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings);
+
+ Send(Direction::Host, Message::InitializeMultiStreamDecodeObjectOK);
+ } break;
+
+ case ShutdownMultiStreamDecodeObject: {
+ auto buffer = shared_memory->host_send_data[0];
+ [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
+
+ auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
+ shared_memory->dsp_return_data[0] = decoder_object.Shutdown();
+
+ Send(Direction::Host, Message::ShutdownMultiStreamDecodeObjectOK);
+ } break;
+
+ case DecodeInterleavedForMultiStream: {
+ auto start_time = system.CoreTiming().GetGlobalTimeUs();
+
+ auto buffer = shared_memory->host_send_data[0];
+ auto input_data = shared_memory->host_send_data[1];
+ auto input_data_size = shared_memory->host_send_data[2];
+ auto output_data = shared_memory->host_send_data[3];
+ auto output_data_size = shared_memory->host_send_data[4];
+ auto final_range = static_cast<u32>(shared_memory->host_send_data[5]);
+ auto reset_requested = shared_memory->host_send_data[6];
+
+ u32 decoded_samples{0};
+
+ auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
+ s32 error_code{OPUS_OK};
+ if (reset_requested) {
+ error_code = decoder_object.ResetDecoder();
+ }
- Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK);
- } break;
+ if (error_code == OPUS_OK) {
+ error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size,
+ input_data, input_data_size);
+ }
- default:
- LOG_ERROR(Service_Audio, "Invalid OpusDecoder command {}", msg);
- continue;
+ if (error_code == OPUS_OK) {
+ if (final_range && decoder_object.GetFinalRange() != final_range) {
+ error_code = OPUS_INVALID_PACKET;
+ }
}
+
+ auto end_time = system.CoreTiming().GetGlobalTimeUs();
+ shared_memory->dsp_return_data[0] = error_code;
+ shared_memory->dsp_return_data[1] = decoded_samples;
+ shared_memory->dsp_return_data[2] = (end_time - start_time).count();
+
+ Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK);
+ } break;
+
+ default:
+ LOG_ERROR(Service_Audio, "Invalid OpusDecoder command {}", msg);
+ continue;
}
- });
- running = true;
- Send(Direction::Host, Message::StartOK);
+ }
}
} // namespace AudioCore::ADSP::OpusDecoder
diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.h b/src/audio_core/adsp/apps/opus/opus_decoder.h
index d554586703..5b3f22bf4c 100644
--- a/src/audio_core/adsp/apps/opus/opus_decoder.h
+++ b/src/audio_core/adsp/apps/opus/opus_decoder.h
@@ -72,6 +72,10 @@ private:
* Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread.
*/
void Init(std::stop_token stop_token);
+ /**
+ * Main OpusDecoder thread, responsible for processing the incoming Opus packets.
+ */
+ void Main(std::stop_token stop_token);
/// Core system
Core::System& system;