[pulseaudio-discuss] [PATCH 20/23] sink-input, source-output: Allow pa_node_put() to do routing

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Wed Nov 20 01:26:12 PST 2013


pa_node_put() will tell the router module, if there is one loaded,
that a new node is being created. The router module can then set the
initial routing for the new node. To set the initial routing for a
stream, the device pointer needs to be set and the format needs to be
negotiated. This patch modifies pa_sink_input_new() and
pa_source_output_new() so that those functions handle it correctly
if i->sink and i->format (or o->source and o->format) get changed
during pa_node_put().

After the complex changes, the rest of the changes are only about
replacing data->sink with i->sink, data->format with i->format etc.
These changes are not mandatory, because the new data is kept in sync
with the final routing, but once i->sink has been set to its final
value, I think it's cleaner to only use i->sink in the rest of the
function.
---
 src/pulsecore/sink-input.c    | 135 ++++++++++++++++++++++++-----------------
 src/pulsecore/source-output.c | 138 ++++++++++++++++++++++++------------------
 2 files changed, 159 insertions(+), 114 deletions(-)

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 6e8f938..b90e787 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -291,7 +291,7 @@ int pa_sink_input_new(
 
     pa_sink_input *i = NULL;
     pa_resampler *resampler = NULL;
-    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], fmt[PA_FORMAT_INFO_SNPRINT_MAX];
+    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
     pa_channel_map original_cm;
     int r;
     char *pt;
@@ -346,8 +346,28 @@ int pa_sink_input_new(
         goto fail;
     }
 
+    /* If something didn't pick a format for us, pick the top-most format since
+     * we assume this is sorted in priority order */
+    if (!data->format && data->nego_formats && !pa_idxset_isempty(data->nego_formats))
+        data->format = pa_format_info_copy(pa_idxset_first(data->nego_formats, NULL));
+
+    /* If the sink has been set, then also the format should have been
+     * negotiated. If the sink hasn't been set, no format negotiation should
+     * have happened either. */
+    pa_assert((data->sink && data->format) || (!data->sink && !data->format));
+
+    /* From now on, routing will be done with the sink input object instead of
+     * the new data, because the routing code that is in pa_node_put() doesn't
+     * have access to the new data. Therefore, let's copy data->req_formats,
+     * data->format and data->sink to i, because the routing code needs access
+     * to those. */
     i->req_formats = pa_idxset_copy(data->req_formats, (pa_copy_func_t) pa_format_info_copy);
 
