aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cubeb_resampler_internal.h
diff options
context:
space:
mode:
authorPaul Adenot <[email protected]>2017-10-03 11:34:20 +0200
committerGitHub <[email protected]>2017-10-03 11:34:20 +0200
commitba2a89611875cd9f2dabae99a362461b03c0dd3d (patch)
tree85bcee4aa636ddb01ecf58a80a1576f9295873c9 /src/cubeb_resampler_internal.h
parentd6ae2ed9c5d1c0f7d0fb7bdcf70bf75c5464f689 (diff)
downloadcubeb-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.h61
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;
}