[02/10] loopback: Limit controller step size to 2.01‰

Submitted by Georg Chini on April 9, 2018, 5:16 p.m.

Details

Message ID 20180409171707.17696-3-georg@chini.tk
State New
Series "loopback: Optimize latency stabilization"
Headers show

Commit Message

Georg Chini April 9, 2018, 5:16 p.m.
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(-)

Patch hide | download patch | download mbox

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;