OpenALHardwareDeviceSession.cs
1 using OpenTK.Audio.OpenAL; 2 using Ryujinx.Audio.Backends.Common; 3 using Ryujinx.Audio.Common; 4 using Ryujinx.Memory; 5 using System; 6 using System.Collections.Generic; 7 using System.Diagnostics; 8 9 namespace Ryujinx.Audio.Backends.OpenAL 10 { 11 class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase 12 { 13 private readonly OpenALHardwareDeviceDriver _driver; 14 private readonly int _sourceId; 15 private readonly ALFormat _targetFormat; 16 private bool _isActive; 17 private readonly Queue<OpenALAudioBuffer> _queuedBuffers; 18 private ulong _playedSampleCount; 19 private float _volume; 20 21 private readonly object _lock = new(); 22 23 public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) 24 { 25 _driver = driver; 26 _queuedBuffers = new Queue<OpenALAudioBuffer>(); 27 _sourceId = AL.GenSource(); 28 _targetFormat = GetALFormat(); 29 _isActive = false; 30 _playedSampleCount = 0; 31 SetVolume(1f); 32 } 33 34 private ALFormat GetALFormat() 35 { 36 return RequestedSampleFormat switch 37 { 38 SampleFormat.PcmInt16 => RequestedChannelCount switch 39 { 40 1 => ALFormat.Mono16, 41 2 => ALFormat.Stereo16, 42 6 => ALFormat.Multi51Chn16Ext, 43 _ => throw new NotImplementedException($"Unsupported channel config {RequestedChannelCount}"), 44 }, 45 _ => throw new NotImplementedException($"Unsupported sample format {RequestedSampleFormat}"), 46 }; 47 } 48 49 public override void PrepareToClose() { } 50 51 private void StartIfNotPlaying() 52 { 53 AL.GetSource(_sourceId, ALGetSourcei.SourceState, out int stateInt); 54 55 ALSourceState State = (ALSourceState)stateInt; 56 57 if (State != ALSourceState.Playing) 58 { 59 AL.SourcePlay(_sourceId); 60 } 61 } 62 63 public override void QueueBuffer(AudioBuffer buffer) 64 { 65 lock (_lock) 66 { 67 OpenALAudioBuffer driverBuffer = new() 68 { 69 DriverIdentifier = buffer.DataPointer, 70 BufferId = AL.GenBuffer(), 71 SampleCount = GetSampleCount(buffer), 72 }; 73 74 AL.BufferData(driverBuffer.BufferId, _targetFormat, buffer.Data, (int)RequestedSampleRate); 75 76 _queuedBuffers.Enqueue(driverBuffer); 77 78 AL.SourceQueueBuffer(_sourceId, driverBuffer.BufferId); 79 80 if (_isActive) 81 { 82 StartIfNotPlaying(); 83 } 84 } 85 } 86 87 public override void SetVolume(float volume) 88 { 89 _volume = volume; 90 91 UpdateMasterVolume(_driver.Volume); 92 } 93 94 public override float GetVolume() 95 { 96 return _volume; 97 } 98 99 public void UpdateMasterVolume(float newVolume) 100 { 101 lock (_lock) 102 { 103 AL.Source(_sourceId, ALSourcef.Gain, newVolume * _volume); 104 } 105 } 106 107 public override void Start() 108 { 109 lock (_lock) 110 { 111 _isActive = true; 112 113 StartIfNotPlaying(); 114 } 115 } 116 117 public override void Stop() 118 { 119 lock (_lock) 120 { 121 SetVolume(0.0f); 122 123 AL.SourceStop(_sourceId); 124 125 _isActive = false; 126 } 127 } 128 129 public override void UnregisterBuffer(AudioBuffer buffer) { } 130 131 public override bool WasBufferFullyConsumed(AudioBuffer buffer) 132 { 133 lock (_lock) 134 { 135 if (!_queuedBuffers.TryPeek(out OpenALAudioBuffer driverBuffer)) 136 { 137 return true; 138 } 139 140 return driverBuffer.DriverIdentifier != buffer.DataPointer; 141 } 142 } 143 144 public override ulong GetPlayedSampleCount() 145 { 146 lock (_lock) 147 { 148 return _playedSampleCount; 149 } 150 } 151 152 public bool Update() 153 { 154 lock (_lock) 155 { 156 if (_isActive) 157 { 158 AL.GetSource(_sourceId, ALGetSourcei.BuffersProcessed, out int releasedCount); 159 160 if (releasedCount > 0) 161 { 162 int[] bufferIds = new int[releasedCount]; 163 164 AL.SourceUnqueueBuffers(_sourceId, releasedCount, bufferIds); 165 166 int i = 0; 167 168 while (_queuedBuffers.TryPeek(out OpenALAudioBuffer buffer) && i < bufferIds.Length) 169 { 170 if (buffer.BufferId == bufferIds[i]) 171 { 172 _playedSampleCount += buffer.SampleCount; 173 174 _queuedBuffers.TryDequeue(out _); 175 176 i++; 177 } 178 } 179 180 Debug.Assert(i == bufferIds.Length, "Unknown buffer ids found!"); 181 182 AL.DeleteBuffers(bufferIds); 183 } 184 185 return releasedCount > 0; 186 } 187 188 return false; 189 } 190 } 191 192 protected virtual void Dispose(bool disposing) 193 { 194 if (disposing && _driver.Unregister(this)) 195 { 196 lock (_lock) 197 { 198 PrepareToClose(); 199 Stop(); 200 201 AL.DeleteSource(_sourceId); 202 } 203 } 204 } 205 206 public override void Dispose() 207 { 208 Dispose(true); 209 GC.SuppressFinalize(this); 210 } 211 } 212 }