aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAc_K <Acoustik666@gmail.com>2020-11-20 21:59:01 +0100
committerGitHub <noreply@github.com>2020-11-20 21:59:01 +0100
commit57c4e6ef21d1f281b172aedcfd993a2ac43456ef (patch)
tree8ee5e5b42ab14bd8df52e823f3fcb4027e5ed873
parent9493cdfe553d77d8f37927ef2acf87cfbab1c467 (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.cs10
-rw-r--r--Ryujinx.Audio/Renderers/DummyAudioOut.cs16
-rw-r--r--Ryujinx.Audio/Renderers/OpenAL/OpenALAudioOut.cs101
-rw-r--r--Ryujinx.Audio/Renderers/OpenAL/OpenALAudioTrack.cs31
-rw-r--r--Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioOut.cs82
-rw-r--r--Ryujinx.Audio/Renderers/SoundIo/SoundIoAudioTrack.cs34
-rw-r--r--Ryujinx.HLE/HOS/Services/Audio/AudioOutManager/IAudioOut.cs43
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);