[pulseaudio-commits] [Git][pulseaudio/pulseaudio][master] 8 commits: source-output: change bool save_source to char *preferred_source

Tanu Kaskinen gitlab at gitlab.freedesktop.org
Sat Dec 14 18:49:36 UTC 2019



Tanu Kaskinen pushed to branch master at PulseAudio / pulseaudio


Commits:
5eec504d by Hui Wang at 2019-12-14T18:40:19Z
source-output: change bool save_source to char *preferred_source

The finial objective is to store the preferred source name in the
source-output struct, and use module-stream-restore to save and
restore it.

This patch just replaces the save_source with preferred_source, and
tries to keep the original logic.

Signed-off-by: Hui Wang <hui.wang at canonical.com>

- - - - -
e529db75 by Hui Wang at 2019-12-14T18:40:19Z
source-output: add a new API pa_source_output_set_preferred_source

If the source here is NULL, that means users want to clear the
preferred_source and move the source-output to the default_source,
otherwise set the preferred_source to the source->name and move the
source-output to the source. After that fire the source_output_change
event.

After adding this API, we can use this API to simplify the entry_apply
in the module-stream-restore.c.

Signed-off-by: Hui Wang <hui.wang at canonical.com>

- - - - -
70bbbcdc by Hui Wang at 2019-12-14T18:40:19Z
source-output: clear the preferred_source if it is default_source

When the user moves a stream to the current default source, the
preferred_source should be set to NULL and module-stream-restore
should clear the routing for that stream in the stream database. From
that point on the stream will be always routed to the default source.

Signed-off-by: Hui Wang <hui.wang at canonical.com>

- - - - -
c254f840 by Hui Wang at 2019-12-14T18:40:19Z
core: move source-outputs conditionally when update default_source

When the default source changes, the streams from the old default
source should be moved to the new default source, unless the
preferred_source string is set to the old default source and the
active port of the old default source is not unavailable

Signed-off-by: Hui Wang <hui.wang at canonical.com>

- - - - -
1cea7ab3 by Hui Wang at 2019-12-14T18:40:19Z
source: move streams to new appeared sources if they prefer these sources

When a new source appears, all streams that have their
preferred_source set to the new source should be moved to the new
source.

Signed-off-by: Hui Wang <hui.wang at canonical.com>

- - - - -
976a366c by Hui Wang at 2019-12-14T18:40:19Z
device-port: moving streams since active_port on source changes status

When the active port of a source becomes unavailable, all streams from
that source should be moved to the default source.

When the active port of a source changes state from unavailable, all
streams that have their preferred_source set to this source should be
moved to this source.

Signed-off-by: Hui Wang <hui.wang at canonical.com>

- - - - -
5e0d5a86 by Hui Wang at 2019-12-14T18:40:19Z
source: move the streams to the default_source when the source unlink

When a source is unlinked, all streams of this source are moved to
default_source, this action is implemented in the core rather than
modules now.

And after this change, the module-rescue-streams is not needed, but
for backward compatibility, we keep it as a dummy module.

Signed-off-by: Hui Wang <hui.wang at canonical.com>

- - - - -
f62a49b8 by Hui Wang at 2019-12-14T18:40:19Z
stream-restore: skip entries set on source from gnome-control-center

When users select an input device from gnome-control-center UI, the
source of this input device will be set to the
configured_default_source and the default_source, these actions are
expected, but after these actions, the gnome-control-center will call
extension_cb() to modify the entries in the database, let all stream
entries to bind the source users select, this is not correct since the
source is default_source now.

This is a temp fix for this issue, after gnome-control-center fixes
this problem, this patch should be reverted.

Signed-off-by: Hui Wang <hui.wang at canonical.com>

- - - - -


16 changed files:

- src/daemon/default.pa.in
- src/daemon/system.pa.in
- src/modules/module-device-manager.c
- src/modules/module-filter-apply.c
- src/modules/module-intended-roles.c
- src/modules/module-rescue-streams.c
- src/modules/module-stream-restore.c
- src/modules/module-switch-on-connect.c
- src/pulsecore/core.c
- src/pulsecore/core.h
- src/pulsecore/device-port.c
- src/pulsecore/device-port.h
- src/pulsecore/source-output.c
- src/pulsecore/source-output.h
- src/pulsecore/source.c
- src/pulsecore/source.h


Changes:

=====================================
src/daemon/default.pa.in
=====================================
@@ -138,10 +138,6 @@ load-module module-gconf
 ### that look up the default sink/source get the right value
 load-module module-default-device-restore
 
-### Automatically move streams to the default sink if the sink they are
-### connected to dies, similar for sources
-load-module module-rescue-streams
-
 ### Make sure we always have a sink around, even if it is a null sink.
 load-module module-always-sink
 


