The current loopback controller can produce a rate jump of up to 1% at startup. This might be audible, so implement a similar controller that will be used in the initial iterations and has a 2â?° limit to the step size. Once the original controller takes over, step size is limited to 2.01â?°. Proof for this can be found in the document "rate_estimator.odt" mentioned previously. --- 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 03f23e3..eee8d53 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -194,21 +194,31 @@ static void teardown(struct userdata *u) { /* rate controller * - 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_1, new_rate_2, new_rate; + 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; } @@ -286,7 +296,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.8.1