Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2008 Lennart Poettering
5 : : Copyright 2009 Colin Guthrie
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as published
9 : : by the Free Software Foundation; either version 2.1 of the License,
10 : : or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public License
18 : : along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : : #include <pulse/context.h>
28 : : #include <pulse/xmalloc.h>
29 : : #include <pulse/fork-detect.h>
30 : : #include <pulse/operation.h>
31 : :
32 : : #include <pulsecore/macro.h>
33 : : #include <pulsecore/pstream-util.h>
34 : :
35 : : #include "internal.h"
36 : : #include "ext-device-manager.h"
37 : :
38 : : enum {
39 : : SUBCOMMAND_TEST,
40 : : SUBCOMMAND_READ,
41 : : SUBCOMMAND_RENAME,
42 : : SUBCOMMAND_DELETE,
43 : : SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
44 : : SUBCOMMAND_REORDER,
45 : : SUBCOMMAND_SUBSCRIBE,
46 : : SUBCOMMAND_EVENT
47 : : };
48 : :
49 : 0 : static void ext_device_manager_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
50 : 0 : pa_operation *o = userdata;
51 : 0 : uint32_t version = PA_INVALID_INDEX;
52 : :
53 [ # # ]: 0 : pa_assert(pd);
54 [ # # ]: 0 : pa_assert(o);
55 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(o) >= 1);
56 : :
57 [ # # ]: 0 : if (!o->context)
58 : : goto finish;
59 : :
60 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
61 [ # # ]: 0 : if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
62 : : goto finish;
63 : :
64 [ # # # # ]: 0 : } else if (pa_tagstruct_getu32(t, &version) < 0 ||
65 : 0 : !pa_tagstruct_eof(t)) {
66 : :
67 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
68 : 0 : goto finish;
69 : : }
70 : :
71 [ # # ]: 0 : if (o->callback) {
72 : 0 : pa_ext_device_manager_test_cb_t cb = (pa_ext_device_manager_test_cb_t) o->callback;
73 : 0 : cb(o->context, version, o->userdata);
74 : : }
75 : :
76 : : finish:
77 : 0 : pa_operation_done(o);
78 : 0 : pa_operation_unref(o);
79 : 0 : }
80 : :
81 : 0 : pa_operation *pa_ext_device_manager_test(
82 : : pa_context *c,
83 : : pa_ext_device_manager_test_cb_t cb,
84 : : void *userdata) {
85 : :
86 : : uint32_t tag;
87 : : pa_operation *o;
88 : : pa_tagstruct *t;
89 : :
90 [ # # ]: 0 : pa_assert(c);
91 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
92 : :
93 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
94 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
95 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
96 : :
97 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
98 : :
99 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
100 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
101 : 0 : pa_tagstruct_puts(t, "module-device-manager");
102 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
103 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
104 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_device_manager_test_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
105 : :
106 : 0 : return o;
107 : : }
108 : :
109 : 0 : static void ext_device_manager_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
110 : 0 : pa_operation *o = userdata;
111 : 0 : int eol = 1;
112 : :
113 [ # # ]: 0 : pa_assert(pd);
114 [ # # ]: 0 : pa_assert(o);
115 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(o) >= 1);
116 : :
117 [ # # ]: 0 : if (!o->context)
118 : : goto finish;
119 : :
120 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
121 [ # # ]: 0 : if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
122 : : goto finish;
123 : :
124 : : eol = -1;
125 : : } else {
126 : :
127 [ # # ]: 0 : while (!pa_tagstruct_eof(t)) {
128 : : pa_ext_device_manager_info i;
129 : :
130 : : memset(&i, 0, sizeof(i));
131 : :
132 [ # # # # ]: 0 : if (pa_tagstruct_gets(t, &i.name) < 0 ||
133 [ # # ]: 0 : pa_tagstruct_gets(t, &i.description) < 0 ||
134 [ # # ]: 0 : pa_tagstruct_gets(t, &i.icon) < 0 ||
135 [ # # ]: 0 : pa_tagstruct_getu32(t, &i.index) < 0 ||
136 : 0 : pa_tagstruct_getu32(t, &i.n_role_priorities) < 0) {
137 : :
138 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
139 : 0 : goto finish;
140 : : }
141 : :
142 [ # # ]: 0 : if (i.n_role_priorities > 0) {
143 : : uint32_t j;
144 : 0 : i.role_priorities = pa_xnew0(pa_ext_device_manager_role_priority_info, i.n_role_priorities+1);
145 : :
146 [ # # ]: 0 : for (j = 0; j < i.n_role_priorities; j++) {
147 : :
148 [ # # # # ]: 0 : if (pa_tagstruct_gets(t, &i.role_priorities[j].role) < 0 ||
149 : 0 : pa_tagstruct_getu32(t, &i.role_priorities[j].priority) < 0) {
150 : :
151 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
152 : 0 : pa_xfree(i.role_priorities);
153 : 0 : goto finish;
154 : : }
155 : : }
156 : :
157 : : /* Terminate with an extra NULL entry, just to make sure */
158 : 0 : i.role_priorities[j].role = NULL;
159 : 0 : i.role_priorities[j].priority = 0;
160 : : }
161 : :
162 [ # # ]: 0 : if (o->callback) {
163 : 0 : pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
164 : 0 : cb(o->context, &i, 0, o->userdata);
165 : : }
166 : :
167 : 0 : pa_xfree(i.role_priorities);
168 : : }
169 : : }
170 : :
171 [ # # ]: 0 : if (o->callback) {
172 : 0 : pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
173 : 0 : cb(o->context, NULL, eol, o->userdata);
174 : : }
175 : :
176 : : finish:
177 : 0 : pa_operation_done(o);
178 : 0 : pa_operation_unref(o);
179 : 0 : }
180 : :
181 : 0 : pa_operation *pa_ext_device_manager_read(
182 : : pa_context *c,
183 : : pa_ext_device_manager_read_cb_t cb,
184 : : void *userdata) {
185 : :
186 : : uint32_t tag;
187 : : pa_operation *o;
188 : : pa_tagstruct *t;
189 : :
190 [ # # ]: 0 : pa_assert(c);
191 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
192 : :
193 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
194 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
195 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
196 : :
197 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
198 : :
199 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
200 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
201 : 0 : pa_tagstruct_puts(t, "module-device-manager");
202 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_READ);
203 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
204 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_device_manager_read_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
205 : :
206 : 0 : return o;
207 : : }
208 : :
209 : 0 : pa_operation *pa_ext_device_manager_set_device_description(
210 : : pa_context *c,
211 : : const char* device,
212 : : const char* description,
213 : : pa_context_success_cb_t cb,
214 : : void *userdata) {
215 : :
216 : : uint32_t tag;
217 : 0 : pa_operation *o = NULL;
218 : 0 : pa_tagstruct *t = NULL;
219 : :
220 [ # # ]: 0 : pa_assert(c);
221 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
222 [ # # ]: 0 : pa_assert(device);
223 [ # # ]: 0 : pa_assert(description);
224 : :
225 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
226 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
227 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
228 : :
229 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
230 : :
231 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
232 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
233 : 0 : pa_tagstruct_puts(t, "module-device-manager");
234 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_RENAME);
235 : :
236 : 0 : pa_tagstruct_puts(t, device);
237 : 0 : pa_tagstruct_puts(t, description);
238 : :
239 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
240 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
241 : :
242 : 0 : return o;
243 : : }
244 : :
245 : 0 : pa_operation *pa_ext_device_manager_delete(
246 : : pa_context *c,
247 : : const char *const s[],
248 : : pa_context_success_cb_t cb,
249 : : void *userdata) {
250 : :
251 : : uint32_t tag;
252 : 0 : pa_operation *o = NULL;
253 : 0 : pa_tagstruct *t = NULL;
254 : : const char *const *k;
255 : :
256 [ # # ]: 0 : pa_assert(c);
257 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
258 [ # # ]: 0 : pa_assert(s);
259 : :
260 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
261 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
262 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
263 : :
264 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
265 : :
266 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
267 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
268 : 0 : pa_tagstruct_puts(t, "module-device-manager");
269 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
270 : :
271 [ # # ]: 0 : for (k = s; *k; k++) {
272 [ # # ][ # # ]: 0 : if (!*k || !**k)
273 : : goto fail;
274 : :
275 : 0 : pa_tagstruct_puts(t, *k);
276 : : }
277 : :
278 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
279 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
280 : :
281 : 0 : return o;
282 : :
283 : : fail:
284 [ # # ]: 0 : if (o) {
285 : 0 : pa_operation_cancel(o);
286 : 0 : pa_operation_unref(o);
287 : : }
288 : :
289 [ # # ]: 0 : if (t)
290 : 0 : pa_tagstruct_free(t);
291 : :
292 : 0 : pa_context_set_error(c, PA_ERR_INVALID);
293 : 0 : return NULL;
294 : : }
295 : :
296 : 0 : pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
297 : : pa_context *c,
298 : : int enable,
299 : : pa_context_success_cb_t cb,
300 : : void *userdata) {
301 : :
302 : : uint32_t tag;
303 : 0 : pa_operation *o = NULL;
304 : 0 : pa_tagstruct *t = NULL;
305 : :
306 [ # # ]: 0 : pa_assert(c);
307 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
308 : :
309 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
310 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
311 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
312 : :
313 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
314 : :
315 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
316 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
317 : 0 : pa_tagstruct_puts(t, "module-device-manager");
318 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING);
319 : 0 : pa_tagstruct_put_boolean(t, !!enable);
320 : :
321 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
322 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
323 : :
324 : 0 : return o;
325 : : }
326 : :
327 : 0 : pa_operation *pa_ext_device_manager_reorder_devices_for_role(
328 : : pa_context *c,
329 : : const char* role,
330 : : const char** devices,
331 : : pa_context_success_cb_t cb,
332 : : void *userdata) {
333 : :
334 : : uint32_t tag, i;
335 : 0 : pa_operation *o = NULL;
336 : 0 : pa_tagstruct *t = NULL;
337 : :
338 [ # # ]: 0 : pa_assert(c);
339 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
340 : :
341 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
342 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
343 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
344 : :
345 [ # # ]: 0 : pa_assert(role);
346 [ # # ]: 0 : pa_assert(devices);
347 : :
348 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
349 : :
350 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
351 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
352 : 0 : pa_tagstruct_puts(t, "module-device-manager");
353 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_REORDER);
354 : 0 : pa_tagstruct_puts(t, role);
355 : :
356 [ # # ]: 0 : i = 0; while (devices[i]) i++;
357 : 0 : pa_tagstruct_putu32(t, i);
358 : :
359 : 0 : i = 0;
360 [ # # ]: 0 : while (devices[i])
361 : 0 : pa_tagstruct_puts(t, devices[i++]);
362 : :
363 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
364 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
365 : :
366 : 0 : return o;
367 : : }
368 : :
369 : 0 : pa_operation *pa_ext_device_manager_subscribe(
370 : : pa_context *c,
371 : : int enable,
372 : : pa_context_success_cb_t cb,
373 : : void *userdata) {
374 : :
375 : : uint32_t tag;
376 : : pa_operation *o;
377 : : pa_tagstruct *t;
378 : :
379 [ # # ]: 0 : pa_assert(c);
380 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
381 : :
382 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
383 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
384 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
385 : :
386 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
387 : :
388 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
389 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
390 : 0 : pa_tagstruct_puts(t, "module-device-manager");
391 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
392 : 0 : pa_tagstruct_put_boolean(t, enable);
393 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
394 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
395 : :
396 : 0 : return o;
397 : : }
398 : :
399 : 0 : void pa_ext_device_manager_set_subscribe_cb(
400 : : pa_context *c,
401 : : pa_ext_device_manager_subscribe_cb_t cb,
402 : : void *userdata) {
403 : :
404 [ # # ]: 0 : pa_assert(c);
405 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
406 : :
407 [ # # ]: 0 : if (pa_detect_fork())
408 : 0 : return;
409 : :
410 : 0 : c->ext_device_manager.callback = cb;
411 : 0 : c->ext_device_manager.userdata = userdata;
412 : : }
413 : :
414 : 0 : void pa_ext_device_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
415 : : uint32_t subcommand;
416 : :
417 [ # # ]: 0 : pa_assert(c);
418 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
419 [ # # ]: 0 : pa_assert(t);
420 : :
421 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
422 : 0 : !pa_tagstruct_eof(t)) {
423 : :
424 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
425 : 0 : return;
426 : : }
427 : :
428 [ # # ]: 0 : if (subcommand != SUBCOMMAND_EVENT) {
429 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
430 : 0 : return;
431 : : }
432 : :
433 [ # # ]: 0 : if (c->ext_device_manager.callback)
434 : 0 : c->ext_device_manager.callback(c, c->ext_device_manager.userdata);
435 : : }
|