Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : :
6 : : PulseAudio is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU Lesser General Public License as published
8 : : by the Free Software Foundation; either version 2.1 of the License,
9 : : or (at your option) any later version.
10 : :
11 : : PulseAudio is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Lesser General Public License
17 : : along with PulseAudio; if not, write to the Free Software
18 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 : : USA.
20 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #include <stdlib.h>
27 : : #include <string.h>
28 : : #include <string.h>
29 : : #include <stdio.h>
30 : :
31 : : #include <pulse/xmalloc.h>
32 : :
33 : : #include <pulsecore/source.h>
34 : : #include <pulsecore/sink.h>
35 : : #include <pulsecore/core-subscribe.h>
36 : : #include <pulsecore/core-util.h>
37 : : #include <pulsecore/macro.h>
38 : :
39 : : #include "namereg.h"
40 : :
41 : : struct namereg_entry {
42 : : pa_namereg_type_t type;
43 : : char *name;
44 : : void *data;
45 : : };
46 : :
47 : : static pa_bool_t is_valid_char(char c) {
48 : 0 : return
49 : 0 : (c >= 'a' && c <= 'z') ||
50 : 0 : (c >= 'A' && c <= 'Z') ||
51 [ # # ][ # # ]: 0 : (c >= '0' && c <= '9') ||
52 : 0 : c == '.' ||
53 [ # # ][ # # ]: 0 : c == '-' ||
[ # # ][ # # ]
54 : 0 : c == '_';
55 : : }
56 : :
57 : 0 : pa_bool_t pa_namereg_is_valid_name(const char *name) {
58 : : const char *c;
59 : :
60 [ # # ]: 0 : pa_assert(name);
61 : :
62 [ # # ]: 0 : if (*name == 0)
63 : : return FALSE;
64 : :
65 [ # # ][ # # ]: 0 : for (c = name; *c && (c-name < PA_NAME_MAX); c++)
66 [ # # ]: 0 : if (!is_valid_char(*c))
67 : : return FALSE;
68 : :
69 [ # # ]: 0 : if (*c)
70 : : return FALSE;
71 : :
72 : 0 : return TRUE;
73 : : }
74 : :
75 : 0 : pa_bool_t pa_namereg_is_valid_name_or_wildcard(const char *name, pa_namereg_type_t type) {
76 : :
77 [ # # ]: 0 : pa_assert(name);
78 : :
79 [ # # ]: 0 : if (pa_namereg_is_valid_name(name))
80 : : return TRUE;
81 : :
82 [ # # ][ # # ]: 0 : if (type == PA_NAMEREG_SINK &&
83 : 0 : pa_streq(name, "@DEFAULT_SINK@"))
84 : : return TRUE;
85 : :
86 [ # # ][ # # ]: 0 : if (type == PA_NAMEREG_SOURCE &&
87 [ # # ]: 0 : (pa_streq(name, "@DEFAULT_SOURCE@") ||
88 : 0 : pa_streq(name, "@DEFAULT_MONITOR@")))
89 : : return TRUE;
90 : :
91 : 0 : return FALSE;
92 : : }
93 : :
94 : 0 : char* pa_namereg_make_valid_name(const char *name) {
95 : : const char *a;
96 : : char *b, *n;
97 : :
98 [ # # ]: 0 : if (*name == 0)
99 : : return NULL;
100 : :
101 : 0 : n = pa_xnew(char, strlen(name)+1);
102 : :
103 [ # # ][ # # ]: 0 : for (a = name, b = n; *a && (a-name < PA_NAME_MAX); a++, b++)
104 [ # # ]: 0 : *b = (char) (is_valid_char(*a) ? *a : '_');
105 : :
106 : 0 : *b = 0;
107 : :
108 : 0 : return n;
109 : : }
110 : :
111 : 0 : const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, pa_bool_t fail) {
112 : : struct namereg_entry *e;
113 : 0 : char *n = NULL;
114 : :
115 [ # # ]: 0 : pa_assert(c);
116 [ # # ]: 0 : pa_assert(name);
117 [ # # ]: 0 : pa_assert(data);
118 : :
119 [ # # ]: 0 : if (!*name)
120 : : return NULL;
121 : :
122 [ # # # # ]: 0 : if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD) &&
123 : 0 : !pa_namereg_is_valid_name(name)) {
124 : :
125 [ # # ]: 0 : if (fail)
126 : : return NULL;
127 : :
128 [ # # ]: 0 : if (!(name = n = pa_namereg_make_valid_name(name)))
129 : : return NULL;
130 : : }
131 : :
132 [ # # ][ # # ]: 0 : if ((e = pa_hashmap_get(c->namereg, name)) && fail) {
133 : 0 : pa_xfree(n);
134 : 0 : return NULL;
135 : : }
136 : :
137 [ # # ]: 0 : if (e) {
138 : : unsigned i;
139 : 0 : size_t l = strlen(name);
140 : : char *k;
141 : :
142 [ # # ]: 0 : if (l+4 > PA_NAME_MAX) {
143 : 0 : pa_xfree(n);
144 : 0 : return NULL;
145 : : }
146 : :
147 : 0 : k = pa_xmalloc(l+4);
148 : :
149 [ # # ]: 0 : for (i = 2; i <= 99; i++) {
150 : 0 : pa_snprintf(k, l+4, "%s.%u", name, i);
151 : :
152 [ # # ]: 0 : if (!(e = pa_hashmap_get(c->namereg, k)))
153 : : break;
154 : : }
155 : :
156 [ # # ]: 0 : if (e) {
157 : 0 : pa_xfree(n);
158 : 0 : pa_xfree(k);
159 : 0 : return NULL;
160 : : }
161 : :
162 : 0 : pa_xfree(n);
163 : 0 : n = k;
164 : : }
165 : :
166 : 0 : e = pa_xnew(struct namereg_entry, 1);
167 : 0 : e->type = type;
168 [ # # ]: 0 : e->name = n ? n : pa_xstrdup(name);
169 : 0 : e->data = data;
170 : :
171 [ # # ]: 0 : pa_assert_se(pa_hashmap_put(c->namereg, e->name, e) >= 0);
172 : :
173 : : /* If a sink or source is registered and there was none registered
174 : : * before we inform the clients which then can ask for the default
175 : : * sink/source which is then assigned. We don't adjust the default
176 : : * sink/source here right away to give the module the chance to
177 : : * register more sinks/sources before we choose a new default
178 : : * sink/source. */
179 : :
180 [ # # ][ # # ]: 0 : if ((!c->default_sink && type == PA_NAMEREG_SINK) ||
181 : 0 : (!c->default_source && type == PA_NAMEREG_SOURCE))
182 : 0 : pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
183 : :
184 : 0 : return e->name;
185 : : }
186 : :
187 : 0 : void pa_namereg_unregister(pa_core *c, const char *name) {
188 : : struct namereg_entry *e;
189 : :
190 [ # # ]: 0 : pa_assert(c);
191 [ # # ]: 0 : pa_assert(name);
192 : :
193 [ # # ]: 0 : pa_assert_se(e = pa_hashmap_remove(c->namereg, name));
194 : :
195 [ # # ]: 0 : if (c->default_sink == e->data)
196 : 0 : pa_namereg_set_default_sink(c, NULL);
197 [ # # ]: 0 : else if (c->default_source == e->data)
198 : 0 : pa_namereg_set_default_source(c, NULL);
199 : :
200 : 0 : pa_xfree(e->name);
201 : 0 : pa_xfree(e);
202 : 0 : }
203 : :
204 : 0 : void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type) {
205 : : struct namereg_entry *e;
206 : : uint32_t idx;
207 [ # # ]: 0 : pa_assert(c);
208 : :
209 [ # # ][ # # ]: 0 : if (type == PA_NAMEREG_SOURCE && (!name || pa_streq(name, "@DEFAULT_SOURCE@"))) {
[ # # ]
210 : : pa_source *s;
211 : :
212 [ # # ]: 0 : if ((s = pa_namereg_get_default_source(c)))
213 : : return s;
214 : :
215 [ # # ][ # # ]: 0 : } else if (type == PA_NAMEREG_SINK && (!name || pa_streq(name, "@DEFAULT_SINK@"))) {
[ # # ]
216 : : pa_sink *s;
217 : :
218 [ # # ]: 0 : if ((s = pa_namereg_get_default_sink(c)))
219 : : return s;
220 : :
221 [ # # ][ # # ]: 0 : } else if (type == PA_NAMEREG_SOURCE && name && pa_streq(name, "@DEFAULT_MONITOR@")) {
222 : : pa_sink *s;
223 : :
224 [ # # ]: 0 : if ((s = pa_namereg_get(c, NULL, PA_NAMEREG_SINK)))
225 : 0 : return s->monitor_source;
226 : : }
227 : :
228 [ # # ]: 0 : if (!name)
229 : : return NULL;
230 : :
231 [ # # # # ]: 0 : if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD) &&
232 : 0 : !pa_namereg_is_valid_name(name))
233 : : return NULL;
234 : :
235 [ # # ]: 0 : if ((e = pa_hashmap_get(c->namereg, name)))
236 [ # # ]: 0 : if (e->type == type)
237 : 0 : return e->data;
238 : :
239 [ # # ]: 0 : if (pa_atou(name, &idx) < 0)
240 : : return NULL;
241 : :
242 [ # # ]: 0 : if (type == PA_NAMEREG_SINK)
243 : 0 : return pa_idxset_get_by_index(c->sinks, idx);
244 [ # # ]: 0 : else if (type == PA_NAMEREG_SOURCE)
245 : 0 : return pa_idxset_get_by_index(c->sources, idx);
246 [ # # ][ # # ]: 0 : else if (type == PA_NAMEREG_SAMPLE && c->scache)
247 : 0 : return pa_idxset_get_by_index(c->scache, idx);
248 [ # # ]: 0 : else if (type == PA_NAMEREG_CARD)
249 : 0 : return pa_idxset_get_by_index(c->cards, idx);
250 : :
251 : : return NULL;
252 : : }
253 : :
254 : 0 : pa_sink* pa_namereg_set_default_sink(pa_core*c, pa_sink *s) {
255 [ # # ]: 0 : pa_assert(c);
256 : :
257 [ # # ][ # # ]: 0 : if (s && !PA_SINK_IS_LINKED(pa_sink_get_state(s)))
258 : : return NULL;
259 : :
260 [ # # ]: 0 : if (c->default_sink != s) {
261 : 0 : c->default_sink = s;
262 : 0 : pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
263 : : }
264 : :
265 : : return s;
266 : : }
267 : :
268 : 0 : pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) {
269 [ # # ]: 0 : pa_assert(c);
270 : :
271 [ # # ][ # # ]: 0 : if (s && !PA_SOURCE_IS_LINKED(pa_source_get_state(s)))
272 : : return NULL;
273 : :
274 [ # # ]: 0 : if (c->default_source != s) {
275 : 0 : c->default_source = s;
276 : 0 : pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
277 : : }
278 : :
279 : : return s;
280 : : }
281 : :
282 : 0 : pa_sink *pa_namereg_get_default_sink(pa_core *c) {
283 : 0 : pa_sink *s, *best = NULL;
284 : : uint32_t idx;
285 : :
286 [ # # ]: 0 : pa_assert(c);
287 : :
288 [ # # ][ # # ]: 0 : if (c->default_sink && PA_SINK_IS_LINKED(pa_sink_get_state(c->default_sink)))
289 : 0 : return c->default_sink;
290 : :
291 [ # # ]: 0 : PA_IDXSET_FOREACH(s, c->sinks, idx)
292 [ # # ]: 0 : if (PA_SINK_IS_LINKED(pa_sink_get_state(s)))
293 [ # # ][ # # ]: 0 : if (!best || s->priority > best->priority)
294 : 0 : best = s;
295 : :
296 : : return best;
297 : : }
298 : :
299 : 0 : pa_source *pa_namereg_get_default_source(pa_core *c) {
300 : 0 : pa_source *s, *best = NULL;
301 : : uint32_t idx;
302 : :
303 [ # # ]: 0 : pa_assert(c);
304 : :
305 [ # # ][ # # ]: 0 : if (c->default_source && PA_SOURCE_IS_LINKED(pa_source_get_state(c->default_source)))
306 : 0 : return c->default_source;
307 : :
308 : : /* First, try to find one that isn't a monitor */
309 [ # # ]: 0 : PA_IDXSET_FOREACH(s, c->sources, idx)
310 [ # # ][ # # ]: 0 : if (!s->monitor_of && PA_SOURCE_IS_LINKED(pa_source_get_state(s)))
311 [ # # ][ # # ]: 0 : if (!best ||
312 : 0 : s->priority > best->priority)
313 : 0 : best = s;
314 : :
315 [ # # ]: 0 : if (best)
316 : : return best;
317 : :
318 : : /* Then, fallback to a monitor */
319 [ # # ]: 0 : PA_IDXSET_FOREACH(s, c->sources, idx)
320 [ # # ]: 0 : if (PA_SOURCE_IS_LINKED(pa_source_get_state(s)))
321 [ # # ][ # # ]: 0 : if (!best ||
322 [ # # ]: 0 : s->priority > best->priority ||
323 [ # # ]: 0 : (s->priority == best->priority &&
324 [ # # ]: 0 : s->monitor_of &&
325 [ # # ]: 0 : best->monitor_of &&
326 : 0 : s->monitor_of->priority > best->monitor_of->priority))
327 : 0 : best = s;
328 : :
329 : : return best;
330 : : }
|