SoundIoHardwareDeviceSession.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. using Ryujinx.Audio.Backends.Common;
  2. using Ryujinx.Audio.Common;
  3. using Ryujinx.Memory;
  4. using SoundIOSharp;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Runtime.CompilerServices;
  8. using System.Threading;
  9. namespace Ryujinx.Audio.Backends.SoundIo
  10. {
  11. class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
  12. {
  13. private object _lock = new object();
  14. private SoundIoHardwareDeviceDriver _driver;
  15. private Queue<SoundIoAudioBuffer> _queuedBuffers;
  16. private SoundIOOutStream _outputStream;
  17. private DynamicRingBuffer _ringBuffer;
  18. private ulong _playedSampleCount;
  19. private ManualResetEvent _updateRequiredEvent;
  20. public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
  21. {
  22. _driver = driver;
  23. _updateRequiredEvent = _driver.GetUpdateRequiredEvent();
  24. _queuedBuffers = new Queue<SoundIoAudioBuffer>();
  25. _ringBuffer = new DynamicRingBuffer();
  26. SetupOutputStream();
  27. }
  28. private void SetupOutputStream()
  29. {
  30. _outputStream = _driver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount);
  31. _outputStream.WriteCallback += Update;
  32. // TODO: Setup other callbacks (errors, ect).
  33. _outputStream.Open();
  34. }
  35. public override ulong GetPlayedSampleCount()
  36. {
  37. lock (_lock)
  38. {
  39. return _playedSampleCount;
  40. }
  41. }
  42. public override float GetVolume()
  43. {
  44. return _outputStream.Volume;
  45. }
  46. public override void PrepareToClose() { }
  47. public override void QueueBuffer(AudioBuffer buffer)
  48. {
  49. lock (_lock)
  50. {
  51. SoundIoAudioBuffer driverBuffer = new SoundIoAudioBuffer
  52. {
  53. DriverIdentifier = buffer.DataPointer,
  54. SampleCount = GetSampleCount(buffer),
  55. SamplePlayed = 0,
  56. };
  57. _ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
  58. _queuedBuffers.Enqueue(driverBuffer);
  59. }
  60. }
  61. public override void SetVolume(float volume)
  62. {
  63. _outputStream.SetVolume(volume);
  64. }
  65. public override void Start()
  66. {
  67. _outputStream.Start();
  68. _outputStream.Pause(false);
  69. _driver.FlushContextEvents();
  70. }
  71. public override void Stop()
  72. {
  73. _outputStream.Pause(true);
  74. _driver.FlushContextEvents();
  75. }
  76. public override void UnregisterBuffer(AudioBuffer buffer) {}
  77. public override bool WasBufferFullyConsumed(AudioBuffer buffer)
  78. {
  79. lock (_lock)
  80. {
  81. if (!_queuedBuffers.TryPeek(out SoundIoAudioBuffer driverBuffer))
  82. {
  83. return true;
  84. }
  85. return driverBuffer.DriverIdentifier != buffer.DataPointer;
  86. }
  87. }
  88. private unsafe void Update(int minFrameCount, int maxFrameCount)
  89. {
  90. int bytesPerFrame = _outputStream.BytesPerFrame;
  91. uint bytesPerSample = (uint)_outputStream.BytesPerSample;
  92. int bufferedFrames = _ringBuffer.Length / bytesPerFrame;
  93. int frameCount = Math.Min(bufferedFrames, maxFrameCount);
  94. if (frameCount == 0)
  95. {
  96. return;
  97. }
  98. SoundIOChannelAreas areas = _outputStream.BeginWrite(ref frameCount);
  99. int channelCount = areas.ChannelCount;
  100. byte[] samples = new byte[frameCount * bytesPerFrame];
  101. _ringBuffer.Read(samples, 0, samples.Length);
  102. // This is a huge ugly block of code, but we save
  103. // a significant amount of time over the generic
  104. // loop that handles other channel counts.
  105. // TODO: Is this still right in 2021?
  106. // Mono
  107. if (channelCount == 1)
  108. {
  109. SoundIOChannelArea area = areas.GetArea(0);
  110. fixed (byte* srcptr = samples)
  111. {
  112. if (bytesPerSample == 1)
  113. {
  114. for (int frame = 0; frame < frameCount; frame++)
  115. {
  116. ((byte*)area.Pointer)[0] = srcptr[frame * bytesPerFrame];
  117. area.Pointer += area.Step;
  118. }
  119. }
  120. else if (bytesPerSample == 2)
  121. {
  122. for (int frame = 0; frame < frameCount; frame++)
  123. {
  124. ((short*)area.Pointer)[0] = ((short*)srcptr)[frame * bytesPerFrame >> 1];
  125. area.Pointer += area.Step;
  126. }
  127. }
  128. else if (bytesPerSample == 4)
  129. {
  130. for (int frame = 0; frame < frameCount; frame++)
  131. {
  132. ((int*)area.Pointer)[0] = ((int*)srcptr)[frame * bytesPerFrame >> 2];
  133. area.Pointer += area.Step;
  134. }
  135. }
  136. else
  137. {
  138. for (int frame = 0; frame < frameCount; frame++)
  139. {
  140. Unsafe.CopyBlockUnaligned((byte*)area.Pointer, srcptr + (frame * bytesPerFrame), bytesPerSample);
  141. area.Pointer += area.Step;
  142. }
  143. }
  144. }
  145. }
  146. // Stereo
  147. else if (channelCount == 2)
  148. {
  149. SoundIOChannelArea area1 = areas.GetArea(0);
  150. SoundIOChannelArea area2 = areas.GetArea(1);
  151. fixed (byte* srcptr = samples)
  152. {
  153. if (bytesPerSample == 1)
  154. {
  155. for (int frame = 0; frame < frameCount; frame++)
  156. {
  157. // Channel 1
  158. ((byte*)area1.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 0];
  159. // Channel 2
  160. ((byte*)area2.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 1];
  161. area1.Pointer += area1.Step;
  162. area2.Pointer += area2.Step;
  163. }
  164. }
  165. else if (bytesPerSample == 2)
  166. {
  167. for (int frame = 0; frame < frameCount; frame++)
  168. {
  169. // Channel 1
  170. ((short*)area1.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 0];
  171. // Channel 2
  172. ((short*)area2.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 1];
  173. area1.Pointer += area1.Step;
  174. area2.Pointer += area2.Step;
  175. }
  176. }
  177. else if (bytesPerSample == 4)
  178. {
  179. for (int frame = 0; frame < frameCount; frame++)
  180. {
  181. // Channel 1
  182. ((int*)area1.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 0];
  183. // Channel 2
  184. ((int*)area2.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 1];
  185. area1.Pointer += area1.Step;
  186. area2.Pointer += area2.Step;
  187. }
  188. }
  189. else
  190. {
  191. for (int frame = 0; frame < frameCount; frame++)
  192. {
  193. // Channel 1
  194. Unsafe.CopyBlockUnaligned((byte*)area1.Pointer, srcptr + (frame * bytesPerFrame) + (0 * bytesPerSample), bytesPerSample);
  195. // Channel 2
  196. Unsafe.CopyBlockUnaligned((byte*)area2.Pointer, srcptr + (frame * bytesPerFrame) + (1 * bytesPerSample), bytesPerSample);
  197. area1.Pointer += area1.Step;
  198. area2.Pointer += area2.Step;
  199. }
  200. }
  201. }
  202. }
  203. // Surround
  204. else if (channelCount == 6)
  205. {
  206. SoundIOChannelArea area1 = areas.GetArea(0);
  207. SoundIOChannelArea area2 = areas.GetArea(1);
  208. SoundIOChannelArea area3 = areas.GetArea(2);
  209. SoundIOChannelArea area4 = areas.GetArea(3);
  210. SoundIOChannelArea area5 = areas.GetArea(4);
  211. SoundIOChannelArea area6 = areas.GetArea(5);
  212. fixed (byte* srcptr = samples)
  213. {
  214. if (bytesPerSample == 1)
  215. {
  216. for (int frame = 0; frame < frameCount; frame++)
  217. {
  218. // Channel 1
  219. ((byte*)area1.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 0];
  220. // Channel 2
  221. ((byte*)area2.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 1];
  222. // Channel 3
  223. ((byte*)area3.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 2];
  224. // Channel 4
  225. ((byte*)area4.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 3];
  226. // Channel 5
  227. ((byte*)area5.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 4];
  228. // Channel 6
  229. ((byte*)area6.Pointer)[0] = srcptr[(frame * bytesPerFrame) + 5];
  230. area1.Pointer += area1.Step;
  231. area2.Pointer += area2.Step;
  232. area3.Pointer += area3.Step;
  233. area4.Pointer += area4.Step;
  234. area5.Pointer += area5.Step;
  235. area6.Pointer += area6.Step;
  236. }
  237. }
  238. else if (bytesPerSample == 2)
  239. {
  240. for (int frame = 0; frame < frameCount; frame++)
  241. {
  242. // Channel 1
  243. ((short*)area1.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 0];
  244. // Channel 2
  245. ((short*)area2.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 1];
  246. // Channel 3
  247. ((short*)area3.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 2];
  248. // Channel 4
  249. ((short*)area4.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 3];
  250. // Channel 5
  251. ((short*)area5.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 4];
  252. // Channel 6
  253. ((short*)area6.Pointer)[0] = ((short*)srcptr)[(frame * bytesPerFrame >> 1) + 5];
  254. area1.Pointer += area1.Step;
  255. area2.Pointer += area2.Step;
  256. area3.Pointer += area3.Step;
  257. area4.Pointer += area4.Step;
  258. area5.Pointer += area5.Step;
  259. area6.Pointer += area6.Step;
  260. }
  261. }
  262. else if (bytesPerSample == 4)
  263. {
  264. for (int frame = 0; frame < frameCount; frame++)
  265. {
  266. // Channel 1
  267. ((int*)area1.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 0];
  268. // Channel 2
  269. ((int*)area2.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 1];
  270. // Channel 3
  271. ((int*)area3.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 2];
  272. // Channel 4
  273. ((int*)area4.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 3];
  274. // Channel 5
  275. ((int*)area5.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 4];
  276. // Channel 6
  277. ((int*)area6.Pointer)[0] = ((int*)srcptr)[(frame * bytesPerFrame >> 2) + 5];
  278. area1.Pointer += area1.Step;
  279. area2.Pointer += area2.Step;
  280. area3.Pointer += area3.Step;
  281. area4.Pointer += area4.Step;
  282. area5.Pointer += area5.Step;
  283. area6.Pointer += area6.Step;
  284. }
  285. }
  286. else
  287. {
  288. for (int frame = 0; frame < frameCount; frame++)
  289. {
  290. // Channel 1
  291. Unsafe.CopyBlockUnaligned((byte*)area1.Pointer, srcptr + (frame * bytesPerFrame) + (0 * bytesPerSample), bytesPerSample);
  292. // Channel 2
  293. Unsafe.CopyBlockUnaligned((byte*)area2.Pointer, srcptr + (frame * bytesPerFrame) + (1 * bytesPerSample), bytesPerSample);
  294. // Channel 3
  295. Unsafe.CopyBlockUnaligned((byte*)area3.Pointer, srcptr + (frame * bytesPerFrame) + (2 * bytesPerSample), bytesPerSample);
  296. // Channel 4
  297. Unsafe.CopyBlockUnaligned((byte*)area4.Pointer, srcptr + (frame * bytesPerFrame) + (3 * bytesPerSample), bytesPerSample);
  298. // Channel 5
  299. Unsafe.CopyBlockUnaligned((byte*)area5.Pointer, srcptr + (frame * bytesPerFrame) + (4 * bytesPerSample), bytesPerSample);
  300. // Channel 6
  301. Unsafe.CopyBlockUnaligned((byte*)area6.Pointer, srcptr + (frame * bytesPerFrame) + (5 * bytesPerSample), bytesPerSample);
  302. area1.Pointer += area1.Step;
  303. area2.Pointer += area2.Step;
  304. area3.Pointer += area3.Step;
  305. area4.Pointer += area4.Step;
  306. area5.Pointer += area5.Step;
  307. area6.Pointer += area6.Step;
  308. }
  309. }
  310. }
  311. }
  312. // Every other channel count
  313. else
  314. {
  315. SoundIOChannelArea[] channels = new SoundIOChannelArea[channelCount];
  316. // Obtain the channel area for each channel
  317. for (int i = 0; i < channelCount; i++)
  318. {
  319. channels[i] = areas.GetArea(i);
  320. }
  321. fixed (byte* srcptr = samples)
  322. {
  323. for (int frame = 0; frame < frameCount; frame++)
  324. for (int channel = 0; channel < areas.ChannelCount; channel++)
  325. {
  326. // Copy channel by channel, frame by frame. This is slow!
  327. Unsafe.CopyBlockUnaligned((byte*)channels[channel].Pointer, srcptr + (frame * bytesPerFrame) + (channel * bytesPerSample), bytesPerSample);
  328. channels[channel].Pointer += channels[channel].Step;
  329. }
  330. }
  331. }
  332. _outputStream.EndWrite();
  333. ulong sampleCount = (ulong)(samples.Length / bytesPerSample / channelCount);
  334. ulong availaibleSampleCount = sampleCount;
  335. bool needUpdate = false;
  336. while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SoundIoAudioBuffer driverBuffer))
  337. {
  338. ulong sampleStillNeeded = driverBuffer.SampleCount - driverBuffer.SamplePlayed;
  339. ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
  340. driverBuffer.SamplePlayed += playedAudioBufferSampleCount;
  341. availaibleSampleCount -= playedAudioBufferSampleCount;
  342. if (driverBuffer.SamplePlayed == driverBuffer.SampleCount)
  343. {
  344. _queuedBuffers.TryDequeue(out _);
  345. needUpdate = true;
  346. }
  347. _playedSampleCount += playedAudioBufferSampleCount;
  348. }
  349. // Notify the output if needed.
  350. if (needUpdate)
  351. {
  352. _updateRequiredEvent.Set();
  353. }
  354. }
  355. protected virtual void Dispose(bool disposing)
  356. {
  357. if (disposing)
  358. {
  359. lock (_lock)
  360. {
  361. PrepareToClose();
  362. Stop();
  363. _outputStream.Dispose();
  364. _driver.Unregister(this);
  365. }
  366. }
  367. }
  368. public override void Dispose()
  369. {
  370. Dispose(true);
  371. }
  372. }
  373. }