]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/source-output.c
source-output: Ensure no volumes are applied for passthrough streams
[pulseaudio] / src / pulsecore / source-output.c
index 0ce77780cc911bc2559e695859157d281f71511a..d54e7f61108175326d382fa649d169ea29cba71e 100644 (file)
@@ -253,8 +253,11 @@ int pa_source_output_new(
 
     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 */
@@ -278,7 +281,6 @@ int pa_source_output_new(
         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);
 
@@ -296,10 +298,13 @@ int pa_source_output_new(
 
     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) {
@@ -542,6 +547,9 @@ void pa_source_output_unlink(pa_source_output*o) {
     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);
@@ -626,6 +634,9 @@ void pa_source_output_put(pa_source_output *o) {
         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;
 
@@ -731,7 +742,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
             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) {
@@ -741,17 +752,17 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
                  * 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);
@@ -769,7 +780,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
             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);
@@ -895,58 +906,6 @@ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
     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;
@@ -1108,6 +1067,58 @@ void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode
     }
 }
 
+/* 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);
@@ -1178,6 +1189,9 @@ int pa_source_output_start_move(pa_source_output *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. */
@@ -1374,9 +1388,10 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
         /* 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 */
 
@@ -1431,6 +1446,9 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
 
     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);