=====================================
src/daemon/system.pa.in
=====================================
@@ -52,10 +52,6 @@ load-module module-native-protocol-unix
 ### that look up the default sink/source get the right value
 load-module module-default-device-restore
 
-### Automatically move streams to the default sink if the sink they are
-### connected to dies, similar for sources
-load-module module-rescue-streams
-
 ### Make sure we always have a sink around, even if it is a null sink.
 load-module module-always-sink
 


=====================================
src/modules/module-device-manager.c
=====================================
@@ -728,10 +728,6 @@ static void route_source_output(struct userdata *u, pa_source_output *so) {
     pa_assert(u);
     pa_assert(u->do_routing);
 
-    /* Don't override user or application routing requests. */
-    if (so->save_source || so->source_requested_by_application)
-        return;
-
     if (so->direct_on_input)
         return;
 
@@ -739,6 +735,10 @@ static void route_source_output(struct userdata *u, pa_source_output *so) {
     if (!so->source)
         return;
 
+    /* Don't override user or application routing requests. */
+    if (pa_safe_streq(so->source->name, so->preferred_source) || so->source_requested_by_application)
+        return;
+
     auto_filtered_prop = pa_proplist_gets(so->proplist, "module-device-manager.auto_filtered");
     if (auto_filtered_prop)
         auto_filtered = (pa_parse_boolean(auto_filtered_prop) == 1);
@@ -1596,7 +1596,7 @@ int pa__init(pa_module*m) {
     }
 
     if (on_rescue) {
-        /* A little bit later than module-stream-restore, a little bit earlier than module-intended-roles, module-rescue-streams, ... */
+        /* A little bit later than module-stream-restore, a little bit earlier than module-intended-roles, ... */
         u->sink_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+5, (pa_hook_cb_t) sink_unlink_hook_callback, u);
         u->source_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+5, (pa_hook_cb_t) source_unlink_hook_callback, u);
     }


