diff --git a/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoder.cpp b/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoder.cpp index c976f3a9..7c0e9966 100644 --- a/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoder.cpp +++ b/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoder.cpp @@ -11,12 +11,12 @@ namespace skyline::service::codec { return util::AlignUp(static_cast(frameSize * channelCount / (OpusFullbandSampleRate / sampleRate)), 0x40); } - IHardwareOpusDecoder::IHardwareOpusDecoder(const DeviceState &state, ServiceManager &manager, i32 sampleRate, i32 channelCount, u32 workBufferSize, KHandle workBufferHandle) + IHardwareOpusDecoder::IHardwareOpusDecoder(const DeviceState &state, ServiceManager &manager, i32 sampleRate, i32 channelCount, u32 workBufferSize, KHandle workBufferHandle, bool isIsLargerSize) : BaseService(state, manager), sampleRate(sampleRate), channelCount(channelCount), workBuffer(state.process->GetHandle(workBufferHandle)), - decoderOutputBufferSize(CalculateOutBufferSize(sampleRate, channelCount, MaxFrameSizeNormal)) { + decoderOutputBufferSize(CalculateOutBufferSize(sampleRate, channelCount, isIsLargerSize ? MaxFrameSizeEx : MaxFrameSizeNormal)) { if (workBufferSize < decoderOutputBufferSize) throw exception("Work Buffer doesn't have adequate space for Opus Decoder: 0x{:X} (Required: 0x{:X})", workBufferSize, decoderOutputBufferSize); diff --git a/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoder.h b/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoder.h index 9521c314..2825c943 100644 --- a/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoder.h +++ b/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoder.h @@ -58,7 +58,7 @@ namespace skyline::service::codec { Result DecodeInterleavedImpl(ipc::IpcRequest &request, ipc::IpcResponse &response, bool writeDecodeTime = false); public: - IHardwareOpusDecoder(const DeviceState &state, ServiceManager &manager, i32 sampleRate, i32 channelCount, u32 workBufferSize, KHandle workBufferHandle); + IHardwareOpusDecoder(const DeviceState &state, ServiceManager &manager, i32 sampleRate, i32 channelCount, u32 workBufferSize, KHandle workBufferHandle, bool isIsLargerSize = false); /** * @brief Decodes the Opus source data, returns decoded data size and decoded sample count diff --git a/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoderManager.cpp b/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoderManager.cpp index d52a45aa..576ee173 100644 --- a/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoderManager.cpp +++ b/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoderManager.cpp @@ -7,9 +7,9 @@ #include "IHardwareOpusDecoder.h" namespace skyline::service::codec { - static u32 CalculateBufferSize(i32 sampleRate, i32 channelCount) { + static u32 CalculateBufferSize(i32 sampleRate, i32 channelCount, i32 useLargerFrameSize = 0) { u32 requiredSize{static_cast(opus_decoder_get_size(channelCount))}; - requiredSize += MaxInputBufferSize + CalculateOutBufferSize(sampleRate, channelCount, MaxFrameSizeNormal); + requiredSize += MaxInputBufferSize + CalculateOutBufferSize(sampleRate, channelCount, useLargerFrameSize ? MaxFrameSizeEx : MaxFrameSizeNormal); return requiredSize; } @@ -32,4 +32,28 @@ namespace skyline::service::codec { response.Push(CalculateBufferSize(sampleRate, channelCount)); return {}; } + + Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + i32 sampleRate{request.Pop()}; + i32 channelCount{request.Pop()}; + i32 useLargerFrameSize{request.Pop()}; + request.Pop(); // Just padding + u32 workBufferSize{request.Pop()}; + KHandle workBuffer{request.copyHandles.at(0)}; + + Logger::Debug("Creating Opus decoder: Sample rate: {}, Channel count: {}, Work buffer handle: 0x{:X} (Size: 0x{:X})", sampleRate, channelCount, workBuffer, workBufferSize); + + manager.RegisterService(std::make_shared(state, manager, sampleRate, channelCount, workBufferSize, workBuffer, useLargerFrameSize), session, response); + return {}; + } + + Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + i32 sampleRate{request.Pop()}; + i32 channelCount{request.Pop()}; + i32 useLargerFrameSize{request.Pop()}; + request.Pop(); // Just padding + + response.Push(CalculateBufferSize(sampleRate, channelCount, useLargerFrameSize)); + return {}; + } } diff --git a/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoderManager.h b/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoderManager.h index 3d3e3dd8..71372a6a 100644 --- a/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoderManager.h +++ b/app/src/main/cpp/skyline/services/codec/IHardwareOpusDecoderManager.h @@ -39,9 +39,23 @@ namespace skyline::service::codec { */ Result GetWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief Returns an IHardwareOpusDecoder object [12.0.0+] + * @url https://switchbrew.org/wiki/Audio_services#OpenHardwareOpusDecoder + */ + Result OpenHardwareOpusDecoderEx(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Returns the required size for the decoder's work buffer [12.0.0+] + * @url https://switchbrew.org/wiki/Audio_services#GetWorkBufferSizeEx + */ + Result GetWorkBufferSizeEx(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + SERVICE_DECL( SFUNC(0x0, IHardwareOpusDecoderManager, OpenHardwareOpusDecoder), SFUNC(0x1, IHardwareOpusDecoderManager, GetWorkBufferSize), + SFUNC(0x4, IHardwareOpusDecoderManager, OpenHardwareOpusDecoderEx), + SFUNC(0x5, IHardwareOpusDecoderManager, GetWorkBufferSizeEx), ) }; }