diff --git a/src/audio_core/hle/audiotoolbox_decoder.cpp b/src/audio_core/hle/audiotoolbox_decoder.cpp index c3e5ebf78..2b122f008 100644 --- a/src/audio_core/hle/audiotoolbox_decoder.cpp +++ b/src/audio_core/hle/audiotoolbox_decoder.cpp @@ -17,11 +17,11 @@ class AudioToolboxDecoder::Impl { public: explicit Impl(Memory::MemorySystem& memory); ~Impl(); - std::optional ProcessRequest(const BinaryRequest& request); + std::optional ProcessRequest(const BinaryMessage& request); private: - std::optional Initalize(const BinaryRequest& request); - std::optional Decode(const BinaryRequest& request); + std::optional Initalize(const BinaryMessage& request); + std::optional Decode(const BinaryMessage& request); void Clear(); bool InitializeDecoder(ADTSData& adts_header); @@ -43,12 +43,11 @@ private: AudioStreamPacketDescription packet_description; }; -AudioToolboxDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {} +AudioToolboxDecoder::Impl::Impl(Memory::MemorySystem& memory_) : memory(memory_) {} -std::optional AudioToolboxDecoder::Impl::Initalize(const BinaryRequest& request) { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; +std::optional AudioToolboxDecoder::Impl::Initalize(const BinaryMessage& request) { + BinaryMessage response = request; + response.header.result = ResultStatus::Success; Clear(); return response; @@ -71,29 +70,29 @@ void AudioToolboxDecoder::Impl::Clear() { } } -std::optional AudioToolboxDecoder::Impl::ProcessRequest( - const BinaryRequest& request) { - if (request.codec != DecoderCodec::AAC) { +std::optional AudioToolboxDecoder::Impl::ProcessRequest( + const BinaryMessage& request) { + if (request.header.codec != DecoderCodec::DecodeAAC) { LOG_ERROR(Audio_DSP, "AudioToolbox AAC Decoder cannot handle such codec: {}", - static_cast(request.codec)); + static_cast(request.header.codec)); return {}; } - switch (request.cmd) { + switch (request.header.cmd) { case DecoderCommand::Init: { return Initalize(request); } - case DecoderCommand::Decode: { + case DecoderCommand::EncodeDecode: { return Decode(request); } case DecoderCommand::Unknown: { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; + BinaryMessage response = request; + response.header.result = ResultStatus::Success; return response; } default: - LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", static_cast(request.cmd)); + LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", + static_cast(request.header.cmd)); return {}; } } @@ -166,22 +165,24 @@ OSStatus AudioToolboxDecoder::Impl::DataFunc( return noErr; } -std::optional AudioToolboxDecoder::Impl::Decode(const BinaryRequest& request) { - BinaryResponse response; - response.codec = request.codec; - response.cmd = request.cmd; - response.size = request.size; +std::optional AudioToolboxDecoder::Impl::Decode(const BinaryMessage& request) { + BinaryMessage response{}; + response.header.codec = request.header.codec; + response.header.cmd = request.header.cmd; + response.decode_aac_response.size = request.decode_aac_request.size; - if (request.src_addr < Memory::FCRAM_PADDR || - request.src_addr + request.size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", request.src_addr); + if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR || + request.decode_aac_request.src_addr + request.decode_aac_request.size > + Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { + LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", + request.decode_aac_request.src_addr); return {}; } - auto data = memory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR); + auto data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR); auto adts_header = ParseADTS(reinterpret_cast(data)); curr_data = data + adts_header.header_length; - curr_data_len = request.size - adts_header.header_length; + curr_data_len = request.decode_aac_request.size - adts_header.header_length; if (!InitializeDecoder(adts_header)) { return std::nullopt; @@ -218,15 +219,17 @@ std::optional AudioToolboxDecoder::Impl::Decode(const BinaryRequ curr_data = nullptr; curr_data_len = 0; - response.sample_rate = GetSampleRateEnum(static_cast(output_format.mSampleRate)); - response.num_channels = output_format.mChannelsPerFrame; - response.num_samples = num_frames; + response.decode_aac_response.sample_rate = + GetSampleRateEnum(static_cast(output_format.mSampleRate)); + response.decode_aac_response.num_channels = output_format.mChannelsPerFrame; + response.decode_aac_response.num_samples = num_frames; // transfer the decoded buffer from vector to the FCRAM for (std::size_t ch = 0; ch < out_streams.size(); ch++) { if (!out_streams[ch].empty()) { auto byte_size = out_streams[ch].size() * bytes_per_sample; - auto dst = ch == 0 ? request.dst_addr_ch0 : request.dst_addr_ch1; + auto dst = ch == 0 ? request.decode_aac_request.dst_addr_ch0 + : request.decode_aac_request.dst_addr_ch1; if (dst < Memory::FCRAM_PADDR || dst + byte_size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch{} {:08x}", ch, dst); @@ -245,7 +248,7 @@ AudioToolboxDecoder::AudioToolboxDecoder(Memory::MemorySystem& memory) AudioToolboxDecoder::~AudioToolboxDecoder() = default; -std::optional AudioToolboxDecoder::ProcessRequest(const BinaryRequest& request) { +std::optional AudioToolboxDecoder::ProcessRequest(const BinaryMessage& request) { return impl->ProcessRequest(request); } diff --git a/src/audio_core/hle/audiotoolbox_decoder.h b/src/audio_core/hle/audiotoolbox_decoder.h index 10337691e..dcfe486d1 100644 --- a/src/audio_core/hle/audiotoolbox_decoder.h +++ b/src/audio_core/hle/audiotoolbox_decoder.h @@ -12,7 +12,7 @@ class AudioToolboxDecoder final : public DecoderBase { public: explicit AudioToolboxDecoder(Memory::MemorySystem& memory); ~AudioToolboxDecoder() override; - std::optional ProcessRequest(const BinaryRequest& request) override; + std::optional ProcessRequest(const BinaryMessage& request) override; bool IsValid() const override; private: diff --git a/src/audio_core/hle/decoder.cpp b/src/audio_core/hle/decoder.cpp index a4d4be181..a11fc4834 100644 --- a/src/audio_core/hle/decoder.cpp +++ b/src/audio_core/hle/decoder.cpp @@ -38,23 +38,25 @@ NullDecoder::NullDecoder() = default; NullDecoder::~NullDecoder() = default; -std::optional NullDecoder::ProcessRequest(const BinaryRequest& request) { - BinaryResponse response; - switch (request.cmd) { +std::optional NullDecoder::ProcessRequest(const BinaryMessage& request) { + BinaryMessage response{}; + switch (request.header.cmd) { case DecoderCommand::Init: case DecoderCommand::Unknown: - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; + response = request; + response.header.result = ResultStatus::Success; return response; - case DecoderCommand::Decode: - response.codec = request.codec; - response.cmd = DecoderCommand::Decode; - response.num_channels = 2; // Just assume stereo here - response.size = request.size; - response.num_samples = 1024; // Just assume 1024 here + case DecoderCommand::EncodeDecode: + response.header.codec = request.header.codec; + response.header.cmd = request.header.cmd; + response.header.result = ResultStatus::Success; + response.decode_aac_response.num_channels = 2; // Just assume stereo here + response.decode_aac_response.size = request.decode_aac_request.size; + response.decode_aac_response.num_samples = 1024; // Just assume 1024 here return response; default: - LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", static_cast(request.cmd)); + LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", + static_cast(request.header.cmd)); return std::nullopt; } }; diff --git a/src/audio_core/hle/decoder.h b/src/audio_core/hle/decoder.h index f713bb895..69bdaba89 100644 --- a/src/audio_core/hle/decoder.h +++ b/src/audio_core/hle/decoder.h @@ -14,18 +14,22 @@ namespace AudioCore::HLE { enum class DecoderCommand : u16 { - Init, - Decode, - Unknown, + Init = 0, + EncodeDecode = 1, + Unknown = 2, // Probably UnInit }; enum class DecoderCodec : u16 { - None, - AAC, + None = 0, + DecodeAAC = 1, + EncodeAAC = 2, +}; + +enum class ResultStatus : u32 { + Success = 0, + Error = 1, }; -// TODO(xperia64): I'm guessing that this is a u32 (from when it was an unknown) -// but it could be a u16 or u8 I suppose enum class DecoderSampleRate : u32 { Rate48000 = 0, Rate44100 = 1, @@ -38,40 +42,94 @@ enum class DecoderSampleRate : u32 { Rate8000 = 8 }; -struct BinaryRequest { - enum_le codec = - DecoderCodec::None; // this is a guess. until now only 0x1 was observed here - enum_le cmd = DecoderCommand::Init; - u32_le fixed = 0; +// The DSP replies with the same contents as the response too. +struct DecodeAACInitRequest { + u32_le unknown1 = 0; // observed 1 here + u32_le unknown2 = 0; // observed -1 here + u32_le unknown3 = 0; // observed 1 here + u32_le unknown4 = 0; // observed 0 here + u32_le unknown5 = 0; // unused? observed 1 here + u32_le unknown6 = 0; // unused? observed 0x20 here +}; + +struct DecodeAACRequest { u32_le src_addr = 0; u32_le size = 0; u32_le dst_addr_ch0 = 0; u32_le dst_addr_ch1 = 0; - u32_le unknown1 = 0; - u32_le unknown2 = 0; + u32_le unknown1 = 0; // unused? + u32_le unknown2 = 0; // unused? }; -static_assert(sizeof(BinaryRequest) == 32, "Unexpected struct size for BinaryRequest"); -struct BinaryResponse { - enum_le codec = - DecoderCodec::None; // this could be something else. until now only 0x1 was observed here - enum_le cmd = DecoderCommand::Init; - u32_le unknown1 = 0; +struct DecodeAACResponse { enum_le sample_rate; u32_le num_channels = 0; // this is a guess, so far I only observed 2 here u32_le size = 0; - u32_le unknown3 = 0; - u32_le unknown4 = 0; + u32_le unknown1 = 0; + u32_le unknown2 = 0; u32_le num_samples = 0; // this is a guess, so far I only observed 1024 here }; -static_assert(sizeof(BinaryResponse) == 32, "Unexpected struct size for BinaryResponse"); + +// The DSP replies with the same contents as the response too. +struct EncodeAACInitRequest { + u32_le unknown1 = 0; // Num channels? 1 or 2. observed 1 here + enum_le sample_rate = + DecoderSampleRate::Rate16000; // the rate the 3DS Sound app uses + u32_le unknown3 = 0; // less than 3 according to the 3DS Sound app. observed 2 here + u32_le unknown4 = + 0; // 0:raw 1:ADTS? less than 2 according to the 3DS Sound app. observed 0 here + u32_le unknown5 = 0; // unused? + u32_le unknown6 = 0; // unused? +}; + +struct EncodeAACRequest { + u32_le src_addr_ch0 = 0; + u32_le src_addr_ch1 = 0; + u32_le dst_addr = 0; + u32_le unknown1 = 0; // the 3DS Sound app explicitly moves 0x003B'4A08, possibly an address + u32_le unknown2 = 0; // unused? + u32_le unknown3 = 0; // unused? +}; + +struct EncodeAACResponse { + u32_le unknown1 = 0; + u32_le unknown2 = 0; + u32_le unknown3 = 0; + u32_le unknown4 = 0; + u32_le unknown5 = 0; // unused? + u32_le unknown6 = 0; // unused? +}; + +struct BinaryMessage { + struct { + enum_le codec = + DecoderCodec::None; // this is a guess. until now only 0x1 was observed here + enum_le cmd = DecoderCommand::Init; + // This is a guess, when tested with Init EncodeAAC, the DSP replies 0x0 for apparently + // valid values and 0x1 (regardless of what was passed in the request) for invalid values in + // other fields + enum_le result = ResultStatus::Error; + } header; + union { + std::array data{}; + + DecodeAACInitRequest decode_aac_init; + DecodeAACRequest decode_aac_request; + DecodeAACResponse decode_aac_response; + + EncodeAACInitRequest encode_aac_init; + EncodeAACRequest encode_aac_request; + EncodeAACResponse encode_aac_response; + }; +}; +static_assert(sizeof(BinaryMessage) == 32, "Unexpected struct size for BinaryMessage"); enum_le GetSampleRateEnum(u32 sample_rate); class DecoderBase { public: virtual ~DecoderBase(); - virtual std::optional ProcessRequest(const BinaryRequest& request) = 0; + virtual std::optional ProcessRequest(const BinaryMessage& request) = 0; /// Return true if this Decoder can be loaded. Return false if the system cannot create the /// decoder virtual bool IsValid() const = 0; @@ -81,7 +139,7 @@ class NullDecoder final : public DecoderBase { public: NullDecoder(); ~NullDecoder() override; - std::optional ProcessRequest(const BinaryRequest& request) override; + std::optional ProcessRequest(const BinaryMessage& request) override; bool IsValid() const override { return true; } diff --git a/src/audio_core/hle/fdk_decoder.cpp b/src/audio_core/hle/fdk_decoder.cpp index 64459ac50..f0ce089c2 100644 --- a/src/audio_core/hle/fdk_decoder.cpp +++ b/src/audio_core/hle/fdk_decoder.cpp @@ -11,15 +11,15 @@ class FDKDecoder::Impl { public: explicit Impl(Memory::MemorySystem& memory); ~Impl(); - std::optional ProcessRequest(const BinaryRequest& request); + std::optional ProcessRequest(const BinaryMessage& request); bool IsValid() const { return decoder != nullptr; } private: - std::optional Initalize(const BinaryRequest& request); + std::optional Initalize(const BinaryMessage& request); - std::optional Decode(const BinaryRequest& request); + std::optional Decode(const BinaryMessage& request); void Clear(); @@ -58,10 +58,9 @@ FDKDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) { } } -std::optional FDKDecoder::Impl::Initalize(const BinaryRequest& request) { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; +std::optional FDKDecoder::Impl::Initalize(const BinaryMessage& request) { + BinaryMessage response = request; + response.header.result = ResultStatus::Success; if (decoder) { LOG_INFO(Audio_DSP, "FDK Decoder initialized"); @@ -90,56 +89,58 @@ void FDKDecoder::Impl::Clear() { AACDEC_FLUSH & AACDEC_INTR & AACDEC_CONCEAL); } -std::optional FDKDecoder::Impl::ProcessRequest(const BinaryRequest& request) { - if (request.codec != DecoderCodec::AAC) { +std::optional FDKDecoder::Impl::ProcessRequest(const BinaryMessage& request) { + if (request.header.codec != DecoderCodec::DecodeAAC) { LOG_ERROR(Audio_DSP, "FDK AAC Decoder cannot handle such codec: {}", - static_cast(request.codec)); + static_cast(request.header.codec)); return {}; } - switch (request.cmd) { + switch (request.header.cmd) { case DecoderCommand::Init: { return Initalize(request); } - case DecoderCommand::Decode: { + case DecoderCommand::EncodeDecode: { return Decode(request); } case DecoderCommand::Unknown: { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; + BinaryMessage response = request; + response.header.result = 0x0; return response; } default: - LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", static_cast(request.cmd)); + LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", + static_cast(request.header.cmd)); return {}; } } -std::optional FDKDecoder::Impl::Decode(const BinaryRequest& request) { - BinaryResponse response; - response.codec = request.codec; - response.cmd = request.cmd; - response.size = request.size; +std::optional FDKDecoder::Impl::Decode(const BinaryMessage& request) { + BinaryMessages response; + response.header.codec = request.header.codec; + response.header.cmd = request.header.cmd; + response.decode_aac_response.size = request.decode_aac_request.size; if (!decoder) { LOG_DEBUG(Audio_DSP, "Decoder not initalized"); // This is a hack to continue games that are not compiled with the aac codec - response.num_channels = 2; - response.num_samples = 1024; + response.decode_aac_response.num_channels = 2; + response.decode_aac_response.num_samples = 1024; return response; } - if (request.src_addr < Memory::FCRAM_PADDR || - request.src_addr + request.size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", request.src_addr); + if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR || + request.decode_aac_request.src_addr + request.decode_aac_request.size > + Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { + LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", + request.decode_aac_request.src_addr); return {}; } - u8* data = memory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR); + u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR); std::array, 2> out_streams; - std::size_t data_size = request.size; + std::size_t data_size = request.decode_aac_request.size; // decoding loops AAC_DECODER_ERROR result = AAC_DEC_OK; @@ -168,9 +169,9 @@ std::optional FDKDecoder::Impl::Decode(const BinaryRequest& requ // get the stream information stream_info = aacDecoder_GetStreamInfo(decoder); // fill the stream information for binary response - response.sample_rate = GetSampleRateEnum(stream_info->sampleRate); - response.num_channels = stream_info->numChannels; - response.num_samples = stream_info->frameSize; + response.decode_aac_response.sample_rate = GetSampleRateEnum(stream_info->sampleRate); + response.decode_aac_response.num_channels = stream_info->numChannels; + response.decode_aac_response.num_samples = stream_info->frameSize; // fill the output // the sample size = frame_size * channel_counts for (int sample = 0; sample < stream_info->frameSize; sample++) { @@ -193,7 +194,8 @@ std::optional FDKDecoder::Impl::Decode(const BinaryRequest& requ for (std::size_t ch = 0; ch < out_streams.size(); ch++) { if (!out_streams[ch].empty()) { auto byte_size = out_streams[ch].size() * sizeof(s16); - auto dst = ch == 0 ? request.dst_addr_ch0 : request.dst_addr_ch1; + auto dst = ch == 0 ? request.decode_aac_request.dst_addr_ch0 + : request.decode_aac_request.dst_addr_ch1; if (dst < Memory::FCRAM_PADDR || dst + byte_size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch{} {:08x}", ch, dst); @@ -211,7 +213,7 @@ FDKDecoder::FDKDecoder(Memory::MemorySystem& memory) : impl(std::make_unique FDKDecoder::ProcessRequest(const BinaryRequest& request) { +std::optional FDKDecoder::ProcessRequest(const BinaryMessage& request) { return impl->ProcessRequest(request); } diff --git a/src/audio_core/hle/fdk_decoder.h b/src/audio_core/hle/fdk_decoder.h index 337c6054a..65d6e8cd3 100644 --- a/src/audio_core/hle/fdk_decoder.h +++ b/src/audio_core/hle/fdk_decoder.h @@ -12,7 +12,7 @@ class FDKDecoder final : public DecoderBase { public: explicit FDKDecoder(Memory::MemorySystem& memory); ~FDKDecoder() override; - std::optional ProcessRequest(const BinaryRequest& request) override; + std::optional ProcessRequest(const BinaryMessage& request) override; bool IsValid() const override; private: diff --git a/src/audio_core/hle/ffmpeg_decoder.cpp b/src/audio_core/hle/ffmpeg_decoder.cpp index c9d7abe3f..00524a8bc 100644 --- a/src/audio_core/hle/ffmpeg_decoder.cpp +++ b/src/audio_core/hle/ffmpeg_decoder.cpp @@ -11,17 +11,17 @@ class FFMPEGDecoder::Impl { public: explicit Impl(Memory::MemorySystem& memory); ~Impl(); - std::optional ProcessRequest(const BinaryRequest& request); + std::optional ProcessRequest(const BinaryMessage& request); bool IsValid() const { return have_ffmpeg_dl; } private: - std::optional Initalize(const BinaryRequest& request); + std::optional Initalize(const BinaryMessage& request); void Clear(); - std::optional Decode(const BinaryRequest& request); + std::optional Decode(const BinaryMessage& request); struct AVPacketDeleter { void operator()(AVPacket* packet) const { @@ -65,39 +65,38 @@ FFMPEGDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) { FFMPEGDecoder::Impl::~Impl() = default; -std::optional FFMPEGDecoder::Impl::ProcessRequest(const BinaryRequest& request) { - if (request.codec != DecoderCodec::AAC) { - LOG_ERROR(Audio_DSP, "Got wrong codec {}", static_cast(request.codec)); +std::optional FFMPEGDecoder::Impl::ProcessRequest(const BinaryMessage& request) { + if (request.header.codec != DecoderCodec::DecodeAAC) { + LOG_ERROR(Audio_DSP, "Got wrong codec {}", static_cast(request.header.codec)); return {}; } - switch (request.cmd) { + switch (request.header.cmd) { case DecoderCommand::Init: { return Initalize(request); } - case DecoderCommand::Decode: { + case DecoderCommand::EncodeDecode: { return Decode(request); } case DecoderCommand::Unknown: { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; + BinaryMessage response = request; + response.header.result = ResultStatus::Success; return response; } default: - LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", static_cast(request.cmd)); + LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", + static_cast(request.header.cmd)); return {}; } } -std::optional FFMPEGDecoder::Impl::Initalize(const BinaryRequest& request) { +std::optional FFMPEGDecoder::Impl::Initalize(const BinaryMessage& request) { if (initalized) { Clear(); } - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; + BinaryMessage response = request; + response.header.result = ResultStatus::Success; if (!have_ffmpeg_dl) { return response; @@ -143,30 +142,32 @@ void FFMPEGDecoder::Impl::Clear() { av_packet.reset(); } -std::optional FFMPEGDecoder::Impl::Decode(const BinaryRequest& request) { - BinaryResponse response; - response.codec = request.codec; - response.cmd = request.cmd; - response.size = request.size; +std::optional FFMPEGDecoder::Impl::Decode(const BinaryMessage& request) { + BinaryMessage response; + response.header.codec = request.header.codec; + response.header.cmd = request.header.cmd; + response.decode_aac_response.size = request.decode_aac_request.size; if (!initalized) { LOG_DEBUG(Audio_DSP, "Decoder not initalized"); // This is a hack to continue games that are not compiled with the aac codec - response.num_channels = 2; - response.num_samples = 1024; + response.decode_aac_response.num_channels = 2; + response.decode_aac_response.num_samples = 1024; return response; } - if (request.src_addr < Memory::FCRAM_PADDR || - request.src_addr + request.size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", request.src_addr); + if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR || + request.decode_aac_request.src_addr + request.decode_aac_request.size > + Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { + LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", + request.decode_aac_request.src_addr); return {}; } - u8* data = memory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR); + u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR); std::array, 2> out_streams; - std::size_t data_size = request.size; + std::size_t data_size = request.decode_aac_request.size; while (data_size > 0) { if (!decoded_frame) { decoded_frame.reset(av_frame_alloc_dl()); @@ -211,9 +212,10 @@ std::optional FFMPEGDecoder::Impl::Decode(const BinaryRequest& r std::size_t size = bytes_per_sample * (decoded_frame->nb_samples); - response.sample_rate = GetSampleRateEnum(decoded_frame->sample_rate); - response.num_channels = decoded_frame->channels; - response.num_samples += decoded_frame->nb_samples; + response.decode_aac_response.sample_rate = + GetSampleRateEnum(decoded_frame->sample_rate); + response.decode_aac_response.num_channels = decoded_frame->channels; + response.decode_aac_response.num_samples += decoded_frame->nb_samples; // FFmpeg converts to 32 signed floating point PCM, we need s16 PCM so we need to // convert it @@ -234,25 +236,29 @@ std::optional FFMPEGDecoder::Impl::Decode(const BinaryRequest& r } if (out_streams[0].size() != 0) { - if (request.dst_addr_ch0 < Memory::FCRAM_PADDR || - request.dst_addr_ch0 + out_streams[0].size() > + if (request.decode_aac_request.dst_addr_ch0 < Memory::FCRAM_PADDR || + request.decode_aac_request.dst_addr_ch0 + out_streams[0].size() > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch0 {:08x}", request.dst_addr_ch0); + LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch0 {:08x}", + request.decode_aac_request.dst_addr_ch0); return {}; } - std::memcpy(memory.GetFCRAMPointer(request.dst_addr_ch0 - Memory::FCRAM_PADDR), - out_streams[0].data(), out_streams[0].size()); + std::memcpy( + memory.GetFCRAMPointer(request.decode_aac_request.dst_addr_ch0 - Memory::FCRAM_PADDR), + out_streams[0].data(), out_streams[0].size()); } if (out_streams[1].size() != 0) { - if (request.dst_addr_ch1 < Memory::FCRAM_PADDR || - request.dst_addr_ch1 + out_streams[1].size() > + if (request.decode_aac_request.dst_addr_ch1 < Memory::FCRAM_PADDR || + request.decode_aac_request.dst_addr_ch1 + out_streams[1].size() > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch1 {:08x}", request.dst_addr_ch1); + LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch1 {:08x}", + request.decode_aac_request.dst_addr_ch1); return {}; } - std::memcpy(memory.GetFCRAMPointer(request.dst_addr_ch1 - Memory::FCRAM_PADDR), - out_streams[1].data(), out_streams[1].size()); + std::memcpy( + memory.GetFCRAMPointer(request.decode_aac_request.dst_addr_ch1 - Memory::FCRAM_PADDR), + out_streams[1].data(), out_streams[1].size()); } return response; } @@ -261,7 +267,7 @@ FFMPEGDecoder::FFMPEGDecoder(Memory::MemorySystem& memory) : impl(std::make_uniq FFMPEGDecoder::~FFMPEGDecoder() = default; -std::optional FFMPEGDecoder::ProcessRequest(const BinaryRequest& request) { +std::optional FFMPEGDecoder::ProcessRequest(const BinaryMessage& request) { return impl->ProcessRequest(request); } diff --git a/src/audio_core/hle/ffmpeg_decoder.h b/src/audio_core/hle/ffmpeg_decoder.h index ee5e8cda7..6c356776a 100644 --- a/src/audio_core/hle/ffmpeg_decoder.h +++ b/src/audio_core/hle/ffmpeg_decoder.h @@ -12,7 +12,7 @@ class FFMPEGDecoder final : public DecoderBase { public: explicit FFMPEGDecoder(Memory::MemorySystem& memory); ~FFMPEGDecoder() override; - std::optional ProcessRequest(const BinaryRequest& request) override; + std::optional ProcessRequest(const BinaryMessage& request) override; bool IsValid() const override; private: diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index 18297ecee..d7e70f328 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -40,7 +40,8 @@ using Service::DSP::DSP_DSP; namespace AudioCore { -DspHle::DspHle() : DspHle(Core::System::GetInstance().Memory()) {} +DspHle::DspHle() + : DspHle(Core::System::GetInstance().Memory(), Core::System::GetInstance().CoreTiming()) {} template void DspHle::serialize(Archive& ar, const unsigned int) { @@ -58,7 +59,7 @@ static constexpr u64 audio_frame_ticks = samples_per_frame * 4096 * 2ull; ///< U struct DspHle::Impl final { public: - explicit Impl(DspHle& parent, Memory::MemorySystem& memory); + explicit Impl(DspHle& parent, Memory::MemorySystem& memory, Core::Timing& timing); ~Impl(); DspState GetDspState() const; @@ -100,6 +101,7 @@ private: HLE::Mixers mixers{}; DspHle& parent; + Core::Timing& core_timing; Core::TimingEventType* tick_event{}; std::unique_ptr decoder{}; @@ -118,7 +120,8 @@ private: friend class boost::serialization::access; }; -DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory) : parent(parent_) { +DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing& timing) + : parent(parent_), core_timing(timing) { dsp_memory.raw_memory.fill(0); for (auto& source : sources) { @@ -152,17 +155,15 @@ DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory) : parent(paren decoder = std::make_unique(); } - Core::Timing& timing = Core::System::GetInstance().CoreTiming(); tick_event = - timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) { + core_timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) { this->AudioTickCallback(cycles_late); }); - timing.ScheduleEvent(audio_frame_ticks, tick_event); + core_timing.ScheduleEvent(audio_frame_ticks, tick_event); } DspHle::Impl::~Impl() { - Core::Timing& timing = Core::System::GetInstance().CoreTiming(); - timing.UnscheduleEvent(tick_event, 0); + core_timing.UnscheduleEvent(tick_event, 0); } DspState DspHle::Impl::GetDspState() const { @@ -291,21 +292,21 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, const std::vector& buffer) } case DspPipe::Binary: { // TODO(B3N30): Make this async, and signal the interrupt - HLE::BinaryRequest request; + HLE::BinaryMessage request{}; if (sizeof(request) != buffer.size()) { LOG_CRITICAL(Audio_DSP, "got binary pipe with wrong size {}", buffer.size()); UNIMPLEMENTED(); return; } std::memcpy(&request, buffer.data(), buffer.size()); - if (request.codec != HLE::DecoderCodec::AAC) { - LOG_CRITICAL(Audio_DSP, "got unknown codec {}", static_cast(request.codec)); + if (request.header.codec != HLE::DecoderCodec::DecodeAAC) { + LOG_CRITICAL(Audio_DSP, "got unknown codec {}", static_cast(request.header.codec)); UNIMPLEMENTED(); return; } - std::optional response = decoder->ProcessRequest(request); + std::optional response = decoder->ProcessRequest(request); if (response) { - const HLE::BinaryResponse& value = *response; + const HLE::BinaryMessage& value = *response; pipe_data[static_cast(pipe_number)].resize(sizeof(value)); std::memcpy(pipe_data[static_cast(pipe_number)].data(), &value, sizeof(value)); } @@ -457,11 +458,11 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) { } // Reschedule recurrent event - Core::Timing& timing = Core::System::GetInstance().CoreTiming(); - timing.ScheduleEvent(audio_frame_ticks - cycles_late, tick_event); + core_timing.ScheduleEvent(audio_frame_ticks - cycles_late, tick_event); } -DspHle::DspHle(Memory::MemorySystem& memory) : impl(std::make_unique(*this, memory)) {} +DspHle::DspHle(Memory::MemorySystem& memory, Core::Timing& timing) + : impl(std::make_unique(*this, memory, timing)) {} DspHle::~DspHle() = default; u16 DspHle::RecvData(u32 register_number) { diff --git a/src/audio_core/hle/hle.h b/src/audio_core/hle/hle.h index 11ec2820a..014a3b73c 100644 --- a/src/audio_core/hle/hle.h +++ b/src/audio_core/hle/hle.h @@ -22,7 +22,7 @@ namespace AudioCore { class DspHle final : public DspInterface { public: - explicit DspHle(Memory::MemorySystem& memory); + explicit DspHle(Memory::MemorySystem& memory, Core::Timing& timing); ~DspHle(); u16 RecvData(u32 register_number) override; diff --git a/src/audio_core/hle/mediandk_decoder.cpp b/src/audio_core/hle/mediandk_decoder.cpp index f78db8e89..4dc3154dc 100644 --- a/src/audio_core/hle/mediandk_decoder.cpp +++ b/src/audio_core/hle/mediandk_decoder.cpp @@ -25,16 +25,16 @@ class MediaNDKDecoder::Impl { public: explicit Impl(Memory::MemorySystem& memory); ~Impl(); - std::optional ProcessRequest(const BinaryRequest& request); + std::optional ProcessRequest(const BinaryMessage& request); bool SetMediaType(const ADTSData& adts_data); private: - std::optional Initalize(const BinaryRequest& request); - std::optional Decode(const BinaryRequest& request); + std::optional Initalize(const BinaryMessage& request); + std::optional Decode(const BinaryMessage& request); - Memory::MemorySystem& mMemory; - std::unique_ptr mDecoder; + Memory::MemorySystem& memory; + std::unique_ptr decoder; // default: 2 channles, 48000 samplerate ADTSData mADTSData{ /*header_length*/ 7, /*MPEG2*/ false, /*profile*/ 2, @@ -42,28 +42,27 @@ private: /*samplerate_idx*/ 3, /*length*/ 0, /*samplerate*/ 48000}; }; -MediaNDKDecoder::Impl::Impl(Memory::MemorySystem& memory) : mMemory(memory) { +MediaNDKDecoder::Impl::Impl(Memory::MemorySystem& memory_) : memory(memory_) { SetMediaType(mADTSData); } MediaNDKDecoder::Impl::~Impl() = default; -std::optional MediaNDKDecoder::Impl::Initalize(const BinaryRequest& request) { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; +std::optional MediaNDKDecoder::Impl::Initalize(const BinaryMessage& request) { + BinaryMessage response = request; + response.header.result = ResultStatus::Success; return response; } bool MediaNDKDecoder::Impl::SetMediaType(const ADTSData& adts_data) { const char* mime = "audio/mp4a-latm"; - if (mDecoder && mADTSData.profile == adts_data.profile && + if (decoder && mADTSData.profile == adts_data.profile && mADTSData.channel_idx == adts_data.channel_idx && mADTSData.samplerate_idx == adts_data.samplerate_idx) { return true; } - mDecoder.reset(AMediaCodec_createDecoderByType(mime)); - if (mDecoder == nullptr) { + decoder.reset(AMediaCodec_createDecoderByType(mime)); + if (decoder == nullptr) { return false; } @@ -78,17 +77,17 @@ bool MediaNDKDecoder::Impl::SetMediaType(const ADTSData& adts_data) { AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_IS_ADTS, 1); AMediaFormat_setBuffer(format, "csd-0", csd_0, sizeof(csd_0)); - media_status_t status = AMediaCodec_configure(mDecoder.get(), format, NULL, NULL, 0); + media_status_t status = AMediaCodec_configure(decoder.get(), format, NULL, NULL, 0); if (status != AMEDIA_OK) { AMediaFormat_delete(format); - mDecoder.reset(); + decoder.reset(); return false; } - status = AMediaCodec_start(mDecoder.get()); + status = AMediaCodec_start(decoder.get()); if (status != AMEDIA_OK) { AMediaFormat_delete(format); - mDecoder.reset(); + decoder.reset(); return false; } @@ -97,51 +96,53 @@ bool MediaNDKDecoder::Impl::SetMediaType(const ADTSData& adts_data) { return true; } -std::optional MediaNDKDecoder::Impl::ProcessRequest(const BinaryRequest& request) { - if (request.codec != DecoderCodec::AAC) { +std::optional MediaNDKDecoder::Impl::ProcessRequest(const BinaryMessage& request) { + if (request.header.codec != DecoderCodec::DecodeAAC) { LOG_ERROR(Audio_DSP, "AAC Decoder cannot handle such codec: {}", - static_cast(request.codec)); + static_cast(request.header.codec)); return {}; } - switch (request.cmd) { + switch (request.header.cmd) { case DecoderCommand::Init: { return Initalize(request); } - case DecoderCommand::Decode: { + case DecoderCommand::EncodeDecode: { return Decode(request); } case DecoderCommand::Unknown: { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; + BinaryMessage response = request; + response.header.result = ResultStatus::Success; return response; } default: - LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", static_cast(request.cmd)); + LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", + static_cast(request.header.cmd)); return {}; } } -std::optional MediaNDKDecoder::Impl::Decode(const BinaryRequest& request) { - BinaryResponse response; - response.codec = request.codec; - response.cmd = request.cmd; - response.size = request.size; - response.num_samples = 1024; +std::optional MediaNDKDecoder::Impl::Decode(const BinaryMessage& request) { + BinaryMessage response{}; + response.header.codec = request.header.codec; + response.header.cmd = request.header.cmd; + response.decode_aac_response.size = request.decode_aac_request.size; + response.decode_aac_response.num_samples = 1024; - if (request.src_addr < Memory::FCRAM_PADDR || - request.src_addr + request.size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", request.src_addr); + if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR || + request.decode_aac_request.src_addr + request.decode_aac_request.size > + Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { + LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", + request.decode_aac_request.src_addr); return response; } - u8* data = mMemory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR); + u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR); ADTSData adts_data = ParseADTS(reinterpret_cast(data)); SetMediaType(adts_data); - response.sample_rate = GetSampleRateEnum(adts_data.samplerate); - response.num_channels = adts_data.channels; - if (!mDecoder) { + response.decode_aac_response.sample_rate = GetSampleRateEnum(adts_data.samplerate); + response.decode_aac_response.num_channels = adts_data.channels; + if (!decoder) { LOG_ERROR(Audio_DSP, "Missing decoder for profile: {}, channels: {}, samplerate: {}", adts_data.profile, adts_data.channels, adts_data.samplerate); return {}; @@ -151,18 +152,18 @@ std::optional MediaNDKDecoder::Impl::Decode(const BinaryRequest& constexpr int timeout = 160; std::size_t buffer_size = 0; u8* buffer = nullptr; - ssize_t buffer_index = AMediaCodec_dequeueInputBuffer(mDecoder.get(), timeout); + ssize_t buffer_index = AMediaCodec_dequeueInputBuffer(decoder.get(), timeout); if (buffer_index < 0) { LOG_ERROR(Audio_DSP, "Failed to enqueue the input samples: {}", buffer_index); return response; } - buffer = AMediaCodec_getInputBuffer(mDecoder.get(), buffer_index, &buffer_size); - if (buffer_size < request.size) { + buffer = AMediaCodec_getInputBuffer(decoder.get(), buffer_index, &buffer_size); + if (buffer_size < request.decode_aac_request.size) { return response; } - std::memcpy(buffer, data, request.size); - media_status_t status = - AMediaCodec_queueInputBuffer(mDecoder.get(), buffer_index, 0, request.size, 0, 0); + std::memcpy(buffer, data, request.decode_aac_request.size); + media_status_t status = AMediaCodec_queueInputBuffer(decoder.get(), buffer_index, 0, + request.decode_aac_request.size, 0, 0); if (status != AMEDIA_OK) { LOG_WARNING(Audio_DSP, "Try queue input buffer again later!"); return response; @@ -171,7 +172,7 @@ std::optional MediaNDKDecoder::Impl::Decode(const BinaryRequest& // output AMediaCodecBufferInfo info; std::array, 2> out_streams; - buffer_index = AMediaCodec_dequeueOutputBuffer(mDecoder.get(), &info, timeout); + buffer_index = AMediaCodec_dequeueOutputBuffer(decoder.get(), &info, timeout); switch (buffer_index) { case AMEDIACODEC_INFO_TRY_AGAIN_LATER: LOG_WARNING(Audio_DSP, "Failed to dequeue output buffer: timeout!"); @@ -180,47 +181,53 @@ std::optional MediaNDKDecoder::Impl::Decode(const BinaryRequest& LOG_WARNING(Audio_DSP, "Failed to dequeue output buffer: buffers changed!"); break; case AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED: { - AMediaFormat* format = AMediaCodec_getOutputFormat(mDecoder.get()); + AMediaFormat* format = AMediaCodec_getOutputFormat(decoder.get()); LOG_WARNING(Audio_DSP, "output format: {}", AMediaFormat_toString(format)); AMediaFormat_delete(format); - buffer_index = AMediaCodec_dequeueOutputBuffer(mDecoder.get(), &info, timeout); + buffer_index = AMediaCodec_dequeueOutputBuffer(decoder.get(), &info, timeout); } default: { int offset = info.offset; - buffer = AMediaCodec_getOutputBuffer(mDecoder.get(), buffer_index, &buffer_size); + buffer = AMediaCodec_getOutputBuffer(decoder.get(), buffer_index, &buffer_size); while (offset < info.size) { - for (int channel = 0; channel < response.num_channels; channel++) { + for (int channel = 0; channel < response.decode_aac_response.num_channels; channel++) { u16 pcm_data; std::memcpy(&pcm_data, buffer + offset, sizeof(pcm_data)); out_streams[channel].push_back(pcm_data); offset += sizeof(pcm_data); } } - AMediaCodec_releaseOutputBuffer(mDecoder.get(), buffer_index, info.size != 0); + AMediaCodec_releaseOutputBuffer(decoder.get(), buffer_index, info.size != 0); } } // transfer the decoded buffer from vector to the FCRAM size_t stream0_size = out_streams[0].size() * sizeof(u16); if (stream0_size != 0) { - if (request.dst_addr_ch0 < Memory::FCRAM_PADDR || - request.dst_addr_ch0 + stream0_size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch0 {:08x}", request.dst_addr_ch0); + if (request.decode_aac_request.dst_addr_ch0 < Memory::FCRAM_PADDR || + request.decode_aac_request.dst_addr_ch0 + stream0_size > + Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { + LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch0 {:08x}", + request.decode_aac_request.dst_addr_ch0); return response; } - std::memcpy(mMemory.GetFCRAMPointer(request.dst_addr_ch0 - Memory::FCRAM_PADDR), - out_streams[0].data(), stream0_size); + std::memcpy( + memory.GetFCRAMPointer(request.decode_aac_request.dst_addr_ch0 - Memory::FCRAM_PADDR), + out_streams[0].data(), stream0_size); } size_t stream1_size = out_streams[1].size() * sizeof(u16); if (stream1_size != 0) { - if (request.dst_addr_ch1 < Memory::FCRAM_PADDR || - request.dst_addr_ch1 + stream1_size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch1 {:08x}", request.dst_addr_ch1); + if (request.decode_aac_request.dst_addr_ch1 < Memory::FCRAM_PADDR || + request.decode_aac_request.dst_addr_ch1 + stream1_size > + Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { + LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch1 {:08x}", + request.decode_aac_request.dst_addr_ch1); return response; } - std::memcpy(mMemory.GetFCRAMPointer(request.dst_addr_ch1 - Memory::FCRAM_PADDR), - out_streams[1].data(), stream1_size); + std::memcpy( + memory.GetFCRAMPointer(request.decode_aac_request.dst_addr_ch1 - Memory::FCRAM_PADDR), + out_streams[1].data(), stream1_size); } return response; } @@ -230,7 +237,7 @@ MediaNDKDecoder::MediaNDKDecoder(Memory::MemorySystem& memory) MediaNDKDecoder::~MediaNDKDecoder() = default; -std::optional MediaNDKDecoder::ProcessRequest(const BinaryRequest& request) { +std::optional MediaNDKDecoder::ProcessRequest(const BinaryMessage& request) { return impl->ProcessRequest(request); } diff --git a/src/audio_core/hle/mediandk_decoder.h b/src/audio_core/hle/mediandk_decoder.h index 1de1e15f7..344c367a5 100644 --- a/src/audio_core/hle/mediandk_decoder.h +++ b/src/audio_core/hle/mediandk_decoder.h @@ -11,7 +11,7 @@ class MediaNDKDecoder final : public DecoderBase { public: explicit MediaNDKDecoder(Memory::MemorySystem& memory); ~MediaNDKDecoder() override; - std::optional ProcessRequest(const BinaryRequest& request) override; + std::optional ProcessRequest(const BinaryMessage& request) override; bool IsValid() const override; private: diff --git a/src/audio_core/hle/wmf_decoder.cpp b/src/audio_core/hle/wmf_decoder.cpp index d5ac13fc8..dca0428fe 100644 --- a/src/audio_core/hle/wmf_decoder.cpp +++ b/src/audio_core/hle/wmf_decoder.cpp @@ -13,15 +13,15 @@ class WMFDecoder::Impl { public: explicit Impl(Memory::MemorySystem& memory); ~Impl(); - std::optional ProcessRequest(const BinaryRequest& request); + std::optional ProcessRequest(const BinaryMessage& request); bool IsValid() const { return is_valid; } private: - std::optional Initalize(const BinaryRequest& request); + std::optional Initalize(const BinaryMessage& request); - std::optional Decode(const BinaryRequest& request); + std::optional Decode(const BinaryMessage& request); MFOutputState DecodingLoop(ADTSData adts_header, std::array, 2>& out_streams); @@ -101,36 +101,35 @@ WMFDecoder::Impl::~Impl() { } } -std::optional WMFDecoder::Impl::ProcessRequest(const BinaryRequest& request) { - if (request.codec != DecoderCodec::AAC) { - LOG_ERROR(Audio_DSP, "Got unknown codec {}", static_cast(request.codec)); +std::optional WMFDecoder::Impl::ProcessRequest(const BinaryMessage& request) { + if (request.header.codec != DecoderCodec::DecodeAAC) { + LOG_ERROR(Audio_DSP, "Got unknown codec {}", static_cast(request.header.codec)); return std::nullopt; } - switch (request.cmd) { + switch (request.header.cmd) { case DecoderCommand::Init: { LOG_INFO(Audio_DSP, "WMFDecoder initializing"); return Initalize(request); } - case DecoderCommand::Decode: { + case DecoderCommand::EncodeDecode: { return Decode(request); } case DecoderCommand::Unknown: { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; + BinaryMessage response = request; + response.header.result = ResultStatus::Success; return response; } default: - LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", static_cast(request.cmd)); + LOG_ERROR(Audio_DSP, "Got unknown binary request: {}", + static_cast(request.header.cmd)); return std::nullopt; } } -std::optional WMFDecoder::Impl::Initalize(const BinaryRequest& request) { - BinaryResponse response; - std::memcpy(&response, &request, sizeof(response)); - response.unknown1 = 0x0; +std::optional WMFDecoder::Impl::Initalize(const BinaryMessage& request) { + BinaryMessage response = request; + response.header.result = ResultStatus::Success; format_selected = false; // select format again if application request initialize the DSP return response; @@ -186,13 +185,13 @@ MFOutputState WMFDecoder::Impl::DecodingLoop(ADTSData adts_header, return MFOutputState::FatalError; } -std::optional WMFDecoder::Impl::Decode(const BinaryRequest& request) { - BinaryResponse response; - response.codec = request.codec; - response.cmd = request.cmd; - response.size = request.size; - response.num_channels = 2; - response.num_samples = 1024; +std::optional WMFDecoder::Impl::Decode(const BinaryMessage& request) { + BinaryMessage response{}; + response.header.codec = request.header.codec; + response.header.cmd = request.header.cmd; + response.decode_aac_response.size = request.decode_aac_request.size; + response.decode_aac_response.num_channels = 2; + response.decode_aac_response.num_samples = 1024; if (!transform_initialized) { LOG_DEBUG(Audio_DSP, "Decoder not initialized"); @@ -200,26 +199,29 @@ std::optional WMFDecoder::Impl::Decode(const BinaryRequest& requ return response; } - if (request.src_addr < Memory::FCRAM_PADDR || - request.src_addr + request.size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", request.src_addr); + if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR || + request.decode_aac_request.src_addr + request.decode_aac_request.size > + Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { + LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}", + request.decode_aac_request.src_addr); return std::nullopt; } - u8* data = memory.GetFCRAMPointer(request.src_addr - Memory::FCRAM_PADDR); + u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR); std::array, 2> out_streams; unique_mfptr sample; MFInputState input_status = MFInputState::OK; MFOutputState output_status = MFOutputState::OK; - std::optional adts_meta = DetectMediaType((char*)data, request.size); + std::optional adts_meta = + DetectMediaType((char*)data, request.decode_aac_request.size); if (!adts_meta) { LOG_ERROR(Audio_DSP, "Unable to deduce decoding parameters from ADTS stream"); return response; } - response.sample_rate = GetSampleRateEnum(adts_meta->ADTSHeader.samplerate); - response.num_channels = adts_meta->ADTSHeader.channels; + response.decode_aac_response.sample_rate = GetSampleRateEnum(adts_meta->ADTSHeader.samplerate); + response.decode_aac_response.num_channels = adts_meta->ADTSHeader.channels; if (!format_selected) { LOG_DEBUG(Audio_DSP, "New ADTS stream: channels = {}, sample rate = {}", @@ -234,7 +236,7 @@ std::optional WMFDecoder::Impl::Decode(const BinaryRequest& requ format_selected = true; } - sample = CreateSample((void*)data, request.size, 1, 0); + sample = CreateSample(data, request.decode_aac_request.size, 1, 0); sample->SetUINT32(MFSampleExtension_CleanPoint, 1); while (true) { @@ -263,25 +265,29 @@ std::optional WMFDecoder::Impl::Decode(const BinaryRequest& requ } if (out_streams[0].size() != 0) { - if (request.dst_addr_ch0 < Memory::FCRAM_PADDR || - request.dst_addr_ch0 + out_streams[0].size() > + if (request.decode_aac_request.dst_addr_ch0 < Memory::FCRAM_PADDR || + request.decode_aac_request.dst_addr_ch0 + out_streams[0].size() > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch0 {:08x}", request.dst_addr_ch0); + LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch0 {:08x}", + request.decode_aac_request.dst_addr_ch0); return std::nullopt; } - std::memcpy(memory.GetFCRAMPointer(request.dst_addr_ch0 - Memory::FCRAM_PADDR), - out_streams[0].data(), out_streams[0].size()); + std::memcpy( + memory.GetFCRAMPointer(request.decode_aac_request.dst_addr_ch0 - Memory::FCRAM_PADDR), + out_streams[0].data(), out_streams[0].size()); } if (out_streams[1].size() != 0) { - if (request.dst_addr_ch1 < Memory::FCRAM_PADDR || - request.dst_addr_ch1 + out_streams[1].size() > + if (request.decode_aac_request.dst_addr_ch1 < Memory::FCRAM_PADDR || + request.decode_aac_request.dst_addr_ch1 + out_streams[1].size() > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) { - LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch1 {:08x}", request.dst_addr_ch1); + LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch1 {:08x}", + request.decode_aac_request.dst_addr_ch1); return std::nullopt; } - std::memcpy(memory.GetFCRAMPointer(request.dst_addr_ch1 - Memory::FCRAM_PADDR), - out_streams[1].data(), out_streams[1].size()); + std::memcpy( + memory.GetFCRAMPointer(request.decode_aac_request.dst_addr_ch1 - Memory::FCRAM_PADDR), + out_streams[1].data(), out_streams[1].size()); } return response; @@ -291,7 +297,7 @@ WMFDecoder::WMFDecoder(Memory::MemorySystem& memory) : impl(std::make_unique WMFDecoder::ProcessRequest(const BinaryRequest& request) { +std::optional WMFDecoder::ProcessRequest(const BinaryMessage& request) { return impl->ProcessRequest(request); } diff --git a/src/audio_core/hle/wmf_decoder.h b/src/audio_core/hle/wmf_decoder.h index a089f2322..73b83acbf 100644 --- a/src/audio_core/hle/wmf_decoder.h +++ b/src/audio_core/hle/wmf_decoder.h @@ -12,7 +12,7 @@ class WMFDecoder final : public DecoderBase { public: explicit WMFDecoder(Memory::MemorySystem& memory); ~WMFDecoder() override; - std::optional ProcessRequest(const BinaryRequest& request) override; + std::optional ProcessRequest(const BinaryMessage& request) override; bool IsValid() const override; private: diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index fbb6f1f07..f644e7541 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -122,8 +122,8 @@ static u8 PipeIndexToSlotIndex(u8 pipe_index, PipeDirection direction) { } struct DspLle::Impl final { - Impl(bool multithread) : multithread(multithread) { - teakra_slice_event = Core::System::GetInstance().CoreTiming().RegisterEvent( + Impl(Core::Timing& timing, bool multithread) : core_timing(timing), multithread(multithread) { + teakra_slice_event = core_timing.RegisterEvent( "DSP slice", [this](u64, int late) { TeakraSliceEvent(static_cast(late)); }); } @@ -137,6 +137,7 @@ struct DspLle::Impl final { bool semaphore_signaled = false; bool data_signaled = false; + Core::Timing& core_timing; Core::TimingEventType* teakra_slice_event; std::atomic loaded = false; @@ -185,7 +186,7 @@ struct DspLle::Impl final { next = 0; else next -= late; - Core::System::GetInstance().CoreTiming().ScheduleEvent(next, teakra_slice_event, 0); + core_timing.ScheduleEvent(next, teakra_slice_event, 0); } u8* GetDspDataPointer(u32 baddr) { @@ -326,7 +327,7 @@ struct DspLle::Impl final { // TODO: load special segment - Core::System::GetInstance().CoreTiming().ScheduleEvent(TeakraSlice, teakra_slice_event, 0); + core_timing.ScheduleEvent(TeakraSlice, teakra_slice_event, 0); if (multithread) { teakra_thread = std::thread(&Impl::TeakraThread, this); @@ -371,7 +372,7 @@ struct DspLle::Impl final { teakra.RecvData(2); // discard the value - Core::System::GetInstance().CoreTiming().UnscheduleEvent(teakra_slice_event, 0); + core_timing.UnscheduleEvent(teakra_slice_event, 0); StopTeakraThread(); } }; @@ -467,6 +468,14 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr dsp) { impl->teakra.SetSemaphoreHandler([ProcessPipeEvent]() { ProcessPipeEvent(false); }); } +void DspLle::SetSemaphoreHandler(std::function handler) { + impl->teakra.SetSemaphoreHandler(handler); +} + +void DspLle::SetRecvDataHandler(u8 index, std::function handler) { + impl->teakra.SetRecvDataHandler(index, handler); +} + void DspLle::LoadComponent(const std::vector& buffer) { impl->LoadComponent(buffer); } @@ -475,8 +484,8 @@ void DspLle::UnloadComponent() { impl->UnloadComponent(); } -DspLle::DspLle(Memory::MemorySystem& memory, bool multithread) - : impl(std::make_unique(multithread)) { +DspLle::DspLle(Memory::MemorySystem& memory, Core::Timing& timing, bool multithread) + : impl(std::make_unique(timing, multithread)) { Teakra::AHBMCallback ahbm; ahbm.read8 = [&memory](u32 address) -> u8 { return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR); diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index dc3647aa0..e3c3ab82b 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -6,11 +6,15 @@ #include "audio_core/dsp_interface.h" +namespace Core { +class Timing; +} + namespace AudioCore { class DspLle final : public DspInterface { public: - explicit DspLle(Memory::MemorySystem& memory, bool multithread); + explicit DspLle(Memory::MemorySystem& memory, Core::Timing& timing, bool multithread); ~DspLle() override; u16 RecvData(u32 register_number) override; @@ -24,6 +28,9 @@ public: void SetServiceToInterrupt(std::weak_ptr dsp) override; + void SetSemaphoreHandler(std::function handler); + void SetRecvDataHandler(u8 index, std::function handler); + void LoadComponent(const std::vector& buffer) override; void UnloadComponent() override; diff --git a/src/core/core.cpp b/src/core/core.cpp index 31de0537e..e1710b4b7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -400,10 +400,10 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, const auto audio_emulation = Settings::values.audio_emulation.GetValue(); if (audio_emulation == Settings::AudioEmulation::HLE) { - dsp_core = std::make_unique(*memory); + dsp_core = std::make_unique(*memory, *timing); } else { const bool multithread = audio_emulation == Settings::AudioEmulation::LLEMultithreaded; - dsp_core = std::make_unique(*memory, multithread); + dsp_core = std::make_unique(*memory, *timing, multithread); } memory->SetDSP(*dsp_core); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 9801f6a09..5b90fc8e8 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -11,6 +11,8 @@ add_executable(tests core/memory/memory.cpp core/memory/vm_manager.cpp precompiled_headers.h + audio_core/hle/hle.cpp + audio_core/lle/lle.cpp audio_core/audio_fixures.h audio_core/decoder_tests.cpp video_core/shader/shader_jit_x64_compiler.cpp diff --git a/src/tests/audio_core/decoder_tests.cpp b/src/tests/audio_core/decoder_tests.cpp index a01c4a870..2409e298c 100644 --- a/src/tests/audio_core/decoder_tests.cpp +++ b/src/tests/audio_core/decoder_tests.cpp @@ -28,26 +28,26 @@ TEST_CASE("DSP HLE Audio Decoder", "[audio_core]") { #elif HAVE_FFMPEG std::make_unique(memory); #endif - AudioCore::HLE::BinaryRequest request; + AudioCore::HLE::BinaryMessage request{}; - request.codec = AudioCore::HLE::DecoderCodec::AAC; - request.cmd = AudioCore::HLE::DecoderCommand::Init; + request.header.codec = AudioCore::HLE::DecoderCodec::DecodeAAC; + request.header.cmd = AudioCore::HLE::DecoderCommand::Init; // initialize decoder - std::optional response = decoder->ProcessRequest(request); + std::optional response = decoder->ProcessRequest(request); - request.cmd = AudioCore::HLE::DecoderCommand::Decode; + request.header.cmd = AudioCore::HLE::DecoderCommand::EncodeDecode; u8* fcram = memory.GetFCRAMPointer(0); memcpy(fcram, fixure_buffer, fixure_buffer_size); - request.src_addr = Memory::FCRAM_PADDR; - request.dst_addr_ch0 = Memory::FCRAM_PADDR + 1024; - request.dst_addr_ch1 = Memory::FCRAM_PADDR + 1048576; // 1 MB - request.size = fixure_buffer_size; + request.decode_aac_request.src_addr = Memory::FCRAM_PADDR; + request.decode_aac_request.dst_addr_ch0 = Memory::FCRAM_PADDR + 1024; + request.decode_aac_request.dst_addr_ch1 = Memory::FCRAM_PADDR + 1048576; // 1 MB + request.decode_aac_request.size = fixure_buffer_size; response = decoder->ProcessRequest(request); response = decoder->ProcessRequest(request); // remove this line - request.src_addr = Memory::FCRAM_PADDR; + request.decode_aac_request.src_addr = Memory::FCRAM_PADDR; } } diff --git a/src/tests/audio_core/hle/hle.cpp b/src/tests/audio_core/hle/hle.cpp new file mode 100644 index 000000000..e70008917 --- /dev/null +++ b/src/tests/audio_core/hle/hle.cpp @@ -0,0 +1,143 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "audio_core/hle/decoder.h" +#include "audio_core/hle/hle.h" +#include "audio_core/lle/lle.h" +#include "common/common_paths.h" +#include "core/core_timing.h" +#include "core/memory.h" + +TEST_CASE("DSP LLE vs HLE", "[audio_core][hle]") { + Memory::MemorySystem hle_memory; + Core::Timing hle_core_timing(1, 100); + + Memory::MemorySystem lle_memory; + Core::Timing lle_core_timing(1, 100); + + AudioCore::DspHle hle(hle_memory, hle_core_timing); + AudioCore::DspLle lle(lle_memory, lle_core_timing, true); + + // Initialiase LLE + { + FileUtil::SetUserPath(); + // see tests/audio_core/lle/lle.cpp for details on dspaudio.cdc + std::string firm_filepath = + FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "3ds" DIR_SEP "dspaudio.cdc"; + + if (!FileUtil::Exists(firm_filepath)) { + SKIP("Test requires dspaudio.cdc"); + } + + FileUtil::IOFile firm_file(firm_filepath, "rb"); + + std::vector firm_file_buf(firm_file.GetSize()); + firm_file.ReadArray(firm_file_buf.data(), firm_file_buf.size()); + lle.LoadComponent(firm_file_buf); + lle.SetSemaphoreHandler([&lle]() { + u16 slot = lle.RecvData(2); + u16 side = slot % 2; + u16 pipe = slot / 2; + fmt::print("SetSemaphoreHandler slot={}\n", slot); + if (pipe > 15) + return; + if (side != 0) + return; + if (pipe == 0) { + // pipe 0 is for debug. 3DS automatically drains this pipe and discards the + // data + lle.PipeRead(static_cast(pipe), + lle.GetPipeReadableSize(static_cast(pipe))); + } + }); + lle.SetRecvDataHandler(0, []() { fmt::print("SetRecvDataHandler 0\n"); }); + lle.SetRecvDataHandler(1, []() { fmt::print("SetRecvDataHandler 1\n"); }); + lle.SetRecvDataHandler(2, []() { fmt::print("SetRecvDataHandler 2\n"); }); + } + + SECTION("Initialise Audio Pipe") { + std::vector buffer(4, 0); + buffer[0] = 0; + + // LLE + { + lle.PipeWrite(AudioCore::DspPipe::Audio, buffer); + lle.SetSemaphore(0x4000); + + // todo: wait for interrupt + do { + lle_core_timing.GetTimer(0)->AddTicks(lle_core_timing.GetTimer(0)->GetDowncount()); + lle_core_timing.GetTimer(0)->Advance(); + lle_core_timing.GetTimer(0)->SetNextSlice(); + } while (lle.GetPipeReadableSize(AudioCore::DspPipe::Audio) == 0); + + REQUIRE(lle.GetPipeReadableSize(AudioCore::DspPipe::Audio) >= 32); + } + std::vector lle_read_buffer; + lle_read_buffer = lle.PipeRead(AudioCore::DspPipe::Audio, 2); + u16 lle_size; + memcpy(&lle_size, lle_read_buffer.data(), sizeof(lle_size)); + lle_read_buffer = lle.PipeRead(AudioCore::DspPipe::Audio, lle_size * 2); + + // HLE + { + hle.PipeWrite(AudioCore::DspPipe::Audio, buffer); + REQUIRE(hle.GetPipeReadableSize(AudioCore::DspPipe::Audio) >= 32); + } + std::vector hle_read_buffer(32); + hle_read_buffer = hle.PipeRead(AudioCore::DspPipe::Audio, 2); + u16 hle_size; + memcpy(&hle_size, hle_read_buffer.data(), sizeof(hle_size)); + hle_read_buffer = hle.PipeRead(AudioCore::DspPipe::Audio, hle_size * 2); + + REQUIRE(hle_size == lle_size); + REQUIRE(hle_read_buffer == lle_read_buffer); + } + + SECTION("Initialise Binary Pipe") { + std::vector buffer(32, 0); + AudioCore::HLE::BinaryMessage& request = + *reinterpret_cast(buffer.data()); + + request.header.codec = AudioCore::HLE::DecoderCodec::DecodeAAC; + request.header.cmd = AudioCore::HLE::DecoderCommand::Init; + + // Values used by Pokemon X + request.header.result = static_cast(3); + request.decode_aac_init.unknown1 = 1; + request.decode_aac_init.unknown2 = 0xFFFF'FFFF; + request.decode_aac_init.unknown3 = 1; + request.decode_aac_init.unknown4 = 0; + request.decode_aac_init.unknown5 = 1; + request.decode_aac_init.unknown6 = 0x20; + + // LLE + lle.PipeWrite(AudioCore::DspPipe::Binary, buffer); + lle.SetSemaphore(0x4000); + + // todo: wait for interrupt + do { + lle_core_timing.GetTimer(0)->AddTicks(lle_core_timing.GetTimer(0)->GetDowncount()); + lle_core_timing.GetTimer(0)->Advance(); + lle_core_timing.GetTimer(0)->SetNextSlice(); + } while (lle.GetPipeReadableSize(AudioCore::DspPipe::Binary) == 0); + + REQUIRE(lle.GetPipeReadableSize(AudioCore::DspPipe::Binary) >= 32); + + std::vector lle_read_buffer = lle.PipeRead(AudioCore::DspPipe::Binary, 32); + AudioCore::HLE::BinaryMessage& resp = + *reinterpret_cast(lle_read_buffer.data()); + CHECK(resp.header.result == AudioCore::HLE::ResultStatus::Success); + + // HLE + { + hle.PipeWrite(AudioCore::DspPipe::Binary, buffer); + REQUIRE(hle.GetPipeReadableSize(AudioCore::DspPipe::Binary) >= 32); + } + std::vector hle_read_buffer = hle.PipeRead(AudioCore::DspPipe::Binary, 32); + + REQUIRE(hle_read_buffer == lle_read_buffer); + } +} diff --git a/src/tests/audio_core/lle/lle.cpp b/src/tests/audio_core/lle/lle.cpp new file mode 100644 index 000000000..9396bb6e1 --- /dev/null +++ b/src/tests/audio_core/lle/lle.cpp @@ -0,0 +1,110 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "audio_core/hle/decoder.h" +#include "audio_core/lle/lle.h" +#include "common/common_paths.h" +#include "core/core_timing.h" +#include "core/memory.h" + +TEST_CASE("DSP LLE Sanity", "[audio_core][lle]") { + Memory::MemorySystem memory; + Core::Timing core_timing(1, 100); + + AudioCore::DspLle lle(memory, core_timing, true); + { + FileUtil::SetUserPath(); + // dspaudio.cdc can be dumped from Pokemon X & Y, It can be found in the romfs at + // "rom:/sound/dspaudio.cdc". + // One could also extract the firmware from the 3DS sound app using a modified version of + // https://github.com/zoogie/DSP1. + std::string firm_filepath = + FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "3ds" DIR_SEP "dspaudio.cdc"; + + if (!FileUtil::Exists(firm_filepath)) { + SKIP("Test requires dspaudio.cdc"); + } + + FileUtil::IOFile firm_file(firm_filepath, "rb"); + + std::vector firm_file_buf(firm_file.GetSize()); + firm_file.ReadArray(firm_file_buf.data(), firm_file_buf.size()); + lle.LoadComponent(firm_file_buf); + } + lle.SetSemaphoreHandler([&lle]() { + u16 slot = lle.RecvData(2); + u16 side = slot % 2; + u16 pipe = slot / 2; + fmt::print("SetSemaphoreHandler slot={}\n", slot); + if (pipe > 15) + return; + if (side != 0) + return; + if (pipe == 0) { + // pipe 0 is for debug. 3DS automatically drains this pipe and discards the + // data + lle.PipeRead(static_cast(pipe), + lle.GetPipeReadableSize(static_cast(pipe))); + } + }); + lle.SetRecvDataHandler(0, []() { fmt::print("SetRecvDataHandler 0\n"); }); + lle.SetRecvDataHandler(1, []() { fmt::print("SetRecvDataHandler 1\n"); }); + lle.SetRecvDataHandler(2, []() { fmt::print("SetRecvDataHandler 2\n"); }); + SECTION("Initialise Audio Pipe") { + std::vector buffer(4, 0); + buffer[0] = 0; + + lle.PipeWrite(AudioCore::DspPipe::Audio, buffer); + lle.SetSemaphore(0x4000); + + // todo: wait for interrupt + do { + core_timing.GetTimer(0)->AddTicks(core_timing.GetTimer(0)->GetDowncount()); + core_timing.GetTimer(0)->Advance(); + core_timing.GetTimer(0)->SetNextSlice(); + } while (lle.GetPipeReadableSize(AudioCore::DspPipe::Audio) == 0); + + REQUIRE(lle.GetPipeReadableSize(AudioCore::DspPipe::Audio) >= 32); + + buffer = lle.PipeRead(AudioCore::DspPipe::Audio, 2); + u16 size; + memcpy(&size, buffer.data(), sizeof(size)); + // see AudioCore::DspHle::Impl::AudioPipeWriteStructAddresses() + REQUIRE(size * 2 == 30); + } + SECTION("Initialise EncodeAAC - Binary Pipe") { + std::vector buffer(32, 0); + AudioCore::HLE::BinaryMessage& request = + *reinterpret_cast(buffer.data()); + + request.header.codec = AudioCore::HLE::DecoderCodec::EncodeAAC; + request.header.cmd = AudioCore::HLE::DecoderCommand::Init; + + // Values used by the 3DS sound app. + request.encode_aac_init.unknown1 = 1; + request.encode_aac_init.sample_rate = static_cast(5); + request.encode_aac_init.unknown3 = 2; + request.encode_aac_init.unknown4 = 0; + request.encode_aac_init.unknown5 = rand(); + request.encode_aac_init.unknown6 = rand(); + lle.PipeWrite(AudioCore::DspPipe::Binary, buffer); + lle.SetSemaphore(0x4000); + + // todo: wait for interrupt + do { + core_timing.GetTimer(0)->AddTicks(core_timing.GetTimer(0)->GetDowncount()); + core_timing.GetTimer(0)->Advance(); + core_timing.GetTimer(0)->SetNextSlice(); + } while (lle.GetPipeReadableSize(AudioCore::DspPipe::Binary) == 0); + + REQUIRE(lle.GetPipeReadableSize(AudioCore::DspPipe::Binary) >= 32); + + buffer = lle.PipeRead(AudioCore::DspPipe::Binary, 32); + AudioCore::HLE::BinaryMessage& resp = + *reinterpret_cast(buffer.data()); + REQUIRE(resp.header.result == AudioCore::HLE::ResultStatus::Success); + REQUIRE(resp.data == request.data); + } +}