=====================================
src/modules/module-filter-apply.c
=====================================
@@ -687,8 +687,7 @@ static pa_hook_result_t sink_unlink_cb(pa_core *core, pa_sink *sink, struct user
             uint32_t idx;
 
             /* Attempt to rescue any streams to the parent sink as this is likely
-             * the best course of action (as opposed to a generic rescue via
-             * module-rescue-streams */
+             * the best course of action */
             if (filter->sink == sink) {
                 pa_sink_input *i;
 
@@ -769,8 +768,7 @@ static pa_hook_result_t source_unlink_cb(pa_core *core, pa_source *source, struc
             uint32_t idx;
 
             /* Attempt to rescue any streams to the parent source as this is likely
-             * the best course of action (as opposed to a generic rescue via
-             * module-rescue-streams */
+             * the best course of action */
             if (filter->source == source) {
                 pa_source_output *o;
 


=====================================
src/modules/module-intended-roles.c
=====================================
@@ -222,9 +222,6 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
         if (so->source == source)
             continue;
 
-        if (so->save_source)
-            continue;
-
         if (so->direct_on_input)
             continue;
 
@@ -233,6 +230,9 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
         if (!so->source)
             continue;
 
+        if (pa_safe_streq(so->source->name, so->preferred_source))
+            continue;
+
         /* It might happen that a stream and a source are set up at the
            same time, in which case we want to make sure we don't
            interfere with that */
@@ -398,7 +398,7 @@ int pa__init(pa_module*m) {
     }
 
     if (on_rescue) {
-        /* A little bit later than module-stream-restore, a little bit earlier than module-rescue-streams, ... */
+        /* A little bit later than module-stream-restore, ... */
         u->sink_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+10, (pa_hook_cb_t) sink_unlink_hook_callback, u);
         u->source_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+10, (pa_hook_cb_t) source_unlink_hook_callback, u);
     }


=====================================
src/modules/module-rescue-streams.c
=====================================
@@ -24,200 +24,23 @@
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core.h>
-#include <pulsecore/source-output.h>
-#include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/core-util.h>
 
 PA_MODULE_AUTHOR("Lennart Poettering");
-PA_MODULE_DESCRIPTION("When a source is removed, try to move its streams to the default source");
+PA_MODULE_DESCRIPTION("This module is obsolete, please remove it from your configuration.");
 PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_LOAD_ONCE(true);
 
-static const char* const valid_modargs[] = {
-    NULL,
-};
-
-struct userdata {
-    pa_hook_slot
-        *source_unlink_slot,
-        *source_output_move_fail_slot;
-};
-
-static pa_source* find_source_from_port(pa_core *c, pa_device_port *port) {
-    pa_source *target;
-    uint32_t idx;
-    void *state;
-    pa_device_port *p;
-
-    if (!port)
-        return NULL;
-
-    PA_IDXSET_FOREACH(target, c->sources, idx)
-        PA_HASHMAP_FOREACH(p, target->ports, state)
-            if (port == p)
-                return target;
-
-    return NULL;
-}
-
-static void build_group_ports(pa_hashmap *g_ports, pa_hashmap *s_ports) {
-    void *state;
-    pa_device_port *p;
-
-    if (!g_ports || !s_ports)
-        return;
-
-    PA_HASHMAP_FOREACH(p, s_ports, state)
-        pa_hashmap_put(g_ports, p, p);
-}
-
-static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_source *skip) {
-    pa_source *target, *fb_source = NULL;
-    uint32_t idx;
-    pa_hashmap *all_ports;
-    pa_device_port *best_port;
-
-    pa_assert(c);
-    pa_assert(o);
-
-    if (c->default_source && c->default_source != skip && pa_source_output_may_move_to(o, c->default_source))
-        return c->default_source;
-
-    all_ports = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
-
-    PA_IDXSET_FOREACH(target, c->sources, idx) {
-        if (target == c->default_source)
-            continue;
-
-        if (target == skip)
-            continue;
-
-        /* We only move to a monitor source if we're already on one */
-        if (skip && !target->monitor_of != !skip->monitor_of)
-            continue;
-
-        if (!PA_SOURCE_IS_LINKED(target->state))
-            continue;
-
-        if (!pa_source_output_may_move_to(o, target))
-            continue;
-
-        if (!fb_source)
-            fb_source = target;
-
-        build_group_ports(all_ports, target->ports);
-    }
-
-    best_port = pa_device_port_find_best(all_ports);
-
-    pa_hashmap_free(all_ports);
-
-    if (best_port)
-        target = find_source_from_port(c, best_port);
-    else
-        target = fb_source;
-
-    if (!target)
-        pa_log_debug("No evacuation source found.");
-
-    return target;
-}
-
-static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, void* userdata) {
-    pa_source_output *o;
-    uint32_t idx;
-
-    pa_assert(c);
-    pa_assert(source);
-
-    /* There's no point in doing anything if the core is shut down anyway */
-    if (c->state == PA_CORE_SHUTDOWN)
-        return PA_HOOK_OK;
-
-    if (pa_idxset_size(source->outputs) <= 0) {
-        pa_log_debug("No source outputs to move away.");
-        return PA_HOOK_OK;
-    }
-
-    PA_IDXSET_FOREACH(o, source->outputs, idx) {
-        pa_source *target;
-
-        if (!(target = find_evacuation_source(c, o, source)))
-            continue;
-
-        if (pa_source_output_move_to(o, target, false) < 0)
-            pa_log_info("Failed to move source output %u \"%s\" to %s.", o->index,
-                        pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), target->name);
-        else
-            pa_log_info("Successfully moved source output %u \"%s\" to %s.", o->index,
-                        pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), target->name);
-    }
-
-    return PA_HOOK_OK;
-}
-
-static pa_hook_result_t source_output_move_fail_hook_callback(pa_core *c, pa_source_output *i, void *userdata) {
-    pa_source *target;
-
-    pa_assert(c);
-    pa_assert(i);
-
-    /* There's no point in doing anything if the core is shut down anyway */
-    if (c->state == PA_CORE_SHUTDOWN)
-        return PA_HOOK_OK;
-
-    if (!(target = find_evacuation_source(c, i, NULL)))
-        return PA_HOOK_OK;
-
-    if (pa_source_output_finish_move(i, target, false) < 0) {
-        pa_log_info("Failed to move source output %u \"%s\" to %s.", i->index,
-                        pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name);
-        return PA_HOOK_OK;
-
-    } else {
-        pa_log_info("Successfully moved source output %u \"%s\" to %s.", i->index,
-                    pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name);
-        return PA_HOOK_STOP;
-    }
-}
 
 int pa__init(pa_module*m) {
-    pa_modargs *ma;
-    struct userdata *u;
 
     pa_assert(m);
 
-    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("Failed to parse module arguments");
-        return -1;
-    }
-
-    m->userdata = u = pa_xnew(struct userdata, 1);
+    pa_log("module-rescue-stream is obsolete and should no longer be loaded. Please remove it from your configuration.");
 
-    /* A little bit later than module-stream-restore, module-intended-roles... */
-    u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+20, (pa_hook_cb_t) source_unlink_hook_callback, u);
+    pa_module_unload_request(m, false);
 
-    u->source_output_move_fail_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], PA_HOOK_LATE+20, (pa_hook_cb_t) source_output_move_fail_hook_callback, u);
-
-    pa_modargs_free(ma);
     return 0;
 }
-
-void pa__done(pa_module*m) {
-    struct userdata *u;
-
-    pa_assert(m);
-
-    if (!(u = m->userdata))
-        return;
-
-    if (u->source_unlink_slot)
-        pa_hook_slot_free(u->source_unlink_slot);
-
-    if (u->source_output_move_fail_slot)
-        pa_hook_slot_free(u->source_output_move_fail_slot);
-
-    pa_xfree(u);
-}


