From d8fc3f403b62e2b3d67ec08791fdc66847ddb4ac Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sat, 18 Mar 2023 20:52:02 +0000 Subject: audio: Interpolate system manager sample count using host sink sample info This avoids the need to stall if the host sink sporadically misses the deadline, in such a case the previous implementation would report them samples as being played on-time, causing the guest to send more samples and leading to a gradual buildup. --- src/audio_core/sink/sink_stream.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/audio_core/sink/sink_stream.cpp') diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index 39a21b0f0..1af96f793 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -14,6 +14,8 @@ #include "common/fixed_point.h" #include "common/settings.h" #include "core/core.h" +#include "core/core_timing.h" +#include "core/core_timing_util.h" namespace AudioCore::Sink { @@ -198,6 +200,7 @@ void SinkStream::ProcessAudioOutAndRender(std::span output_buffer, std::siz const std::size_t frame_size = num_channels; const std::size_t frame_size_bytes = frame_size * sizeof(s16); size_t frames_written{0}; + size_t actual_frames_written{0}; // If we're paused or going to shut down, we don't want to consume buffers as coretiming is // paused and we'll desync, so just play silence. @@ -248,6 +251,7 @@ void SinkStream::ProcessAudioOutAndRender(std::span output_buffer, std::siz frames_available * frame_size); frames_written += frames_available; + actual_frames_written += frames_available; playing_buffer.frames_played += frames_available; // If that's all the frames in the current buffer, add its samples and mark it as @@ -260,6 +264,13 @@ void SinkStream::ProcessAudioOutAndRender(std::span output_buffer, std::siz std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size], frame_size_bytes); + { + std::scoped_lock lk{sample_count_lock}; + last_sample_count_update_time = Core::Timing::CyclesToUs(system.CoreTiming().GetClockTicks()); + min_played_sample_count = max_played_sample_count; + max_played_sample_count += actual_frames_written; + } + if (system.IsMulticore() && queued_buffers <= max_queue_size) { Unstall(); } @@ -282,4 +293,14 @@ void SinkStream::Unstall() { stalled_lock.unlock(); } +u64 SinkStream::GetExpectedPlayedSampleCount() { + std::scoped_lock lk{sample_count_lock}; + auto cur_time{Core::Timing::CyclesToUs(system.CoreTiming().GetClockTicks())}; + auto time_delta{cur_time - last_sample_count_update_time}; + auto exp_played_sample_count{min_played_sample_count + + (TargetSampleRate * time_delta) / std::chrono::seconds{1}}; + + return std::min(exp_played_sample_count, max_played_sample_count); +} + } // namespace AudioCore::Sink -- cgit v1.2.3