[pulseaudio-discuss] [PATCH v2 19/21] sink-input, source-output: Allow pa_node_put() to do routing
Tanu Kaskinen
tanu.kaskinen at linux.intel.com
Thu Dec 5 06:19:19 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 0469a15..d045402 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;
@@ -345,8 +345,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;
@@ -365,9 +385,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) {
@@ -375,61 +396,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;
@@ -437,8 +462,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);
}
@@ -475,54 +500,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");
@@ -547,28 +572,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) |
@@ -581,20 +606,18 @@ int pa_sink_input_new(
}
i->driver = pa_xstrdup(pa_path_get_filename(data->driver));
- i->sink = data->sink;
i->requested_resample_method = data->resample_method;
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 28381f5..c050292 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;
@@ -278,8 +278,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;
@@ -298,9 +318,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) {
@@ -319,55 +340,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;
@@ -375,8 +400,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);
}
@@ -418,9 +443,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;
}
@@ -429,54 +454,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");
@@ -501,26 +526,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) |
@@ -534,21 +559,18 @@ int pa_source_output_new(
}
o->driver = pa_xstrdup(pa_path_get_filename(data->driver));
- o->source = data->source;
-
o->requested_resample_method = data->resample_method;
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