From 521ed3a664f7f1b1219056a8f2e6a2eb4dc059f9 Mon Sep 17 00:00:00 2001
From: Maarten Bosmans <mkbosmans@gmail.com>
Date: Fri, 7 Jan 2011 01:25:55 +0100
Subject: [PATCH] module-combine: limit the size of the rate adjustments

Only adjust the sample rate of the slave input streams by small, inaudible steps
---
 src/modules/module-combine.c |   14 +++++++++-----
 1 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c
index bcea229..068b3a8 100644
--- a/src/modules/module-combine.c
+++ b/src/modules/module-combine.c
@@ -218,19 +218,23 @@ static void adjust_rates(struct userdata *u) {
 
     PA_IDXSET_FOREACH(o, u->outputs, idx) {
         uint32_t r = base_rate;
+        uint32_t current_rate = o->sink_input->sample_spec.rate;
 
         if (!o->sink_input || !PA_SINK_IS_OPENED(pa_sink_get_state(o->sink)))
             continue;
 
-        if (o->total_latency < target_latency)
-            r -= (uint32_t) ((((double) (target_latency - o->total_latency))/(double)u->adjust_time)*(double)r);
-        else if (o->total_latency > target_latency)
-            r += (uint32_t) ((((double) (o->total_latency - target_latency))/(double)u->adjust_time)*(double)r);
+        if (o->total_latency != target_latency)
+            r += (uint32_t) (((double) o->total_latency - (double) target_latency) / (double) u->adjust_time * (double) r);
 
-        if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) {
+        if (r < (uint32_t) (base_rate*0.8) || r > (uint32_t) (base_rate*1.25)) {
             pa_log_warn("[%s] sample rates too different, not adjusting (%u vs. %u).", o->sink_input->sink->name, base_rate, r);
             pa_sink_input_set_rate(o->sink_input, base_rate);
         } else {
+            /* Do the adjustment in small steps; 2‰ can be considered inaudible */
+            if (r < (uint32_t) (current_rate*0.998) || r > (uint32_t) (current_rate*1.002)) {
+                pa_log_warn("[%s] new rate of %u Hz not within 2‰ of %u Hz, forcing smaller adjustment", o->sink_input->sink->name, r, current_rate);
+                r = PA_CLAMP(r, (uint32_t) (current_rate*0.998), (uint32_t) (current_rate*1.002));
+            }
             pa_log_info("[%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.", o->sink_input->sink->name, r, (double) r / base_rate, (float) o->total_latency);
             pa_sink_input_set_rate(o->sink_input, r);
         }
-- 
1.7.1