=====================================
src/modules/module-stream-restore.c
=====================================
@@ -64,8 +64,8 @@ PA_MODULE_USAGE(
         "restore_device=<Save/restore sinks/sources?> "
         "restore_volume=<Save/restore volumes?> "
         "restore_muted=<Save/restore muted states?> "
-        "on_hotplug=<When new device becomes available, recheck streams?> "
-        "on_rescue=<When device becomes unavailable, recheck streams?> "
+        "on_hotplug=<This argument is obsolete, please remove it from configuration> "
+        "on_rescue=<This argument is obsolete, please remove it from configuration> "
         "fallback_table=<filename>");
 
 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
@@ -95,8 +95,6 @@ struct userdata {
         *sink_input_fixate_hook_slot,
         *source_output_new_hook_slot,
         *source_output_fixate_hook_slot,
-        *source_put_hook_slot,
-        *source_unlink_hook_slot,
         *connection_unlink_hook_slot;
     pa_time_event *save_time_event;
     pa_database* database;
@@ -104,8 +102,6 @@ struct userdata {
     bool restore_device:1;
     bool restore_volume:1;
     bool restore_muted:1;
-    bool on_hotplug:1;
-    bool on_rescue:1;
 
     pa_native_protocol *protocol;
     pa_idxset *subscribed;
@@ -1369,16 +1365,22 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
             mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted);
         }
 
-        if (source_output->save_source) {
+        if (source_output->preferred_source != NULL || !created_new_entry) {
+            pa_source *s = NULL;
+
             pa_xfree(entry->device);
-            entry->device = pa_xstrdup(source_output->source->name);
+            entry->device = pa_xstrdup(source_output->preferred_source);
             entry->device_valid = true;
 
-            device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device));
+            if (!entry->device)
+                entry->device_valid = false;
 
-            if (source_output->source->card) {
-                pa_xfree(entry->card);
-                entry->card = pa_xstrdup(source_output->source->card->name);
+            device_updated = !created_new_entry && !pa_safe_streq(entry->device, old->device);
+            pa_xfree(entry->card);
+            entry->card = NULL;
+            entry->card_valid = false;
+            if (entry->device_valid && (s = pa_namereg_get(c, entry->device, PA_NAMEREG_SOURCE)) && s->card) {
+                entry->card = pa_xstrdup(s->card->name);
                 entry->card_valid = true;
             }
         }
@@ -1637,110 +1639,6 @@ static pa_hook_result_t source_output_fixate_hook_callback(pa_core *c, pa_source
     return PA_HOOK_OK;
 }
 
-static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
-    pa_source_output *so;
-    uint32_t idx;
-
-    pa_assert(c);
-    pa_assert(source);
-    pa_assert(u);
-    pa_assert(u->on_hotplug && u->restore_device);
-
-    PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
-        char *name;
-        struct entry *e;
-
-        if (so->source == source)
-            continue;
-
-        if (so->save_source)
-            continue;
-
-        if (so->direct_on_input)
-            continue;
-
-        /* Skip this if it is already in the process of being moved anyway */
-        if (!so->source)
-            continue;
-
-        /* Skip this source output if it is connecting a filter source to
-         * the master */
-        if (so->destination_source)
-            continue;
-
-        /* It might happen that a stream and a source are set up at the
-           same time, in which case we want to make sure we don't
-           interfere with that */
-        if (!PA_SOURCE_OUTPUT_IS_LINKED(so->state))
-            continue;
-
-        if (!(name = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
-            continue;
-
-        if ((e = entry_read(u, name))) {
-            if (e->device_valid && pa_streq(e->device, source->name))
-                pa_source_output_move_to(so, source, true);
-
-            entry_free(e);
-        }
-
-        pa_xfree(name);
-    }
-
-    return PA_HOOK_OK;
-}
-
-static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
-    pa_source_output *so;
-    uint32_t idx;
-
-    pa_assert(c);
-    pa_assert(source);
-    pa_assert(u);
-    pa_assert(u->on_rescue && u->restore_device);
-
-    /* There's no point in doing anything if the core is shut down anyway */
-    if (c->state == PA_CORE_SHUTDOWN)
-        return PA_HOOK_OK;
-
-    PA_IDXSET_FOREACH(so, source->outputs, idx) {
-        char *name;
-        struct entry *e;
-
-        if (so->direct_on_input)
-            continue;
-
-        if (!so->source)
-            continue;
-
-        /* Skip this source output if it is connecting a filter source to
-         * the master */
-        if (so->destination_source)
-            continue;
-
-        if (!(name = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
-            continue;
-
-        if ((e = entry_read(u, name))) {
-
-            if (e->device_valid) {
-                pa_source *d;
-
-                if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) &&
-                    d != source &&
-                    PA_SOURCE_IS_LINKED(d->state))
-                    pa_source_output_move_to(so, d, true);
-            }
-
-            entry_free(e);
-        }
-
-        pa_xfree(name);
-    }
-
-    return PA_HOOK_OK;
-}
-
 static int fill_db(struct userdata *u, const char *filename) {
     FILE *f;
     int n = 0;
@@ -1898,21 +1796,16 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) {
 
         if (u->restore_device) {
             if (!e->device_valid) {
-                if (so->save_source) {
+                if (so->preferred_source != NULL) {
                     pa_log_info("Ensuring device is not saved for stream %s.", name);
                     /* If the device is not valid we should make sure the
-                       save flag is cleared as the user may have specifically
+                       preferred_source is cleared as the user may have specifically
                        removed the source element from the rule. */
-                    so->save_source = false;
-                    /* This is cheating a bit. The source output itself has not changed
-                       but the rules governing its routing have, so we fire this event
-                       such that other routing modules (e.g. module-device-manager)
-                       will pick up the change and reapply their routing */
-                    pa_subscription_post(so->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, so->index);
+                    pa_source_output_set_preferred_source(so, NULL);
                 }
             } else if ((s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SOURCE))) {
                 pa_log_info("Restoring device for stream %s.", name);
-                pa_source_output_move_to(so, s, true);
+                pa_source_output_set_preferred_source(so, s);
             }
         }
     }
