]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/source.c
sink, source: Fix error reporting style for rate updates
[pulseaudio] / src / pulsecore / source.c
index 00294545d9e995341cfc82bd5b403a2c6c168888..f695655dcd059befe556f34a9704be04344d18ea 100644 (file)
@@ -967,39 +967,46 @@ void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *
 }
 
 /* Called from main thread */
-bool pa_source_update_rate(pa_source *s, uint32_t rate, bool passthrough) {
-    bool ret = false;
+int pa_source_update_rate(pa_source *s, uint32_t rate, bool passthrough) {
+    int ret;
     uint32_t desired_rate = rate;
     uint32_t default_rate = s->default_sample_rate;
     uint32_t alternate_rate = s->alternate_sample_rate;
-    uint32_t idx;
-    pa_source_output *o;
     bool use_alternate = false;
 
-    if (!s->update_rate)
-        return false;
+    if (rate == s->sample_spec.rate)
+        return 0;
+
+    if (!s->update_rate && !s->monitor_of)
+        return -1;
 
     if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough)) {
         pa_log_debug("Default and alternate sample rates are the same.");
-        return false;
+        return -1;
     }
 
     if (PA_SOURCE_IS_RUNNING(s->state)) {
         pa_log_info("Cannot update rate, SOURCE_IS_RUNNING, will keep using %u Hz",
                     s->sample_spec.rate);
-        return false;
+        return -1;
+    }
+
+    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 -1;
+        }
     }
 
     if (PA_UNLIKELY (desired_rate < 8000 ||
                      desired_rate > PA_RATE_MAX))
-        return false;
+        return -1;
 
     if (!passthrough) {
-        pa_assert(default_rate % 4000 || default_rate % 11025);
-        pa_assert(alternate_rate % 4000 || alternate_rate % 11025);
+        pa_assert((default_rate % 4000 == 0) || (default_rate % 11025 == 0));
+        pa_assert((alternate_rate % 4000 == 0) || (alternate_rate % 11025 == 0));
 
-        if (default_rate % 4000) {
-            /* default is a 11025 multiple */
+        if (default_rate % 11025 == 0) {
             if ((alternate_rate % 4000 == 0) && (desired_rate % 4000 == 0))
                 use_alternate=true;
         } else {
@@ -1017,22 +1024,55 @@ bool pa_source_update_rate(pa_source *s, uint32_t rate, bool passthrough) {
     }
 
     if (desired_rate == s->sample_spec.rate)
-        return false;
+        return -1;
 
     if (!passthrough && pa_source_used_by(s) > 0)
-        return false;
+        return -1;
 
     pa_log_debug("Suspending source %s due to changing the sample rate.", s->name);
     pa_source_suspend(s, true, PA_SUSPEND_INTERNAL);
 
-    if (s->update_rate(s, desired_rate) == true) {
-        pa_log_info("Changed sampling rate successfully ");
+    if (s->update_rate)
+        ret = s->update_rate(s, desired_rate);
+    else {
+        /* This is a monitor source. */
+
+        /* 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 < 0) {
+                /* 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 = -1;
+    }
+
+    if (ret >= 0) {
+        uint32_t idx;
+        pa_source_output *o;
 
         PA_IDXSET_FOREACH(o, s->outputs, idx) {
             if (o->state == PA_SOURCE_OUTPUT_CORKED)
                 pa_source_output_update_rate(o);
         }
-        ret = true;
+
+        pa_log_info("Changed sampling rate successfully");
     }
 
     pa_source_suspend(s, false, PA_SUSPEND_INTERNAL);