diff options
| author | Ac_K <Acoustik666@gmail.com> | 2020-11-20 21:59:01 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-20 21:59:01 +0100 |
| commit | 57c4e6ef21d1f281b172aedcfd993a2ac43456ef (patch) | |
| tree | 8ee5e5b42ab14bd8df52e823f3fcb4027e5ed873 | |
| parent | 9493cdfe553d77d8f37927ef2acf87cfbab1c467 (diff) | |
audout: Implement and fix some calls (#1725)
* audout: Implement GetAudioOutBufferCount, GetAudioOutPlayedSampleCount and FlushAudioOutBuffers
This PR implement audout service calls:
- GetAudioOutBufferCount
- GetAudioOutPlayedSampleCount
- FlushAudioOutBuffers
The RE calls just give some hints about no extra checks.
Since we use a totally different implementation because of our backend, I can't do something better for now.
SetAudioOutVolume and GetAudioOutVolume are fixed too by set/get the volume of the current opened track, previous implementation was wrong.
This fix #1133, fix #1258 and fix #1519.
Thanks to @jduncanator for this help during the implementation and all his precious advices.
* Fix some debug leftovers
* Address jD feedback
| -rw-r--r-- | Ryujinx.Audio/IAalOutput.cs | 10 | ||||
| -rw-r--r-- | Ryujinx.Audio/Renderers/DummyAudioOut.cs | 16 | ||||
| -rw-r--r-- | Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs | 101 | ||||
| -rw-r--r-- | Ryujinx.Audio/Renderers/OpenAL/OpenALAudioTrack.cs | 31 | ||||
| -rw-r--r-- | Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs | 82 | ||||
| -rw-r--r-- | Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs | 34 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs | 43 |
7 files changed, 254 insertions, 63 deletions
diff --git a/Ryujinx.Audio/IAalOutput.cs b/Ryujinx.Audio/IAalOutput.cs index 821c1ffb..056b4665 100644 --- a/Ryujinx.Audio/IAalOutput.cs +++ b/Ryujinx.Audio/IAalOutput.cs @@ -45,9 +45,15 @@ namespace Ryujinx.Audio void Stop(int trackId); - float GetVolume(); + uint GetBufferCount(int trackId); - void SetVolume(float volume); + ulong GetPlayedSampleCount(int trackId); + + bool FlushBuffers(int trackId); + + float GetVolume(int trackId); + + void SetVolume(int trackId, float volume); PlaybackState GetState(int trackId); } diff --git a/Ryujinx.Audio/Renderers/DummyAudioOut.cs b/Ryujinx.Audio/Renderers/DummyAudioOut.cs index 2698b928..cd197592 100644 --- a/Ryujinx.Audio/Renderers/DummyAudioOut.cs +++ b/Ryujinx.Audio/Renderers/DummyAudioOut.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Collections.Generic; namespace Ryujinx.Audio @@ -15,6 +14,7 @@ namespace Ryujinx.Audio private ConcurrentQueue<int> _trackIds; private ConcurrentQueue<long> _buffers; private ConcurrentDictionary<int, ReleaseCallback> _releaseCallbacks; + private ulong _playedSampleCount; public DummyAudioOut() { @@ -76,6 +76,8 @@ namespace Ryujinx.Audio { _buffers.Enqueue(bufferTag); + _playedSampleCount += (ulong)buffer.Length; + if (_releaseCallbacks.TryGetValue(trackId, out var callback)) { callback?.Invoke(); @@ -86,9 +88,15 @@ namespace Ryujinx.Audio public void Stop(int trackId) { } - public float GetVolume() => _volume; + public uint GetBufferCount(int trackId) => (uint)_buffers.Count; + + public ulong GetPlayedSampleCount(int trackId) => _playedSampleCount; + + public bool FlushBuffers(int trackId) => false; + + public float GetVolume(int trackId) => _volume; - public void SetVolume(float volume) + public void SetVolume(int trackId, float volume) { _volume = volume; } diff --git a/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs b/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs index fe82fced..abad0f17 100644 --- a/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs +++ b/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs @@ -38,16 +38,6 @@ namespace Ryujinx.Audio private Thread _audioPollerThread; /// <summary> - /// The volume of audio renderer - /// </summary> - private float _volume = 1.0f; - - /// <summary> - /// True if the volume of audio renderer have changed - /// </summary> - private bool _volumeChanged; - - /// <summary> /// True if OpenAL is supported on the device /// </summary> public static bool IsSupported @@ -248,6 +238,8 @@ namespace Ryujinx.Audio AL.SourceQueueBuffer(track.SourceId, bufferId); StartPlaybackIfNeeded(track); + + track.PlayedSampleCount += (ulong)buffer.Length; } } } @@ -277,13 +269,6 @@ namespace Ryujinx.Audio if (State != ALSourceState.Playing && track.State == PlaybackState.Playing) { - if (_volumeChanged) - { - AL.Source(track.SourceId, ALSourcef.Gain, _volume); - - _volumeChanged = false; - } - AL.SourcePlay(track.SourceId); } } @@ -306,21 +291,87 @@ namespace Ryujinx.Audio } /// <summary> - /// Get playback volume + /// Get track buffer count /// </summary> - public float GetVolume() => _volume; + /// <param name="trackId">The ID of the track to get buffer count</param> + public uint GetBufferCount(int trackId) + { + if (_tracks.TryGetValue(trackId, out OpenALAudioTrack track)) + { + lock (track) + { + return track.BufferCount; + } + } + + return 0; + } /// <summary> - /// Set playback volume + /// Get track played sample count /// </summary> - /// <param name="volume">The volume of the playback</param> - public void SetVolume(float volume) + /// <param name="trackId">The ID of the track to get played sample count</param> + public ulong GetPlayedSampleCount(int trackId) { - if (!_volumeChanged) + if (_tracks.TryGetValue(trackId, out OpenALAudioTrack track)) { - _volume = volume; - _volumeChanged = true; + lock (track) + { + return track.PlayedSampleCount; + } } + + return 0; + } + + /// <summary> + /// Flush all track buffers + /// </summary> + /// <param name="trackId">The ID of the track to flush</param> + public bool FlushBuffers(int trackId) + { + if (_tracks.TryGetValue(trackId, out OpenALAudioTrack track)) + { + lock (track) + { + track.FlushBuffers(); + } + } + + return false; + } + + /// <summary> + /// Set track volume + /// </summary> + /// <param name="trackId">The ID of the track to set volume</param> + /// <param name="volume">The volume of the track</param> + public void SetVolume(int trackId, float volume) + { + if (_tracks.TryGetValue(trackId, out OpenALAudioTrack track)) + { + lock (track) + { + track.SetVolume(volume); + } + } + } + + /// <summary> + /// Get track volume + /// </summary> + /// <param name="trackId">The ID of the track to get volume</param> + public float GetVolume(int trackId) + { + if (_tracks.TryGetValue(trackId, out OpenALAudioTrack track)) + { + lock (track) + { + return track.Volume; + } + } + + return 1.0f; } /// <summary> diff --git a/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioTrack.cs b/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioTrack.cs index 2f150998..6e016713 100644 --- a/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioTrack.cs +++ b/Ryujinx.Audio/Renderers/OpenAL/OpenALAudioTrack.cs @@ -11,9 +11,12 @@ namespace Ryujinx.Audio public int SampleRate { get; private set; } public ALFormat Format { get; private set; } public PlaybackState State { get; set; } + public float Volume { get; private set; } public int HardwareChannels { get; } public int VirtualChannels { get; } + public uint BufferCount => (uint)_buffers.Count; + public ulong PlayedSampleCount { get; set; } private ReleaseCallback _callback; @@ -125,6 +128,34 @@ namespace Ryujinx.Audio } } + public bool FlushBuffers() + { + while (_queuedTagsQueue.TryDequeue(out long tag)) + { + _releasedTagsQueue.Enqueue(tag); + } + + _callback(); + + foreach (var buffer in _buffers) + { + AL.DeleteBuffer(buffer.Value); + } + + bool heldBuffers = _buffers.Count > 0; + + _buffers.Clear(); + + return heldBuffers; + } + + public void SetVolume(float volume) + { + Volume = volume; + + AL.Source(SourceId, ALSourcef.Gain, Volume); + } + public void Dispose() { Dispose(true); diff --git a/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs b/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs index fa3961e4..eb6caa60 100644 --- a/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs +++ b/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs @@ -16,16 +16,6 @@ namespace Ryujinx.Audio private const int MaximumTracks = 256; /// <summary> - /// The volume of audio renderer - /// </summary> - private float _volume = 1.0f; - - /// <summary> - /// True if the volume of audio renderer have changed - /// </summary> - private bool _volumeChanged; - - /// <summary> /// The <see cref="SoundIO"/> audio context /// </summary> private SoundIO _audioContext; @@ -155,14 +145,7 @@ namespace Ryujinx.Audio public void AppendBuffer<T>(int trackId, long bufferTag, T[] buffer) where T : struct { if (_trackPool.TryGet(trackId, out SoundIoAudioTrack track)) - { - if (_volumeChanged) - { - track.AudioStream.SetVolume(_volume); - - _volumeChanged = false; - } - + { track.AppendBuffer(bufferTag, buffer); } } @@ -192,24 +175,73 @@ namespace Ryujinx.Audio } /// <summary> - /// Get playback volume + /// Get track buffer count /// </summary> - public float GetVolume() => _volume; + /// <param name="trackId">The ID of the track to get buffer count</param> + public uint GetBufferCount(int trackId) + { + if (_trackPool.TryGet(trackId, out SoundIoAudioTrack track)) + { + return track.BufferCount; + } + + return 0; + } /// <summary> - /// Set playback volume + /// Get track played sample count + /// </summary> + /// <param name="trackId">The ID of the track to get played sample</param> + public ulong GetPlayedSampleCount(int trackId) + { + if (_trackPool.TryGet(trackId, out SoundIoAudioTrack track)) + { + return track.PlayedSampleCount; + } + + return 0; + } + + /// <summary> + /// Flush all track buffers + /// </summary> + /// <param name="trackId">The ID of the track to flush</param> + public bool FlushBuffers(int trackId) + { + if (_trackPool.TryGet(trackId, out SoundIoAudioTrack track)) + { + return track.FlushBuffers(); + } + + return false; + } + + /// <summary> + /// Set track volume /// </summary> /// <param name="volume">The volume of the playback</param> - public void SetVolume(float volume) + public void SetVolume(int trackId, float volume) { - if (!_volumeChanged) + if (_trackPool.TryGet(trackId, out SoundIoAudioTrack track)) { - _volume = volume; - _volumeChanged = true; + track.AudioStream.SetVolume(volume); } } /// <summary> + /// Get track volume + /// </summary> + public float GetVolume(int trackId) + { + if (_trackPool.TryGet(trackId, out SoundIoAudioTrack track)) + { + return track.AudioStream.Volume; + } + + return 1.0f; + } + + /// <summary> /// Gets the current playback state of the specified track /// </summary> /// <param name="trackId">The track to retrieve the playback state for</param> diff --git a/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs b/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs index 6fdeb991..52c4ebc9 100644 --- a/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs +++ b/Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs @@ -54,6 +54,16 @@ namespace Ryujinx.Audio.SoundIo /// </summary> public ConcurrentQueue<long> ReleasedBuffers { get; private set; } + /// <summary> + /// Buffer count of the track + /// </summary> + public uint BufferCount => (uint)m_ReservedBuffers.Count; + + /// <summary> + /// Played sample count of the track + /// </summary> + public ulong PlayedSampleCount { get; private set; } + private int _hardwareChannels; private int _virtualChannels; @@ -430,6 +440,8 @@ namespace Ryujinx.Audio.SoundIo AudioStream.EndWrite(); + PlayedSampleCount += (ulong)samples.Length; + UpdateReleasedBuffers(samples.Length); } @@ -572,6 +584,28 @@ namespace Ryujinx.Audio.SoundIo } /// <summary> + /// Flush all track buffers + /// </summary> + public bool FlushBuffers() + { + m_Buffer.Clear(); + + if (m_ReservedBuffers.Count > 0) + { + foreach (var buffer in m_ReservedBuffers) + { + ReleasedBuffers.Enqueue(buffer.Tag); + } + + OnBufferReleased(); + + return true; + } + + return false; + } + + /// <summary> /// Closes the <see cref="SoundIoAudioTrack"/> /// </summary> public void Close() diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs index d75fecf2..eaf644f6 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs @@ -149,17 +149,46 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager return ResultCode.Success; } + [Command(9)] // 4.0.0+ + // GetAudioOutBufferCount() -> u32 + public ResultCode GetAudioOutBufferCount(ServiceCtx context) + { + uint bufferCount = _audioOut.GetBufferCount(_track); + + context.ResponseData.Write(bufferCount); + + return ResultCode.Success; + } + + [Command(10)] // 4.0.0+ + // GetAudioOutPlayedSampleCount() -> u64 + public ResultCode GetAudioOutPlayedSampleCount(ServiceCtx context) + { + ulong playedSampleCount = _audioOut.GetPlayedSampleCount(_track); + + context.ResponseData.Write(playedSampleCount); + + return ResultCode.Success; + } + + [Command(11)] // 4.0.0+ + // FlushAudioOutBuffers() -> b8 + public ResultCode FlushAudioOutBuffers(ServiceCtx context) + { + bool heldBuffers = _audioOut.FlushBuffers(_track); + + context.ResponseData.Write(heldBuffers); + + return ResultCode.Success; + } + [Command(12)] // 6.0.0+ // SetAudioOutVolume(s32) public ResultCode SetAudioOutVolume(ServiceCtx context) { - // Games send a gain value here, so we need to apply it on the current volume value. - - float gain = context.RequestData.ReadSingle(); - float currentVolume = _audioOut.GetVolume(); - float newVolume = Math.Clamp(currentVolume + gain, 0.0f, 1.0f); + float volume = context.RequestData.ReadSingle(); - _audioOut.SetVolume(newVolume); + _audioOut.SetVolume(_track, volume); return ResultCode.Success; } @@ -168,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioOutManager // GetAudioOutVolume() -> s32 public ResultCode GetAudioOutVolume(ServiceCtx context) { - float volume = _audioOut.GetVolume(); + float volume = _audioOut.GetVolume(_track); context.ResponseData.Write(volume); |