@@ -2094,11 +1987,13 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
                 }
                 /* When users select an output device from gnome-control-center, the gnome-control-center will change all entries
                  * in the database to bind the sink of this output device, this is not correct since at this moment, the sink is
-                 * default_sink and we shouldn't bind a stream to default_sink via preferred_sink or database.
+                 * default_sink and we shouldn't bind a stream to default_sink via preferred_sink or database. This also applies
+                 * to source, default_source and preferred_source.
                  * After gnome-control-center fix the issue, let us remove this code */
                 client_name = pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c)->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
                 if (pa_safe_streq(client_name, "gnome-control-center")) {
-                    if (entry->device_valid && m->core->default_sink && pa_safe_streq(device, m->core->default_sink->name)) {
+                    if (entry->device_valid && ((m->core->default_sink && pa_safe_streq(device, m->core->default_sink->name)) ||
+			(m->core->default_source && pa_safe_streq(device, m->core->default_source->name)))) {
                         entry_free(entry);
                         pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
                         return 0;
@@ -2325,7 +2220,8 @@ int pa__init(pa_module*m) {
     pa_sink_input *si;
     pa_source_output *so;
     uint32_t idx;
-    bool restore_device = true, restore_volume = true, restore_muted = true, on_hotplug = true, on_rescue = true;
+    bool restore_device = true, restore_volume = true, restore_muted = true;
+
 #ifdef HAVE_DBUS
     pa_datum key;
     bool done;
@@ -2340,13 +2236,15 @@ int pa__init(pa_module*m) {
 
     if (pa_modargs_get_value_boolean(ma, "restore_device", &restore_device) < 0 ||
         pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
-        pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
-        pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
-        pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
-        pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
+        pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0) {
+        pa_log("restore_device=, restore_volume= and restore_muted= expect boolean arguments");
         goto fail;
     }
 
+    if (pa_modargs_get_value(ma, "on_hotplug", NULL) != NULL ||
+	pa_modargs_get_value(ma, "on_rescue", NULL) != NULL)
+        pa_log("on_hotplug and on_rescue are obsolete arguments, please remove them from your configuration");
+
     if (!restore_muted && !restore_volume && !restore_device)
         pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
 
@@ -2356,8 +2254,6 @@ int pa__init(pa_module*m) {
     u->restore_device = restore_device;
     u->restore_volume = restore_volume;
     u->restore_muted = restore_muted;
-    u->on_hotplug = on_hotplug;
-    u->on_rescue = on_rescue;
     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
     u->protocol = pa_native_protocol_get(m->core);
@@ -2373,16 +2269,6 @@ int pa__init(pa_module*m) {
         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_new_hook_callback, u);
     }
 
-    if (restore_device && on_hotplug) {
-        /* A little bit earlier than module-intended-roles ... */
-        pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE, (pa_hook_cb_t) source_put_hook_callback, u);
-    }
-
-    if (restore_device && on_rescue) {
-        /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
-        pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_unlink_hook_callback, u);
-    }
-
     if (restore_volume || restore_muted) {
         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_fixate_hook_callback, u);
         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_fixate_hook_callback, u);


=====================================
src/modules/module-switch-on-connect.c
=====================================
@@ -116,9 +116,6 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void*
 }
 
 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, void* userdata) {
-    pa_source_output *o;
-    uint32_t idx;
-    pa_source *old_default_source;
     const char *s;
     struct userdata *u = userdata;
 
@@ -172,29 +169,9 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
             return PA_HOOK_OK;
         }
 
