[PATCH v2 2/3] source: When updating a monitor source's rate, update the sink rate too

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index c692511..5e59a40 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -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) {
-- 
1.8.1.2



[Index of Archives]     [Linux Audio Users]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux