diff --git a/src/common/audio_stream.cpp b/src/common/audio_stream.cpp index 1a2abff0a..6dbe60f48 100644 --- a/src/common/audio_stream.cpp +++ b/src/common/audio_stream.cpp @@ -61,10 +61,9 @@ void AudioStream::Shutdown() void AudioStream::BeginWrite(SampleType** buffer_ptr, u32* num_samples) { - m_buffer_lock.lock(); + m_buffer_mutex.lock(); - if (m_num_free_buffers == 0) - DropBuffer(); + EnsureBuffer(); Buffer& buffer = m_buffers[m_first_free_buffer]; *buffer_ptr = buffer.data.data() + buffer.write_position; @@ -73,13 +72,12 @@ void AudioStream::BeginWrite(SampleType** buffer_ptr, u32* num_samples) void AudioStream::WriteSamples(const SampleType* samples, u32 num_samples) { - std::lock_guard guard(m_buffer_lock); u32 remaining_samples = num_samples; + std::unique_lock lock(m_buffer_mutex); while (remaining_samples > 0) { - if (m_num_free_buffers == 0) - DropBuffer(); + EnsureBuffer(); Buffer& buffer = m_buffers[m_first_free_buffer]; const u32 to_this_buffer = std::min(m_buffer_size - buffer.write_position, remaining_samples); @@ -120,13 +118,13 @@ void AudioStream::EndWrite(u32 num_samples) m_num_available_buffers++; } - m_buffer_lock.unlock(); + m_buffer_mutex.unlock(); } u32 AudioStream::ReadSamples(SampleType* samples, u32 num_samples) { - std::lock_guard guard(m_buffer_lock); u32 remaining_samples = num_samples; + std::unique_lock lock(m_buffer_mutex); while (remaining_samples > 0 && m_num_available_buffers > 0) { @@ -148,6 +146,7 @@ u32 AudioStream::ReadSamples(SampleType* samples, u32 num_samples) m_num_available_buffers--; m_first_available_buffer = (m_first_available_buffer + 1) % m_buffers.size(); m_num_free_buffers++; + m_buffer_available_cv.notify_one(); } } @@ -171,6 +170,23 @@ void AudioStream::AllocateBuffers(u32 buffer_count) m_num_free_buffers = buffer_count; } +void AudioStream::EnsureBuffer() +{ + if (m_num_free_buffers > 0) + return; + + if (m_sync) + { + std::unique_lock lock(m_buffer_mutex, std::adopt_lock); + m_buffer_available_cv.wait(lock, [this]() { return m_num_free_buffers > 0; }); + lock.release(); + } + else + { + DropBuffer(); + } +} + void AudioStream::DropBuffer() { DebugAssert(m_num_available_buffers > 0); diff --git a/src/common/audio_stream.h b/src/common/audio_stream.h index c502d6b28..7efe496f6 100644 --- a/src/common/audio_stream.h +++ b/src/common/audio_stream.h @@ -1,5 +1,6 @@ #pragma once #include "types.h" +#include #include #include #include @@ -25,9 +26,11 @@ public: u32 GetChannels() const { return m_channels; } u32 GetBufferSize() const { return m_buffer_size; } u32 GetBufferCount() const { return static_cast(m_buffers.size()); } + bool IsSyncing() const { return m_sync; } bool Reconfigure(u32 output_sample_rate = DefaultOutputSampleRate, u32 channels = 1, u32 buffer_size = DefaultBufferSize, u32 buffer_count = DefaultBufferCount); + void SetSync(bool enable) { m_sync = enable; } void PauseOutput(bool paused); void EmptyBuffers(); @@ -60,10 +63,11 @@ private: }; void AllocateBuffers(u32 buffer_count); + void EnsureBuffer(); void DropBuffer(); std::vector m_buffers; - std::mutex m_buffer_lock; + std::mutex m_buffer_mutex; // For input. u32 m_first_free_buffer = 0; @@ -73,5 +77,9 @@ private: u32 m_num_available_buffers = 0; u32 m_first_available_buffer = 0; + // TODO: Switch to semaphore + std::condition_variable m_buffer_available_cv; + bool m_output_paused = true; + bool m_sync = true; }; \ No newline at end of file