]> code.delx.au - pulseaudio/commitdiff
source: When updating a monitor source's rate, update the sink rate too
authorTanu Kaskinen <tanu.kaskinen@linux.intel.com>
Fri, 9 Aug 2013 06:39:49 +0000 (09:39 +0300)
committerTanu Kaskinen <tanu.kaskinen@linux.intel.com>
Tue, 27 Aug 2013 12:34:33 +0000 (15:34 +0300)
If the sink rate is not updated, then the monitor source will appear
to have a different rate than the sink, but in reality there's never
any resampling done when moving data from the sink to the monitor
source, so it's a lie that the monitor source has a different rate.
The result of lying is that clients that capture from the monitor
source will have streams that run too fast or slow.

src/pulsecore/source.c

index c6925112740ac66b4321908a6d4d41d469d7e3c0..5e59a406b49d26ba342317e7b9abed81c6601f53 100644 (file)
@@ -991,6 +991,13 @@ bool pa_source_update_rate(pa_source *s, uint32_t rate, bool passthrough) {
         return false;
     }
 
+    if (s->monitor_of) {
+        if (PA_SINK_IS_RUNNING(s->monitor_of->state)) {
+            pa_log_info("Cannot update rate, this is a monitor source and the sink is running.");
+            return false;
+        }
+    }
+
     if (PA_UNLIKELY (desired_rate < 8000 ||
                      desired_rate > PA_RATE_MAX))
         return false;
@@ -1029,8 +1036,31 @@ bool pa_source_update_rate(pa_source *s, uint32_t rate, bool passthrough) {
         ret = s->update_rate(s, desired_rate);
     else {
         /* This is a monitor source. */
-        s->sample_spec.rate = desired_rate;
-        ret = true;
+
+        /* XXX: This code is written with non-passthrough streams in mind. I
+         * have no idea whether the behaviour with passthrough streams is
+         * sensible. */
+        if (!passthrough) {
+            uint32_t old_rate = s->sample_spec.rate;
+
+            s->sample_spec.rate = desired_rate;
+            ret = pa_sink_update_rate(s->monitor_of, desired_rate, false);
+
+            if (!ret) {
+                /* Changing the sink rate failed, roll back the old rate for
+                 * the monitor source. Why did we set the source rate before
+                 * calling pa_sink_update_rate(), you may ask. The reason is
+                 * that pa_sink_update_rate() tries to update the monitor
+                 * source rate, but we are already in the process of updating
+                 * the monitor source rate, so there's a risk of entering an
+                 * infinite loop. Setting the source rate before calling
+                 * pa_sink_update_rate() makes the rate == s->sample_spec.rate
+                 * check in the beginning of this function return early, so we
+                 * avoid looping. */
+                s->sample_spec.rate = old_rate;
+            }
+        } else
+            ret = false;
     }
 
     if (ret) {