summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Chini <georg@chini.tk>2023-03-11 18:05:26 +0100
committerPulseAudio Marge Bot <pulseaudio-maintainers@lists.freedesktop.org>2023-03-16 20:19:39 +0000
commit3aaeb5113d2cec907bd101df22bb28b1a1b8394d (patch)
treef6d6218aa9dffa0b62c7879fcd77f4ece0efe06e
parent39b6a4c1236ccb9f826ce5c58f258b72eb06740e (diff)
downloadpulseaudio-3aaeb5113d2cec907bd101df22bb28b1a1b8394d.tar.gz
switch-on-connect: Do not overwrite user configured default sink/source
Currently module-switch-on-connect overwrites the default sink or source that the user has configured. This means that when the overwritten default sink or source becomes unavailable, the new default will be chosen based on priority and the default will not return to the originally configured value. This patch solves the issue by introducing new core variables for the sink or source chosen by the policy module which have higher priority than the user configured defaults. Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/784>
-rw-r--r--src/modules/module-switch-on-connect.c8
-rw-r--r--src/pulsecore/core.c125
-rw-r--r--src/pulsecore/core.h9
3 files changed, 131 insertions, 11 deletions
diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c
index 950ecbee2..edbab078a 100644
--- a/src/modules/module-switch-on-connect.c
+++ b/src/modules/module-switch-on-connect.c
@@ -100,7 +100,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_policy_default_sink(c, sink->name);
return PA_HOOK_OK;
}
@@ -116,7 +116,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void*
}
/* Actually do the switch to the new sink */
- pa_core_set_configured_default_sink(c, sink->name);
+ pa_core_set_policy_default_sink(c, sink->name);
return PA_HOOK_OK;
}
@@ -160,7 +160,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
/* No default source, nothing to move away, just set the new default */
if (!c->default_source) {
- pa_core_set_configured_default_source(c, source->name);
+ pa_core_set_policy_default_source(c, source->name);
return PA_HOOK_OK;
}
@@ -176,7 +176,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
}
/* Actually do the switch to the new source */
- pa_core_set_configured_default_source(c, source->name);
+ pa_core_set_policy_default_source(c, source->name);
return PA_HOOK_OK;
}
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 132f08bbb..df7b72461 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -40,6 +40,7 @@
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/strbuf.h>
+#include <pulsecore/namereg.h>
#include "core.h"
@@ -149,6 +150,10 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t
c->default_source = NULL;
c->default_sink = NULL;
+ c->configured_default_source = NULL;
+ c->configured_default_sink = NULL;
+ c->policy_default_source = NULL;
+ c->policy_default_sink = NULL;
c->default_sample_spec.format = PA_SAMPLE_S16NE;
c->default_sample_spec.rate = 44100;
@@ -261,6 +266,8 @@ static void core_free(pa_object *o) {
pa_assert(!c->default_sink);
pa_xfree(c->configured_default_source);
pa_xfree(c->configured_default_sink);
+ pa_xfree(c->policy_default_source);
+ pa_xfree(c->policy_default_sink);
pa_silence_cache_done(&c->silence_cache);
pa_mempool_unref(c->mempool);
@@ -271,6 +278,36 @@ static void core_free(pa_object *o) {
pa_xfree(c);
}
+static bool is_sink_available(pa_core *core, const char *sink_name) {
+ pa_sink *sink;
+
+ if (!(sink = pa_namereg_get(core, sink_name, PA_NAMEREG_SINK)))
+ return false;
+
+ if (!PA_SINK_IS_LINKED(sink->state))
+ return false;
+
+ if (sink->active_port && sink->active_port->available == PA_AVAILABLE_NO)
+ return false;
+
+ return true;
+}
+
+static bool is_source_available(pa_core *core, const char *source_name) {
+ pa_source *source;
+
+ if (!(source = pa_namereg_get(core, source_name, PA_NAMEREG_SOURCE)))
+ return false;
+
+ if (!PA_SOURCE_IS_LINKED(source->state))
+ return false;
+
+ if (source->active_port && source->active_port->available == PA_AVAILABLE_NO)
+ return false;
+
+ return true;
+}
+
void pa_core_set_configured_default_sink(pa_core *core, const char *sink) {
char *old_sink;
@@ -278,13 +315,21 @@ void pa_core_set_configured_default_sink(pa_core *core, const char *sink) {
old_sink = pa_xstrdup(core->configured_default_sink);
- if (pa_safe_streq(sink, old_sink))
+ /* The default sink was overwritten by the policy default sink, but the user is
+ * now setting a new default manually. Clear the policy default sink. */
+ if (core->policy_default_sink && is_sink_available(core, core->policy_default_sink)) {
+ pa_xfree(core->policy_default_sink);
+ core->policy_default_sink = NULL;
+
+ } else if (pa_safe_streq(sink, old_sink))
goto finish;
pa_xfree(core->configured_default_sink);
core->configured_default_sink = pa_xstrdup(sink);
- pa_log_info("configured_default_sink: %s -> %s",
- old_sink ? old_sink : "(unset)", sink ? sink : "(unset)");
+ if (!pa_safe_streq(sink, old_sink)) {
+ pa_log_info("configured_default_sink: %s -> %s",
+ 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);
@@ -300,12 +345,64 @@ void pa_core_set_configured_default_source(pa_core *core, const char *source) {
old_source = pa_xstrdup(core->configured_default_source);
- if (pa_safe_streq(source, old_source))
+ /* The default source was overwritten by the policy default source, but the user is
+ * now setting a new default manually. Clear the policy default source. */
+ if (core->policy_default_source && is_source_available(core, core->policy_default_source)) {
+ pa_xfree(core->policy_default_source);
+ core->policy_default_source = NULL;
+
+ } else if (pa_safe_streq(source, old_source))
goto finish;
pa_xfree(core->configured_default_source);
core->configured_default_source = pa_xstrdup(source);
- pa_log_info("configured_default_source: %s -> %s",
+ if (!pa_safe_streq(source, old_source)) {
+ pa_log_info("configured_default_source: %s -> %s",
+ old_source ? old_source : "(unset)", source ? source : "(unset)");
+ }
+ pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
+
+ pa_core_update_default_source(core);
+
+finish:
+ pa_xfree(old_source);
+}
+
+void pa_core_set_policy_default_sink(pa_core *core, const char *sink) {
+ char *old_sink;
+
+ pa_assert(core);
+
+ old_sink = pa_xstrdup(core->policy_default_sink);
+
+ if (pa_safe_streq(sink, old_sink))
+ goto finish;
+
+ pa_xfree(core->policy_default_sink);
+ core->policy_default_sink = pa_xstrdup(sink);
+ pa_log_info("policy_default_sink: %s -> %s",
+ 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);
+
+finish:
+ pa_xfree(old_sink);
+}
+
+void pa_core_set_policy_default_source(pa_core *core, const char *source) {
+ char *old_source;
+
+ pa_assert(core);
+
+ old_source = pa_xstrdup(core->policy_default_source);
+
+ if (pa_safe_streq(source, old_source))
+ goto finish;
+
+ pa_xfree(core->policy_default_source);
+ core->policy_default_source = pa_xstrdup(source);
+ pa_log_info("policy_default_source: %s -> %s",
old_source ? old_source : "(unset)", source ? source : "(unset)");
pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
@@ -331,7 +428,14 @@ static int compare_sinks(pa_sink *a, pa_sink *b) {
&& (!a->active_port || a->active_port->available != PA_AVAILABLE_NO))
return 1;
- /* The configured default sink is preferred over any other sink. */
+ /* The policy default sink is preferred over any other sink. */
+ if (pa_safe_streq(b->name, core->policy_default_sink))
+ return -1;
+ if (pa_safe_streq(a->name, core->policy_default_sink))
+ return 1;
+
+ /* The configured default sink is preferred over any other sink
+ * except the policy default sink. */
if (pa_safe_streq(b->name, core->configured_default_sink))
return -1;
if (pa_safe_streq(a->name, core->configured_default_sink))
@@ -412,7 +516,14 @@ static int compare_sources(pa_source *a, pa_source *b) {
&& (!a->active_port || a->active_port->available != PA_AVAILABLE_NO))
return 1;
- /* The configured default source is preferred over any other source. */
+ /* The policy default source is preferred over any other source. */
+ if (pa_safe_streq(b->name, core->policy_default_source))
+ return -1;
+ if (pa_safe_streq(a->name, core->policy_default_source))
+ return 1;
+
+ /* The configured default source is preferred over any other source
+ * except the policy default source. */
if (pa_safe_streq(b->name, core->configured_default_source))
return -1;
if (pa_safe_streq(a->name, core->configured_default_source))
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 118dcf291..7ac06f5d7 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -176,6 +176,13 @@ struct pa_core {
char *configured_default_sink;
char *configured_default_source;
+ /* The default sink/source set by some policy module. This will override
+ * the user configured default sink/source, so that the default will
+ * return to the user configured sink/source once the sink/source set by
+ * the policy module is no longer available. */
+ char *policy_default_sink;
+ char *policy_default_source;
+
/* The effective default sink/source. If no sink or source is explicitly
* configured as the default, we pick the device that ranks highest
* according to the compare_sinks() and compare_sources() functions in
@@ -249,6 +256,8 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t
void pa_core_set_configured_default_sink(pa_core *core, const char *sink);
void pa_core_set_configured_default_source(pa_core *core, const char *source);
+void pa_core_set_policy_default_sink(pa_core *core, const char *sink);
+void pa_core_set_policy_default_source(pa_core *core, const char *source);
/* These should be called whenever something changes that may affect the
* default sink or source choice.