SoundIoAudioTrackPool.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. using SoundIOSharp;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Linq;
  5. namespace Ryujinx.Audio.SoundIo
  6. {
  7. /// <summary>
  8. /// An object pool containing a set of audio tracks
  9. /// </summary>
  10. internal class SoundIoAudioTrackPool : IDisposable
  11. {
  12. /// <summary>
  13. /// The current size of the <see cref="SoundIoAudioTrackPool"/>
  14. /// </summary>
  15. private int m_Size;
  16. /// <summary>
  17. /// The maximum size of the <see cref="SoundIoAudioTrackPool"/>
  18. /// </summary>
  19. private int m_MaxSize;
  20. /// <summary>
  21. /// The <see cref="SoundIO"/> audio context this track pool belongs to
  22. /// </summary>
  23. private SoundIO m_Context;
  24. /// <summary>
  25. /// The <see cref="SoundIODevice"/> audio device this track pool belongs to
  26. /// </summary>
  27. private SoundIODevice m_Device;
  28. /// <summary>
  29. /// The queue that keeps track of the available <see cref="SoundIoAudioTrack"/> in the pool.
  30. /// </summary>
  31. private ConcurrentQueue<SoundIoAudioTrack> m_Queue;
  32. /// <summary>
  33. /// The dictionary providing mapping between a TrackID and <see cref="SoundIoAudioTrack"/>
  34. /// </summary>
  35. private ConcurrentDictionary<int, SoundIoAudioTrack> m_TrackList;
  36. /// <summary>
  37. /// Gets the current size of the <see cref="SoundIoAudioTrackPool"/>
  38. /// </summary>
  39. public int Size { get => m_Size; }
  40. /// <summary>
  41. /// Gets the maximum size of the <see cref="SoundIoAudioTrackPool"/>
  42. /// </summary>
  43. public int MaxSize { get => m_MaxSize; }
  44. /// <summary>
  45. /// Gets a value that indicates whether the <see cref="SoundIoAudioTrackPool"/> is empty
  46. /// </summary>
  47. public bool IsEmpty { get => m_Queue.IsEmpty; }
  48. /// <summary>
  49. /// Constructs a new instance of a <see cref="SoundIoAudioTrackPool"/> that is empty
  50. /// </summary>
  51. /// <param name="maxSize">The maximum amount of tracks that can be created</param>
  52. public SoundIoAudioTrackPool(SoundIO context, SoundIODevice device, int maxSize)
  53. {
  54. m_Size = 0;
  55. m_Context = context;
  56. m_Device = device;
  57. m_MaxSize = maxSize;
  58. m_Queue = new ConcurrentQueue<SoundIoAudioTrack>();
  59. m_TrackList = new ConcurrentDictionary<int, SoundIoAudioTrack>();
  60. }
  61. /// <summary>
  62. /// Constructs a new instance of a <see cref="SoundIoAudioTrackPool"/> that contains
  63. /// the specified amount of <see cref="SoundIoAudioTrack"/>
  64. /// </summary>
  65. /// <param name="maxSize">The maximum amount of tracks that can be created</param>
  66. /// <param name="initialCapacity">The initial number of tracks that the pool contains</param>
  67. public SoundIoAudioTrackPool(SoundIO context, SoundIODevice device, int maxSize, int initialCapacity)
  68. : this(context, device, maxSize)
  69. {
  70. var trackCollection = Enumerable.Range(0, initialCapacity)
  71. .Select(TrackFactory);
  72. m_Size = initialCapacity;
  73. m_Queue = new ConcurrentQueue<SoundIoAudioTrack>(trackCollection);
  74. }
  75. /// <summary>
  76. /// Creates a new <see cref="SoundIoAudioTrack"/> with the proper AudioContext and AudioDevice
  77. /// and the specified <paramref name="trackId" />
  78. /// </summary>
  79. /// <param name="trackId">The ID of the track to be created</param>
  80. /// <returns>A new AudioTrack with the specified ID</returns>
  81. private SoundIoAudioTrack TrackFactory(int trackId)
  82. {
  83. // Create a new AudioTrack
  84. SoundIoAudioTrack track = new SoundIoAudioTrack(trackId, m_Context, m_Device);
  85. // Keep track of issued tracks
  86. m_TrackList[trackId] = track;
  87. return track;
  88. }
  89. /// <summary>
  90. /// Retrieves a <see cref="SoundIoAudioTrack"/> from the pool
  91. /// </summary>
  92. /// <returns>An AudioTrack from the pool</returns>
  93. public SoundIoAudioTrack Get()
  94. {
  95. // If we have a track available, reuse it
  96. if (m_Queue.TryDequeue(out SoundIoAudioTrack track))
  97. {
  98. return track;
  99. }
  100. // Have we reached the maximum size of our pool?
  101. if (m_Size >= m_MaxSize)
  102. {
  103. return null;
  104. }
  105. // We don't have any pooled tracks, so create a new one
  106. return TrackFactory(m_Size++);
  107. }
  108. /// <summary>
  109. /// Retrieves the <see cref="SoundIoAudioTrack"/> associated with the specified <paramref name="trackId"/> from the pool
  110. /// </summary>
  111. /// <param name="trackId">The ID of the track to retrieve</param>
  112. public SoundIoAudioTrack Get(int trackId)
  113. {
  114. if (m_TrackList.TryGetValue(trackId, out SoundIoAudioTrack track))
  115. {
  116. return track;
  117. }
  118. return null;
  119. }
  120. /// <summary>
  121. /// Attempts to get a <see cref="SoundIoAudioTrack"/> from the pool
  122. /// </summary>
  123. /// <param name="track">The track retrieved from the pool</param>
  124. /// <returns>True if retrieve was successful</returns>
  125. public bool TryGet(out SoundIoAudioTrack track)
  126. {
  127. track = Get();
  128. return track != null;
  129. }
  130. /// <summary>
  131. /// Attempts to get the <see cref="SoundIoAudioTrack" /> associated with the specified <paramref name="trackId"/> from the pool
  132. /// </summary>
  133. /// <param name="trackId">The ID of the track to retrieve</param>
  134. /// <param name="track">The track retrieved from the pool</param>
  135. public bool TryGet(int trackId, out SoundIoAudioTrack track)
  136. {
  137. return m_TrackList.TryGetValue(trackId, out track);
  138. }
  139. /// <summary>
  140. /// Returns an <see cref="SoundIoAudioTrack"/> back to the pool for reuse
  141. /// </summary>
  142. /// <param name="track">The track to be returned to the pool</param>
  143. public void Put(SoundIoAudioTrack track)
  144. {
  145. // Ensure the track is disposed and not playing audio
  146. track.Close();
  147. // Requeue the track for reuse later
  148. m_Queue.Enqueue(track);
  149. }
  150. /// <summary>
  151. /// Releases the unmanaged resources used by the <see cref="SoundIoAudioTrackPool" />
  152. /// </summary>
  153. public void Dispose()
  154. {
  155. foreach (var track in m_TrackList)
  156. {
  157. track.Value.Close();
  158. track.Value.Dispose();
  159. }
  160. m_Size = 0;
  161. m_Queue.Clear();
  162. m_TrackList.Clear();
  163. }
  164. }
  165. }