[v3,4/8] core: move sink-inputs conditionally when update default_sink

Submitted by Hui Wang on Aug. 18, 2019, 5:32 a.m.

Details

Message ID 20190818053241.22161-5-hui.wang@canonical.com
State New
Headers show
Series "Change the bool sink_save to char *preferred_sink" ( rev: 2 ) in PulseAudio

Not browsing as part of any series.

Commit Message

Hui Wang Aug. 18, 2019, 5:32 a.m.
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/dbus/iface-core.c               |  2 +-
 src/modules/module-default-device-restore.c |  2 +-
 src/modules/module-switch-on-connect.c      | 27 ++-------------
 src/pulsecore/cli-command.c                 |  2 +-
 src/pulsecore/core.c                        | 10 ++++--
 src/pulsecore/core.h                        |  4 +--
 src/pulsecore/device-port.c                 |  2 +-
 src/pulsecore/protocol-native.c             |  2 +-
 src/pulsecore/sink.c                        | 38 +++++++++++++++++++--
 src/pulsecore/sink.h                        |  6 ++++
 10 files changed, 57 insertions(+), 38 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/modules/dbus/iface-core.c b/src/modules/dbus/iface-core.c
index 5229c0467..9763480d2 100644
--- a/src/modules/dbus/iface-core.c
+++ b/src/modules/dbus/iface-core.c
@@ -721,7 +721,7 @@  static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, DBu
         return;
     }
 
-    pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name);
+    pa_core_set_configured_default_sink(c->core, pa_dbusiface_device_get_sink(fallback_sink)->name, true);
 
     pa_dbus_send_empty_reply(conn, msg);
 }
diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c
index c4dbad99f..33e74c071 100644
--- a/src/modules/module-default-device-restore.c
+++ b/src/modules/module-default-device-restore.c
@@ -69,7 +69,7 @@  static void load(struct userdata *u) {
             pa_log_warn("Invalid sink name: %s", ln);
         else {
             pa_log_info("Restoring default sink '%s'.", ln);
-            pa_core_set_configured_default_sink(u->core, ln);
+            pa_core_set_configured_default_sink(u->core, ln, false);
         }
 
     } else if (errno != ENOENT)
diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c
index f0cb29a7c..3ceac8b4f 100644
--- a/src/modules/module-switch-on-connect.c
+++ b/src/modules/module-switch-on-connect.c
@@ -54,9 +54,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;
 
@@ -88,7 +85,7 @@  static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void*
 
     /* No default sink, nothing to move away, just set the new default */
     if (!c->default_sink) {
-        pa_core_set_configured_default_sink(c, sink->name);
+        pa_core_set_configured_default_sink(c, sink->name, false);
         return PA_HOOK_OK;
     }
 
@@ -103,28 +100,8 @@  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);
-    }
+    pa_core_set_configured_default_sink(c, sink->name, false);
 
     return PA_HOOK_OK;
 }
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 5205349bd..cc7addaa1 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -1036,7 +1036,7 @@  static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *b
     }
 
     if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK)))
-        pa_core_set_configured_default_sink(c, s->name);
+        pa_core_set_configured_default_sink(c, s->name, true);
     else
         pa_strbuf_printf(buf, "Sink %s does not exist.\n", n);
 
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index e5bb2e47b..a112ff753 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -230,7 +230,7 @@  static void core_free(pa_object *o) {
     pa_xfree(c);
 }
 
