diff --git a/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs b/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs index b341f087..d8e4f75d 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/IHardwareOpusDecoderManager.cs @@ -1,4 +1,6 @@ +using Ryujinx.Common; using Ryujinx.HLE.HOS.Services.Audio.HardwareOpusDecoderManager; +using Ryujinx.HLE.HOS.Services.Audio.Types; namespace Ryujinx.HLE.HOS.Services.Audio { @@ -26,7 +28,7 @@ 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. + // NOTE: The sample rate is ignored because it is fixed to 48KHz. int sampleRate = context.RequestData.ReadInt32(); int channelsCount = context.RequestData.ReadInt32(); @@ -35,6 +37,33 @@ namespace Ryujinx.HLE.HOS.Services.Audio return ResultCode.Success; } + [CommandHipc(4)] // 12.0.0+ + // InitializeEx(OpusParametersEx, u32, handle) -> object + public ResultCode InitializeEx(ServiceCtx context) + { + OpusParametersEx parameters = context.RequestData.ReadStruct(); + + // 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)); + + // 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(5)] // 12.0.0+ + // GetWorkBufferSizeEx(OpusParametersEx) -> u32 + public ResultCode GetWorkBufferSizeEx(ServiceCtx context) + { + OpusParametersEx parameters = context.RequestData.ReadStruct(); + + // NOTE: The sample rate is ignored because it is fixed to 48KHz. + context.ResponseData.Write(GetOpusDecoderSize(parameters.ChannelCount)); + + return ResultCode.Success; + } + private static int GetOpusDecoderSize(int channelsCount) { const int silkDecoderSize = 0x2198; diff --git a/Ryujinx.HLE/HOS/Services/Audio/Types/OpusDecoderFlags.cs b/Ryujinx.HLE/HOS/Services/Audio/Types/OpusDecoderFlags.cs new file mode 100644 index 00000000..e49c294c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/Types/OpusDecoderFlags.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Audio.Types +{ + [Flags] + enum OpusDecoderFlags : uint + { + None, + LargeFrameSize = 1 << 0, + } +} diff --git a/Ryujinx.HLE/HOS/Services/Audio/Types/OpusParametersEx.cs b/Ryujinx.HLE/HOS/Services/Audio/Types/OpusParametersEx.cs new file mode 100644 index 00000000..f00df2f8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Audio/Types/OpusParametersEx.cs @@ -0,0 +1,15 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Audio.Types +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + struct OpusParametersEx + { + public int SampleRate; + public int ChannelCount; + public OpusDecoderFlags UseLargeFrameSize; + + Array4 Padding1; + } +}