core: move sink-inputs conditionally when update default_sink
authorHui Wang <hui.wang@canonical.com>
Wed, 16 Jan 2019 02:35:45 +0000 (10:35 +0800)
committerHui Wang <hui.wang@canonical.com>
Wed, 27 Nov 2019 04:09:21 +0000 (12:09 +0800)
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 <hui.wang@canonical.com>
src/modules/module-switch-on-connect.c
src/pulsecore/core.c
src/pulsecore/sink.c
src/pulsecore/sink.h

index bde91e4..74cd977 100644 (file)
@@ -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;
 }
 
index e5bb2e4..c511c6a 100644 (file)
@@ -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
index 55e9af3..f8ce271 100644 (file)
@@ -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);
+    }
+}
index b9dd64f..7a72937 100644 (file)
@@ -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. */