-void pa_core_set_configured_default_sink(pa_core *core, const char *sink) {
+void pa_core_set_configured_default_sink(pa_core *core, const char *sink, bool from_user) {
     char *old_sink;
 
     pa_assert(core);
@@ -246,7 +246,7 @@  void pa_core_set_configured_default_sink(pa_core *core, const char *sink) {
                 old_sink ? old_sink : "(unset)", sink ? sink : "(unset)");
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
 
-    pa_core_update_default_sink(core);
+    pa_core_update_default_sink(core, from_user);
 
 finish:
     pa_xfree(old_sink);
@@ -312,7 +312,7 @@  static int compare_sinks(pa_sink *a, pa_sink *b) {
     return 0;
 }
 
-void pa_core_update_default_sink(pa_core *core) {
+void pa_core_update_default_sink(pa_core *core, bool from_user) {
     pa_sink *best = NULL;
     pa_sink *sink;
     uint32_t idx;
@@ -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, from_user);
 }
 
 /* a  < b  ->  return -1
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index d03897c47..04f11f8e9 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -243,7 +243,7 @@  enum {
 
 pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t shm_size);
 
-void pa_core_set_configured_default_sink(pa_core *core, const char *sink);
+void pa_core_set_configured_default_sink(pa_core *core, const char *sink, bool from_user);
 void pa_core_set_configured_default_source(pa_core *core, const char *source);
 
 /* These should be called whenever something changes that may affect the
@@ -255,7 +255,7 @@  void pa_core_set_configured_default_source(pa_core *core, const char *source);
  * pa_core_update_default_source() internally, so it's sufficient to only call
  * pa_core_update_default_sink() when something happens that affects the sink
  * ordering. */
-void pa_core_update_default_sink(pa_core *core);
+void pa_core_update_default_sink(pa_core *core, bool from_user);
 void pa_core_update_default_source(pa_core *core);
 
 void pa_core_set_exit_idle_time(pa_core *core, int time);
diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
index fb1277215..464c3f8a2 100644
--- a/src/pulsecore/device-port.c
+++ b/src/pulsecore/device-port.c
@@ -96,7 +96,7 @@  void pa_device_port_set_available(pa_device_port *p, pa_available_t status) {
          * default sink/source, so port availability changes may affect the
          * default sink/source choice. */
         if (p->direction == PA_DIRECTION_OUTPUT)
-            pa_core_update_default_sink(p->core);
+            pa_core_update_default_sink(p->core, false);
         else
             pa_core_update_default_source(p->core);
 
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 72457418a..535e29837 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -4375,7 +4375,7 @@  static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t comman
         sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
         CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
 
-        pa_core_set_configured_default_sink(c->protocol->core, sink->name);
+        pa_core_set_configured_default_sink(c->protocol->core, sink->name, true);
     }
 
     pa_pstream_send_simple_ack(c->pstream, tag);
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 55e9af3e7..aca116c7f 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -726,7 +726,7 @@  void pa_sink_put(pa_sink* 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 */
-    pa_core_update_default_sink(s->core);
+    pa_core_update_default_sink(s->core, false);
 }
 
 /* Called from main context */
@@ -755,7 +755,7 @@  void pa_sink_unlink(pa_sink* s) {
         pa_namereg_unregister(s->core, s->name);
     pa_idxset_remove_by_data(s->core->sinks, s, NULL);
 
-    pa_core_update_default_sink(s->core);
+    pa_core_update_default_sink(s->core, false);
 
     if (s->card)
         pa_idxset_remove_by_data(s->card->sinks, s, NULL);
@@ -3425,7 +3425,7 @@  int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
     pa_sink_set_port_latency_offset(s, s->active_port->latency_offset);
 
     /* The active port affects the default sink selection. */
-    pa_core_update_default_sink(s->core);
+    pa_core_update_default_sink(s->core, false);
 
     pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
 
@@ -3931,3 +3931,35 @@  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, bool from_user) {
+    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;
+
+    if (pa_idxset_size(old_sink->inputs) > 0) {
+        PA_IDXSET_FOREACH(i, old_sink->inputs, idx) {
+            if (!PA_SINK_INPUT_IS_LINKED(i->state))
+                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 default_sink is changed.",
+                        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, from_user);
+        }
+    }
+}
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index b9dd64f6f..b67d579dd 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, bool from_user);
+
 /* 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. */