R/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrackPool.cs
Alex Barney b2b736abc2 Misc cleanup (#708)
* Fix typos

* Remove unneeded using statements

* Enforce var style more

* Remove redundant qualifiers

* Fix some indentation

* Disable naming warnings on files with external enum names

* Fix build

* Mass find & replace for comments with no spacing

* Standardize todo capitalization and for/if spacing
2019-07-02 04:39:22 +02:00

193 lines
6.8 KiB
C#

using SoundIOSharp;
using System;
using System.Collections.Concurrent;
using System.Linq;
namespace Ryujinx.Audio.SoundIo
{
/// <summary>
/// An object pool containing a set of audio tracks
/// </summary>
internal class SoundIoAudioTrackPool : IDisposable
{
/// <summary>
/// The current size of the <see cref="SoundIoAudioTrackPool"/>
/// </summary>
private int m_Size;
/// <summary>
/// The maximum size of the <see cref="SoundIoAudioTrackPool"/>
/// </summary>
private int m_MaxSize;
/// <summary>
/// The <see cref="SoundIO"/> audio context this track pool belongs to
/// </summary>
private SoundIO m_Context;
/// <summary>
/// The <see cref="SoundIODevice"/> audio device this track pool belongs to
/// </summary>
private SoundIODevice m_Device;
/// <summary>
/// The queue that keeps track of the available <see cref="SoundIoAudioTrack"/> in the pool.
/// </summary>
private ConcurrentQueue<SoundIoAudioTrack> m_Queue;
/// <summary>
/// The dictionary providing mapping between a TrackID and <see cref="SoundIoAudioTrack"/>
/// </summary>
private ConcurrentDictionary<int, SoundIoAudioTrack> m_TrackList;
/// <summary>
/// Gets the current size of the <see cref="SoundIoAudioTrackPool"/>
/// </summary>
public int Size { get => m_Size; }
/// <summary>
/// Gets the maximum size of the <see cref="SoundIoAudioTrackPool"/>
/// </summary>
public int MaxSize { get => m_MaxSize; }
/// <summary>
/// Gets a value that indicates whether the <see cref="SoundIoAudioTrackPool"/> is empty
/// </summary>
public bool IsEmpty { get => m_Queue.IsEmpty; }
/// <summary>
/// Constructs a new instance of a <see cref="SoundIoAudioTrackPool"/> that is empty
/// </summary>
/// <param name="maxSize">The maximum amount of tracks that can be created</param>
public SoundIoAudioTrackPool(SoundIO context, SoundIODevice device, int maxSize)
{
m_Size = 0;
m_Context = context;
m_Device = device;
m_MaxSize = maxSize;
m_Queue = new ConcurrentQueue<SoundIoAudioTrack>();
m_TrackList = new ConcurrentDictionary<int, SoundIoAudioTrack>();
}
/// <summary>
/// Constructs a new instance of a <see cref="SoundIoAudioTrackPool"/> that contains
/// the specified amount of <see cref="SoundIoAudioTrack"/>
/// </summary>
/// <param name="maxSize">The maximum amount of tracks that can be created</param>
/// <param name="initialCapacity">The initial number of tracks that the pool contains</param>
public SoundIoAudioTrackPool(SoundIO context, SoundIODevice device, int maxSize, int initialCapacity)
: this(context, device, maxSize)
{
var trackCollection = Enumerable.Range(0, initialCapacity)
.Select(TrackFactory);
m_Size = initialCapacity;
m_Queue = new ConcurrentQueue<SoundIoAudioTrack>(trackCollection);
}
/// <summary>
/// Creates a new <see cref="SoundIoAudioTrack"/> with the proper AudioContext and AudioDevice
/// and the specified <paramref name="trackId" />
/// </summary>
/// <param name="trackId">The ID of the track to be created</param>
/// <returns>A new AudioTrack with the specified ID</returns>
private SoundIoAudioTrack TrackFactory(int trackId)
{
// Create a new AudioTrack
SoundIoAudioTrack track = new SoundIoAudioTrack(trackId, m_Context, m_Device);
// Keep track of issued tracks
m_TrackList[trackId] = track;
return track;
}
/// <summary>
/// Retrieves a <see cref="SoundIoAudioTrack"/> from the pool
/// </summary>
/// <returns>An AudioTrack from the pool</returns>
public SoundIoAudioTrack Get()
{
// If we have a track available, reuse it
if (m_Queue.TryDequeue(out SoundIoAudioTrack track))
{
return track;
}
// Have we reached the maximum size of our pool?
if (m_Size >= m_MaxSize)
{
return null;
}
// We don't have any pooled tracks, so create a new one
return TrackFactory(m_Size++);
}
/// <summary>
/// Retrieves the <see cref="SoundIoAudioTrack"/> associated with the specified <paramref name="trackId"/> from the pool
/// </summary>
/// <param name="trackId">The ID of the track to retrieve</param>
public SoundIoAudioTrack Get(int trackId)
{
if (m_TrackList.TryGetValue(trackId, out SoundIoAudioTrack track))
{
return track;
}
return null;
}
/// <summary>
/// Attempts to get a <see cref="SoundIoAudioTrack"/> from the pool
/// </summary>
/// <param name="track">The track retrieved from the pool</param>
/// <returns>True if retrieve was successful</returns>
public bool TryGet(out SoundIoAudioTrack track)
{
track = Get();
return track != null;
}
/// <summary>
/// Attempts to get the <see cref="SoundIoAudioTrack" /> associated with the specified <paramref name="trackId"/> from the pool
/// </summary>
/// <param name="trackId">The ID of the track to retrieve</param>
/// <param name="track">The track retrieved from the pool</param>
public bool TryGet(int trackId, out SoundIoAudioTrack track)
{
return m_TrackList.TryGetValue(trackId, out track);
}
/// <summary>
/// Returns an <see cref="SoundIoAudioTrack"/> back to the pool for reuse
/// </summary>
/// <param name="track">The track to be returned to the pool</param>
public void Put(SoundIoAudioTrack track)
{
// Ensure the track is disposed and not playing audio
track.Close();
// Requeue the track for reuse later
m_Queue.Enqueue(track);
}
/// <summary>
/// Releases the unmanaged resources used by the <see cref="SoundIoAudioTrackPool" />
/// </summary>
public void Dispose()
{
foreach (var track in m_TrackList)
{
track.Value.Close();
track.Value.Dispose();
}
m_Size = 0;
m_Queue.Clear();
m_TrackList.Clear();
}
}
}