Commit 37d21af0 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

PulseAudio: more stable resampling scheme

parent f5b7eea1
...@@ -173,34 +173,41 @@ static void stream_latency_cb(pa_stream *s, void *userdata) ...@@ -173,34 +173,41 @@ static void stream_latency_cb(pa_stream *s, void *userdata)
//msg_Dbg(aout, "desync: %+"PRId64" us (variation: %+"PRId64" us)", //msg_Dbg(aout, "desync: %+"PRId64" us (variation: %+"PRId64" us)",
// delta, change); // delta, change);
/* Compute playback sample rate */ if (delta < -AOUT_MAX_PTS_DELAY)
const unsigned inrate = aout->output.output.i_rate;
/* NOTE: AOUT_MAX_RESAMPLING (10%) is way too high... */
const int limit = inrate >> 6;
if (delta < -AOUT_MAX_PTS_DELAY) {
msg_Warn(aout, "too late by %"PRId64" us", -delta); msg_Warn(aout, "too late by %"PRId64" us", -delta);
if (change < 0) else if (delta > +AOUT_MAX_PTS_ADVANCE)
delta += change; /* be more severe if really out of sync */
} else if (delta > +AOUT_MAX_PTS_ADVANCE) {
msg_Warn(aout, "too early by %"PRId64" us", delta); msg_Warn(aout, "too early by %"PRId64" us", delta);
if (change > 0)
delta += change;
}
/* Compute playback sample rate */
const unsigned inrate = aout->output.output.i_rate;
#define ADJUST_FACTOR 4
#define ADJUST_MAX 1000 /* Hz (max rate variation per call) */
/* This is empirical. Feel free to define something smarter. */ /* This is empirical. Feel free to define something smarter. */
int outrate = inrate * delta / -(CLOCK_FREQ * 10); int adj = sys->rate * (delta + change) / (CLOCK_FREQ * ADJUST_FACTOR);
if (16 * abs(outrate) < limit)
outrate = inrate; /* favor native rate to avoid resampling */ /* This avoids too fast rate variation. They sound ugly as hell and they
else if (outrate > limit) * make the algorithm unstable (e.g. oscillation around inrate). */
if (adj > +ADJUST_MAX)
adj = +ADJUST_MAX;
if (adj < -ADJUST_MAX)
adj = -ADJUST_MAX;
if (abs(adj) < (inrate >> 10))
adj = 0; /* favor native rate to avoid resampling */
/* This keeps the effective rate within specified range
* (+/-AOUT_MAX_RESAMPLING% - see <vlc_aout.h>) of the nominal rate. */
unsigned outrate = inrate - adj;
const int limit = inrate * AOUT_MAX_RESAMPLING / 100;
if (outrate > inrate + limit)
outrate = inrate + limit; outrate = inrate + limit;
else if (outrate < -limit) if (outrate < inrate - limit)
outrate = inrate - limit; outrate = inrate - limit;
else
outrate += inrate;
/* Apply adjusted sample rate */ /* Apply adjusted sample rate */
if (outrate == (int)sys->rate) if (outrate == sys->rate)
return; return;
pa_operation *op = pa_stream_update_sample_rate(s, outrate, NULL, NULL); pa_operation *op = pa_stream_update_sample_rate(s, outrate, NULL, NULL);
if (unlikely(op == NULL)) { if (unlikely(op == NULL)) {
...@@ -208,7 +215,7 @@ static void stream_latency_cb(pa_stream *s, void *userdata) ...@@ -208,7 +215,7 @@ static void stream_latency_cb(pa_stream *s, void *userdata)
return; return;
} }
pa_operation_unref(op); pa_operation_unref(op);
msg_Dbg(aout, "changed sample rate to %d Hz", outrate); msg_Dbg(aout, "changed sample rate to %u Hz",outrate);
sys->rate = outrate; sys->rate = outrate;
} }
...@@ -365,11 +372,13 @@ static void Play(aout_instance_t *aout) ...@@ -365,11 +372,13 @@ static void Play(aout_instance_t *aout)
float *zeroes = calloc (nb, size); float *zeroes = calloc (nb, size);
msg_Dbg(aout, "prepending %zu zeroes", nb); msg_Dbg(aout, "prepending %zu zeroes", nb);
#if 0 /* Fault injector: add delay */
pa_stream_write(s, zeroes, nb * size, NULL, 0, PA_SEEK_RELATIVE);
pa_stream_write(s, zeroes, nb * size, NULL, 0, PA_SEEK_RELATIVE);
#endif
if (likely(zeroes != NULL)) if (likely(zeroes != NULL))
#if 1 /* Fault injection: remove this to be too early */
if (pa_stream_write(s, zeroes, nb * size, free, 0, if (pa_stream_write(s, zeroes, nb * size, free, 0,
PA_SEEK_RELATIVE) < 0) PA_SEEK_RELATIVE) < 0)
#endif
free(zeroes); free(zeroes);
} }
...@@ -382,7 +391,7 @@ static void Play(aout_instance_t *aout) ...@@ -382,7 +391,7 @@ static void Play(aout_instance_t *aout)
msg_Dbg(aout, "uncorking"); msg_Dbg(aout, "uncorking");
} }
#if 0 /* Fault injector to be too late / test underrun recovery */ #if 0 /* Fault injector to test underrun recovery */
static unsigned u = 0; static unsigned u = 0;
if ((++u % 500) == 0) { if ((++u % 500) == 0) {
msg_Err(aout, "fault injection"); msg_Err(aout, "fault injection");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment