From c6d8d1d7c19a105b224eac393e44bae319897b6b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fr=C3=A9d=C3=A9ric=20Dalleau?= Date: Wed, 20 Jun 2012 17:33:35 +0200 Subject: [PATCH] loopback: Enable routing on loopback streams At module-loopback load, if no sink is given, the default sink is used. If the stream has a media.role property, the property cannot be used because a the source or sink is forced to default. Both module-intended-roles and module-device-manager are affected. The same apply to sources. With this patch, if sink or source is missing, routing modules can be used. --- src/modules/module-loopback.c | 115 ++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 26 deletions(-) diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index 1a69445f..9054700c 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -647,15 +647,18 @@ static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { int pa__init(pa_module *m) { pa_modargs *ma = NULL; struct userdata *u; - pa_sink *sink; + pa_sink *sink = NULL; pa_sink_input_new_data sink_input_data; pa_bool_t sink_dont_move; - pa_source *source; + pa_source *source = NULL; pa_source_output_new_data source_output_data; pa_bool_t source_dont_move; uint32_t latency_msec; pa_sample_spec ss; pa_channel_map map; + bool format_set = false; + bool rate_set = false; + bool channels_set = false; pa_memchunk silence; uint32_t adjust_time_sec; const char *n; @@ -668,12 +671,14 @@ int pa__init(pa_module *m) { goto fail; } - if (!(source = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) { + n = pa_modargs_get_value(ma, "source", NULL); + if (n && !(source = pa_namereg_get(m->core, n, PA_NAMEREG_SOURCE))) { pa_log("No such source."); goto fail; } - if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) { + n = pa_modargs_get_value(ma, "sink", NULL); + if (n && !(sink = pa_namereg_get(m->core, n, PA_NAMEREG_SINK))) { pa_log("No such sink."); goto fail; } @@ -683,13 +688,45 @@ int pa__init(pa_module *m) { goto fail; } - ss = sink->sample_spec; - map = sink->channel_map; + if (sink) { + ss = sink->sample_spec; + map = sink->channel_map; + format_set = true; + rate_set = true; + channels_set = true; + } else if (source) { + ss = source->sample_spec; + map = source->channel_map; + format_set = true; + rate_set = true; + channels_set = true; + } else { + /* FIXME: Dummy stream format, needed because pa_sink_input_new() + * requires valid sample spec and channel map even when all the FIX_* + * stream flags are specified. pa_sink_input_new() should be changed + * to ignore the sample spec and channel map when the FIX_* flags are + * present. */ + ss.format = PA_SAMPLE_U8; + ss.rate = 8000; + ss.channels = 1; + map.channels = 1; + map.map[0] = PA_CHANNEL_POSITION_MONO; + } + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("Invalid sample format specification or channel map"); goto fail; } + if (pa_modargs_get_value(ma, "format", NULL)) + format_set = true; + + if (pa_modargs_get_value(ma, "rate", NULL)) + rate_set = true; + + if (pa_modargs_get_value(ma, "channels", NULL) || pa_modargs_get_value(ma, "channel_map", NULL)) + channels_set = true; + latency_msec = DEFAULT_LATENCY_MSEC; if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 2000) { pa_log("Invalid latency specification"); @@ -715,7 +752,9 @@ int pa__init(pa_module *m) { pa_sink_input_new_data_init(&sink_input_data); sink_input_data.driver = __FILE__; sink_input_data.module = m; - pa_sink_input_new_data_set_sink(&sink_input_data, sink, FALSE); + + if (sink) + pa_sink_input_new_data_set_sink(&sink_input_data, sink, FALSE); if (pa_modargs_get_proplist(ma, "sink_input_properties", sink_input_data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Failed to parse the sink_input_properties value."); @@ -723,20 +762,24 @@ int pa__init(pa_module *m) { goto fail; } - if (!pa_proplist_contains(sink_input_data.proplist, PA_PROP_MEDIA_NAME)) - pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback from %s", - pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION))); - if (!pa_proplist_contains(sink_input_data.proplist, PA_PROP_MEDIA_ROLE)) pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); - if (!pa_proplist_contains(sink_input_data.proplist, PA_PROP_MEDIA_ICON_NAME) - && (n = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME))) - pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ICON_NAME, n); - pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); - sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE | (remix ? 0 : PA_SINK_INPUT_NO_REMIX); + sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE; + + if (!remix) + sink_input_data.flags |= PA_SINK_INPUT_NO_REMIX; + + if (!format_set) + sink_input_data.flags |= PA_SINK_INPUT_FIX_FORMAT; + + if (!rate_set) + sink_input_data.flags |= PA_SINK_INPUT_FIX_RATE; + + if (!channels_set) + sink_input_data.flags |= PA_SINK_INPUT_FIX_CHANNELS; sink_dont_move = FALSE; if (pa_modargs_get_value_boolean(ma, "sink_dont_move", &sink_dont_move) < 0) { @@ -770,7 +813,8 @@ int pa__init(pa_module *m) { pa_source_output_new_data_init(&source_output_data); source_output_data.driver = __FILE__; source_output_data.module = m; - pa_source_output_new_data_set_source(&source_output_data, source, FALSE); + if (source) + pa_source_output_new_data_set_source(&source_output_data, source, FALSE); if (pa_modargs_get_proplist(ma, "source_output_properties", source_output_data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Failed to parse the source_output_properties value."); @@ -778,20 +822,23 @@ int pa__init(pa_module *m) { goto fail; } - if (!pa_proplist_contains(source_output_data.proplist, PA_PROP_MEDIA_NAME)) - pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s", - pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION))); - if (!pa_proplist_contains(source_output_data.proplist, PA_PROP_MEDIA_ROLE)) pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); - if (!pa_proplist_contains(source_output_data.proplist, PA_PROP_MEDIA_ICON_NAME) - && (n = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME))) - pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ICON_NAME, n); - pa_source_output_new_data_set_sample_spec(&source_output_data, &ss); pa_source_output_new_data_set_channel_map(&source_output_data, &map); - source_output_data.flags = (remix ? 0 : PA_SOURCE_OUTPUT_NO_REMIX); + + if (!remix) + source_output_data.flags |= PA_SOURCE_OUTPUT_NO_REMIX; + + if (!format_set) + source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_FORMAT; + + if (!rate_set) + source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_RATE; + + if (!channels_set) + source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_CHANNELS; source_dont_move = FALSE; if (pa_modargs_get_value_boolean(ma, "source_dont_move", &source_dont_move) < 0) { @@ -836,6 +883,22 @@ int pa__init(pa_module *m) { u->asyncmsgq = pa_asyncmsgq_new(0); + if (!pa_proplist_contains(u->source_output->proplist, PA_PROP_MEDIA_NAME)) + pa_proplist_setf(u->source_output->proplist, PA_PROP_MEDIA_NAME, "Loopback to %s", + pa_strnull(pa_proplist_gets(u->sink_input->sink->proplist, PA_PROP_DEVICE_DESCRIPTION))); + + if (!pa_proplist_contains(u->source_output->proplist, PA_PROP_MEDIA_ICON_NAME) + && (n = pa_proplist_gets(u->sink_input->sink->proplist, PA_PROP_DEVICE_ICON_NAME))) + pa_proplist_sets(u->source_output->proplist, PA_PROP_MEDIA_ICON_NAME, n); + + if (!pa_proplist_contains(u->sink_input->proplist, PA_PROP_MEDIA_NAME)) + pa_proplist_setf(u->sink_input->proplist, PA_PROP_MEDIA_NAME, "Loopback from %s", + pa_strnull(pa_proplist_gets(u->source_output->source->proplist, PA_PROP_DEVICE_DESCRIPTION))); + + if (source && !pa_proplist_contains(u->sink_input->proplist, PA_PROP_MEDIA_ICON_NAME) + && (n = pa_proplist_gets(u->source_output->source->proplist, PA_PROP_DEVICE_ICON_NAME))) + pa_proplist_sets(u->sink_input->proplist, PA_PROP_MEDIA_ICON_NAME, n); + pa_sink_input_put(u->sink_input); pa_source_output_put(u->source_output); -- 2.11.4.GIT