Ensure that buffers are available after a signal when GetReleasedBuffers is called (#369)

This commit is contained in:
gdkchan 2018-09-18 00:12:47 -03:00 committed by GitHub
parent c7387be0d2
commit bec95cacc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -28,16 +28,12 @@ namespace Ryujinx.Audio.OpenAL
public PlaybackState State { get; set; } public PlaybackState State { get; set; }
private bool ShouldCallReleaseCallback;
private ConcurrentDictionary<long, int> Buffers; private ConcurrentDictionary<long, int> Buffers;
private Queue<long> QueuedTagsQueue; private Queue<long> QueuedTagsQueue;
private Queue<long> ReleasedTagsQueue; private Queue<long> ReleasedTagsQueue;
private int LastReleasedCount;
private bool Disposed; private bool Disposed;
public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback) public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback)
@ -59,8 +55,6 @@ namespace Ryujinx.Audio.OpenAL
public bool ContainsBuffer(long Tag) public bool ContainsBuffer(long Tag)
{ {
SyncQueuedTags();
foreach (long QueuedTag in QueuedTagsQueue) foreach (long QueuedTag in QueuedTagsQueue)
{ {
if (QueuedTag == Tag) if (QueuedTag == Tag)
@ -72,20 +66,29 @@ namespace Ryujinx.Audio.OpenAL
return false; return false;
} }
public long[] GetReleasedBuffers(int MaxCount) public long[] GetReleasedBuffers(int Count)
{ {
ClearReleased(); AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
ReleasedCount += ReleasedTagsQueue.Count;
if (Count > ReleasedCount)
{
Count = ReleasedCount;
}
List<long> Tags = new List<long>(); List<long> Tags = new List<long>();
HashSet<long> Unique = new HashSet<long>(); while (Count-- > 0 && ReleasedTagsQueue.TryDequeue(out long Tag))
while (MaxCount-- > 0 && ReleasedTagsQueue.TryDequeue(out long Tag))
{
if (Unique.Add(Tag))
{ {
Tags.Add(Tag); Tags.Add(Tag);
} }
while (Count-- > 0 && QueuedTagsQueue.TryDequeue(out long Tag))
{
AL.SourceUnqueueBuffers(SourceId, 1);
Tags.Add(Tag);
} }
return Tags.ToArray(); return Tags.ToArray();
@ -112,67 +115,27 @@ namespace Ryujinx.Audio.OpenAL
return Id; return Id;
} }
public void ClearReleased() public void CallReleaseCallbackIfNeeded()
{ {
SyncQueuedTags();
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount); AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
CheckReleaseChanges(ReleasedCount);
if (ReleasedCount > 0) if (ReleasedCount > 0)
{ {
AL.SourceUnqueueBuffers(SourceId, ReleasedCount); //If we signal, then we also need to have released buffers available
} //to return when GetReleasedBuffers is called.
} //If playback needs to be re-started due to all buffers being processed,
//then OpenAL zeros the counts (ReleasedCount), so we keep it on the queue.
public void CallReleaseCallbackIfNeeded() while (ReleasedCount-- > 0 && QueuedTagsQueue.TryDequeue(out long Tag))
{ {
CheckReleaseChanges(); AL.SourceUnqueueBuffers(SourceId, 1);
if (ShouldCallReleaseCallback) ReleasedTagsQueue.Enqueue(Tag);
{ }
ShouldCallReleaseCallback = false;
Callback(); Callback();
} }
} }
private void CheckReleaseChanges()
{
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
CheckReleaseChanges(ReleasedCount);
}
private void CheckReleaseChanges(int NewReleasedCount)
{
if (LastReleasedCount != NewReleasedCount)
{
LastReleasedCount = NewReleasedCount;
ShouldCallReleaseCallback = true;
}
}
private void SyncQueuedTags()
{
AL.GetSource(SourceId, ALGetSourcei.BuffersQueued, out int QueuedCount);
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
QueuedCount -= ReleasedCount;
while (QueuedTagsQueue.Count > QueuedCount)
{
ReleasedTagsQueue.Enqueue(QueuedTagsQueue.Dequeue());
}
while (ReleasedTagsQueue.Count > MaxReleased)
{
ReleasedTagsQueue.Dequeue();
}
}
public void Dispose() public void Dispose()
{ {
Dispose(true); Dispose(true);
@ -265,17 +228,23 @@ namespace Ryujinx.Audio.OpenAL
public void CloseTrack(int Track) public void CloseTrack(int Track)
{ {
if (Tracks.TryRemove(Track, out Track Td)) if (Tracks.TryRemove(Track, out Track Td))
{
lock (Td)
{ {
Td.Dispose(); Td.Dispose();
} }
} }
}
public bool ContainsBuffer(int Track, long Tag) public bool ContainsBuffer(int Track, long Tag)
{ {
if (Tracks.TryGetValue(Track, out Track Td)) if (Tracks.TryGetValue(Track, out Track Td))
{
lock (Td)
{ {
return Td.ContainsBuffer(Tag); return Td.ContainsBuffer(Tag);
} }
}
return false; return false;
} }
@ -283,9 +252,12 @@ namespace Ryujinx.Audio.OpenAL
public long[] GetReleasedBuffers(int Track, int MaxCount) public long[] GetReleasedBuffers(int Track, int MaxCount)
{ {
if (Tracks.TryGetValue(Track, out Track Td)) if (Tracks.TryGetValue(Track, out Track Td))
{
lock (Td)
{ {
return Td.GetReleasedBuffers(MaxCount); return Td.GetReleasedBuffers(MaxCount);
} }
}
return null; return null;
} }
@ -293,6 +265,8 @@ namespace Ryujinx.Audio.OpenAL
public void AppendBuffer<T>(int Track, long Tag, T[] Buffer) where T : struct public void AppendBuffer<T>(int Track, long Tag, T[] Buffer) where T : struct
{ {
if (Tracks.TryGetValue(Track, out Track Td)) if (Tracks.TryGetValue(Track, out Track Td))
{
lock (Td)
{ {
int BufferId = Td.AppendBuffer(Tag); int BufferId = Td.AppendBuffer(Tag);
@ -305,16 +279,20 @@ namespace Ryujinx.Audio.OpenAL
StartPlaybackIfNeeded(Td); StartPlaybackIfNeeded(Td);
} }
} }
}
public void Start(int Track) public void Start(int Track)
{ {
if (Tracks.TryGetValue(Track, out Track Td)) if (Tracks.TryGetValue(Track, out Track Td))
{
lock (Td)
{ {
Td.State = PlaybackState.Playing; Td.State = PlaybackState.Playing;
StartPlaybackIfNeeded(Td); StartPlaybackIfNeeded(Td);
} }
} }
}
private void StartPlaybackIfNeeded(Track Td) private void StartPlaybackIfNeeded(Track Td)
{ {
@ -324,8 +302,6 @@ namespace Ryujinx.Audio.OpenAL
if (State != ALSourceState.Playing && Td.State == PlaybackState.Playing) if (State != ALSourceState.Playing && Td.State == PlaybackState.Playing)
{ {
Td.ClearReleased();
AL.SourcePlay(Td.SourceId); AL.SourcePlay(Td.SourceId);
} }
} }
@ -333,12 +309,15 @@ namespace Ryujinx.Audio.OpenAL
public void Stop(int Track) public void Stop(int Track)
{ {
if (Tracks.TryGetValue(Track, out Track Td)) if (Tracks.TryGetValue(Track, out Track Td))
{
lock (Td)
{ {
Td.State = PlaybackState.Stopped; Td.State = PlaybackState.Stopped;
AL.SourceStop(Td.SourceId); AL.SourceStop(Td.SourceId);
} }
} }
}
public PlaybackState GetState(int Track) public PlaybackState GetState(int Track)
{ {