]> code.delx.au - pulseaudio/blob - src/pulse/ext-device-manager.c
conf-parser: Add support for parsing property lists.
[pulseaudio] / src / pulse / ext-device-manager.c
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 static void ext_device_manager_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
50 pa_operation *o = userdata;
51 uint32_t version = PA_INVALID_INDEX;
52
53 pa_assert(pd);
54 pa_assert(o);
55 pa_assert(PA_REFCNT_VALUE(o) >= 1);
56
57 if (!o->context)
58 goto finish;
59
60 if (command != PA_COMMAND_REPLY) {
61 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
62 goto finish;
63
64 } else if (pa_tagstruct_getu32(t, &version) < 0 ||
65 !pa_tagstruct_eof(t)) {
66
67 pa_context_fail(o->context, PA_ERR_PROTOCOL);
68 goto finish;
69 }
70
71 if (o->callback) {
72 pa_ext_device_manager_test_cb_t cb = (pa_ext_device_manager_test_cb_t) o->callback;
73 cb(o->context, version, o->userdata);
74 }
75
76 finish:
77 pa_operation_done(o);
78 pa_operation_unref(o);
79 }
80
81 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 pa_assert(c);
91 pa_assert(PA_REFCNT_VALUE(c) >= 1);
92
93 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
94 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
95 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
96
97 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
98
99 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
100 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
101 pa_tagstruct_puts(t, "module-device-manager");
102 pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
103 pa_pstream_send_tagstruct(c->pstream, t);
104 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 return o;
107 }
108
109 static void ext_device_manager_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
110 pa_operation *o = userdata;
111 int eol = 1;
112
113 pa_assert(pd);
114 pa_assert(o);
115 pa_assert(PA_REFCNT_VALUE(o) >= 1);
116
117 if (!o->context)
118 goto finish;
119
120 if (command != PA_COMMAND_REPLY) {
121 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
122 goto finish;
123
124 eol = -1;
125 } else {
126
127 while (!pa_tagstruct_eof(t)) {
128 pa_ext_device_manager_info i;
129
130 memset(&i, 0, sizeof(i));
131
132 if (pa_tagstruct_gets(t, &i.name) < 0 ||
133 pa_tagstruct_gets(t, &i.description) < 0 ||
134 pa_tagstruct_gets(t, &i.icon) < 0 ||
135 pa_tagstruct_getu32(t, &i.index) < 0 ||
136 pa_tagstruct_getu32(t, &i.n_role_priorities) < 0) {
137
138 pa_context_fail(o->context, PA_ERR_PROTOCOL);
139 goto finish;
140 }
141
142 if (i.n_role_priorities > 0) {
143 uint32_t j;
144 i.role_priorities = pa_xnew0(pa_ext_device_manager_role_priority_info, i.n_role_priorities+1);
145
146 for (j = 0; j < i.n_role_priorities; j++) {
147
148 if (pa_tagstruct_gets(t, &i.role_priorities[j].role) < 0 ||
149 pa_tagstruct_getu32(t, &i.role_priorities[j].priority) < 0) {
150
151 pa_context_fail(o->context, PA_ERR_PROTOCOL);
152 pa_xfree(i.role_priorities);
153 goto finish;
154 }
155 }
156
157 /* Terminate with an extra NULL entry, just to make sure */
158 i.role_priorities[j].role = NULL;
159 i.role_priorities[j].priority = 0;
160 }
161
162 if (o->callback) {
163 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
164 cb(o->context, &i, 0, o->userdata);
165 }
166
167 pa_xfree(i.role_priorities);
168 }
169 }
170
171 if (o->callback) {
172 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
173 cb(o->context, NULL, eol, o->userdata);
174 }
175
176 finish:
177 pa_operation_done(o);
178 pa_operation_unref(o);
179 }
180
181 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 pa_assert(c);
191 pa_assert(PA_REFCNT_VALUE(c) >= 1);
192
193 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
194 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
195 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
196
197 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
198
199 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
200 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
201 pa_tagstruct_puts(t, "module-device-manager");
202 pa_tagstruct_putu32(t, SUBCOMMAND_READ);
203 pa_pstream_send_tagstruct(c->pstream, t);
204 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 return o;
207 }
208
209 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 pa_operation *o = NULL;
218 pa_tagstruct *t = NULL;
219
220 pa_assert(c);
221 pa_assert(PA_REFCNT_VALUE(c) >= 1);
222 pa_assert(device);
223 pa_assert(description);
224
225 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
226 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
227 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
228
229 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
230
231 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
232 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
233 pa_tagstruct_puts(t, "module-device-manager");
234 pa_tagstruct_putu32(t, SUBCOMMAND_RENAME);
235
236 pa_tagstruct_puts(t, device);
237 pa_tagstruct_puts(t, description);
238
239 pa_pstream_send_tagstruct(c->pstream, t);
240 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 return o;
243 }
244
245 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 pa_operation *o = NULL;
253 pa_tagstruct *t = NULL;
254 const char *const *k;
255
256 pa_assert(c);
257 pa_assert(PA_REFCNT_VALUE(c) >= 1);
258 pa_assert(s);
259
260 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
261 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
262 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
263
264 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
265
266 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
267 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
268 pa_tagstruct_puts(t, "module-device-manager");
269 pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
270
271 for (k = s; *k; k++) {
272 if (!*k || !**k)
273 goto fail;
274
275 pa_tagstruct_puts(t, *k);
276 }
277
278 pa_pstream_send_tagstruct(c->pstream, t);
279 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 return o;
282
283 fail:
284 if (o) {
285 pa_operation_cancel(o);
286 pa_operation_unref(o);
287 }
288
289 if (t)
290 pa_tagstruct_free(t);
291
292 pa_context_set_error(c, PA_ERR_INVALID);
293 return NULL;
294 }
295
296 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 pa_operation *o = NULL;
304 pa_tagstruct *t = NULL;
305
306 pa_assert(c);
307 pa_assert(PA_REFCNT_VALUE(c) >= 1);
308
309 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
310 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
311 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
312
313 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
314
315 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
316 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
317 pa_tagstruct_puts(t, "module-device-manager");
318 pa_tagstruct_putu32(t, SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING);
319 pa_tagstruct_put_boolean(t, !!enable);
320
321 pa_pstream_send_tagstruct(c->pstream, t);
322 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 return o;
325 }
326
327 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 pa_operation *o = NULL;
336 pa_tagstruct *t = NULL;
337
338 pa_assert(c);
339 pa_assert(PA_REFCNT_VALUE(c) >= 1);
340
341 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
342 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
343 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
344
345 pa_assert(role);
346 pa_assert(devices);
347
348 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
349
350 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
351 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
352 pa_tagstruct_puts(t, "module-device-manager");
353 pa_tagstruct_putu32(t, SUBCOMMAND_REORDER);
354 pa_tagstruct_puts(t, role);
355
356 i = 0; while (devices[i]) i++;
357 pa_tagstruct_putu32(t, i);
358
359 i = 0;
360 while (devices[i])
361 pa_tagstruct_puts(t, devices[i++]);
362
363 pa_pstream_send_tagstruct(c->pstream, t);
364 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 return o;
367 }
368
369 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 pa_assert(c);
380 pa_assert(PA_REFCNT_VALUE(c) >= 1);
381
382 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
383 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
384 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
385
386 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
387
388 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
389 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
390 pa_tagstruct_puts(t, "module-device-manager");
391 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
392 pa_tagstruct_put_boolean(t, enable);
393 pa_pstream_send_tagstruct(c->pstream, t);
394 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 return o;
397 }
398
399 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 pa_assert(c);
405 pa_assert(PA_REFCNT_VALUE(c) >= 1);
406
407 if (pa_detect_fork())
408 return;
409
410 c->ext_device_manager.callback = cb;
411 c->ext_device_manager.userdata = userdata;
412 }
413
414 void pa_ext_device_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
415 uint32_t subcommand;
416
417 pa_assert(c);
418 pa_assert(PA_REFCNT_VALUE(c) >= 1);
419 pa_assert(t);
420
421 if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
422 !pa_tagstruct_eof(t)) {
423
424 pa_context_fail(c, PA_ERR_PROTOCOL);
425 return;
426 }
427
428 if (subcommand != SUBCOMMAND_EVENT) {
429 pa_context_fail(c, PA_ERR_PROTOCOL);
430 return;
431 }
432
433 if (c->ext_device_manager.callback)
434 c->ext_device_manager.callback(c, c->ext_device_manager.userdata);
435 }