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

_______________________________________________
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss

Reply via email to