AudioStream: Add option to wait until a full buffer is queued

This commit is contained in:
Connor McLaughlin 2021-01-28 20:12:24 +10:00
parent 9316ce532b
commit 4e583890ea
2 changed files with 28 additions and 3 deletions

View file

@ -27,6 +27,7 @@ bool AudioStream::Reconfigure(u32 input_sample_rate /* = DefaultInputSampleRate
m_output_sample_rate = output_sample_rate; m_output_sample_rate = output_sample_rate;
m_channels = channels; m_channels = channels;
m_buffer_size = buffer_size; m_buffer_size = buffer_size;
m_buffer_filling.store(m_wait_for_buffer_fill);
m_output_paused = true; m_output_paused = true;
if (!SetBufferSize(buffer_size)) if (!SetBufferSize(buffer_size))
@ -55,6 +56,14 @@ void AudioStream::SetInputSampleRate(u32 sample_rate)
InternalSetInputSampleRate(sample_rate); InternalSetInputSampleRate(sample_rate);
} }
void AudioStream::SetWaitForBufferFill(bool enabled)
{
std::unique_lock<std::mutex> buffer_lock(m_buffer_mutex);
m_wait_for_buffer_fill = enabled;
if (enabled && m_buffer.IsEmpty())
m_buffer_filling.store(true);
}
void AudioStream::InternalSetInputSampleRate(u32 sample_rate) void AudioStream::InternalSetInputSampleRate(u32 sample_rate)
{ {
if (m_input_sample_rate == sample_rate) if (m_input_sample_rate == sample_rate)
@ -123,6 +132,11 @@ void AudioStream::WriteFrames(const SampleType* frames, u32 num_frames)
void AudioStream::EndWrite(u32 num_frames) void AudioStream::EndWrite(u32 num_frames)
{ {
m_buffer.AdvanceTail(num_frames * m_channels); m_buffer.AdvanceTail(num_frames * m_channels);
if (m_buffer_filling.load())
{
if ((m_buffer.GetSize() / m_channels) >= m_buffer_size)
m_buffer_filling.store(false);
}
m_buffer_mutex.unlock(); m_buffer_mutex.unlock();
FramesAvailable(); FramesAvailable();
} }
@ -165,8 +179,9 @@ void AudioStream::ReadFrames(SampleType* samples, u32 num_frames, bool apply_vol
{ {
const u32 total_samples = num_frames * m_channels; const u32 total_samples = num_frames * m_channels;
u32 samples_copied = 0; u32 samples_copied = 0;
std::unique_lock<std::mutex> buffer_lock(m_buffer_mutex);
if (!m_buffer_filling.load())
{ {
std::unique_lock<std::mutex> buffer_lock(m_buffer_mutex);
if (m_input_sample_rate == m_output_sample_rate) if (m_input_sample_rate == m_output_sample_rate)
{ {
samples_copied = std::min(m_buffer.GetSize(), total_samples); samples_copied = std::min(m_buffer.GetSize(), total_samples);
@ -187,6 +202,10 @@ void AudioStream::ReadFrames(SampleType* samples, u32 num_frames, bool apply_vol
m_resampled_buffer.PopRange(samples, samples_copied); m_resampled_buffer.PopRange(samples, samples_copied);
} }
} }
else
{
ReleaseBufferLock(std::move(buffer_lock));
}
if (samples_copied < total_samples) if (samples_copied < total_samples)
{ {
@ -214,16 +233,18 @@ void AudioStream::ReadFrames(SampleType* samples, u32 num_frames, bool apply_vol
resample_subpos %= 65536u; resample_subpos %= 65536u;
} }
Log_DevPrintf("Audio buffer underflow, resampled %u frames to %u", samples_copied / m_channels, num_frames); Log_VerbosePrintf("Audio buffer underflow, resampled %u frames to %u", samples_copied / m_channels, num_frames);
m_underflow_flag.store(true); m_underflow_flag.store(true);
} }
else else
{ {
// read nothing, so zero-fill // read nothing, so zero-fill
std::memset(samples, 0, sizeof(SampleType) * total_samples); std::memset(samples, 0, sizeof(SampleType) * total_samples);
Log_DevPrintf("Audio buffer underflow with no samples, added %u frames silence", num_frames); Log_VerbosePrintf("Audio buffer underflow with no samples, added %u frames silence", num_frames);
m_underflow_flag.store(true); m_underflow_flag.store(true);
} }
m_buffer_filling.store(m_wait_for_buffer_fill);
} }
if (apply_volume && m_output_volume != FullVolume) if (apply_volume && m_output_volume != FullVolume)
@ -267,6 +288,7 @@ void AudioStream::EmptyBuffers()
std::unique_lock<std::mutex> resampler_lock(m_resampler_mutex); std::unique_lock<std::mutex> resampler_lock(m_resampler_mutex);
m_buffer.Clear(); m_buffer.Clear();
m_underflow_flag.store(false); m_underflow_flag.store(false);
m_buffer_filling.store(m_wait_for_buffer_fill);
ResetResampler(); ResetResampler();
} }

View file

@ -37,6 +37,7 @@ public:
void SetSync(bool enable) { m_sync = enable; } void SetSync(bool enable) { m_sync = enable; }
void SetInputSampleRate(u32 sample_rate); void SetInputSampleRate(u32 sample_rate);
void SetWaitForBufferFill(bool enabled);
virtual void SetOutputVolume(u32 volume); virtual void SetOutputVolume(u32 volume);
@ -109,10 +110,12 @@ private:
std::vector<SampleType> m_resample_buffer; std::vector<SampleType> m_resample_buffer;
std::atomic_bool m_underflow_flag{false}; std::atomic_bool m_underflow_flag{false};
std::atomic_bool m_buffer_filling{false};
u32 m_max_samples = 0; u32 m_max_samples = 0;
bool m_output_paused = true; bool m_output_paused = true;
bool m_sync = true; bool m_sync = true;
bool m_wait_for_buffer_fill = false;
// Resampling // Resampling
double m_resampler_ratio = 1.0; double m_resampler_ratio = 1.0;