diff options
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs')
-rw-r--r-- | Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs | 146 |
1 files changed, 127 insertions, 19 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs index d8e4f75d..81ea952b 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs @@ -1,6 +1,7 @@ using Ryujinx.Common; using Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager; using Ryujinx.HLE.HOS.Services.Audio.Types; +using System.Runtime.InteropServices; namespace Ryujinx.HLE.HOS.Services.Audio { @@ -16,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio int sampleRate = context.RequestData.ReadInt32(); int channelsCount = context.RequestData.ReadInt32(); - MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount)); + MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount, OpusDecoderFlags.None)); // Close transfer memory immediately as we don't use it. context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]); @@ -28,11 +29,50 @@ namespace Ryujinx.HLE.HOS.Services.Audio // GetWorkBufferSize(bytes<8, 4>) -> u32 public ResultCode GetWorkBufferSize(ServiceCtx context) { - // NOTE: The sample rate is ignored because it is fixed to 48KHz. int sampleRate = context.RequestData.ReadInt32(); int channelsCount = context.RequestData.ReadInt32(); - context.ResponseData.Write(GetOpusDecoderSize(channelsCount)); + int opusDecoderSize = GetOpusDecoderSize(channelsCount); + + int frameSize = BitUtils.AlignUp(channelsCount * 1920 / (48000 / sampleRate), 64); + int totalSize = opusDecoderSize + 1536 + frameSize; + + context.ResponseData.Write(totalSize); + + return ResultCode.Success; + } + + [CommandHipc(2)] // 3.0.0+ + // InitializeForMultiStream(u32, handle<copy>, buffer<unknown<0x110>, 0x19>) -> object<nn::codec::detail::IHardwareOpusDecoder> + public ResultCode InitializeForMultiStream(ServiceCtx context) + { + ulong parametersAddress = context.Request.PtrBuff[0].Position; + + OpusMultiStreamParameters parameters = context.Memory.Read<OpusMultiStreamParameters>(parametersAddress); + + MakeObject(context, new IHardwareOpusDecoder(parameters.SampleRate, parameters.ChannelsCount, OpusDecoderFlags.None)); + + // Close transfer memory immediately as we don't use it. + context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]); + + return ResultCode.Success; + } + + [CommandHipc(3)] // 3.0.0+ + // GetWorkBufferSizeForMultiStream(buffer<unknown<0x110>, 0x19>) -> u32 + public ResultCode GetWorkBufferSizeForMultiStream(ServiceCtx context) + { + ulong parametersAddress = context.Request.PtrBuff[0].Position; + + OpusMultiStreamParameters parameters = context.Memory.Read<OpusMultiStreamParameters>(parametersAddress); + + int opusDecoderSize = GetOpusMultistreamDecoderSize(parameters.NumberOfStreams, parameters.NumberOfStereoStreams); + + int streamSize = BitUtils.AlignUp(parameters.NumberOfStreams * 1500, 64); + int frameSize = BitUtils.AlignUp(parameters.ChannelsCount * 1920 / (48000 / parameters.SampleRate), 64); + int totalSize = opusDecoderSize + streamSize + frameSize; + + context.ResponseData.Write(totalSize); return ResultCode.Success; } @@ -44,7 +84,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio OpusParametersEx parameters = context.RequestData.ReadStruct<OpusParametersEx>(); // UseLargeFrameSize can be ignored due to not relying on fixed size buffers for storing the decoded result. - MakeObject(context, new IHardwareOpusDecoder(parameters.SampleRate, parameters.ChannelCount)); + MakeObject(context, new IHardwareOpusDecoder(parameters.SampleRate, parameters.ChannelsCount, parameters.Flags)); // Close transfer memory immediately as we don't use it. context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]); @@ -58,15 +98,84 @@ namespace Ryujinx.HLE.HOS.Services.Audio { OpusParametersEx parameters = context.RequestData.ReadStruct<OpusParametersEx>(); - // NOTE: The sample rate is ignored because it is fixed to 48KHz. - context.ResponseData.Write(GetOpusDecoderSize(parameters.ChannelCount)); + int opusDecoderSize = GetOpusDecoderSize(parameters.ChannelsCount); + + int frameSizeMono48KHz = parameters.Flags.HasFlag(OpusDecoderFlags.LargeFrameSize) ? 5760 : 1920; + int frameSize = BitUtils.AlignUp(parameters.ChannelsCount * frameSizeMono48KHz / (48000 / parameters.SampleRate), 64); + int totalSize = opusDecoderSize + 1536 + frameSize; + + context.ResponseData.Write(totalSize); + + return ResultCode.Success; + } + + [CommandHipc(6)] // 12.0.0+ + // InitializeForMultiStreamEx(u32, handle<copy>, buffer<unknown<0x118>, 0x19>) -> object<nn::codec::detail::IHardwareOpusDecoder> + public ResultCode InitializeForMultiStreamEx(ServiceCtx context) + { + ulong parametersAddress = context.Request.PtrBuff[0].Position; + + OpusMultiStreamParametersEx parameters = context.Memory.Read<OpusMultiStreamParametersEx>(parametersAddress); + + byte[] mappings = MemoryMarshal.Cast<uint, byte>(parameters.ChannelMappings.ToSpan()).ToArray(); + + // UseLargeFrameSize can be ignored due to not relying on fixed size buffers for storing the decoded result. + MakeObject(context, new IHardwareOpusDecoder( + parameters.SampleRate, + parameters.ChannelsCount, + parameters.NumberOfStreams, + parameters.NumberOfStereoStreams, + parameters.Flags, + mappings)); + + // Close transfer memory immediately as we don't use it. + context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]); + + return ResultCode.Success; + } + + [CommandHipc(7)] // 12.0.0+ + // GetWorkBufferSizeForMultiStreamEx(buffer<unknown<0x118>, 0x19>) -> u32 + public ResultCode GetWorkBufferSizeForMultiStreamEx(ServiceCtx context) + { + ulong parametersAddress = context.Request.PtrBuff[0].Position; + + OpusMultiStreamParametersEx parameters = context.Memory.Read<OpusMultiStreamParametersEx>(parametersAddress); + + int opusDecoderSize = GetOpusMultistreamDecoderSize(parameters.NumberOfStreams, parameters.NumberOfStereoStreams); + + int frameSizeMono48KHz = parameters.Flags.HasFlag(OpusDecoderFlags.LargeFrameSize) ? 5760 : 1920; + int streamSize = BitUtils.AlignUp(parameters.NumberOfStreams * 1500, 64); + int frameSize = BitUtils.AlignUp(parameters.ChannelsCount * frameSizeMono48KHz / (48000 / parameters.SampleRate), 64); + int totalSize = opusDecoderSize + streamSize + frameSize; + + context.ResponseData.Write(totalSize); return ResultCode.Success; } + private static int GetOpusMultistreamDecoderSize(int streams, int coupledStreams) + { + if (streams < 1 || coupledStreams > streams || coupledStreams < 0) + { + return 0; + } + + int coupledSize = GetOpusDecoderSize(2); + int monoSize = GetOpusDecoderSize(1); + + return Align4(monoSize - GetOpusDecoderAllocSize(1)) * (streams - coupledStreams) + + Align4(coupledSize - GetOpusDecoderAllocSize(2)) * coupledStreams + 0xb90c; + } + + private static int Align4(int value) + { + return BitUtils.AlignUp(value, 4); + } + private static int GetOpusDecoderSize(int channelsCount) { - const int silkDecoderSize = 0x2198; + const int SilkDecoderSize = 0x2160; if (channelsCount < 1 || channelsCount > 2) { @@ -74,24 +183,23 @@ namespace Ryujinx.HLE.HOS.Services.Audio } int celtDecoderSize = GetCeltDecoderSize(channelsCount); + int opusDecoderSize = GetOpusDecoderAllocSize(channelsCount) | 0x4c; - int opusDecoderSize = (channelsCount * 0x800 + 0x4807) & -0x800 | 0x50; + return opusDecoderSize + SilkDecoderSize + celtDecoderSize; + } - return opusDecoderSize + silkDecoderSize + celtDecoderSize; + private static int GetOpusDecoderAllocSize(int channelsCount) + { + return (channelsCount * 0x800 + 0x4803) & -0x800; } private static int GetCeltDecoderSize(int channelsCount) { - const int decodeBufferSize = 0x2030; - const int celtDecoderSize = 0x58; - const int celtSigSize = 0x4; - const int overlap = 120; - const int eBandsCount = 21; - - return (decodeBufferSize + overlap * 4) * channelsCount + - eBandsCount * 16 + - celtDecoderSize + - celtSigSize; + const int DecodeBufferSize = 0x2030; + const int Overlap = 120; + const int EBandsCount = 21; + + return (DecodeBufferSize + Overlap * 4) * channelsCount + EBandsCount * 16 + 0x50; } } }
\ No newline at end of file |