+
+/* Called from main context */
+/* Updates the sink input's resampler with whatever the current sink requires
+ * -- useful when the underlying sink's rate might have changed */
+int pa_sink_input_update_rate(pa_sink_input *i) {
+ pa_resampler *new_resampler;
+ char *memblockq_name;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_ctl_context();
+
+ if (i->thread_info.resampler &&
+ pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &i->sink->sample_spec) &&
+ pa_channel_map_equal(pa_resampler_output_channel_map(i->thread_info.resampler), &i->sink->channel_map))
+
+ new_resampler = i->thread_info.resampler;
+
+ else if (!pa_sink_input_is_passthrough(i) &&
+ ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
+ !pa_sample_spec_equal(&i->sample_spec, &i->sink->sample_spec) ||
+ !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map))) {
+
+ new_resampler = pa_resampler_new(i->core->mempool,
+ &i->sample_spec, &i->channel_map,
+ &i->sink->sample_spec, &i->sink->channel_map,
+ i->requested_resample_method,
+ ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
+ ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
+ (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
+ (i->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 == i->thread_info.resampler)
+ return 0;
+
+ if (i->thread_info.resampler)
+ pa_resampler_free(i->thread_info.resampler);
+
+ i->thread_info.resampler = new_resampler;
+
+ pa_memblockq_free(i->thread_info.render_memblockq);
+
+ memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
+ i->thread_info.render_memblockq = pa_memblockq_new(
+ memblockq_name,
+ 0,
+ MEMBLOCKQ_MAXLENGTH,
+ 0,
+ &i->sink->sample_spec,
+ 0,
+ 1,
+ 0,
+ &i->sink->silence);
+ pa_xfree(memblockq_name);
+
+ i->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
+
+ pa_log_debug("Updated resampler for sink input %d", i->index);
+
+ return 0;
+}
+
+/* Called from the main thread. */
+void pa_sink_input_set_volume_direct(pa_sink_input *i, 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(i);
+ pa_assert(volume);
+
+ old_volume = i->volume;
+
+ if (pa_cvolume_equal(volume, &old_volume))
+ return;
+
+ i->volume = *volume;
+ pa_log_debug("The volume of sink input %u changed from %s to %s.", i->index,
+ pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &i->channel_map, true),
+ pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &i->channel_map, true));
+
+ if (i->volume_changed)
+ i->volume_changed(i);
+
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+}