pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
- if (!data->source)
- pa_source_output_new_data_set_source(data, pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE), FALSE);
+ if (!data->source) {
+ pa_source *source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE);
+ pa_return_val_if_fail(source, -PA_ERR_NOENTITY);
+ pa_source_output_new_data_set_source(data, source, FALSE);
+ }
/* Routing's done, we have a source. Now let's fix the format and set up the
* sample spec */
pa_source_output_new_data_set_sample_spec(data, &ss);
}
- pa_return_val_if_fail(data->source, -PA_ERR_NOENTITY);
pa_return_val_if_fail(PA_SOURCE_IS_LINKED(pa_source_get_state(data->source)), -PA_ERR_BADSTATE);
pa_return_val_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of, -PA_ERR_INVALID);
pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);
- /* Don't restore (or save) stream volume for passthrough streams */
- if (!pa_format_info_is_pcm(data->format)) {
- data->volume_is_set = FALSE;
- data->volume_factor_is_set = FALSE;
+ /* Don't restore (or save) stream volume for passthrough streams and
+ * prevent attenuation/gain */
+ if (pa_source_output_new_data_is_passthrough(data)) {
+ data->volume_is_set = TRUE;
+ pa_cvolume_reset(&data->volume, data->sample_spec.channels);
+ data->volume_is_absolute = TRUE;
+ data->save_volume = FALSE;
}
if (!data->volume_is_set) {
o->state = PA_SOURCE_OUTPUT_UNLINKED;
if (linked && o->source) {
+ if (pa_source_output_is_passthrough(o))
+ pa_source_leave_passthrough(o->source);
+
/* We might need to update the source's volume if we are in flat volume mode. */
if (pa_source_flat_volume_enabled(o->source))
pa_source_set_volume(o->source, NULL, FALSE, FALSE);
set_real_ratio(o, &o->volume);
}
+ if (pa_source_output_is_passthrough(o))
+ pa_source_enter_passthrough(o->source);
+
o->thread_info.soft_volume = o->soft_volume;
o->thread_info.muted = o->muted;
pa_memchunk_make_writable(&qchunk, 0);
if (o->thread_info.muted) {
- pa_silence_memchunk(&qchunk, &o->thread_info.sample_spec);
+ pa_silence_memchunk(&qchunk, &o->source->sample_spec);
nvfs = FALSE;
} else if (!o->thread_info.resampler && nvfs) {
* post and the pre volume adjustment into one */
pa_sw_cvolume_multiply(&v, &o->thread_info.soft_volume, &o->volume_factor_source);
- pa_volume_memchunk(&qchunk, &o->thread_info.sample_spec, &v);
+ pa_volume_memchunk(&qchunk, &o->source->sample_spec, &v);
nvfs = FALSE;
} else
- pa_volume_memchunk(&qchunk, &o->thread_info.sample_spec, &o->thread_info.soft_volume);
+ pa_volume_memchunk(&qchunk, &o->source->sample_spec, &o->thread_info.soft_volume);
}
if (!o->thread_info.resampler) {
if (nvfs) {
pa_memchunk_make_writable(&qchunk, 0);
- pa_volume_memchunk(&qchunk, &o->source->sample_spec, &o->volume_factor_source);
+ pa_volume_memchunk(&qchunk, &o->thread_info.sample_spec, &o->volume_factor_source);
}
o->push(o, &qchunk);
if (rchunk.length > 0) {
if (nvfs) {
pa_memchunk_make_writable(&rchunk, 0);
- pa_volume_memchunk(&rchunk, &o->source->sample_spec, &o->volume_factor_source);
+ pa_volume_memchunk(&rchunk, &o->thread_info.sample_spec, &o->volume_factor_source);
}
o->push(o, &rchunk);
return o->thread_info.requested_source_latency;
}
-/* Called from main context */
-void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
- pa_source_output_assert_ref(o);
- pa_assert_ctl_context();
- pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
-
- source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING);
-}
-
-/* Called from main context */
-int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
- pa_source_output_assert_ref(o);
- pa_assert_ctl_context();
- pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
- pa_return_val_if_fail(o->thread_info.resampler, -PA_ERR_BADSTATE);
-
- if (o->sample_spec.rate == rate)
- return 0;
-
- o->sample_spec.rate = rate;
-
- pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL);
-
- pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
- return 0;
-}
-
-/* Called from main context */
-void pa_source_output_set_name(pa_source_output *o, const char *name) {
- const char *old;
- pa_assert_ctl_context();
- pa_source_output_assert_ref(o);
-
- if (!name && !pa_proplist_contains(o->proplist, PA_PROP_MEDIA_NAME))
- return;
-
- old = pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME);
-
- if (old && name && !strcmp(old, name))
- return;
-
- if (name)
- pa_proplist_sets(o->proplist, PA_PROP_MEDIA_NAME, name);
- else
- pa_proplist_unset(o->proplist, PA_PROP_MEDIA_NAME);
-
- if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
- pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
- pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
- }
-}
-
/* Called from main context */
void pa_source_output_set_volume(pa_source_output *o, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) {
pa_cvolume v;
}
}
+/* Called from main context */
+void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
+ pa_source_output_assert_ref(o);
+ pa_assert_ctl_context();
+ pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
+
+ source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING);
+}
+
+/* Called from main context */
+int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
+ pa_source_output_assert_ref(o);
+ pa_assert_ctl_context();
+ pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
+ pa_return_val_if_fail(o->thread_info.resampler, -PA_ERR_BADSTATE);
+
+ if (o->sample_spec.rate == rate)
+ return 0;
+
+ o->sample_spec.rate = rate;
+
+ pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL);
+
+ pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
+ return 0;
+}
+
+/* Called from main context */
+void pa_source_output_set_name(pa_source_output *o, const char *name) {
+ const char *old;
+ pa_assert_ctl_context();
+ pa_source_output_assert_ref(o);
+
+ if (!name && !pa_proplist_contains(o->proplist, PA_PROP_MEDIA_NAME))
+ return;
+
+ old = pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME);
+
+ if (old && name && !strcmp(old, name))
+ return;
+
+ if (name)
+ pa_proplist_sets(o->proplist, PA_PROP_MEDIA_NAME, name);
+ else
+ pa_proplist_unset(o->proplist, PA_PROP_MEDIA_NAME);
+
+ if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
+ pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
+ pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
+ }
+}
+
/* Called from main context */
pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
pa_source_output_assert_ref(o);
if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
pa_assert_se(origin->n_corked-- >= 1);
+ if (pa_source_output_is_passthrough(o))
+ pa_source_leave_passthrough(o->source);
+
if (pa_source_flat_volume_enabled(o->source))
/* We might need to update the source's volume if we are in flat
* volume mode. */
/* Try to reuse the old resampler if possible */
new_resampler = o->thread_info.resampler;
- else if ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
- !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) ||
- !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) {
+ else if (!pa_source_output_is_passthrough(o) &&
+ ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
+ !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) ||
+ !pa_channel_map_equal(&o->channel_map, &dest->channel_map))) {
/* Okay, we need a new resampler for the new source */
update_volume_due_to_moving(o, dest);
+ if (pa_source_output_is_passthrough(o))
+ pa_source_enter_passthrough(o->source);
+
pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0);
pa_log_debug("Successfully moved source output %i to %s.", o->index, dest->name);