using SoundIOSharp;
using System;
using System.Collections.Concurrent;
using System.Linq;
namespace Ryujinx.Audio.SoundIo
{
///
/// An object pool containing a set of audio tracks
///
internal class SoundIoAudioTrackPool : IDisposable
{
///
/// The current size of the
///
private int m_Size;
///
/// The maximum size of the
///
private int m_MaxSize;
///
/// The audio context this track pool belongs to
///
private SoundIO m_Context;
///
/// The audio device this track pool belongs to
///
private SoundIODevice m_Device;
///
/// The queue that keeps track of the available in the pool.
///
private ConcurrentQueue m_Queue;
///
/// The dictionary providing mapping between a TrackID and
///
private ConcurrentDictionary m_TrackList;
///
/// Gets the current size of the
///
public int Size { get => m_Size; }
///
/// Gets the maximum size of the
///
public int MaxSize { get => m_MaxSize; }
///
/// Gets a value that indicates whether the is empty
///
public bool IsEmpty { get => m_Queue.IsEmpty; }
///
/// Constructs a new instance of a that is empty
///
/// The maximum amount of tracks that can be created
public SoundIoAudioTrackPool(SoundIO context, SoundIODevice device, int maxSize)
{
m_Size = 0;
m_Context = context;
m_Device = device;
m_MaxSize = maxSize;
m_Queue = new ConcurrentQueue();
m_TrackList = new ConcurrentDictionary();
}
///
/// Constructs a new instance of a that contains
/// the specified amount of
///
/// The maximum amount of tracks that can be created
/// The initial number of tracks that the pool contains
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(trackCollection);
}
///
/// Creates a new with the proper AudioContext and AudioDevice
/// and the specified
///
/// The ID of the track to be created
/// A new AudioTrack with the specified ID
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;
}
///
/// Retrieves a from the pool
///
/// An AudioTrack from the pool
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++);
}
///
/// Retrieves the associated with the specified from the pool
///
/// The ID of the track to retrieve
public SoundIoAudioTrack Get(int trackId)
{
if (m_TrackList.TryGetValue(trackId, out SoundIoAudioTrack track))
{
return track;
}
return null;
}
///
/// Attempts to get a from the pool
///
/// The track retrieved from the pool
/// True if retrieve was successful
public bool TryGet(out SoundIoAudioTrack track)
{
track = Get();
return track != null;
}
///
/// Attempts to get the associated with the specified from the pool
///
/// The ID of the track to retrieve
/// The track retrieved from the pool
public bool TryGet(int trackId, out SoundIoAudioTrack track)
{
return m_TrackList.TryGetValue(trackId, out track);
}
///
/// Returns an back to the pool for reuse
///
/// The track to be returned to the pool
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);
}
///
/// Releases the unmanaged resources used by the
///
public void Dispose()
{
foreach (var track in m_TrackList)
{
track.Value.Close();
track.Value.Dispose();
}
m_Size = 0;
m_Queue.Clear();
m_TrackList.Clear();
}
}
}