-    old_default_source = c->default_source;
-
     /* Actually do the switch to the new source */
     pa_core_set_configured_default_source(c, source->name);
 
-    /* Now move all old outputs over */
-    if (pa_idxset_size(old_default_source->outputs) <= 0) {
-        pa_log_debug("No source outputs to move away.");
-        return PA_HOOK_OK;
-    }
-
-    PA_IDXSET_FOREACH(o, old_default_source->outputs, idx) {
-        if (o->save_source || !PA_SOURCE_OUTPUT_IS_LINKED(o->state))
-            continue;
-
-        if (pa_source_output_move_to(o, source, false) < 0)
-            pa_log_info("Failed to move source output %u \"%s\" to %s.", o->index,
-                        pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), source->name);
-        else
-            pa_log_info("Successfully moved source output %u \"%s\" to %s.", o->index,
-                        pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), source->name);
-    }
-
     return PA_HOOK_OK;
 }
 
@@ -211,7 +188,6 @@ int pa__init(pa_module*m) {
 
     m->userdata = u = pa_xnew0(struct userdata, 1);
 
-    /* A little bit later than module-rescue-streams... */
     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+30, (pa_hook_cb_t) sink_put_hook_callback, u);
     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+20, (pa_hook_cb_t) source_put_hook_callback, u);
 


=====================================
src/pulsecore/core.c
=====================================
@@ -435,6 +435,10 @@ void pa_core_update_default_source(pa_core *core) {
                 old_default_source ? old_default_source->name : "(unset)", best ? best->name : "(unset)");
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
     pa_hook_fire(&core->hooks[PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED], core->default_source);
+
+    /* try to move the streams from old_default_source to the new default_source conditionally */
+    if (old_default_source)
+	pa_source_move_streams_to_default_source(core, old_default_source, true);
 }
 
 void pa_core_set_exit_idle_time(pa_core *core, int time) {
@@ -555,6 +559,41 @@ void pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink
 
 }
 
+void pa_core_move_streams_to_newly_available_preferred_source(pa_core *c, pa_source *s) {
+    pa_source_output *so;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(s);
+
+    PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
+        if (so->source == s)
+            continue;
+
+        if (so->direct_on_input)
+            continue;
+
+        if (!so->source)
+            continue;
+
+        /* Skip this source output if it is connecting a filter source to
+         * the master */
+        if (so->destination_source)
+            continue;
+
+        /* It might happen that a stream and a source are set up at the
+           same time, in which case we want to make sure we don't
+           interfere with that */
+        if (!PA_SOURCE_OUTPUT_IS_LINKED(so->state))
+            continue;
+
+        if (pa_safe_streq(so->preferred_source, s->name))
+            pa_source_output_move_to(so, s, false);
+    }
+
+}
+
+
 /* Helper macro to reduce repetition in pa_suspend_cause_to_string().
  * Parameters:
  *   char *p: the current position in the write buffer


=====================================
src/pulsecore/core.h
=====================================
@@ -281,4 +281,6 @@ const char *pa_suspend_cause_to_string(pa_suspend_cause_t cause, char buf[PA_SUS
 
 void pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink *s);
 
+void pa_core_move_streams_to_newly_available_preferred_source(pa_core *c, pa_source *s);
+
 #endif


=====================================
src/pulsecore/device-port.c
=====================================
@@ -110,6 +110,16 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t status) {
                 else
                     pa_core_move_streams_to_newly_available_preferred_sink(p->core, sink);
             }
+        } else {
+            pa_source *source;
+
+            source = pa_device_port_get_source(p);
+            if (source && p == source->active_port) {
+                if (source->active_port->available == PA_AVAILABLE_NO)
+                    pa_source_move_streams_to_default_source(p->core, source, false);
+                else
+                    pa_core_move_streams_to_newly_available_preferred_source(p->core, source);
+            }
         }
 
         pa_subscription_post(p->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index);
@@ -249,3 +259,16 @@ pa_sink *pa_device_port_get_sink(pa_device_port *p) {
         }
     return rs;
 }
+
+pa_source *pa_device_port_get_source(pa_device_port *p) {
+    pa_source *rs = NULL;
+    pa_source *source;
+    uint32_t state;
+
+    PA_IDXSET_FOREACH(source, p->card->sources, state)
+        if (p == pa_hashmap_get(source->ports, p->name)) {
+            rs = source;
+            break;
+        }
+    return rs;
+}


=====================================
src/pulsecore/device-port.h
=====================================
@@ -89,4 +89,6 @@ pa_device_port *pa_device_port_find_best(pa_hashmap *ports);
 
 pa_sink *pa_device_port_get_sink(pa_device_port *p);
 
+pa_source *pa_device_port_get_source(pa_device_port *p);
+
 #endif


=====================================
src/pulsecore/source-output.c
=====================================
@@ -134,7 +134,10 @@ bool pa_source_output_new_data_set_source(pa_source_output_new_data *data, pa_so
     if (!data->req_formats) {
         /* We're not working with the extended API */
         data->source = s;
