Prior to this patch the initial routing for a sink input could be set by setting the sink for the input, and for a source output by setting the source or direct_on_input for the output. Now the initial routing is configured by setting requested connections (nodes) for the input or output. Previously, when configuring the sink or source, it was possible to specify if the initial device should be saved. Now it's not possible, so newly created streams always have the "save_sink" or "save_source" field set to false. This doesn't have any practical effects, however. "save" was set to true only by module-stream-restore. The only effect of setting "save" to true is that module-stream-restore then saves the stream's device in the stream database, but if module-stream-restore is setting the device for a newly created stream, it means that the device is already in the database. There's no point in writing it there again. --- src/modules/echo-cancel/module-echo-cancel.c | 4 +- src/modules/module-combine-sink.c | 2 +- src/modules/module-device-manager.c | 11 ++-- src/modules/module-intended-roles.c | 12 ++--- src/modules/module-ladspa-sink.c | 2 +- src/modules/module-loopback.c | 4 +- src/modules/module-remap-sink.c | 2 +- src/modules/module-remap-source.c | 2 +- src/modules/module-sine.c | 2 +- src/modules/module-stream-restore.c | 13 ++--- src/modules/module-virtual-sink.c | 2 +- src/modules/module-virtual-source.c | 2 +- src/modules/module-virtual-surround-sink.c | 2 +- src/modules/rtp/module-rtp-recv.c | 2 +- src/modules/rtp/module-rtp-send.c | 2 +- src/pulsecore/play-memblockq.c | 2 +- src/pulsecore/protocol-esound.c | 4 +- src/pulsecore/protocol-http.c | 2 +- src/pulsecore/protocol-native.c | 77 ++++++++++++++++++++++------ src/pulsecore/protocol-simple.c | 4 +- src/pulsecore/sink-input.c | 39 +++++++++----- src/pulsecore/sink-input.h | 8 ++- src/pulsecore/sound-file-stream.c | 2 +- src/pulsecore/source-output.c | 46 +++++++++-------- src/pulsecore/source-output.h | 9 ++-- 25 files changed, 158 insertions(+), 99 deletions(-) diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c index 84116f7..b120f4d 100644 --- a/src/modules/echo-cancel/module-echo-cancel.c +++ b/src/modules/echo-cancel/module-echo-cancel.c @@ -1859,13 +1859,13 @@ 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_master, false); source_output_data.destination_source = u->source; pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Echo-Cancel Source Stream"); pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_source_output_new_data_set_sample_spec(&source_output_data, &source_output_ss); pa_source_output_new_data_set_channel_map(&source_output_data, &source_output_map); + pa_source_output_new_data_set_requested_connection(&source_output_data, pa_source_get_node(source_master)); pa_source_output_new(&u->source_output, m->core, &source_output_data); pa_source_output_new_data_done(&source_output_data); @@ -1894,12 +1894,12 @@ 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_master, false); sink_input_data.origin_sink = u->sink; pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Echo-Cancel Sink Stream"); pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &sink_ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &sink_map); + pa_sink_input_new_data_set_requested_connection(&sink_input_data, pa_sink_get_node(sink_master)); sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE; pa_sink_input_new(&u->sink_input, m->core, &sink_input_data); diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c index da9a424..30ee286 100644 --- a/src/modules/module-combine-sink.c +++ b/src/modules/module-combine-sink.c @@ -855,12 +855,12 @@ static int output_create_sink_input(struct output *o) { return 0; pa_sink_input_new_data_init(&data); - pa_sink_input_new_data_set_sink(&data, o->sink, false); data.driver = __FILE__; pa_proplist_setf(data.proplist, PA_PROP_MEDIA_NAME, "Simultaneous output on %s", pa_sink_get_description(o->sink)); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&data, &o->userdata->sink->sample_spec); pa_sink_input_new_data_set_channel_map(&data, &o->userdata->sink->channel_map); + pa_sink_input_new_data_set_requested_connection(&data, pa_sink_get_node(o->sink)); data.module = o->userdata->module; data.resample_method = o->userdata->resample_method; data.flags = PA_SINK_INPUT_VARIABLE_RATE|PA_SINK_INPUT_DONT_MOVE|PA_SINK_INPUT_NO_CREATE_ON_SUSPEND; diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c index 4740051..19fe949 100644 --- a/src/modules/module-device-manager.c +++ b/src/modules/module-device-manager.c @@ -950,7 +950,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n if (!u->do_routing) return PA_HOOK_OK; - if (new_data->sink) + if (new_data->n_requested_connections > 0) pa_log_debug("Not restoring device for stream because already set."); else { if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE))) @@ -966,7 +966,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n pa_sink *sink; if ((sink = pa_idxset_get_by_index(u->core->sinks, device_index))) - pa_sink_input_new_data_set_sink(new_data, sink, false); + pa_sink_input_new_data_set_requested_connection(new_data, pa_sink_get_node(sink)); } } } @@ -985,10 +985,7 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou if (!u->do_routing) return PA_HOOK_OK; - if (new_data->direct_on_input) - return PA_HOOK_OK; - - if (new_data->source) + if (new_data->n_requested_connections > 0) pa_log_debug("Not restoring device for stream because already set."); else { if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE))) @@ -1004,7 +1001,7 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou pa_source *source; if ((source = pa_idxset_get_by_index(u->core->sources, device_index))) - pa_source_output_new_data_set_source(new_data, source, false); + pa_source_output_new_data_set_requested_connection(new_data, pa_source_get_node(source)); } } } diff --git a/src/modules/module-intended-roles.c b/src/modules/module-intended-roles.c index 19bee2d..9619bcb 100644 --- a/src/modules/module-intended-roles.c +++ b/src/modules/module-intended-roles.c @@ -83,7 +83,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n return PA_HOOK_OK; } - if (new_data->sink) { + if (new_data->n_requested_connections > 0) { pa_log_debug("Not setting device for stream %s, because already set.", pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME))); return PA_HOOK_OK; } @@ -96,7 +96,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n /* Prefer the default sink over any other sink, just in case... */ if ((def = pa_namereg_get_default_sink(c))) { if (role_match(def->proplist, role)) { - pa_sink_input_new_data_set_sink(new_data, def, false); + pa_sink_input_new_data_set_requested_connection(new_data, pa_sink_get_node(def)); return PA_HOOK_OK; } } @@ -110,7 +110,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n continue; if (role_match(s->proplist, role)) { - pa_sink_input_new_data_set_sink(new_data, s, false); + pa_sink_input_new_data_set_requested_connection(new_data, pa_sink_get_node(s)); return PA_HOOK_OK; } } @@ -132,7 +132,7 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou return PA_HOOK_OK; } - if (new_data->source) { + if (new_data->n_requested_connections > 0) { pa_log_debug("Not setting device for stream %s, because already set.", pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME))); return PA_HOOK_OK; } @@ -145,7 +145,7 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou /* Prefer the default source over any other source, just in case... */ if ((def = pa_namereg_get_default_source(c))) if (role_match(def->proplist, role)) { - pa_source_output_new_data_set_source(new_data, def, false); + pa_source_output_new_data_set_requested_connection(new_data, pa_source_get_node(def)); return PA_HOOK_OK; } @@ -161,7 +161,7 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou /* @todo: favour the highest priority device, not the first one we find? */ if (role_match(s->proplist, role)) { - pa_source_output_new_data_set_source(new_data, s, false); + pa_source_output_new_data_set_requested_connection(new_data, pa_source_get_node(s)); return PA_HOOK_OK; } } diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 320b106..3cf56a9 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -1252,12 +1252,12 @@ 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, master, false); sink_input_data.origin_sink = u->sink; pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "LADSPA Stream"); pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); + pa_sink_input_new_data_set_requested_connection(&sink_input_data, pa_sink_get_node(master)); pa_sink_input_new(&u->sink_input, m->core, &sink_input_data); pa_sink_input_new_data_done(&sink_input_data); diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index 4353061..fe8557b 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -837,7 +837,7 @@ int pa__init(pa_module *m) { sink_input_data.module = m; if (sink) - pa_sink_input_new_data_set_sink(&sink_input_data, sink, false); + pa_sink_input_new_data_set_requested_connection(&sink_input_data, pa_sink_get_node(sink)); 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."); @@ -904,7 +904,7 @@ int pa__init(pa_module *m) { source_output_data.driver = __FILE__; source_output_data.module = m; if (source) - pa_source_output_new_data_set_source(&source_output_data, source, false); + pa_source_output_new_data_set_requested_connection(&source_output_data, pa_source_get_node(source)); 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."); diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 0c08822..1273a2f 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -405,12 +405,12 @@ 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, master, false); sink_input_data.origin_sink = u->sink; pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Remapped Stream"); pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &stream_map); + pa_sink_input_new_data_set_requested_connection(&sink_input_data, pa_sink_get_node(master)); sink_input_data.flags = (remix ? 0 : PA_SINK_INPUT_NO_REMIX); pa_sink_input_new(&u->sink_input, m->core, &sink_input_data); diff --git a/src/modules/module-remap-source.c b/src/modules/module-remap-source.c index 2b6236c..68413f1 100644 --- a/src/modules/module-remap-source.c +++ b/src/modules/module-remap-source.c @@ -350,13 +350,13 @@ 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, master, false); source_output_data.destination_source = u->source; pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Remapped Stream"); pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_source_output_new_data_set_sample_spec(&source_output_data, &ss); pa_source_output_new_data_set_channel_map(&source_output_data, &stream_map); + pa_source_output_new_data_set_requested_connection(&source_output_data, pa_source_get_node(master)); source_output_data.flags = remix ? 0 : PA_SOURCE_OUTPUT_NO_REMIX; pa_source_output_new(&u->source_output, m->core, &source_output_data); diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 573a7c0..dee7ff9 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -155,11 +155,11 @@ int pa__init(pa_module*m) { pa_sink_input_new_data_init(&data); data.driver = __FILE__; data.module = m; - pa_sink_input_new_data_set_sink(&data, sink, false); pa_proplist_setf(data.proplist, PA_PROP_MEDIA_NAME, "%u Hz Sine", frequency); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); pa_proplist_setf(data.proplist, "sine.hz", "%u", frequency); pa_sink_input_new_data_set_sample_spec(&data, &ss); + pa_sink_input_new_data_set_requested_connection(&data, pa_sink_get_node(sink)); pa_sink_input_new(&u->sink_input, m->core, &data); pa_sink_input_new_data_done(&data); diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 33e04f6..de146ba 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -1423,8 +1423,8 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n if (!(name = pa_proplist_get_stream_group(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY))) return PA_HOOK_OK; - if (new_data->sink) - pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name, new_data->sink->name); + if (new_data->n_requested_connections > 0) + pa_log_debug("Not restoring device for stream %s, because already set.", name); else if ((e = entry_read(u, name))) { pa_sink *s = NULL; @@ -1443,7 +1443,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n interfere with that */ if (s && PA_SINK_IS_LINKED(pa_sink_get_state(s))) { pa_log_info("Restoring device for stream %s.", name); - pa_sink_input_new_data_set_sink(new_data, s, true); + pa_sink_input_new_data_set_requested_connection(new_data, pa_sink_get_node(s)); } entry_free(e); @@ -1514,13 +1514,10 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou pa_assert(u); pa_assert(u->restore_device); - if (new_data->direct_on_input) - return PA_HOOK_OK; - if (!(name = pa_proplist_get_stream_group(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY))) return PA_HOOK_OK; - if (new_data->source) + if (new_data->n_requested_connections > 0) pa_log_debug("Not restoring device for stream %s, because already set", name); else if ((e = entry_read(u, name))) { pa_source *s = NULL; @@ -1540,7 +1537,7 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou interfere with that */ if (s && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) { pa_log_info("Restoring device for stream %s.", name); - pa_source_output_new_data_set_source(new_data, s, true); + pa_source_output_new_data_set_requested_connection(new_data, pa_source_get_node(s)); } entry_free(e); diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c index 165cc7f..d36a2a1 100644 --- a/src/modules/module-virtual-sink.c +++ b/src/modules/module-virtual-sink.c @@ -567,7 +567,7 @@ 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, master, false); + pa_sink_input_new_data_set_requested_connection(&sink_input_data, pa_sink_get_node(master)); sink_input_data.origin_sink = u->sink; pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Sink Stream from %s", pa_sink_get_description(u->sink)); diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c index e71a9b6..5f567d2 100644 --- a/src/modules/module-virtual-source.c +++ b/src/modules/module-virtual-source.c @@ -576,7 +576,7 @@ 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, master, false); + pa_source_output_new_data_set_requested_connection(&source_output_data, pa_source_get_node(master)); source_output_data.destination_source = u->source; pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, diff --git a/src/modules/module-virtual-surround-sink.c b/src/modules/module-virtual-surround-sink.c index ed9dbaa..2c6758f 100644 --- a/src/modules/module-virtual-surround-sink.c +++ b/src/modules/module-virtual-surround-sink.c @@ -669,7 +669,7 @@ 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, master, false); + pa_sink_input_new_data_set_requested_connection(&sink_input_data, pa_sink_get_node(master)); sink_input_data.origin_sink = u->sink; pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Surround Sink Stream from %s", pa_sink_get_description(u->sink)); diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index a4f7733..211a198 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -519,7 +519,6 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in goto fail; pa_sink_input_new_data_init(&data); - pa_sink_input_new_data_set_sink(&data, sink, false); data.driver = __FILE__; pa_proplist_sets(data.proplist, PA_PROP_MEDIA_ROLE, "stream"); pa_proplist_setf(data.proplist, PA_PROP_MEDIA_NAME, @@ -534,6 +533,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_proplist_setf(data.proplist, "rtp.payload", "%u", (unsigned) sdp_info->payload); data.module = u->module; pa_sink_input_new_data_set_sample_spec(&data, &sdp_info->sample_spec); + pa_sink_input_new_data_set_requested_connection(&data, pa_sink_get_node(sink)); data.flags = PA_SINK_INPUT_VARIABLE_RATE; pa_sink_input_new(&s->sink_input, u->module->core, &data); diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 7f05277..81ced18 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -368,9 +368,9 @@ int pa__init(pa_module*m) { pa_proplist_setf(data.proplist, "rtp.ttl", "%lu", (unsigned long) ttl); data.driver = __FILE__; data.module = m; - pa_source_output_new_data_set_source(&data, s, false); pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); + pa_source_output_new_data_set_requested_connection(&data, pa_source_get_node(s)); data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; pa_source_output_new(&o, m->core, &data); diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index ff0c52b..55889d2 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -199,11 +199,11 @@ pa_sink_input* pa_memblockq_sink_input_new( u->memblockq = NULL; pa_sink_input_new_data_init(&data); - pa_sink_input_new_data_set_sink(&data, sink, false); data.driver = __FILE__; pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_channel_map(&data, map); pa_sink_input_new_data_set_volume(&data, volume); + pa_sink_input_new_data_set_requested_connection(&data, pa_sink_get_node(sink)); pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p); data.flags |= flags; diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 7c1b7a2..8c81dd2 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -425,7 +425,7 @@ static int esd_proto_stream_play(connection *c, esd_proto_t request, const void sdata.module = c->options->module; sdata.client = c->client; if (sink) - pa_sink_input_new_data_set_sink(&sdata, sink, false); + pa_sink_input_new_data_set_requested_connection(&sdata, pa_sink_get_node(sink)); pa_sink_input_new_data_set_sample_spec(&sdata, &ss); pa_sink_input_new(&c->sink_input, c->protocol->core, &sdata); @@ -525,7 +525,7 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi sdata.module = c->options->module; sdata.client = c->client; if (source) - pa_source_output_new_data_set_source(&sdata, source, false); + pa_source_output_new_data_set_requested_connection(&sdata, pa_source_get_node(source)); pa_source_output_new_data_set_sample_spec(&sdata, &ss); pa_source_output_new(&c->source_output, c->protocol->core, &sdata); diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c index c2d9b60..cf15e5d 100644 --- a/src/pulsecore/protocol-http.c +++ b/src/pulsecore/protocol-http.c @@ -561,10 +561,10 @@ static void handle_listen_prefix(struct connection *c, const char *source_name) data.driver = __FILE__; data.module = c->module; data.client = c->client; - pa_source_output_new_data_set_source(&data, source, false); pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); + pa_source_output_new_data_set_requested_connection(&data, pa_source_get_node(source)); pa_source_output_new(&c->source_output, c->protocol->core, &data); pa_source_output_new_data_done(&data); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index f41f2f3..ec8cee7 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -633,7 +633,8 @@ static void fix_record_buffer_attr_post(record_stream *s) { /* Called from main context */ static record_stream* record_stream_new( pa_native_connection *c, - pa_source *source, + pa_node * const *requested_connections, + unsigned n_requested_connections, pa_sample_spec *ss, pa_channel_map *map, pa_idxset *formats, @@ -647,7 +648,6 @@ static record_stream* record_stream_new( bool early_requests, bool relative_volume, bool peak_detect, - pa_sink_input *direct_on_input, int *ret) { record_stream *s; @@ -656,6 +656,7 @@ static record_stream* record_stream_new( char *memblockq_name; pa_assert(c); + pa_assert(requested_connections || n_requested_connections == 0); pa_assert(ss); pa_assert(p); pa_assert(ret); @@ -666,15 +667,14 @@ static record_stream* record_stream_new( data.driver = __FILE__; data.module = c->options->module; data.client = c->client; - if (source) - pa_source_output_new_data_set_source(&data, source, false); + if (n_requested_connections > 0) + pa_source_output_new_data_set_requested_connections(&data, requested_connections, n_requested_connections); if (pa_sample_spec_valid(ss)) pa_source_output_new_data_set_sample_spec(&data, ss); if (pa_channel_map_valid(map)) pa_source_output_new_data_set_channel_map(&data, map); if (formats) pa_source_output_new_data_set_formats(&data, formats); - data.direct_on_input = direct_on_input; if (volume) { pa_source_output_new_data_set_volume(&data, volume); data.volume_is_absolute = !relative_volume; @@ -1074,7 +1074,8 @@ static void fix_playback_buffer_attr(playback_stream *s) { /* Called from main context */ static playback_stream* playback_stream_new( pa_native_connection *c, - pa_sink *sink, + pa_node * const *requested_connections, + unsigned n_requested_connections, pa_sample_spec *ss, pa_channel_map *map, pa_idxset *formats, @@ -1095,6 +1096,7 @@ static playback_stream* playback_stream_new( * to take extra care to not leak it */ playback_stream *ssync; + pa_node *sink_node; playback_stream *s = NULL; pa_sink_input *sink_input = NULL; pa_memchunk silence; @@ -1104,6 +1106,7 @@ static playback_stream* playback_stream_new( char *memblockq_name; pa_assert(c); + pa_assert(requested_connections || n_requested_connections == 0); pa_assert(ss); pa_assert(missing); pa_assert(p); @@ -1121,10 +1124,12 @@ static playback_stream* playback_stream_new( /* Synced streams must connect to the same sink */ if (ssync) { + sink_node = pa_sink_get_node(ssync->sink_input->sink); - if (!sink) - sink = ssync->sink_input->sink; - else if (sink != ssync->sink_input->sink) { + if (n_requested_connections == 0) { + requested_connections = &sink_node; + n_requested_connections = 1; + } else if (requested_connections[0] != sink_node || n_requested_connections > 1) { *ret = PA_ERR_INVALID; goto out; } @@ -1136,8 +1141,8 @@ static playback_stream* playback_stream_new( data.driver = __FILE__; data.module = c->options->module; data.client = c->client; - if (sink) - pa_sink_input_new_data_set_sink(&data, sink, false); + if (n_requested_connections > 0) + pa_sink_input_new_data_set_requested_connections(&data, requested_connections, n_requested_connections); if (pa_sample_spec_valid(ss)) pa_sink_input_new_data_set_sample_spec(&data, ss); if (pa_channel_map_valid(map)) @@ -1981,6 +1986,8 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u pa_channel_map map; pa_tagstruct *reply; pa_sink *sink = NULL; + pa_node **nodes = NULL; + uint32_t n_nodes = 0; pa_cvolume volume; bool corked = false, @@ -2159,6 +2166,15 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u } } + if (sink) { + pa_node *sink_node; + + pa_assert(n_nodes == 0); + sink_node = pa_sink_get_node(sink); + nodes = pa_xmemdup(&sink_node, sizeof(pa_node *)); + n_nodes = 1; + } + flags = (corked ? PA_SINK_INPUT_START_CORKED : 0) | (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) | @@ -2176,7 +2192,8 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u * flag. For older versions we synthesize it here */ muted_set = muted_set || muted; - s = playback_stream_new(c, sink, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, syncid, &missing, &ret); + s = playback_stream_new(c, nodes, n_nodes, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, + p, adjust_latency, early_requests, relative_volume, syncid, &missing, &ret); /* We no longer own the formats idxset */ formats = NULL; @@ -2232,6 +2249,8 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u pa_pstream_send_tagstruct(c->pstream, reply); finish: + pa_xfree(nodes); + if (p) pa_proplist_free(p); if (formats) @@ -2306,6 +2325,8 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin pa_channel_map map; pa_tagstruct *reply; pa_source *source = NULL; + pa_node **nodes = NULL; + unsigned n_nodes = 0; pa_cvolume volume; bool corked = false, @@ -2463,6 +2484,16 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin goto finish; } + if (direct_on_input_idx != PA_INVALID_INDEX) { + if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + goto finish; + } + + nodes = pa_xmemdup(&direct_on_input->node, sizeof(pa_node *)); + n_nodes = 1; + } + if (source_index != PA_INVALID_INDEX) { if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) { @@ -2478,12 +2509,21 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin } } - if (direct_on_input_idx != PA_INVALID_INDEX) { - - if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + if (source) { + if (direct_on_input && source != direct_on_input->sink->monitor_source) { + pa_log_info("Source is incompatible with direct_on_input."); + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); goto finish; + } else if (!direct_on_input) { + pa_node *source_node; + + pa_assert(n_nodes == 0); + source_node = pa_source_get_node(source); + nodes = pa_xmemdup(&source_node, sizeof(pa_node *)); + n_nodes = 1; } + + pa_assert(n_nodes > 0); } flags = @@ -2499,7 +2539,8 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) | (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0); - s = record_stream_new(c, source, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, peak_detect, direct_on_input, &ret); + s = record_stream_new(c, nodes, n_nodes, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, + p, adjust_latency, early_requests, relative_volume, peak_detect, &ret); CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish); @@ -2546,6 +2587,8 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin pa_pstream_send_tagstruct(c->pstream, reply); finish: + pa_xfree(nodes); + if (p) pa_proplist_free(p); if (formats) diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index fc36880..a4142e7 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -536,9 +536,9 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp data.driver = __FILE__; data.module = o->module; data.client = c->client; - pa_sink_input_new_data_set_sink(&data, sink, false); pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); pa_sink_input_new_data_set_sample_spec(&data, &o->sample_spec); + pa_sink_input_new_data_set_requested_connection(&data, pa_sink_get_node(sink)); pa_sink_input_new(&c->sink_input, p->core, &data); pa_sink_input_new_data_done(&data); @@ -592,9 +592,9 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp data.driver = __FILE__; data.module = o->module; data.client = c->client; - pa_source_output_new_data_set_source(&data, source, false); pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); pa_source_output_new_data_set_sample_spec(&data, &o->sample_spec); + pa_source_output_new_data_set_requested_connection(&data, pa_source_get_node(source)); pa_source_output_new(&c->source_output, p->core, &data); pa_source_output_new_data_done(&data); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index cecdf3e..ad3dc6e 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -173,14 +173,6 @@ void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, bool mute) { data->muted = !!mute; } -void pa_sink_input_new_data_set_sink(pa_sink_input_new_data *data, pa_sink *s, bool save) { - pa_assert(data); - pa_assert(s); - - data->sink = s; - data->save_sink = save; -} - void pa_sink_input_new_data_set_formats(pa_sink_input_new_data *data, pa_idxset *formats) { pa_assert(data); pa_assert(formats); @@ -191,6 +183,28 @@ void pa_sink_input_new_data_set_formats(pa_sink_input_new_data *data, pa_idxset data->req_formats = formats; } +void pa_sink_input_new_data_set_requested_connections(pa_sink_input_new_data *data, pa_node * const *connections, + unsigned n_connections) { + pa_assert(data); + + pa_xfree(data->requested_connections); + data->n_requested_connections = n_connections; + + if (n_connections == 0) + data->requested_connections = NULL; + else + data->requested_connections = pa_xmemdup(connections, n_connections * sizeof(pa_node *)); +} + +void pa_sink_input_new_data_set_requested_connection(pa_sink_input_new_data *data, pa_node *connection) { + pa_assert(data); + + if (connection) + pa_sink_input_new_data_set_requested_connections(data, &connection, 1); + else + pa_sink_input_new_data_set_requested_connections(data, NULL, 0); +} + void pa_sink_input_new_data_done(pa_sink_input_new_data *data) { pa_assert(data); @@ -205,6 +219,7 @@ void pa_sink_input_new_data_done(pa_sink_input_new_data *data) { if (data->volume_factor_sink_items) pa_hashmap_free(data->volume_factor_sink_items); + pa_xfree(data->requested_connections); pa_proplist_free(data->proplist); } @@ -245,7 +260,6 @@ int pa_sink_input_new( char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_channel_map original_cm; int r; - pa_node *sink_node = NULL; char *pt; char *memblockq_name; pa_sample_spec ss; @@ -297,9 +311,6 @@ int pa_sink_input_new( goto fail; } - if (data->sink) - sink_node = pa_sink_get_node(data->sink); - i->req_formats = pa_idxset_copy(data->req_formats, (pa_copy_func_t) pa_format_info_copy); if (data->driver && !pa_utf8_valid(data->driver)) { @@ -321,7 +332,7 @@ int pa_sink_input_new( i->node->owner = i; /* This will set i->sink and i->format. */ - r = pa_node_put(i->node, &sink_node, sink_node ? 1 : 0); + r = pa_node_put(i->node, data->requested_connections, data->n_requested_connections); if (r < 0) { ret = r; @@ -334,6 +345,7 @@ int pa_sink_input_new( /* Modules may want to access the sink in the FIXATE hook, so let's make * the sink available in the new data. FIXME: It would be cleaner to just * pass the real sink input object to the FIXATE hook. */ + pa_assert(!data->sink); data->sink = i->sink; /* Routing's done, we have a sink and a format. Now populate the sample @@ -547,7 +559,6 @@ int pa_sink_input_new( pa_cvolume_reset(&i->real_ratio, i->sample_spec.channels); i->volume_writable = data->volume_writable; i->save_volume = data->save_volume; - i->save_sink = data->save_sink; i->save_muted = data->save_muted; i->muted = data->muted; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 9c29408..9f7fbe5 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -290,6 +290,8 @@ typedef struct pa_sink_input_new_data { pa_client *client; pa_sink *sink; + pa_node **requested_connections; + unsigned n_requested_connections; pa_sink *origin_sink; pa_resample_method_t resample_method; @@ -314,7 +316,7 @@ typedef struct pa_sink_input_new_data { bool volume_writable:1; - bool save_sink:1, save_volume:1, save_muted:1; + bool save_volume:1, save_muted:1; pa_node_new_data node_data; } pa_sink_input_new_data; @@ -326,8 +328,10 @@ void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cv void pa_sink_input_new_data_add_volume_factor(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor); void pa_sink_input_new_data_add_volume_factor_sink(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor); void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, bool mute); -void pa_sink_input_new_data_set_sink(pa_sink_input_new_data *data, pa_sink *s, bool save); void pa_sink_input_new_data_set_formats(pa_sink_input_new_data *data, pa_idxset *formats); +void pa_sink_input_new_data_set_requested_connections(pa_sink_input_new_data *data, pa_node * const *connections, + unsigned n_connections); +void pa_sink_input_new_data_set_requested_connection(pa_sink_input_new_data *data, pa_node *connection); void pa_sink_input_new_data_done(pa_sink_input_new_data *data); /* To be called by the implementing module only */ diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 33f7337..214bb9c 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -298,11 +298,11 @@ int pa_play_file( u->readf_function = pa_sndfile_readf_function(&ss); pa_sink_input_new_data_init(&data); - pa_sink_input_new_data_set_sink(&data, sink, false); data.driver = __FILE__; pa_sink_input_new_data_set_sample_spec(&data, &ss); pa_sink_input_new_data_set_channel_map(&data, &cm); pa_sink_input_new_data_set_volume(&data, volume); + pa_sink_input_new_data_set_requested_connection(&data, pa_sink_get_node(sink)); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname)); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname); pa_sndfile_init_proplist(u->sndfile, data.proplist); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index ed46a41..f243e8d 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -117,14 +117,6 @@ void pa_source_output_new_data_set_muted(pa_source_output_new_data *data, bool m data->muted = !!mute; } -void pa_source_output_new_data_set_source(pa_source_output_new_data *data, pa_source *s, bool save) { - pa_assert(data); - pa_assert(s); - - data->source = s; - data->save_source = save; -} - void pa_source_output_new_data_set_formats(pa_source_output_new_data *data, pa_idxset *formats) { pa_assert(data); pa_assert(formats); @@ -135,6 +127,28 @@ void pa_source_output_new_data_set_formats(pa_source_output_new_data *data, pa_i data->req_formats = formats; } +void pa_source_output_new_data_set_requested_connections(pa_source_output_new_data *data, pa_node * const *connections, + unsigned n_connections) { + pa_assert(data); + + pa_xfree(data->requested_connections); + data->n_requested_connections = n_connections; + + if (n_connections == 0) + data->requested_connections = NULL; + else + data->requested_connections = pa_xmemdup(connections, n_connections * sizeof(pa_node *)); +} + +void pa_source_output_new_data_set_requested_connection(pa_source_output_new_data *data, pa_node *connection) { + pa_assert(data); + + if (connection) + pa_source_output_new_data_set_requested_connections(data, &connection, 1); + else + pa_source_output_new_data_set_requested_connections(data, NULL, 0); +} + void pa_source_output_new_data_done(pa_source_output_new_data *data) { pa_assert(data); @@ -143,6 +157,7 @@ void pa_source_output_new_data_done(pa_source_output_new_data *data) { if (data->req_formats) pa_idxset_free(data->req_formats, (pa_free_cb_t) pa_format_info_free); + pa_xfree(data->requested_connections); pa_proplist_free(data->proplist); } @@ -181,7 +196,6 @@ int pa_source_output_new( char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_channel_map original_cm; int r; - pa_node *source_node; char *pt; pa_sample_spec ss; pa_channel_map map; @@ -202,11 +216,9 @@ int pa_source_output_new( o->module = data->module; o->client = data->client; o->destination_source = data->destination_source; - o->direct_on_input = data->direct_on_input; o->thread_info.state = o->state; o->thread_info.requested_source_latency = (pa_usec_t) -1; - o->thread_info.direct_on_input = o->direct_on_input; if (data->client) pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); @@ -230,9 +242,6 @@ int pa_source_output_new( goto fail; } - if (data->source) - source_node = pa_source_get_node(data->source); - o->req_formats = pa_idxset_copy(data->req_formats, (pa_copy_func_t) pa_format_info_copy); if (data->driver && !pa_utf8_valid(data->driver)) { @@ -254,7 +263,7 @@ int pa_source_output_new( o->node->owner = o; /* This will set o->source and o->format. */ - r = pa_node_put(o->node, &source_node, source_node ? 1 : 0); + r = pa_node_put(o->node, data->requested_connections, data->n_requested_connections); if (r < 0) { ret = r; @@ -267,6 +276,7 @@ int pa_source_output_new( /* Modules may want to access the source in the FIXATE hook, so let's make * the source available in the new data. FIXME: It would be cleaner to just * pass the real source output object to the FIXATE hook. */ + pa_assert(!data->source); data->source = o->source; /* Routing's done, we have a source and a format. Now populate the sample @@ -287,11 +297,6 @@ int pa_source_output_new( goto fail; } - 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 = o->source->sample_spec; @@ -483,7 +488,6 @@ int pa_source_output_new( pa_cvolume_reset(&o->real_ratio, o->sample_spec.channels); o->volume_writable = data->volume_writable; o->save_volume = data->save_volume; - o->save_source = data->save_source; o->save_muted = data->save_muted; o->muted = data->muted; diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 3119a66..ce511dd 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -242,13 +242,14 @@ typedef struct pa_source_output_new_data { pa_source_output_flags_t flags; pa_proplist *proplist; - pa_sink_input *direct_on_input; const char *driver; pa_module *module; pa_client *client; pa_source *source; + pa_node **requested_connections; + unsigned n_requested_connections; pa_source *destination_source; pa_resample_method_t resample_method; @@ -270,7 +271,7 @@ typedef struct pa_source_output_new_data { bool volume_writable:1; - bool save_source:1, save_volume:1, save_muted:1; + bool save_volume:1, save_muted:1; pa_node_new_data node_data; } pa_source_output_new_data; @@ -282,8 +283,10 @@ void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const void pa_source_output_new_data_apply_volume_factor(pa_source_output_new_data *data, const pa_cvolume *volume_factor); void pa_source_output_new_data_apply_volume_factor_source(pa_source_output_new_data *data, const pa_cvolume *volume_factor); void pa_source_output_new_data_set_muted(pa_source_output_new_data *data, bool mute); -void pa_source_output_new_data_set_source(pa_source_output_new_data *data, pa_source *s, bool save); void pa_source_output_new_data_set_formats(pa_source_output_new_data *data, pa_idxset *formats); +void pa_source_output_new_data_set_requested_connections(pa_source_output_new_data *data, pa_node * const *connections, + unsigned n_connections); +void pa_source_output_new_data_set_requested_connection(pa_source_output_new_data *data, pa_node *connection); void pa_source_output_new_data_done(pa_source_output_new_data *data); /* To be called by the implementing module only */ -- 1.8.3.1