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 --- src/modules/module-loopback.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index 32780380..9ca84b9d 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -232,21 +232,31 @@ static void teardown(struct userdata *u) { /* rate controller, called from main context * - 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 */ static uint32_t rate_controller( - uint32_t base_rate, - pa_usec_t adjust_time, + struct userdata *u, + uint32_t base_rate, uint32_t old_rate, int32_t latency_difference_usec) { - uint32_t new_rate; - double min_cycles; + uint32_t new_rate, new_rate_1, new_rate_2; + 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 - * slightly below 1% difference from base_rate */ - min_cycles = (double)abs(latency_difference_usec) / adjust_time / 0.01 + 1; - new_rate = base_rate * (1.0 + (double)latency_difference_usec / min_cycles / adjust_time); + * 1% difference from base_rate */ + min_cycles_2 = (double)abs(latency_difference_usec) / u->real_adjust_time / 0.01 + 1; + 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(new_rate_1 - base_rate) < abs(new_rate_2 - base_rate)) + new_rate = new_rate_1; + else + new_rate = new_rate_2; return new_rate; } @@ -392,7 +402,7 @@ static void adjust_rates(struct userdata *u) { pa_log_debug("Loopback latency at base rate is %0.2f ms", (double)latency_at_optimum_rate / PA_USEC_PER_MSEC); /* 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; -- 2.14.1