OpenALHardwareDeviceDriver.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using OpenTK.Audio.OpenAL;
  2. using Ryujinx.Audio.Common;
  3. using Ryujinx.Audio.Integration;
  4. using Ryujinx.Memory;
  5. using System;
  6. using System.Collections.Concurrent;
  7. using System.Linq;
  8. using System.Threading;
  9. using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
  10. namespace Ryujinx.Audio.Backends.OpenAL
  11. {
  12. public class OpenALHardwareDeviceDriver : IHardwareDeviceDriver
  13. {
  14. private readonly ALDevice _device;
  15. private readonly ALContext _context;
  16. private readonly ManualResetEvent _updateRequiredEvent;
  17. private readonly ManualResetEvent _pauseEvent;
  18. private readonly ConcurrentDictionary<OpenALHardwareDeviceSession, byte> _sessions;
  19. private bool _stillRunning;
  20. private readonly Thread _updaterThread;
  21. private float _volume;
  22. public float Volume
  23. {
  24. get
  25. {
  26. return _volume;
  27. }
  28. set
  29. {
  30. _volume = value;
  31. foreach (OpenALHardwareDeviceSession session in _sessions.Keys)
  32. {
  33. session.UpdateMasterVolume(value);
  34. }
  35. }
  36. }
  37. public OpenALHardwareDeviceDriver()
  38. {
  39. _device = ALC.OpenDevice("");
  40. _context = ALC.CreateContext(_device, new ALContextAttributes());
  41. _updateRequiredEvent = new ManualResetEvent(false);
  42. _pauseEvent = new ManualResetEvent(true);
  43. _sessions = new ConcurrentDictionary<OpenALHardwareDeviceSession, byte>();
  44. _stillRunning = true;
  45. _updaterThread = new Thread(Update)
  46. {
  47. Name = "HardwareDeviceDriver.OpenAL",
  48. };
  49. _volume = 1f;
  50. _updaterThread.Start();
  51. }
  52. public static bool IsSupported
  53. {
  54. get
  55. {
  56. try
  57. {
  58. return ALC.GetStringList(GetEnumerationStringList.DeviceSpecifier).Any();
  59. }
  60. catch
  61. {
  62. return false;
  63. }
  64. }
  65. }
  66. public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount)
  67. {
  68. if (channelCount == 0)
  69. {
  70. channelCount = 2;
  71. }
  72. if (sampleRate == 0)
  73. {
  74. sampleRate = Constants.TargetSampleRate;
  75. }
  76. if (direction != Direction.Output)
  77. {
  78. throw new ArgumentException($"{direction}");
  79. }
  80. else if (!SupportsChannelCount(channelCount))
  81. {
  82. throw new ArgumentException($"{channelCount}");
  83. }
  84. OpenALHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
  85. _sessions.TryAdd(session, 0);
  86. return session;
  87. }
  88. internal bool Unregister(OpenALHardwareDeviceSession session)
  89. {
  90. return _sessions.TryRemove(session, out _);
  91. }
  92. public ManualResetEvent GetUpdateRequiredEvent()
  93. {
  94. return _updateRequiredEvent;
  95. }
  96. public ManualResetEvent GetPauseEvent()
  97. {
  98. return _pauseEvent;
  99. }
  100. private void Update()
  101. {
  102. ALC.MakeContextCurrent(_context);
  103. while (_stillRunning)
  104. {
  105. bool updateRequired = false;
  106. foreach (OpenALHardwareDeviceSession session in _sessions.Keys)
  107. {
  108. if (session.Update())
  109. {
  110. updateRequired = true;
  111. }
  112. }
  113. if (updateRequired)
  114. {
  115. _updateRequiredEvent.Set();
  116. }
  117. // If it's not slept it will waste cycles.
  118. Thread.Sleep(10);
  119. }
  120. }
  121. public void Dispose()
  122. {
  123. GC.SuppressFinalize(this);
  124. Dispose(true);
  125. }
  126. protected virtual void Dispose(bool disposing)
  127. {
  128. if (disposing)
  129. {
  130. _stillRunning = false;
  131. foreach (OpenALHardwareDeviceSession session in _sessions.Keys)
  132. {
  133. session.Dispose();
  134. }
  135. ALC.DestroyContext(_context);
  136. ALC.CloseDevice(_device);
  137. _pauseEvent.Dispose();
  138. }
  139. }
  140. public bool SupportsSampleRate(uint sampleRate)
  141. {
  142. return true;
  143. }
  144. public bool SupportsSampleFormat(SampleFormat sampleFormat)
  145. {
  146. return true;
  147. }
  148. public bool SupportsChannelCount(uint channelCount)
  149. {
  150. return channelCount == 1 || channelCount == 2 || channelCount == 6;
  151. }
  152. public bool SupportsDirection(Direction direction)
  153. {
  154. return direction == Direction.Output;
  155. }
  156. }
  157. }