X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/29c7a288177c260cf2b3d8f80e807305b96594ba..eca082a93f2619cfa10733947a81fa779cb49573:/src/pulsecore/namereg.c diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 3b9ce886..7704abe4 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -5,7 +5,7 @@ PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but @@ -30,7 +30,6 @@ #include -#include #include #include #include @@ -45,7 +44,7 @@ struct namereg_entry { void *data; }; -static pa_bool_t is_valid_char(char c) { +static bool is_valid_char(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || @@ -55,20 +54,41 @@ static pa_bool_t is_valid_char(char c) { c == '_'; } -pa_bool_t pa_namereg_is_valid_name(const char *name) { +bool pa_namereg_is_valid_name(const char *name) { const char *c; + pa_assert(name); + if (*name == 0) - return FALSE; + return false; for (c = name; *c && (c-name < PA_NAME_MAX); c++) if (!is_valid_char(*c)) - return FALSE; + return false; if (*c) - return FALSE; + return false; + + return true; +} + +bool pa_namereg_is_valid_name_or_wildcard(const char *name, pa_namereg_type_t type) { + + pa_assert(name); + + if (pa_namereg_is_valid_name(name)) + return true; + + if (type == PA_NAMEREG_SINK && + pa_streq(name, "@DEFAULT_SINK@")) + return true; + + if (type == PA_NAMEREG_SOURCE && + (pa_streq(name, "@DEFAULT_SOURCE@") || + pa_streq(name, "@DEFAULT_MONITOR@"))) + return true; - return TRUE; + return false; } char* pa_namereg_make_valid_name(const char *name) { @@ -78,7 +98,7 @@ char* pa_namereg_make_valid_name(const char *name) { if (*name == 0) return NULL; - n = pa_xmalloc(strlen(name)+1); + n = pa_xnew(char, strlen(name)+1); for (a = name, b = n; *a && (a-name < PA_NAME_MAX); a++, b++) *b = (char) (is_valid_char(*a) ? *a : '_'); @@ -88,17 +108,7 @@ char* pa_namereg_make_valid_name(const char *name) { return n; } -void pa_namereg_free(pa_core *c) { - pa_assert(c); - - if (!c->namereg) - return; - - pa_assert(pa_hashmap_size(c->namereg) == 0); - pa_hashmap_free(c->namereg, NULL, NULL); -} - -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, pa_bool_t fail) { +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, bool fail) { struct namereg_entry *e; char *n = NULL; @@ -119,9 +129,6 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t return NULL; } - if (!c->namereg) - c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - if ((e = pa_hashmap_get(c->namereg, name)) && fail) { pa_xfree(n); return NULL; @@ -163,6 +170,17 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t pa_assert_se(pa_hashmap_put(c->namereg, e->name, e) >= 0); + /* If a sink or source is registered and there was none registered + * before we inform the clients which then can ask for the default + * sink/source which is then assigned. We don't adjust the default + * sink/source here right away to give the module the chance to + * register more sinks/sources before we choose a new default + * sink/source. */ + + if ((!c->default_sink && type == PA_NAMEREG_SINK) || + (!c->default_source && type == PA_NAMEREG_SOURCE)) + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); + return e->name; } @@ -174,6 +192,11 @@ void pa_namereg_unregister(pa_core *c, const char *name) { pa_assert_se(e = pa_hashmap_remove(c->namereg, name)); + if (c->default_sink == e->data) + pa_namereg_set_default_sink(c, NULL); + else if (c->default_source == e->data) + pa_namereg_set_default_source(c, NULL); + pa_xfree(e->name); pa_xfree(e); } @@ -183,35 +206,33 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type) { uint32_t idx; pa_assert(c); - if (!name) { + if (type == PA_NAMEREG_SOURCE && (!name || pa_streq(name, "@DEFAULT_SOURCE@"))) { + pa_source *s; - if (type == PA_NAMEREG_SOURCE) - name = pa_namereg_get_default_source_name(c); - else if (type == PA_NAMEREG_SINK) - name = pa_namereg_get_default_sink_name(c); + if ((s = pa_namereg_get_default_source(c))) + return s; - } else if (strcmp(name, "@DEFAULT_SINK@") == 0) { - if (type == PA_NAMEREG_SINK) - name = pa_namereg_get_default_sink_name(c); + } else if (type == PA_NAMEREG_SINK && (!name || pa_streq(name, "@DEFAULT_SINK@"))) { + pa_sink *s; - } else if (strcmp(name, "@DEFAULT_SOURCE@") == 0) { - if (type == PA_NAMEREG_SOURCE) - name = pa_namereg_get_default_source_name(c); + if ((s = pa_namereg_get_default_sink(c))) + return s; - } else if (strcmp(name, "@DEFAULT_MONITOR@") == 0) { - if (type == PA_NAMEREG_SOURCE) { - pa_sink *k; + } else if (type == PA_NAMEREG_SOURCE && name && pa_streq(name, "@DEFAULT_MONITOR@")) { + pa_sink *s; - if ((k = pa_namereg_get(c, NULL, PA_NAMEREG_SINK))) - return k->monitor_source; - } - } else if (*name == '@') - name = NULL; + if ((s = pa_namereg_get(c, NULL, PA_NAMEREG_SINK))) + return s->monitor_source; + } if (!name) return NULL; - if (c->namereg && (e = pa_hashmap_get(c->namereg, name))) + if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD) && + !pa_namereg_is_valid_name(name)) + return NULL; + + if ((e = pa_hashmap_get(c->namereg, name))) if (e->type == type) return e->data; @@ -224,66 +245,86 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type) { return pa_idxset_get_by_index(c->sources, idx); else if (type == PA_NAMEREG_SAMPLE && c->scache) return pa_idxset_get_by_index(c->scache, idx); + else if (type == PA_NAMEREG_CARD) + return pa_idxset_get_by_index(c->cards, idx); return NULL; } -int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { - char **s; - +pa_sink* pa_namereg_set_default_sink(pa_core*c, pa_sink *s) { pa_assert(c); - pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE); - s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name; + if (s && !PA_SINK_IS_LINKED(pa_sink_get_state(s))) + return NULL; + + if (c->default_sink != s) { + c->default_sink = s; + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); + } - if (!name && !*s) - return 0; + return s; +} - if (name && *s && !strcmp(name, *s)) - return 0; +pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) { + pa_assert(c); - if (!pa_namereg_is_valid_name(name)) - return -1; + if (s && !PA_SOURCE_IS_LINKED(pa_source_get_state(s))) + return NULL; - pa_xfree(*s); - *s = pa_xstrdup(name); - pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); + if (c->default_source != s) { + c->default_source = s; + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); + } - return 0; + return s; } -const char *pa_namereg_get_default_sink_name(pa_core *c) { - pa_sink *s; +pa_sink *pa_namereg_get_default_sink(pa_core *c) { + pa_sink *s, *best = NULL; + uint32_t idx; pa_assert(c); - if (c->default_sink_name) - return c->default_sink_name; + if (c->default_sink && PA_SINK_IS_LINKED(pa_sink_get_state(c->default_sink))) + return c->default_sink; - if ((s = pa_idxset_first(c->sinks, NULL))) - pa_namereg_set_default(c, s->name, PA_NAMEREG_SINK); + PA_IDXSET_FOREACH(s, c->sinks, idx) + if (PA_SINK_IS_LINKED(pa_sink_get_state(s))) + if (!best || s->priority > best->priority) + best = s; - return c->default_sink_name; + return best; } -const char *pa_namereg_get_default_source_name(pa_core *c) { - pa_source *s; +pa_source *pa_namereg_get_default_source(pa_core *c) { + pa_source *s, *best = NULL; uint32_t idx; pa_assert(c); - if (c->default_source_name) - return c->default_source_name; - - for (s = pa_idxset_first(c->sources, &idx); s; s = pa_idxset_next(c->sources, &idx)) - if (!s->monitor_of) { - pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); - break; - } - - if (!c->default_source_name) - if ((s = pa_idxset_first(c->sources, NULL))) - pa_namereg_set_default(c, s->name, PA_NAMEREG_SOURCE); - - return c->default_source_name; + if (c->default_source && PA_SOURCE_IS_LINKED(pa_source_get_state(c->default_source))) + return c->default_source; + + /* First, try to find one that isn't a monitor */ + PA_IDXSET_FOREACH(s, c->sources, idx) + if (!s->monitor_of && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) + if (!best || + s->priority > best->priority) + best = s; + + if (best) + return best; + + /* Then, fallback to a monitor */ + PA_IDXSET_FOREACH(s, c->sources, idx) + if (PA_SOURCE_IS_LINKED(pa_source_get_state(s))) + if (!best || + s->priority > best->priority || + (s->priority == best->priority && + s->monitor_of && + best->monitor_of && + s->monitor_of->priority > best->monitor_of->priority)) + best = s; + + return best; }