From 40d92e9b1ad37f45f555946368eb42c77354819c Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 16 Jan 2019 10:35:45 +0800 Subject: [PATCH] core: move sink-inputs conditionally when update default_sink When the default sink changes, the streams from the old default sink should be moved to the new default sink, unless the preferred_sink string is set to the old default sink and the active port of the old default sink is not unavailable Signed-off-by: Hui Wang --- src/modules/module-switch-on-connect.c | 23 --------------- src/pulsecore/core.c | 4 +++ src/pulsecore/sink.c | 40 ++++++++++++++++++++++++-- src/pulsecore/sink.h | 6 ++++ 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index bde91e42d..74cd977b2 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -57,9 +57,6 @@ struct userdata { }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { - pa_sink_input *i; - uint32_t idx; - pa_sink *old_default_sink; const char *s; struct userdata *u = userdata; @@ -112,29 +109,9 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* return PA_HOOK_OK; } - old_default_sink = c->default_sink; - /* Actually do the switch to the new sink */ pa_core_set_configured_default_sink(c, sink->name); - /* Now move all old inputs over */ - if (pa_idxset_size(old_default_sink->inputs) <= 0) { - pa_log_debug("No sink inputs to move away."); - return PA_HOOK_OK; - } - - PA_IDXSET_FOREACH(i, old_default_sink->inputs, idx) { - if (pa_safe_streq(i->sink->name, i->preferred_sink) || !PA_SINK_INPUT_IS_LINKED(i->state)) - continue; - - if (pa_sink_input_move_to(i, sink, false) < 0) - pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, - pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); - else - pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index, - pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name); - } - return PA_HOOK_OK; } diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index e5bb2e47b..c511c6a18 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -349,6 +349,10 @@ void pa_core_update_default_sink(pa_core *core) { pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); pa_hook_fire(&core->hooks[PA_CORE_HOOK_DEFAULT_SINK_CHANGED], core->default_sink); + + /* try to move the streams from old_default_sink to the new default_sink conditionally */ + if (old_default_sink) + pa_sink_move_streams_to_default_sink(core, old_default_sink); } /* a < b -> return -1 diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 55e9af3e7..f8ce27175 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -724,8 +724,11 @@ void pa_sink_put(pa_sink* s) { pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s); - /* This function must be called after the PA_CORE_HOOK_SINK_PUT hook, - * because module-switch-on-connect needs to know the old default sink */ + /* It's good to fire the SINK_PUT hook before updating the default sink, + * because module-switch-on-connect will set the new sink as the default + * sink, and if we were to call pa_core_update_default_sink() before that, + * the default sink might change twice, causing unnecessary stream moving. */ + pa_core_update_default_sink(s->core); } @@ -3931,3 +3934,36 @@ void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume) { pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], s); } + +void pa_sink_move_streams_to_default_sink(pa_core *core, pa_sink *old_sink) { + pa_sink_input *i; + uint32_t idx; + bool old_sink_is_unavailable = false; + + pa_assert(core); + pa_assert(old_sink); + + if (core->default_sink == NULL || core->default_sink->unlink_requested) + return; + + if (old_sink == core->default_sink) + return; + + if (old_sink->active_port && old_sink->active_port->available == PA_AVAILABLE_NO) + old_sink_is_unavailable = true; + + PA_IDXSET_FOREACH(i, old_sink->inputs, idx) { + if (!PA_SINK_INPUT_IS_LINKED(i->state)) + continue; + + if (!i->sink) + continue; + + if (pa_safe_streq(old_sink->name, i->preferred_sink) && !old_sink_is_unavailable) + continue; + + pa_log_info("The sink input %u \"%s\" is moving to %s due to change of the default sink.", + i->index, pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), core->default_sink->name); + pa_sink_input_move_to(i, core->default_sink, false); + } +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index b9dd64f6f..7a72937c3 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -558,6 +558,12 @@ int64_t pa_sink_get_latency_within_thread(pa_sink *s, bool allow_negative); * s->reference_volume and fires change notifications. */ void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume); +/* When the default_sink is changed or the active_port of a sink is changed to + * PA_AVAILABLE_NO, this function is called to move the streams of the old + * default_sink or the sink with active_port equals PA_AVAILABLE_NO to the + * current default_sink conditionally*/ +void pa_sink_move_streams_to_default_sink(pa_core *core, pa_sink *old_sink); + /* Verify that we called in IO context (aka 'thread context), or that * the sink is not yet set up, i.e. the thread not set up yet. See * pa_assert_io_context() in thread-mq.h for more information. */