summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.