aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs')
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs146
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