}
/* 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;
+ bool use_alternate = false;
- if (s->update_rate) {
- 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 (rate == s->sample_spec.rate)
+ return 0;
- if (PA_UNLIKELY(default_rate == alternate_rate)) {
- pa_log_warn("Default and alternate sample rates are the same.");
- return false;
- }
+ if (!s->update_rate && !s->monitor_of)
+ 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;
+ if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough)) {
+ pa_log_debug("Default and alternate sample rates are the same.");
+ 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 -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;
+ if (PA_UNLIKELY (desired_rate < 8000 ||
+ desired_rate > PA_RATE_MAX))
+ return -1;
- if (!passthrough) {
- pa_assert(default_rate % 4000 || default_rate % 11025);
- pa_assert(alternate_rate % 4000 || alternate_rate % 11025);
-
- if (default_rate % 4000) {
- /* default is a 11025 multiple */
- if ((alternate_rate % 4000 == 0) && (desired_rate % 4000 == 0))
- use_alternate=true;
- } else {
- /* default is 4000 multiple */
- if ((alternate_rate % 11025 == 0) && (desired_rate % 11025 == 0))
- use_alternate=true;
- }
+ if (!passthrough) {
+ pa_assert((default_rate % 4000 == 0) || (default_rate % 11025 == 0));
+ pa_assert((alternate_rate % 4000 == 0) || (alternate_rate % 11025 == 0));
- if (use_alternate)
- desired_rate = alternate_rate;
- else
- desired_rate = default_rate;
+ if (default_rate % 11025 == 0) {
+ if ((alternate_rate % 4000 == 0) && (desired_rate % 4000 == 0))
+ use_alternate=true;
} else {
- desired_rate = rate; /* use stream sampling rate, discard default/alternate settings */
+ /* default is 4000 multiple */
+ if ((alternate_rate % 11025 == 0) && (desired_rate % 11025 == 0))
+ use_alternate=true;
}
- if (desired_rate == s->sample_spec.rate)
- return false;
+ if (use_alternate)
+ desired_rate = alternate_rate;
+ else
+ desired_rate = default_rate;
+ } else {
+ desired_rate = rate; /* use stream sampling rate, discard default/alternate settings */
+ }
- if (!passthrough && pa_source_used_by(s) > 0)
- return false;
+ if (desired_rate == s->sample_spec.rate)
+ return -1;
+
+ if (!passthrough && pa_source_used_by(s) > 0)
+ return -1;
- pa_log_debug("Suspending source %s due to changing the sample rate.", s->name);
- pa_source_suspend(s, true, PA_SUSPEND_INTERNAL);
+ 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. */
- PA_IDXSET_FOREACH(o, s->outputs, idx) {
- if (o->state == PA_SOURCE_OUTPUT_CORKED)
- pa_source_output_update_rate(o);
+ /* 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;
}
- ret = true;
+ } 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);
}
- pa_source_suspend(s, false, PA_SUSPEND_INTERNAL);
+ pa_log_info("Changed sampling rate successfully");
}
+ pa_source_suspend(s, false, PA_SUSPEND_INTERNAL);
+
return ret;
}