forked from Mirror/Ryujinx
8406ec6272
* Refactor Ryujinx.Common and HLE Stub Logging * Resolve review comments * Rename missed loop variable * Optimize PrintStub logging function * Pass the call-sites Thread ID through to the logger * Remove superfluous lock from ConsoleLog * Process logged data objects in the logger target Pass the data object all the way to the output logger targets, to allow them to "serialize" this in whatever appropriate format they're logging in. * Use existing StringBuilder to build the properties string * Add a ServiceNotImplemented Exception Useful for printing debug information about unimplemented service calls * Resolve Style Nits * Resolve Merge Issues * Fix typo and align declarations
186 lines
6.9 KiB
C#
186 lines
6.9 KiB
C#
using Ryujinx.Audio;
|
|
using Ryujinx.Common.Logging;
|
|
using Ryujinx.HLE.HOS.Ipc;
|
|
using Ryujinx.HLE.HOS.Services.Aud.AudioRenderer;
|
|
using Ryujinx.HLE.Utilities;
|
|
using System.Collections.Generic;
|
|
|
|
using static Ryujinx.HLE.HOS.ErrorCode;
|
|
|
|
namespace Ryujinx.HLE.HOS.Services.Aud
|
|
{
|
|
class IAudioRendererManager : IpcService
|
|
{
|
|
private const int Rev0Magic = ('R' << 0) |
|
|
('E' << 8) |
|
|
('V' << 16) |
|
|
('0' << 24);
|
|
|
|
private const int Rev = 4;
|
|
|
|
public const int RevMagic = Rev0Magic + (Rev << 24);
|
|
|
|
private Dictionary<int, ServiceProcessRequest> _commands;
|
|
|
|
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
|
|
|
public IAudioRendererManager()
|
|
{
|
|
_commands = new Dictionary<int, ServiceProcessRequest>
|
|
{
|
|
{ 0, OpenAudioRenderer },
|
|
{ 1, GetAudioRendererWorkBufferSize },
|
|
{ 2, GetAudioDeviceService },
|
|
{ 4, GetAudioDeviceServiceWithRevisionInfo }
|
|
};
|
|
}
|
|
|
|
public long OpenAudioRenderer(ServiceCtx context)
|
|
{
|
|
IAalOutput audioOut = context.Device.AudioOut;
|
|
|
|
AudioRendererParameter Params = GetAudioRendererParameter(context);
|
|
|
|
MakeObject(context, new IAudioRenderer(
|
|
context.Device.System,
|
|
context.Memory,
|
|
audioOut,
|
|
Params));
|
|
|
|
return 0;
|
|
}
|
|
|
|
public long GetAudioRendererWorkBufferSize(ServiceCtx context)
|
|
{
|
|
AudioRendererParameter Params = GetAudioRendererParameter(context);
|
|
|
|
int revision = (Params.Revision - Rev0Magic) >> 24;
|
|
|
|
if (revision <= Rev)
|
|
{
|
|
bool isSplitterSupported = revision >= 3;
|
|
|
|
long size;
|
|
|
|
size = IntUtils.AlignUp(Params.Unknown8 * 4, 64);
|
|
size += Params.MixCount * 0x400;
|
|
size += (Params.MixCount + 1) * 0x940;
|
|
size += Params.VoiceCount * 0x3F0;
|
|
size += IntUtils.AlignUp((Params.MixCount + 1) * 8, 16);
|
|
size += IntUtils.AlignUp(Params.VoiceCount * 8, 16);
|
|
size += IntUtils.AlignUp(
|
|
((Params.SinkCount + Params.MixCount) * 0x3C0 + Params.SampleCount * 4) *
|
|
(Params.Unknown8 + 6), 64);
|
|
size += (Params.SinkCount + Params.MixCount) * 0x2C0;
|
|
size += (Params.EffectCount + Params.VoiceCount * 4) * 0x30 + 0x50;
|
|
|
|
if (isSplitterSupported)
|
|
{
|
|
size += IntUtils.AlignUp((
|
|
NodeStatesGetWorkBufferSize(Params.MixCount + 1) +
|
|
EdgeMatrixGetWorkBufferSize(Params.MixCount + 1)), 16);
|
|
|
|
size += Params.SplitterDestinationDataCount * 0xE0;
|
|
size += Params.SplitterCount * 0x20;
|
|
size += IntUtils.AlignUp(Params.SplitterDestinationDataCount * 4, 16);
|
|
}
|
|
|
|
size = Params.EffectCount * 0x4C0 +
|
|
Params.SinkCount * 0x170 +
|
|
Params.VoiceCount * 0x100 +
|
|
IntUtils.AlignUp(size, 64) + 0x40;
|
|
|
|
if (Params.PerformanceManagerCount >= 1)
|
|
{
|
|
size += (((Params.EffectCount +
|
|
Params.SinkCount +
|
|
Params.VoiceCount +
|
|
Params.MixCount + 1) * 16 + 0x658) *
|
|
(Params.PerformanceManagerCount + 1) + 0x13F) & ~0x3FL;
|
|
}
|
|
|
|
size = (size + 0x1907D) & ~0xFFFL;
|
|
|
|
context.ResponseData.Write(size);
|
|
|
|
Logger.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}.");
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
context.ResponseData.Write(0L);
|
|
|
|
Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!");
|
|
|
|
return MakeError(ErrorModule.Audio, AudErr.UnsupportedRevision);
|
|
}
|
|
}
|
|
|
|
private AudioRendererParameter GetAudioRendererParameter(ServiceCtx context)
|
|
{
|
|
AudioRendererParameter Params = new AudioRendererParameter();
|
|
|
|
Params.SampleRate = context.RequestData.ReadInt32();
|
|
Params.SampleCount = context.RequestData.ReadInt32();
|
|
Params.Unknown8 = context.RequestData.ReadInt32();
|
|
Params.MixCount = context.RequestData.ReadInt32();
|
|
Params.VoiceCount = context.RequestData.ReadInt32();
|
|
Params.SinkCount = context.RequestData.ReadInt32();
|
|
Params.EffectCount = context.RequestData.ReadInt32();
|
|
Params.PerformanceManagerCount = context.RequestData.ReadInt32();
|
|
Params.VoiceDropEnable = context.RequestData.ReadInt32();
|
|
Params.SplitterCount = context.RequestData.ReadInt32();
|
|
Params.SplitterDestinationDataCount = context.RequestData.ReadInt32();
|
|
Params.Unknown2C = context.RequestData.ReadInt32();
|
|
Params.Revision = context.RequestData.ReadInt32();
|
|
|
|
return Params;
|
|
}
|
|
|
|
private static int NodeStatesGetWorkBufferSize(int value)
|
|
{
|
|
int result = IntUtils.AlignUp(value, 64);
|
|
|
|
if (result < 0)
|
|
{
|
|
result |= 7;
|
|
}
|
|
|
|
return 4 * (value * value) + 0x12 * value + 2 * (result / 8);
|
|
}
|
|
|
|
private static int EdgeMatrixGetWorkBufferSize(int value)
|
|
{
|
|
int result = IntUtils.AlignUp(value * value, 64);
|
|
|
|
if (result < 0)
|
|
{
|
|
result |= 7;
|
|
}
|
|
|
|
return result / 8;
|
|
}
|
|
|
|
// GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
|
|
public long GetAudioDeviceService(ServiceCtx context)
|
|
{
|
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
|
|
|
MakeObject(context, new IAudioDevice(context.Device.System));
|
|
|
|
return 0;
|
|
}
|
|
|
|
// GetAudioDeviceServiceWithRevisionInfo(nn::applet::AppletResourceUserId, u32) -> object<nn::audio::detail::IAudioDevice>
|
|
private long GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context)
|
|
{
|
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
|
int revisionInfo = context.RequestData.ReadInt32();
|
|
|
|
Logger.PrintStub(LogClass.ServiceAudio, new { appletResourceUserId, revisionInfo });
|
|
|
|
return GetAudioDeviceService(context);
|
|
}
|
|
}
|
|
}
|