Haydn: Make SoundIO session implementation lock-free (#2068)
* Haydn: Fix race condition in SoundIO Update implementation This should fix weird crashes happening for some people with SoundIO. Fix #2062 * haydn: Make SoundIO session lock-free
This commit is contained in:
parent
460a98390e
commit
d02eeed9c1
2 changed files with 28 additions and 40 deletions
|
@ -2,8 +2,15 @@
|
||||||
{
|
{
|
||||||
class SoundIoAudioBuffer
|
class SoundIoAudioBuffer
|
||||||
{
|
{
|
||||||
public ulong DriverIdentifier;
|
public readonly ulong DriverIdentifier;
|
||||||
public ulong SampleCount;
|
public readonly ulong SampleCount;
|
||||||
public ulong SamplePlayed;
|
public ulong SamplePlayed;
|
||||||
|
|
||||||
|
public SoundIoAudioBuffer(ulong driverIdentifier, ulong sampleCount)
|
||||||
|
{
|
||||||
|
DriverIdentifier = driverIdentifier;
|
||||||
|
SampleCount = sampleCount;
|
||||||
|
SamplePlayed = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ using Ryujinx.Audio.Common;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using SoundIOSharp;
|
using SoundIOSharp;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Concurrent;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -11,10 +11,8 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
{
|
{
|
||||||
class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||||
{
|
{
|
||||||
private object _lock = new object();
|
|
||||||
|
|
||||||
private SoundIoHardwareDeviceDriver _driver;
|
private SoundIoHardwareDeviceDriver _driver;
|
||||||
private Queue<SoundIoAudioBuffer> _queuedBuffers;
|
private ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
|
||||||
private SoundIOOutStream _outputStream;
|
private SoundIOOutStream _outputStream;
|
||||||
private DynamicRingBuffer _ringBuffer;
|
private DynamicRingBuffer _ringBuffer;
|
||||||
private ulong _playedSampleCount;
|
private ulong _playedSampleCount;
|
||||||
|
@ -24,7 +22,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
{
|
{
|
||||||
_driver = driver;
|
_driver = driver;
|
||||||
_updateRequiredEvent = _driver.GetUpdateRequiredEvent();
|
_updateRequiredEvent = _driver.GetUpdateRequiredEvent();
|
||||||
_queuedBuffers = new Queue<SoundIoAudioBuffer>();
|
_queuedBuffers = new ConcurrentQueue<SoundIoAudioBuffer>();
|
||||||
_ringBuffer = new DynamicRingBuffer();
|
_ringBuffer = new DynamicRingBuffer();
|
||||||
|
|
||||||
SetupOutputStream();
|
SetupOutputStream();
|
||||||
|
@ -42,10 +40,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
|
|
||||||
public override ulong GetPlayedSampleCount()
|
public override ulong GetPlayedSampleCount()
|
||||||
{
|
{
|
||||||
lock (_lock)
|
return Interlocked.Read(ref _playedSampleCount);
|
||||||
{
|
|
||||||
return _playedSampleCount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override float GetVolume()
|
public override float GetVolume()
|
||||||
|
@ -57,20 +52,12 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
|
|
||||||
public override void QueueBuffer(AudioBuffer buffer)
|
public override void QueueBuffer(AudioBuffer buffer)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
SoundIoAudioBuffer driverBuffer = new SoundIoAudioBuffer(buffer.DataPointer, GetSampleCount(buffer));
|
||||||
{
|
|
||||||
SoundIoAudioBuffer driverBuffer = new SoundIoAudioBuffer
|
|
||||||
{
|
|
||||||
DriverIdentifier = buffer.DataPointer,
|
|
||||||
SampleCount = GetSampleCount(buffer),
|
|
||||||
SamplePlayed = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
||||||
|
|
||||||
_queuedBuffers.Enqueue(driverBuffer);
|
_queuedBuffers.Enqueue(driverBuffer);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetVolume(float volume)
|
public override void SetVolume(float volume)
|
||||||
{
|
{
|
||||||
|
@ -95,8 +82,6 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
public override void UnregisterBuffer(AudioBuffer buffer) {}
|
public override void UnregisterBuffer(AudioBuffer buffer) {}
|
||||||
|
|
||||||
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
{
|
||||||
if (!_queuedBuffers.TryPeek(out SoundIoAudioBuffer driverBuffer))
|
if (!_queuedBuffers.TryPeek(out SoundIoAudioBuffer driverBuffer))
|
||||||
{
|
{
|
||||||
|
@ -105,7 +90,6 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
|
|
||||||
return driverBuffer.DriverIdentifier != buffer.DataPointer;
|
return driverBuffer.DriverIdentifier != buffer.DataPointer;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe void Update(int minFrameCount, int maxFrameCount)
|
private unsafe void Update(int minFrameCount, int maxFrameCount)
|
||||||
{
|
{
|
||||||
|
@ -413,20 +397,20 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
|
|
||||||
while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SoundIoAudioBuffer driverBuffer))
|
while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SoundIoAudioBuffer driverBuffer))
|
||||||
{
|
{
|
||||||
ulong sampleStillNeeded = driverBuffer.SampleCount - driverBuffer.SamplePlayed;
|
ulong sampleStillNeeded = driverBuffer.SampleCount - Interlocked.Read(ref driverBuffer.SamplePlayed);
|
||||||
ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
|
ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
|
||||||
|
|
||||||
driverBuffer.SamplePlayed += playedAudioBufferSampleCount;
|
Interlocked.Add(ref driverBuffer.SamplePlayed, playedAudioBufferSampleCount);
|
||||||
availaibleSampleCount -= playedAudioBufferSampleCount;
|
availaibleSampleCount -= playedAudioBufferSampleCount;
|
||||||
|
|
||||||
if (driverBuffer.SamplePlayed == driverBuffer.SampleCount)
|
if (Interlocked.Read(ref driverBuffer.SamplePlayed) == driverBuffer.SampleCount)
|
||||||
{
|
{
|
||||||
_queuedBuffers.TryDequeue(out _);
|
_queuedBuffers.TryDequeue(out _);
|
||||||
|
|
||||||
needUpdate = true;
|
needUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_playedSampleCount += playedAudioBufferSampleCount;
|
Interlocked.Add(ref _playedSampleCount, playedAudioBufferSampleCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the output if needed.
|
// Notify the output if needed.
|
||||||
|
@ -439,8 +423,6 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
{
|
||||||
PrepareToClose();
|
PrepareToClose();
|
||||||
Stop();
|
Stop();
|
||||||
|
@ -450,7 +432,6 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
_driver.Unregister(this);
|
_driver.Unregister(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue