diff options
author | Paul Adenot <[email protected]> | 2017-10-03 11:34:20 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2017-10-03 11:34:20 +0200 |
commit | ba2a89611875cd9f2dabae99a362461b03c0dd3d (patch) | |
tree | 85bcee4aa636ddb01ecf58a80a1576f9295873c9 /src/cubeb_resampler_internal.h | |
parent | d6ae2ed9c5d1c0f7d0fb7bdcf70bf75c5464f689 (diff) | |
download | cubeb-ba2a89611875cd9f2dabae99a362461b03c0dd3d.tar.gz cubeb-ba2a89611875cd9f2dabae99a362461b03c0dd3d.zip |
Implement some rudimentary underrun protection for duplex streams (#354)
* Implement some rudimentary underrun protection for duplex streams
* Fix resampler api change that broke test_resampler.cpp
* Address review comments, clean things up a bit
* Address acronop comments, and add a test.
* Address more comments from achronop, and test mono and stereo input
* Fix warning.
Diffstat (limited to 'src/cubeb_resampler_internal.h')
-rw-r--r-- | src/cubeb_resampler_internal.h | 61 |
1 files changed, 55 insertions, 6 deletions
diff --git a/src/cubeb_resampler_internal.h b/src/cubeb_resampler_internal.h index bb5da05..b15bdba 100644 --- a/src/cubeb_resampler_internal.h +++ b/src/cubeb_resampler_internal.h @@ -38,6 +38,17 @@ MOZ_END_STD_NAMESPACE #include <stdio.h> /* This header file contains the internal C++ API of the resamplers, for testing. */ +namespace { +// When dropping audio input frames to prevent building +// an input delay, this function returns the number of frames +// to keep in the buffer. +// @parameter sample_rate The sample rate of the stream. +// @return A number of frames to keep. +uint32_t min_buffered_audio_frame(uint32_t sample_rate) +{ + return sample_rate / 20; +} +} int to_speex_quality(cubeb_resampler_quality q); @@ -75,7 +86,8 @@ public: passthrough_resampler(cubeb_stream * s, cubeb_data_callback cb, void * ptr, - uint32_t input_channels); + uint32_t input_channels, + uint32_t sample_rate); virtual long fill(void * input_buffer, long * input_frames_count, void * output_buffer, long output_frames); @@ -85,6 +97,15 @@ public: return 0; } + void drop_audio_if_needed() + { + uint32_t to_keep = min_buffered_audio_frame(sample_rate); + uint32_t available = samples_to_frames(internal_input_buffer.length()); + if (available > to_keep) { + internal_input_buffer.pop(nullptr, frames_to_samples(available - to_keep)); + } + } + private: cubeb_stream * const stream; const cubeb_data_callback data_callback; @@ -92,6 +113,7 @@ private: /* This allows to buffer some input to account for the fact that we buffer * some inputs. */ auto_array<T> internal_input_buffer; + uint32_t sample_rate; }; /** Bidirectional resampler, can resample an input and an output stream, or just @@ -164,6 +186,7 @@ public: int quality) : processor(channels) , resampling_ratio(static_cast<float>(source_rate) / target_rate) + , source_rate(source_rate) , additional_latency(0) , leftover_samples(0) { @@ -296,6 +319,16 @@ public: resampling_in_buffer.set_length(leftover_samples + frames_to_samples(written_frames)); } + + void drop_audio_if_needed() + { + // Keep at most 100ms buffered. + uint32_t available = samples_to_frames(resampling_in_buffer.length()); + uint32_t to_keep = min_buffered_audio_frame(source_rate); + if (available > to_keep) { + resampling_in_buffer.pop(nullptr, frames_to_samples(available - to_keep)); + } + } private: /** Wrapper for the speex resampling functions to have a typed * interface. */ @@ -332,6 +365,7 @@ private: SpeexResamplerState * speex_resampler; /** Source rate / target rate. */ const float resampling_ratio; + const uint32_t source_rate; /** Storage for the input frames, to be resampled. Also contains * any unresampled frames after resampling. */ auto_array<T> resampling_in_buffer; @@ -350,11 +384,13 @@ class delay_line : public processor { public: /** Constructor * @parameter frames the number of frames of delay. - * @parameter channels the number of channels of this delay line. */ - delay_line(uint32_t frames, uint32_t channels) + * @parameter channels the number of channels of this delay line. + * @parameter sample_rate sample-rate of the audio going through this delay line */ + delay_line(uint32_t frames, uint32_t channels, uint32_t sample_rate) : processor(channels) , length(frames) , leftover_samples(0) + , sample_rate(sample_rate) { /* Fill the delay line with some silent frames to add latency. */ delay_input_buffer.push_silence(frames * channels); @@ -444,6 +480,15 @@ public: { return length; } + + void drop_audio_if_needed() + { + size_t available = samples_to_frames(delay_input_buffer.length()); + uint32_t to_keep = min_buffered_audio_frame(sample_rate); + if (available > to_keep) { + delay_input_buffer.pop(nullptr, frames_to_samples(available - to_keep)); + } + } private: /** The length, in frames, of this delay line */ uint32_t length; @@ -455,6 +500,7 @@ private: /** The output buffer. This is only ever used if using the ::output with a * single argument. */ auto_array<T> delay_output_buffer; + uint32_t sample_rate; }; /** This sits behind the C API and is more typed. */ @@ -485,7 +531,8 @@ cubeb_resampler_create_internal(cubeb_stream * stream, (output_params && !input_params && (output_params->rate == target_rate))) { return new passthrough_resampler<T>(stream, callback, user_ptr, - input_params ? input_params->channels : 0); + input_params ? input_params->channels : 0, + target_rate); } /* Determine if we need to resampler one or both directions, and create the @@ -517,13 +564,15 @@ cubeb_resampler_create_internal(cubeb_stream * stream, * other direction so that the streams are synchronized. */ if (input_resampler && !output_resampler && input_params && output_params) { output_delay.reset(new delay_line<T>(input_resampler->latency(), - output_params->channels)); + output_params->channels, + output_params->rate)); if (!output_delay) { return NULL; } } else if (output_resampler && !input_resampler && input_params && output_params) { input_delay.reset(new delay_line<T>(output_resampler->latency(), - input_params->channels)); + input_params->channels, + output_params->rate)); if (!input_delay) { return NULL; } |