Ryujinx/Ryujinx.HLE/HOS/Services/Audio/IAudioRendererManager.cs
Ac_K f17b772c56 audren: Fix AudioRenderer implementation (#773)
* Fix AudioRenderer implementation

According to RE:
- `GetAudioRendererWorkBufferSize` is updated and improved to support `REV7`
- `RequestUpdateAudioRenderer` is updated to `REV7` too

Should improve results on recent game and close #718 and #707

* Fix NodeStates.GetWorkBufferSize

* Use BitUtils instead of IntUtils

* Nits
2019-09-20 01:49:05 +02:00

148 lines
6.4 KiB
C#

using Ryujinx.Audio;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Audio.AudioRendererManager;
namespace Ryujinx.HLE.HOS.Services.Audio
{
[Service("audren:u")]
class IAudioRendererManager : IpcService
{
public IAudioRendererManager(ServiceCtx context) { }
[Command(0)]
// OpenAudioRenderer(nn::audio::detail::AudioRendererParameterInternal, u64, nn::applet::AppletResourceUserId, pid, handle<copy>, handle<copy>)
// -> object<nn::audio::detail::IAudioRenderer>
public ResultCode OpenAudioRenderer(ServiceCtx context)
{
IAalOutput audioOut = context.Device.AudioOut;
AudioRendererParameter Params = GetAudioRendererParameter(context);
MakeObject(context, new IAudioRenderer(
context.Device.System,
context.Memory,
audioOut,
Params));
return ResultCode.Success;
}
[Command(1)]
// GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal) -> u64
public ResultCode GetAudioRendererWorkBufferSize(ServiceCtx context)
{
AudioRendererParameter parameters = GetAudioRendererParameter(context);
if (AudioRendererCommon.CheckValidRevision(parameters))
{
BehaviorInfo behaviorInfo = new BehaviorInfo();
behaviorInfo.SetUserLibRevision(parameters.Revision);
long size;
int totalMixCount = parameters.SubMixCount + 1;
size = BitUtils.AlignUp(parameters.MixBufferCount * 4, AudioRendererConsts.BufferAlignment) +
parameters.SubMixCount * 0x400 +
totalMixCount * 0x940 +
parameters.VoiceCount * 0x3F0 +
BitUtils.AlignUp(totalMixCount * 8, 16) +
BitUtils.AlignUp(parameters.VoiceCount * 8, 16) +
BitUtils.AlignUp(((parameters.SinkCount + parameters.SubMixCount) * 0x3C0 + parameters.SampleCount * 4) *
(parameters.MixBufferCount + 6), AudioRendererConsts.BufferAlignment) +
(parameters.SinkCount + parameters.SubMixCount) * 0x2C0 +
(parameters.EffectCount + parameters.VoiceCount * 4) * 0x30 +
0x50;
if (behaviorInfo.IsSplitterSupported())
{
size += BitUtils.AlignUp(NodeStates.GetWorkBufferSize(totalMixCount) + EdgeMatrix.GetWorkBufferSize(totalMixCount), 16);
}
size = parameters.SinkCount * 0x170 +
(parameters.SinkCount + parameters.SubMixCount) * 0x280 +
parameters.EffectCount * 0x4C0 +
((size + SplitterContext.CalcWorkBufferSize(behaviorInfo, parameters) + 0x30 * parameters.EffectCount + (4 * parameters.VoiceCount) + 0x8F) & ~0x3FL) +
((parameters.VoiceCount << 8) | 0x40);
if (parameters.PerformanceManagerCount >= 1)
{
size += (PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(behaviorInfo, parameters) *
(parameters.PerformanceManagerCount + 1) + 0xFF) & ~0x3FL;
}
if (behaviorInfo.IsVariadicCommandBufferSizeSupported())
{
size += CommandGenerator.CalculateCommandBufferSize(parameters) + 0x7E;
}
else
{
size += 0x1807E;
}
size = BitUtils.AlignUp(size, 0x1000);
context.ResponseData.Write(size);
Logger.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}.");
return ResultCode.Success;
}
else
{
context.ResponseData.Write(0L);
Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision REV{AudioRendererCommon.GetRevisionVersion(parameters.Revision)} is not supported!");
return ResultCode.UnsupportedRevision;
}
}
private AudioRendererParameter GetAudioRendererParameter(ServiceCtx context)
{
AudioRendererParameter Params = new AudioRendererParameter
{
SampleRate = context.RequestData.ReadInt32(),
SampleCount = context.RequestData.ReadInt32(),
MixBufferCount = context.RequestData.ReadInt32(),
SubMixCount = context.RequestData.ReadInt32(),
VoiceCount = context.RequestData.ReadInt32(),
SinkCount = context.RequestData.ReadInt32(),
EffectCount = context.RequestData.ReadInt32(),
PerformanceManagerCount = context.RequestData.ReadInt32(),
VoiceDropEnable = context.RequestData.ReadInt32(),
SplitterCount = context.RequestData.ReadInt32(),
SplitterDestinationDataCount = context.RequestData.ReadInt32(),
Unknown2C = context.RequestData.ReadInt32(),
Revision = context.RequestData.ReadInt32()
};
return Params;
}
[Command(2)]
// GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
public ResultCode GetAudioDeviceService(ServiceCtx context)
{
long appletResourceUserId = context.RequestData.ReadInt64();
MakeObject(context, new IAudioDevice(context.Device.System));
return ResultCode.Success;
}
[Command(4)] // 4.0.0+
// GetAudioDeviceServiceWithRevisionInfo(nn::applet::AppletResourceUserId, u32) -> object<nn::audio::detail::IAudioDevice>
public ResultCode GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context)
{
long appletResourceUserId = context.RequestData.ReadInt64();
int revisionInfo = context.RequestData.ReadInt32();
Logger.PrintStub(LogClass.ServiceAudio, new { appletResourceUserId, revisionInfo });
return GetAudioDeviceService(context);
}
}
}