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
|
||||
{
|
||||
public ulong DriverIdentifier;
|
||||
public ulong SampleCount;
|
||||
public readonly ulong DriverIdentifier;
|
||||
public readonly ulong SampleCount;
|
||||
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 SoundIOSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -11,10 +11,8 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||
{
|
||||
class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||
{
|
||||
private object _lock = new object();
|
||||
|
||||
private SoundIoHardwareDeviceDriver _driver;
|
||||
private Queue<SoundIoAudioBuffer> _queuedBuffers;
|
||||
private ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
|
||||
private SoundIOOutStream _outputStream;
|
||||
private DynamicRingBuffer _ringBuffer;
|
||||
private ulong _playedSampleCount;
|
||||
|
@ -24,7 +22,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||
{
|
||||
_driver = driver;
|
||||
_updateRequiredEvent = _driver.GetUpdateRequiredEvent();
|
||||
_queuedBuffers = new Queue<SoundIoAudioBuffer>();
|
||||
_queuedBuffers = new ConcurrentQueue<SoundIoAudioBuffer>();
|
||||
_ringBuffer = new DynamicRingBuffer();
|
||||
|
||||
SetupOutputStream();
|
||||
|
@ -42,10 +40,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||
|
||||
public override ulong GetPlayedSampleCount()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _playedSampleCount;
|
||||
}
|
||||
return Interlocked.Read(ref _playedSampleCount);
|
||||
}
|
||||
|
||||
public override float GetVolume()
|
||||
|
@ -57,19 +52,11 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||
|
||||
public override void QueueBuffer(AudioBuffer buffer)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
SoundIoAudioBuffer driverBuffer = new SoundIoAudioBuffer
|
||||
{
|
||||
DriverIdentifier = buffer.DataPointer,
|
||||
SampleCount = GetSampleCount(buffer),
|
||||
SamplePlayed = 0,
|
||||
};
|
||||
SoundIoAudioBuffer driverBuffer = new SoundIoAudioBuffer(buffer.DataPointer, GetSampleCount(buffer));
|
||||
|
||||
_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)
|
||||
|
@ -96,15 +83,12 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||
|
||||
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
||||
{
|
||||
lock (_lock)
|
||||
if (!_queuedBuffers.TryPeek(out SoundIoAudioBuffer driverBuffer))
|
||||
{
|
||||
if (!_queuedBuffers.TryPeek(out SoundIoAudioBuffer driverBuffer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return driverBuffer.DriverIdentifier != buffer.DataPointer;
|
||||
return true;
|
||||
}
|
||||
|
||||
return driverBuffer.DriverIdentifier != buffer.DataPointer;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
ulong sampleStillNeeded = driverBuffer.SampleCount - driverBuffer.SamplePlayed;
|
||||
ulong sampleStillNeeded = driverBuffer.SampleCount - Interlocked.Read(ref driverBuffer.SamplePlayed);
|
||||
ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
|
||||
|
||||
driverBuffer.SamplePlayed += playedAudioBufferSampleCount;
|
||||
Interlocked.Add(ref driverBuffer.SamplePlayed, playedAudioBufferSampleCount);
|
||||
availaibleSampleCount -= playedAudioBufferSampleCount;
|
||||
|
||||
if (driverBuffer.SamplePlayed == driverBuffer.SampleCount)
|
||||
if (Interlocked.Read(ref driverBuffer.SamplePlayed) == driverBuffer.SampleCount)
|
||||
{
|
||||
_queuedBuffers.TryDequeue(out _);
|
||||
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
_playedSampleCount += playedAudioBufferSampleCount;
|
||||
Interlocked.Add(ref _playedSampleCount, playedAudioBufferSampleCount);
|
||||
}
|
||||
|
||||
// Notify the output if needed.
|
||||
|
@ -440,15 +424,12 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
PrepareToClose();
|
||||
Stop();
|
||||
PrepareToClose();
|
||||
Stop();
|
||||
|
||||
_outputStream.Dispose();
|
||||
_outputStream.Dispose();
|
||||
|
||||
_driver.Unregister(this);
|
||||
}
|
||||
_driver.Unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue