+
+/* Called from main context */
+/* Updates the source output's resampler with whatever the current source
+ * requires -- useful when the underlying source's rate might have changed */
+int pa_source_output_update_rate(pa_source_output *o) {
+ pa_resampler *new_resampler;
+ char *memblockq_name;
+
+ pa_source_output_assert_ref(o);
+ pa_assert_ctl_context();
+
+ if (o->thread_info.resampler &&
+ pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &o->source->sample_spec) &&
+ pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &o->source->channel_map))
+
+ new_resampler = o->thread_info.resampler;
+
+ else if (!pa_source_output_is_passthrough(o) &&
+ ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
+ !pa_sample_spec_equal(&o->sample_spec, &o->source->sample_spec) ||
+ !pa_channel_map_equal(&o->channel_map, &o->source->channel_map))) {
+
+ new_resampler = pa_resampler_new(o->core->mempool,
+ &o->source->sample_spec, &o->source->channel_map,
+ &o->sample_spec, &o->channel_map,
+ o->requested_resample_method,
+ ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
+ ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
+ (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
+ (o->core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0));
+
+ if (!new_resampler) {
+ pa_log_warn("Unsupported resampling operation.");
+ return -PA_ERR_NOTSUPPORTED;
+ }
+ } else
+ new_resampler = NULL;
+
+ if (new_resampler == o->thread_info.resampler)
+ return 0;
+
+ if (o->thread_info.resampler)
+ pa_resampler_free(o->thread_info.resampler);
+
+ o->thread_info.resampler = new_resampler;
+
+ pa_memblockq_free(o->thread_info.delay_memblockq);
+
+ memblockq_name = pa_sprintf_malloc("source output delay_memblockq [%u]", o->index);
+ o->thread_info.delay_memblockq = pa_memblockq_new(
+ memblockq_name,
+ 0,
+ MEMBLOCKQ_MAXLENGTH,
+ 0,
+ &o->source->sample_spec,
+ 0,
+ 1,
+ 0,
+ &o->source->silence);
+ pa_xfree(memblockq_name);
+
+ o->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
+
+ pa_log_debug("Updated resampler for source output %d", o->index);
+
+ return 0;
+}
+
+/* Called from the main thread. */
+void pa_source_output_set_volume_direct(pa_source_output *o, const pa_cvolume *volume) {
+ pa_cvolume old_volume;
+ char old_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
+ char new_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
+
+ pa_assert(o);
+ pa_assert(volume);
+
+ old_volume = o->volume;
+
+ if (pa_cvolume_equal(volume, &old_volume))
+ return;
+
+ o->volume = *volume;
+ pa_log_debug("The volume of source output %u changed from %s to %s.", o->index,
+ pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &o->channel_map, true),
+ pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &o->channel_map, true));
+
+ if (o->volume_changed)
+ o->volume_changed(o);
+
+ pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
+}