MeloNX/src/Ryujinx.Audio/Backends/Common/HardwareDeviceSessionOutputBase.cs
riperiperi 60442064e4 Audio: Add optional artificial audio delay layer
This driver runs ahead by the given duration (measured in samples at 48000hz). For games that rely on buffer release feedback to know when to provide audio frames, this can trick them into running with a higher audio latency on platforms that require it to avoid stuttering.

See `Switch.cs` for the sampleDelay definition. It's currently 0, though in future it could be configurable or switch on automatically for certain configurations.

For audio sources that _do not_ care about sample release timing, such as the current AudioRenderer, this will not change their behaviour.
2024-01-06 20:17:06 +00:00

77 lines
2.5 KiB
C#

using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Memory;
using System.Runtime.CompilerServices;
namespace Ryujinx.Audio.Backends.Common
{
public abstract class HardwareDeviceSessionOutputBase : IHardwareDeviceSession
{
public IVirtualMemoryManager MemoryManager { get; }
public SampleFormat RequestedSampleFormat { get; }
public uint RequestedSampleRate { get; }
public uint RequestedChannelCount { get; }
public HardwareDeviceSessionOutputBase(IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount)
{
MemoryManager = memoryManager;
RequestedSampleFormat = requestedSampleFormat;
RequestedSampleRate = requestedSampleRate;
RequestedChannelCount = requestedChannelCount;
}
private byte[] GetBufferSamples(AudioBuffer buffer)
{
if (buffer.DataPointer == 0)
{
return null;
}
byte[] data = new byte[buffer.DataSize];
MemoryManager.Read(buffer.DataPointer, data);
return data;
}
protected ulong GetSampleCount(AudioBuffer buffer)
{
return GetSampleCount((int)buffer.DataSize);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual ulong GetSampleCount(int dataSize)
{
return (ulong)BackendHelper.GetSampleCount(RequestedSampleFormat, (int)RequestedChannelCount, dataSize);
}
public abstract void Dispose();
public abstract void PrepareToClose();
public abstract void QueueBuffer(AudioBuffer buffer);
public abstract void SetVolume(float volume);
public abstract float GetVolume();
public abstract void Start();
public abstract void Stop();
public abstract ulong GetPlayedSampleCount();
public abstract bool WasBufferFullyConsumed(AudioBuffer buffer);
public virtual bool RegisterBuffer(AudioBuffer buffer)
{
return RegisterBuffer(buffer, GetBufferSamples(buffer));
}
public virtual bool RegisterBuffer(AudioBuffer buffer, byte[] samples)
{
if (samples == null)
{
return false;
}
buffer.Data ??= samples;
return true;
}
public virtual void UnregisterBuffer(AudioBuffer buffer) { }
}
}