diff --git a/src/common/audio_stream.cpp b/src/common/audio_stream.cpp index 5175fb1e9..dd57f2aec 100644 --- a/src/common/audio_stream.cpp +++ b/src/common/audio_stream.cpp @@ -17,6 +17,9 @@ bool AudioStream::Reconfigure(u32 input_sample_rate /* = DefaultInputSampleRate u32 output_sample_rate /* = DefaultOutputSampleRate */, u32 channels /* = 1 */, u32 buffer_size /* = DefaultBufferSize */) { + std::unique_lock buffer_lock(m_buffer_mutex); + std::unique_lock resampler_Lock(m_resampler_mutex); + DestroyResampler(); if (IsDeviceOpen()) CloseDevice(); @@ -39,17 +42,24 @@ bool AudioStream::Reconfigure(u32 input_sample_rate /* = DefaultInputSampleRate } CreateResampler(); - SetInputSampleRate(input_sample_rate); + InternalSetInputSampleRate(input_sample_rate); return true; } void AudioStream::SetInputSampleRate(u32 sample_rate) +{ + std::unique_lock buffer_lock(m_buffer_mutex); + std::unique_lock resampler_lock(m_resampler_mutex); + + InternalSetInputSampleRate(sample_rate); +} + +void AudioStream::InternalSetInputSampleRate(u32 sample_rate) { if (m_input_sample_rate == sample_rate) return; - std::unique_lock lock(m_buffer_mutex); m_input_sample_rate = sample_rate; m_resampler_ratio = static_cast(m_output_sample_rate) / static_cast(sample_rate); src_set_ratio(static_cast(m_resampler_state), m_resampler_ratio); @@ -156,19 +166,22 @@ void AudioStream::ReadFrames(SampleType* samples, u32 num_frames, bool apply_vol const u32 total_samples = num_frames * m_channels; u32 samples_copied = 0; { - m_buffer_mutex.lock(); + std::unique_lock buffer_lock(m_buffer_mutex); if (m_input_sample_rate == m_output_sample_rate) { samples_copied = std::min(m_buffer.GetSize(), total_samples); if (samples_copied > 0) m_buffer.PopRange(samples, samples_copied); - m_buffer_mutex.unlock(); - m_buffer_draining_cv.notify_one(); + ReleaseBufferLock(std::move(buffer_lock)); } else { - ResampleInput(); + if (m_resampled_buffer.GetSize() < total_samples) + ResampleInput(std::move(buffer_lock)); + else + ReleaseBufferLock(std::move(buffer_lock)); + samples_copied = std::min(m_resampled_buffer.GetSize(), total_samples); if (samples_copied > 0) m_resampled_buffer.PopRange(samples, samples_copied); @@ -251,6 +264,7 @@ void AudioStream::DropFrames(u32 count) void AudioStream::EmptyBuffers() { std::unique_lock lock(m_buffer_mutex); + std::unique_lock resampler_lock(m_resampler_mutex); m_buffer.Clear(); m_underflow_flag.store(false); ResetResampler(); @@ -280,8 +294,10 @@ void AudioStream::ResetResampler() src_reset(static_cast(m_resampler_state)); } -void AudioStream::ResampleInput() +void AudioStream::ResampleInput(std::unique_lock buffer_lock) { + std::unique_lock resampler_lock(m_resampler_mutex); + const u32 input_space_from_output = (m_resampled_buffer.GetSpace() * m_output_sample_rate) / m_input_sample_rate; u32 remaining = std::min(m_buffer.GetSize(), input_space_from_output); if (m_resample_in_buffer.size() < remaining) @@ -300,8 +316,7 @@ void AudioStream::ResampleInput() } } - m_buffer_mutex.unlock(); - m_buffer_draining_cv.notify_one(); + ReleaseBufferLock(std::move(buffer_lock)); const u32 potential_output_size = (static_cast(m_resample_in_buffer.size()) * m_input_sample_rate) / m_output_sample_rate; diff --git a/src/common/audio_stream.h b/src/common/audio_stream.h index c60a5edbe..eb0115272 100644 --- a/src/common/audio_stream.h +++ b/src/common/audio_stream.h @@ -89,12 +89,19 @@ protected: private: ALWAYS_INLINE u32 GetBufferSpace() const { return (m_max_samples - m_buffer.GetSize()); } + ALWAYS_INLINE void ReleaseBufferLock(std::unique_lock lock) + { + // lock is released implicitly by destruction + m_buffer_draining_cv.notify_one(); + } + void EnsureBuffer(u32 size); void CreateResampler(); void DestroyResampler(); void ResetResampler(); - void ResampleInput(); + void InternalSetInputSampleRate(u32 sample_rate); + void ResampleInput(std::unique_lock buffer_lock); HeapFIFOQueue m_buffer; mutable std::mutex m_buffer_mutex; @@ -110,6 +117,7 @@ private: // Resampling double m_resampler_ratio = 1.0; void* m_resampler_state = nullptr; + std::mutex m_resampler_mutex; HeapFIFOQueue m_resampled_buffer; std::vector m_resample_in_buffer; std::vector m_resample_out_buffer;