+    if (data->format)
+        i->format = pa_format_info_copy(data->format);
+
+    i->sink = data->sink;
+
     if (data->driver && !pa_utf8_valid(data->driver)) {
         ret = -PA_ERR_INVALID;
         goto fail;
@@ -366,9 +386,10 @@ int pa_sink_input_new(
 
     i->node->owner = i;
 
+    /* This may update i->sink and i->format. */
     pa_node_put(i->node);
 
-    if (!data->sink) {
+    if (!i->sink) {
         pa_sink *sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK);
 
         if (!sink) {
@@ -376,61 +397,65 @@ int pa_sink_input_new(
             goto fail;
         }
 
-        pa_sink_input_new_data_set_sink(data, sink, false);
-    }
+        r = pa_sink_input_set_initial_sink(i, sink);
 
-    /* Routing's done, we have a sink. Now let's fix the format and set up the
-     * sample spec */
-
-    /* If something didn't pick a format for us, pick the top-most format since
-     * we assume this is sorted in priority order */
-    if (!data->format && data->nego_formats && !pa_idxset_isempty(data->nego_formats))
-        data->format = pa_format_info_copy(pa_idxset_first(data->nego_formats, NULL));
+        if (r < 0) {
+            pa_log_info("Format negotiation between sink input \"%s\" and the default sink (%s) failed.",
+                        pa_sink_input_get_description(i), sink->name);
+            ret = r;
+            goto fail;
+        }
+    }
 
-    if (PA_LIKELY(data->format)) {
-        pa_log_debug("Negotiated format: %s", pa_format_info_snprint(fmt, sizeof(fmt), data->format));
-    } else {
-        pa_format_info *format;
-        uint32_t idx;
+    pa_assert(i->sink);
+    pa_assert(i->format);
+
+    /* Modules may want to look at the sink and format in the FIXATE hook, so
+     * let's make sure that the new data is in sync with the sink input. Also,
+     * pa_sink_input_new_data_is_passthrough() uses data->format too, and we
+     * call that function a few times. (XXX: It would probably be better to
+     * pass the sink input object to the FIXATE hook instead of the new data,
+     * and replace the pa_sink_input_new_data_is_passthrough() usage with
+     * something that uses the sink input object instead of the new data. Then
+     * this extra syncing could be removed.) */
+    data->sink = i->sink;
 
-        pa_log_info("Sink does not support any requested format:");
-        PA_IDXSET_FOREACH(format, data->req_formats, idx)
-            pa_log_info(" -- %s", pa_format_info_snprint(fmt, sizeof(fmt), format));
+    if (data->format)
+        pa_format_info_free(data->format);
 
-        ret = -PA_ERR_NOTSUPPORTED;
-        goto fail;
-    }
+    data->format = pa_format_info_copy(i->format);
 
-    /* Now populate the sample spec and format according to the final
-     * format that we've negotiated */
+    /* Routing's done, we have a sink and a format. Now populate the sample
+     * spec and channel map according to the final format that we've
+     * negotiated. */
 
-    if (pa_format_info_to_sample_spec(data->format, &ss, &map) < 0) {
+    if (pa_format_info_to_sample_spec(i->format, &ss, &map) < 0) {
         ret = -PA_ERR_INVALID;
         goto fail;
     }
 
     pa_sink_input_new_data_set_sample_spec(data, &ss);
-    if (pa_format_info_is_pcm(data->format) && pa_channel_map_valid(&map))
+    if (pa_format_info_is_pcm(i->format) && pa_channel_map_valid(&map))
         pa_sink_input_new_data_set_channel_map(data, &map);
 
-    if (!PA_SINK_IS_LINKED(pa_sink_get_state(data->sink))) {
+    if (!PA_SINK_IS_LINKED(pa_sink_get_state(i->sink))) {
         ret = -PA_ERR_BADSTATE;
         goto fail;
     }
 
-    if (data->sync_base && !(data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED)) {
+    if (data->sync_base && !(data->sync_base->sink == i->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED)) {
         ret = -PA_ERR_INVALID;
         goto fail;
     }
 
-    r = check_passthrough_connection(pa_sink_input_new_data_is_passthrough(data), data->sink);
+    r = check_passthrough_connection(pa_sink_input_new_data_is_passthrough(data), i->sink);
     if (r != PA_OK) {
         ret = r;
         goto fail;
     }
 
     if (!data->sample_spec_is_set)
-        data->sample_spec = data->sink->sample_spec;
+        data->sample_spec = i->sink->sample_spec;
 
     if (!pa_sample_spec_valid(&data->sample_spec)) {
         ret = -PA_ERR_INVALID;
@@ -438,8 +463,8 @@ int pa_sink_input_new(
     }
 
     if (!data->channel_map_is_set) {
-        if (pa_channel_map_compatible(&data->sink->channel_map, &data->sample_spec))
-            data->channel_map = data->sink->channel_map;
+        if (pa_channel_map_compatible(&i->sink->channel_map, &data->sample_spec))
+            data->channel_map = i->sink->channel_map;
         else
             pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
     }
@@ -476,54 +501,54 @@ int pa_sink_input_new(
         data->muted = false;
 
     if (data->flags & PA_SINK_INPUT_FIX_FORMAT) {
-        if (!pa_format_info_is_pcm(data->format)) {
+        if (!pa_format_info_is_pcm(i->format)) {
             ret = -PA_ERR_INVALID;
             goto fail;
         }
 
-        data->sample_spec.format = data->sink->sample_spec.format;
-        pa_format_info_set_sample_format(data->format, data->sample_spec.format);
+        data->sample_spec.format = i->sink->sample_spec.format;
+        pa_format_info_set_sample_format(i->format, data->sample_spec.format);
     }
 
     if (data->flags & PA_SINK_INPUT_FIX_RATE) {
-        if (!pa_format_info_is_pcm(data->format)) {
+        if (!pa_format_info_is_pcm(i->format)) {
             ret = -PA_ERR_INVALID;
             goto fail;
         }
 
-        data->sample_spec.rate = data->sink->sample_spec.rate;
-        pa_format_info_set_rate(data->format, data->sample_spec.rate);
+        data->sample_spec.rate = i->sink->sample_spec.rate;
+        pa_format_info_set_rate(i->format, data->sample_spec.rate);
     }
 
     original_cm = data->channel_map;
 
     if (data->flags & PA_SINK_INPUT_FIX_CHANNELS) {
-        if (!pa_format_info_is_pcm(data->format)) {
+        if (!pa_format_info_is_pcm(i->format)) {
             ret = -PA_ERR_INVALID;
             goto fail;
         }
 
-        data->sample_spec.channels = data->sink->sample_spec.channels;
-        data->channel_map = data->sink->channel_map;
-        pa_format_info_set_channels(data->format, data->sample_spec.channels);
-        pa_format_info_set_channel_map(data->format, &data->channel_map);
+        data->sample_spec.channels = i->sink->sample_spec.channels;
+        data->channel_map = i->sink->channel_map;
+        pa_format_info_set_channels(i->format, data->sample_spec.channels);
+        pa_format_info_set_channel_map(i->format, &data->channel_map);
     }
 
     pa_assert(pa_sample_spec_valid(&data->sample_spec));
     pa_assert(pa_channel_map_valid(&data->channel_map));
 
     if (!(data->flags & PA_SINK_INPUT_VARIABLE_RATE) &&
-        !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec)) {
+        !pa_sample_spec_equal(&data->sample_spec, &i->sink->sample_spec)) {
         /* try to change sink rate. This is done before the FIXATE hook since
            module-suspend-on-idle can resume a sink */
 
         pa_log_info("Trying to change sample rate");
-        if (pa_sink_update_rate(data->sink, data->sample_spec.rate, pa_sink_input_new_data_is_passthrough(data)) >= 0)
-            pa_log_info("Rate changed to %u Hz", data->sink->sample_spec.rate);
+        if (pa_sink_update_rate(i->sink, data->sample_spec.rate, pa_sink_input_new_data_is_passthrough(data)) >= 0)
+            pa_log_info("Rate changed to %u Hz", i->sink->sample_spec.rate);
     }
 
     if (pa_sink_input_new_data_is_passthrough(data) &&
-        !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec)) {
+        !pa_sample_spec_equal(&data->sample_spec, &i->sink->sample_spec)) {
         /* rate update failed, or other parts of sample spec didn't match */
 
         pa_log_debug("Could not update sink sample spec to match passthrough stream");
@@ -548,28 +573,28 @@ int pa_sink_input_new(
     }
 
     if ((data->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) &&
-        pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) {
+        pa_sink_get_state(i->sink) == PA_SINK_SUSPENDED) {
         pa_log_warn("Failed to create sink input: sink is suspended.");
         ret = -PA_ERR_BADSTATE;
         goto fail;
     }
 
-    if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
+    if (pa_idxset_size(i->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
         pa_log_warn("Failed to create sink input: too many inputs per sink.");
         ret = -PA_ERR_TOOLARGE;
         goto fail;
     }
 
     if ((data->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
-        !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) ||
-        !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) {
+        !pa_sample_spec_equal(&data->sample_spec, &i->sink->sample_spec) ||
+        !pa_channel_map_equal(&data->channel_map, &i->sink->channel_map)) {
 
         /* Note: for passthrough content we need to adjust the output rate to that of the current sink-input */
         if (!pa_sink_input_new_data_is_passthrough(data)) /* no resampler for passthrough content */
             if (!(resampler = pa_resampler_new(
                           core->mempool,
                           &data->sample_spec, &data->channel_map,
-                          &data->sink->sample_spec, &data->sink->channel_map,
+                          &i->sink->sample_spec, &i->sink->channel_map,
                           data->resample_method,
                           ((data->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
                           ((data->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
@@ -582,19 +607,17 @@ int pa_sink_input_new(
     }
 
     i->driver = pa_xstrdup(pa_path_get_filename(data->driver));
-    i->sink = data->sink;
     i->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
     i->sample_spec = data->sample_spec;
     i->channel_map = data->channel_map;
-    i->format = pa_format_info_copy(data->format);
 
     if (!data->volume_is_absolute && pa_sink_flat_volume_enabled(i->sink)) {
         pa_cvolume remapped;
 
         /* When the 'absolute' bool is not set then we'll treat the volume
          * as relative to the sink volume even in flat volume mode */
-        remapped = data->sink->reference_volume;
-        pa_cvolume_remap(&remapped, &data->sink->channel_map, &data->channel_map);
+        remapped = i->sink->reference_volume;
+        pa_cvolume_remap(&remapped, &i->sink->channel_map, &data->channel_map);
         pa_sw_cvolume_multiply(&i->volume, &data->volume, &remapped);
     } else
         i->volume = data->volume;
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index b677a23..dd42dfe 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -227,7 +227,7 @@ int pa_source_output_new(
 
     pa_source_output *o = NULL;
     pa_resampler *resampler = NULL;
-    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], fmt[PA_FORMAT_INFO_SNPRINT_MAX];
+    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
     pa_channel_map original_cm;
     int r;
     char *pt;
@@ -279,8 +279,28 @@ int pa_source_output_new(
         goto fail;
     }
 
+    /* If something didn't pick a format for us, pick the top-most format since
+     * we assume this is sorted in priority order */
+    if (!data->format && data->nego_formats && !pa_idxset_isempty(data->nego_formats))
+        data->format = pa_format_info_copy(pa_idxset_first(data->nego_formats, NULL));
+
+    /* If the source has been set, then also the format should have been
+     * negotiated. If the source hasn't been set, no format negotiation should
+     * have happened either. */
+    pa_assert((data->source && data->format) || (!data->source && !data->format));
+
+    /* From now on, routing will be done with the source output object instead
+     * of the new data, because the routing code that is in pa_node_put()
+     * doesn't have access to the new data. Therefore, let's copy
+     * data->req_formats, data->format and data->source to o, because the
+     * routing code needs access to those. */
     o->req_formats = pa_idxset_copy(data->req_formats, (pa_copy_func_t) pa_format_info_copy);
 
+    if (data->format)
+        o->format = pa_format_info_copy(data->format);
+
+    o->source = data->source;
+
     if (data->driver && !pa_utf8_valid(data->driver)) {
         ret = -PA_ERR_INVALID;
         goto fail;
@@ -299,9 +319,10 @@ int pa_source_output_new(
 
     o->node->owner = o;
 
+    /* This may update o->source and o->format. */
     pa_node_put(o->node);
 
-    if (!data->source) {
+    if (!o->source) {
         pa_source *source;
 
         if (data->direct_on_input) {
@@ -320,55 +341,59 @@ int pa_source_output_new(
             }
         }
 
-        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 */
+        r = pa_source_output_set_initial_source(o, source);
 
-    /* If something didn't pick a format for us, pick the top-most format since
-     * we assume this is sorted in priority order */
-    if (!data->format && data->nego_formats && !pa_idxset_isempty(data->nego_formats))
-        data->format = pa_format_info_copy(pa_idxset_first(data->nego_formats, NULL));
+        if (r < 0) {
+            pa_log_info("Format negotiation between source output \"%s\" and the default source (%s) failed.",
+                        pa_source_output_get_description(o), source->name);
+            ret = r;
+            goto fail;
+        }
+    }
 
-    if (PA_LIKELY(data->format)) {
-        pa_log_debug("Negotiated format: %s", pa_format_info_snprint(fmt, sizeof(fmt), data->format));
-    } else {
-        pa_format_info *format;
-        uint32_t idx;
+    pa_assert(o->source);
+    pa_assert(o->format);
+
+    /* Modules may want to look at the source and format in the FIXATE hook, so
+     * let's make sure that the new data is in sync with the source output.
+     * Also, pa_source_output_new_data_is_passthrough() uses data->format too,
+     * and we call that function a few times. (XXX: It would probably be better
+     * to pass the source output object to the FIXATE hook instead of the new
+     * data, and replace the pa_source_output_new_data_is_passthrough() usage
+     * with something that uses the source output object instead of the new
+     * data. Then this extra syncing could be removed.) */
+    data->source = o->source;
 
-        pa_log_info("Source does not support any requested format:");
-        PA_IDXSET_FOREACH(format, data->req_formats, idx)
-            pa_log_info(" -- %s", pa_format_info_snprint(fmt, sizeof(fmt), format));
+    if (data->format)
+        pa_format_info_free(data->format);
 
-        ret = -PA_ERR_NOTSUPPORTED;
-        goto fail;
-    }
+    data->format = pa_format_info_copy(o->format);
 
-    /* Now populate the sample spec and format according to the final
-     * format that we've negotiated */
+    /* Routing's done, we have a source and a format. Now populate the sample
+     * spec and channel map according to the final format that we've
+     * negotiated. */
 
-    if (pa_format_info_to_sample_spec(data->format, &ss, &map) < 0) {
+    if (pa_format_info_to_sample_spec(o->format, &ss, &map) < 0) {
         ret = -PA_ERR_INVALID;
         goto fail;
     }
 
     pa_source_output_new_data_set_sample_spec(data, &ss);
-    if (pa_format_info_is_pcm(data->format) && pa_channel_map_valid(&map))
+    if (pa_format_info_is_pcm(o->format) && pa_channel_map_valid(&map))
         pa_source_output_new_data_set_channel_map(data, &map);
 
-    if (!PA_SOURCE_IS_LINKED(pa_source_get_state(data->source))) {
+    if (!PA_SOURCE_IS_LINKED(pa_source_get_state(o->source))) {
         ret = -PA_ERR_BADSTATE;
         goto fail;
     }
 
-    if (data->direct_on_input && data->direct_on_input->sink != data->source->monitor_of) {
+    if (data->direct_on_input && data->direct_on_input->sink != o->source->monitor_of) {
         ret = -PA_ERR_INVALID;
         goto fail;
     }
 
     if (!data->sample_spec_is_set)
-        data->sample_spec = data->source->sample_spec;
+        data->sample_spec = o->source->sample_spec;
 
     if (!pa_sample_spec_valid(&data->sample_spec)) {
         ret = -PA_ERR_INVALID;
@@ -376,8 +401,8 @@ int pa_source_output_new(
     }
 
     if (!data->channel_map_is_set) {
-        if (pa_channel_map_compatible(&data->source->channel_map, &data->sample_spec))
-            data->channel_map = data->source->channel_map;
+        if (pa_channel_map_compatible(&o->source->channel_map, &data->sample_spec))
+            data->channel_map = o->source->channel_map;
         else
             pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
     }
@@ -419,9 +444,9 @@ int pa_source_output_new(
     }
 
     if (!data->volume_factor_source_is_set)
-        pa_cvolume_reset(&data->volume_factor_source, data->source->sample_spec.channels);
+        pa_cvolume_reset(&data->volume_factor_source, o->source->sample_spec.channels);
 
-    if (!pa_cvolume_compatible(&data->volume_factor_source, &data->source->sample_spec)) {
+    if (!pa_cvolume_compatible(&data->volume_factor_source, &o->source->sample_spec)) {
         ret = -PA_ERR_INVALID;
         goto fail;
     }
@@ -430,54 +455,54 @@ int pa_source_output_new(
         data->muted = false;
 
     if (data->flags & PA_SOURCE_OUTPUT_FIX_FORMAT) {
-        if (!pa_format_info_is_pcm(data->format)) {
+        if (!pa_format_info_is_pcm(o->format)) {
             ret = -PA_ERR_INVALID;
             goto fail;
         }
 
-        data->sample_spec.format = data->source->sample_spec.format;
-        pa_format_info_set_sample_format(data->format, data->sample_spec.format);
+        data->sample_spec.format = o->source->sample_spec.format;
+        pa_format_info_set_sample_format(o->format, data->sample_spec.format);
     }
 
     if (data->flags & PA_SOURCE_OUTPUT_FIX_RATE) {
-        if (!pa_format_info_is_pcm(data->format)) {
+        if (!pa_format_info_is_pcm(o->format)) {
             ret = -PA_ERR_INVALID;
             goto fail;
         }
 
-        pa_format_info_set_rate(data->format, data->sample_spec.rate);
-        data->sample_spec.rate = data->source->sample_spec.rate;
+        pa_format_info_set_rate(o->format, data->sample_spec.rate);
+        data->sample_spec.rate = o->source->sample_spec.rate;
     }
 
     original_cm = data->channel_map;
 
     if (data->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) {
-        if (!pa_format_info_is_pcm(data->format)) {
+        if (!pa_format_info_is_pcm(o->format)) {
             ret = -PA_ERR_INVALID;
             goto fail;
         }
 
-        data->sample_spec.channels = data->source->sample_spec.channels;
-        data->channel_map = data->source->channel_map;
-        pa_format_info_set_channels(data->format, data->sample_spec.channels);
-        pa_format_info_set_channel_map(data->format, &data->channel_map);
+        data->sample_spec.channels = o->source->sample_spec.channels;
+        data->channel_map = o->source->channel_map;
+        pa_format_info_set_channels(o->format, data->sample_spec.channels);
+        pa_format_info_set_channel_map(o->format, &data->channel_map);
     }
 
     pa_assert(pa_sample_spec_valid(&data->sample_spec));
     pa_assert(pa_channel_map_valid(&data->channel_map));
 
     if (!(data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) &&
-        !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec)) {
+        !pa_sample_spec_equal(&data->sample_spec, &o->source->sample_spec)) {
         /* try to change source rate. This is done before the FIXATE hook since
            module-suspend-on-idle can resume a source */
 
         pa_log_info("Trying to change sample rate");
-        if (pa_source_update_rate(data->source, data->sample_spec.rate, pa_source_output_new_data_is_passthrough(data)) >= 0)
-            pa_log_info("Rate changed to %u Hz", data->source->sample_spec.rate);
+        if (pa_source_update_rate(o->source, data->sample_spec.rate, pa_source_output_new_data_is_passthrough(data)) >= 0)
+            pa_log_info("Rate changed to %u Hz", o->source->sample_spec.rate);
     }
 
     if (pa_source_output_new_data_is_passthrough(data) &&
-        !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec)) {
+        !pa_sample_spec_equal(&data->sample_spec, &o->source->sample_spec)) {
         /* rate update failed, or other parts of sample spec didn't match */
 
         pa_log_debug("Could not update source sample spec to match passthrough stream");
@@ -502,26 +527,26 @@ int pa_source_output_new(
     }
 
     if ((data->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) &&
-        pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) {
+        pa_source_get_state(o->source) == PA_SOURCE_SUSPENDED) {
         pa_log("Failed to create source output: source is suspended.");
         ret = -PA_ERR_BADSTATE;
         goto fail;
     }
 
-    if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
+    if (pa_idxset_size(o->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
         pa_log("Failed to create source output: too many outputs per source.");
         ret = -PA_ERR_TOOLARGE;
         goto fail;
     }
 
     if ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
-        !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
-        !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) {
+        !pa_sample_spec_equal(&data->sample_spec, &o->source->sample_spec) ||
+        !pa_channel_map_equal(&data->channel_map, &o->source->channel_map)) {
 
         if (!pa_source_output_new_data_is_passthrough(data)) /* no resampler for passthrough content */
             if (!(resampler = pa_resampler_new(
                         core->mempool,
-                        &data->source->sample_spec, &data->source->channel_map,
+                        &o->source->sample_spec, &o->source->channel_map,
                         &data->sample_spec, &data->channel_map,
                         data->resample_method,
                         ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
@@ -535,20 +560,17 @@ int pa_source_output_new(
     }
 
     o->driver = pa_xstrdup(pa_path_get_filename(data->driver));
-    o->source = data->source;
-
     o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
     o->sample_spec = data->sample_spec;
     o->channel_map = data->channel_map;
-    o->format = pa_format_info_copy(data->format);
 
     if (!data->volume_is_absolute && pa_source_flat_volume_enabled(o->source)) {
         pa_cvolume remapped;
 
         /* When the 'absolute' bool is not set then we'll treat the volume
          * as relative to the source volume even in flat volume mode */
-        remapped = data->source->reference_volume;
-        pa_cvolume_remap(&remapped, &data->source->channel_map, &data->channel_map);
+        remapped = o->source->reference_volume;
+        pa_cvolume_remap(&remapped, &o->source->channel_map, &data->channel_map);
         pa_sw_cvolume_multiply(&o->volume, &data->volume, &remapped);
     } else
         o->volume = data->volume;
-- 
1.8.3.1



More information about the pulseaudio-discuss mailing list