diff options
-rw-r--r-- | src/modules/module-switch-on-connect.c | 8 | ||||
-rw-r--r-- | src/pulsecore/core.c | 125 | ||||
-rw-r--r-- | src/pulsecore/core.h | 9 |
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. |