2018-11-15 03:22:50 +01:00
|
|
|
|
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>
|
2019-07-02 04:39:22 +02:00
|
|
|
|
/// Attempts to get a <see cref="SoundIoAudioTrack"/> from the pool
|
2018-11-15 03:22:50 +01:00
|
|
|
|
/// </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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|