loopback: Limit controller step size to 2.01‰

The current loopback controller can produce a rate jump of up to 1% at startup,
which may be audible. To prevent large initial jumps, a second controller is
introduced, which produces a rate, that is not more than 2‰ away from the last
rate. Only during the startup phase, the rates produced by this controller will
be nearer to the base rate than those produced by the original controller.
Therefore choosing the rate which is nearer to the base rate will ensure that
the secondary controller only moderates the startup phase and has no influence
during continued operation.
The maximum step size of the original controller after the initial jump is
limited to 2.01‰ of the base rate, see documentation at
https://www.freedesktop.org/software/pulseaudio/misc/rate_estimator.odt

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/56>
This commit is contained in:
Georg Chini 2020-01-27 19:22:35 +01:00
parent e7abd862b1
commit 285427ce30

View file

@ -240,21 +240,31 @@ static void teardown(struct userdata *u) {
/* rate controller, called from main context /* rate controller, called from main context
* - maximum deviation from base rate is less than 1% * - maximum deviation from base rate is less than 1%
* - can create audible artifacts by changing the rate too quickly * - controller step size is limited to 2.01
* - exhibits hunting with USB or Bluetooth sources * - exhibits hunting with USB or Bluetooth sources
*/ */
static uint32_t rate_controller( static uint32_t rate_controller(
uint32_t base_rate, struct userdata *u,
pa_usec_t adjust_time, uint32_t base_rate, uint32_t old_rate,
int32_t latency_difference_usec) { int32_t latency_difference_usec) {
uint32_t new_rate; uint32_t new_rate, new_rate_1, new_rate_2;
double min_cycles; double min_cycles_1, min_cycles_2;
/* Calculate next rate that is not more than 2‰ away from the last rate */
min_cycles_1 = (double)abs(latency_difference_usec) / u->real_adjust_time / 0.002 + 1;
new_rate_1 = old_rate + base_rate * (double)latency_difference_usec / min_cycles_1 / u->real_adjust_time;
/* Calculate best rate to correct the current latency offset, limit at /* Calculate best rate to correct the current latency offset, limit at
* slightly below 1% difference from base_rate */ * 1% difference from base_rate */
min_cycles = (double)abs(latency_difference_usec) / adjust_time / 0.01 + 1; min_cycles_2 = (double)abs(latency_difference_usec) / u->real_adjust_time / 0.01 + 1;
new_rate = base_rate * (1.0 + (double)latency_difference_usec / min_cycles / adjust_time); new_rate_2 = (double)base_rate * (1.0 + (double)latency_difference_usec / min_cycles_2 / u->real_adjust_time);
/* Choose the rate that is nearer to base_rate */
if (abs((int)new_rate_1 - (int)base_rate) < abs((int)new_rate_2 - (int)base_rate))
new_rate = new_rate_1;
else
new_rate = new_rate_2;
return new_rate; return new_rate;
} }
@ -415,7 +425,7 @@ static void adjust_rates(struct userdata *u) {
} }
/* Calculate new rate */ /* Calculate new rate */
new_rate = rate_controller(base_rate, u->real_adjust_time, latency_difference); new_rate = rate_controller(u, base_rate, old_rate, latency_difference);
u->source_sink_changed = false; u->source_sink_changed = false;