-        data->save_source = save;
+        if (save) {
+            pa_xfree(data->preferred_source);
+            data->preferred_source = pa_xstrdup(s->name);
+        }
         data->source_requested_by_application = requested_by_application;
     } else {
         /* Extended API: let's see if this source supports the formats the client would like */
@@ -143,7 +146,10 @@ bool pa_source_output_new_data_set_source(pa_source_output_new_data *data, pa_so
         if (formats && !pa_idxset_isempty(formats)) {
             /* Source supports at least one of the requested formats */
             data->source = s;
-            data->save_source = save;
+            if (save) {
+                pa_xfree(data->preferred_source);
+                data->preferred_source = pa_xstrdup(s->name);
+            }
             data->source_requested_by_application = requested_by_application;
             if (data->nego_formats)
                 pa_idxset_free(data->nego_formats, (pa_free_cb_t) pa_format_info_free);
@@ -170,7 +176,7 @@ bool pa_source_output_new_data_set_formats(pa_source_output_new_data *data, pa_i
 
     if (data->source) {
         /* Trigger format negotiation */
-        return pa_source_output_new_data_set_source(data, data->source, data->save_source,
+        return pa_source_output_new_data_set_source(data, data->source, (data->preferred_source != NULL),
                                                     data->source_requested_by_application);
     }
 
@@ -189,6 +195,9 @@ void pa_source_output_new_data_done(pa_source_output_new_data *data) {
     if (data->format)
         pa_format_info_free(data->format);
 
+    if (data->preferred_source)
+        pa_xfree(data->preferred_source);
+
     pa_proplist_free(data->proplist);
 }
 
@@ -460,7 +469,7 @@ 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->preferred_source = pa_xstrdup(data->preferred_source);
     o->save_muted = data->save_muted;
 
     o->muted = data->muted;
@@ -652,6 +661,9 @@ static void source_output_free(pa_object* mo) {
     if (o->proplist)
         pa_proplist_free(o->proplist);
 
+    if (o->preferred_source)
+        pa_xfree(o->preferred_source);
+
     pa_xfree(o->driver);
     pa_xfree(o);
 }
@@ -1545,7 +1557,16 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, bool save
         o->moving(o, dest);
 
     o->source = dest;
-    o->save_source = save;
+    /* save == true, means user is calling the move_to() and want to
+       save the preferred_source */
+    if (save) {
+        pa_xfree(o->preferred_source);
+        if (dest == dest->core->default_source)
+            o->preferred_source = NULL;
+        else
+            o->preferred_source = pa_xstrdup(dest->name);
+    }
+
     pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL);
 
     pa_cvolume_remap(&o->volume_factor_source, &o->channel_map, &o->source->channel_map);
@@ -1869,3 +1890,17 @@ void pa_source_output_set_reference_ratio(pa_source_output *o, const pa_cvolume
                  pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &o->channel_map, true),
                  pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &o->channel_map, true));
 }
+
+/* Called from the main thread. */
+void pa_source_output_set_preferred_source(pa_source_output *o, pa_source *s) {
+    pa_assert(o);
+
+    pa_xfree(o->preferred_source);
+    if (s) {
+        o->preferred_source = pa_xstrdup(s->name);
+        pa_source_output_move_to(o, s, false);
+    } else {
+        o->preferred_source = NULL;
+        pa_source_output_move_to(o, o->core->default_source, false);
+    }
+}


=====================================
src/pulsecore/source-output.h
=====================================
@@ -106,11 +106,15 @@ struct pa_source_output {
 
     bool muted:1;
 
-    /* if true then the source we are connected to and/or the volume
-     * set is worth remembering, i.e. was explicitly chosen by the
-     * user and not automatically. module-stream-restore looks for
-     * this.*/
-    bool save_source:1, save_volume:1, save_muted:1;
+    /* if true then the volume and the mute state of this source-output
+     * are worth remembering, module-stream-restore looks for this. */
+    bool save_volume:1, save_muted:1;
+
+    /* if users move the source-output to a source, and the source is not
+     * default_source, the source->name will be saved in preferred_source. And
+     * later if source-output is moved to other sources for some reason, it
+     * still can be restored to the preferred_source at an appropriate time */
+    char *preferred_source;
 
     pa_resample_method_t requested_resample_method, actual_resample_method;
 
@@ -277,7 +281,8 @@ 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;
+    char *preferred_source;
 } pa_source_output_new_data;
 
 pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data);
@@ -397,6 +402,8 @@ void pa_source_output_set_volume_direct(pa_source_output *o, const pa_cvolume *v
  * o->reference_ratio and logs a message if the value changes. */
 void pa_source_output_set_reference_ratio(pa_source_output *o, const pa_cvolume *ratio);
 
+void pa_source_output_set_preferred_source(pa_source_output *o, pa_source *s);
+
 #define pa_source_output_assert_io_context(s) \
     pa_assert(pa_thread_mq_get() || !PA_SOURCE_OUTPUT_IS_LINKED((s)->state))
 


=====================================
src/pulsecore/source.c
=====================================
@@ -666,9 +666,13 @@ void pa_source_put(pa_source *s) {
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
     pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
 
-    /* This function must be called after the PA_CORE_HOOK_SOURCE_PUT hook,
-     * because module-switch-on-connect needs to know the old default source */
+    /* It's good to fire the SOURCE_PUT hook before updating the default source,
+     * because module-switch-on-connect will set the new source as the default
+     * source, and if we were to call pa_core_update_default_source() before that,
+     * the default source might change twice, causing unnecessary stream moving. */
     pa_core_update_default_source(s->core);
+
+    pa_core_move_streams_to_newly_available_preferred_source(s->core, s);
 }
 
 /* Called from main context */
@@ -698,6 +702,9 @@ void pa_source_unlink(pa_source *s) {
 
     pa_core_update_default_source(s->core);
 
+    if (linked)
+	pa_source_move_streams_to_default_source(s->core, s, false);
+
     if (s->card)
         pa_idxset_remove_by_data(s->card->sources, s, NULL);
 
@@ -2988,3 +2995,47 @@ void pa_source_set_reference_volume_direct(pa_source *s, const pa_cvolume *volum
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
     pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED], s);
 }
+
+void pa_source_move_streams_to_default_source(pa_core *core, pa_source *old_source, bool default_source_changed) {
+    pa_source_output *o;
+    uint32_t idx;
+    bool old_source_is_unavailable = false;
+
+    pa_assert(core);
+    pa_assert(old_source);
+
+    if (core->state == PA_CORE_SHUTDOWN)
+        return;
+
+    if (core->default_source == NULL || core->default_source->unlink_requested)
+        return;
+
+    if (old_source == core->default_source)
+        return;
+
+    if (old_source->active_port && old_source->active_port->available == PA_AVAILABLE_NO)
+        old_source_is_unavailable = true;
+
+    PA_IDXSET_FOREACH(o, old_source->outputs, idx) {
+        if (!PA_SOURCE_OUTPUT_IS_LINKED(o->state))
+            continue;
+
+        if (!o->source)
+            continue;
+
+        if (pa_safe_streq(old_source->name, o->preferred_source) && !old_source_is_unavailable)
+            continue;
+
+        if (!pa_source_output_may_move_to(o, core->default_source))
+            continue;
+
+        if (default_source_changed)
+            pa_log_info("The source output %u \"%s\" is moving to %s due to change of the default source.",
+                        o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), core->default_source->name);
+        else
+            pa_log_info("The source output %u \"%s\" is moving to %s due to unlink of a source.",
+                        o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), core->default_source->name);
+
+        pa_source_output_move_to(o, core->default_source, false);
+    }
+}


=====================================
src/pulsecore/source.h
=====================================
@@ -479,6 +479,12 @@ int64_t pa_source_get_latency_within_thread(pa_source *s, bool allow_negative);
  * sets s->reference_volume and fires change notifications. */
 void pa_source_set_reference_volume_direct(pa_source *s, const pa_cvolume *volume);
 
+/* When the default_source is changed or the active_port of a source is changed to
+ * PA_AVAILABLE_NO, this function is called to move the streams of the old
+ * default_source or the source with active_port equals PA_AVAILABLE_NO to the
+ * current default_source conditionally*/
+void pa_source_move_streams_to_default_source(pa_core *core, pa_source *old_source, bool default_source_changed);
+
 #define pa_source_assert_io_context(s) \
     pa_assert(pa_thread_mq_get() || !PA_SOURCE_IS_LINKED((s)->state))
 



View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/compare/734a00c849815a45697970d593068c301a04ebbb...f62a49b8cf109c011a9818d2358beb6834e6ec25

-- 
View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/compare/734a00c849815a45697970d593068c301a04ebbb...f62a49b8cf109c011a9818d2358beb6834e6ec25
You're receiving this email because of your account on gitlab.freedesktop.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/pulseaudio-commits/attachments/20191214/037d5600/attachment-0001.htm>


More information about the pulseaudio-commits mailing list