]> code.delx.au - pulseaudio/blob - src/pulse/ext-device-manager.c
Merge branch 'master' of git://0pointer.de/pulseaudio
[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/gccmacro.h>
29 #include <pulse/xmalloc.h>
30
31 #include <pulsecore/macro.h>
32 #include <pulsecore/pstream-util.h>
33
34 #include "internal.h"
35 #include "operation.h"
36 #include "fork-detect.h"
37
38 #include "ext-device-manager.h"
39
40 enum {
41 SUBCOMMAND_TEST,
42 SUBCOMMAND_READ,
43 SUBCOMMAND_RENAME,
44 SUBCOMMAND_DELETE,
45 SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
46 SUBCOMMAND_REORDER,
47 SUBCOMMAND_SUBSCRIBE,
48 SUBCOMMAND_EVENT
49 };
50
51 static void ext_device_manager_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
52 pa_operation *o = userdata;
53 uint32_t version = PA_INVALID_INDEX;
54
55 pa_assert(pd);
56 pa_assert(o);
57 pa_assert(PA_REFCNT_VALUE(o) >= 1);
58
59 if (!o->context)
60 goto finish;
61
62 if (command != PA_COMMAND_REPLY) {
63 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
64 goto finish;
65
66 } else if (pa_tagstruct_getu32(t, &version) < 0 ||
67 !pa_tagstruct_eof(t)) {
68
69 pa_context_fail(o->context, PA_ERR_PROTOCOL);
70 goto finish;
71 }
72
73 if (o->callback) {
74 pa_ext_device_manager_test_cb_t cb = (pa_ext_device_manager_test_cb_t) o->callback;
75 cb(o->context, version, o->userdata);
76 }
77
78 finish:
79 pa_operation_done(o);
80 pa_operation_unref(o);
81 }
82
83 pa_operation *pa_ext_device_manager_test(
84 pa_context *c,
85 pa_ext_device_manager_test_cb_t cb,
86 void *userdata) {
87
88 uint32_t tag;
89 pa_operation *o;
90 pa_tagstruct *t;
91
92 pa_assert(c);
93 pa_assert(PA_REFCNT_VALUE(c) >= 1);
94
95 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
96 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
97 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
98
99 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
100
101 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
102 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
103 pa_tagstruct_puts(t, "module-device-manager");
104 pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
105 pa_pstream_send_tagstruct(c->pstream, t);
106 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);
107
108 return o;
109 }
110
111 static void ext_device_manager_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
112 pa_operation *o = userdata;
113 int eol = 1;
114
115 pa_assert(pd);
116 pa_assert(o);
117 pa_assert(PA_REFCNT_VALUE(o) >= 1);
118
119 if (!o->context)
120 goto finish;
121
122 if (command != PA_COMMAND_REPLY) {
123 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
124 goto finish;
125
126 eol = -1;
127 } else {
128
129 while (!pa_tagstruct_eof(t)) {
130 pa_ext_device_manager_info i;
131 pa_bool_t available;
132
133 memset(&i, 0, sizeof(i));
134 available = FALSE;
135
136 if (pa_tagstruct_gets(t, &i.name) < 0 ||
137 pa_tagstruct_gets(t, &i.description) < 0 ||
138 pa_tagstruct_gets(t, &i.icon) < 0 ||
139 pa_tagstruct_get_boolean(t, &available) < 0 ||
140 pa_tagstruct_getu32(t, &i.n_role_priorities) < 0) {
141
142 pa_context_fail(o->context, PA_ERR_PROTOCOL);
143 goto finish;
144 }
145 i.available = (uint8_t)available;
146
147 if (i.n_role_priorities > 0) {
148 uint32_t j;
149 i.role_priorities = pa_xnew0(pa_ext_device_manager_role_priority_info, i.n_role_priorities+1);
150
151 for (j = 0; j < i.n_role_priorities; j++) {
152
153 if (pa_tagstruct_gets(t, &i.role_priorities[j].role) < 0 ||
154 pa_tagstruct_getu32(t, &i.role_priorities[j].priority) < 0) {
155
156 pa_context_fail(o->context, PA_ERR_PROTOCOL);
157 pa_xfree(i.role_priorities);
158 goto finish;
159 }
160 }
161
162 /* Terminate with an extra NULL entry, just to make sure */
163 i.role_priorities[j].role = NULL;
164 i.role_priorities[j].priority = 0;
165 }
166
167 if (o->callback) {
168 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
169 cb(o->context, &i, 0, o->userdata);
170 }
171
172 pa_xfree(i.role_priorities);
173 }
174 }
175
176 if (o->callback) {
177 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
178 cb(o->context, NULL, eol, o->userdata);
179 }
180
181 finish:
182 pa_operation_done(o);
183 pa_operation_unref(o);
184 }
185
186 pa_operation *pa_ext_device_manager_read(
187 pa_context *c,
188 pa_ext_device_manager_read_cb_t cb,
189 void *userdata) {
190
191 uint32_t tag;
192 pa_operation *o;
193 pa_tagstruct *t;
194
195 pa_assert(c);
196 pa_assert(PA_REFCNT_VALUE(c) >= 1);
197
198 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
199 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
200 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
201
202 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
203
204 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
205 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
206 pa_tagstruct_puts(t, "module-device-manager");
207 pa_tagstruct_putu32(t, SUBCOMMAND_READ);
208 pa_pstream_send_tagstruct(c->pstream, t);
209 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);
210
211 return o;
212 }
213
214 pa_operation *pa_ext_device_manager_set_device_description(
215 pa_context *c,
216 const char* device,
217 const char* description,
218 pa_context_success_cb_t cb,
219 void *userdata) {
220
221 uint32_t tag;
222 pa_operation *o = NULL;
223 pa_tagstruct *t = NULL;
224
225 pa_assert(c);
226 pa_assert(PA_REFCNT_VALUE(c) >= 1);
227 pa_assert(device);
228 pa_assert(description);
229
230 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
231 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
232 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
233
234 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
235
236 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
237 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
238 pa_tagstruct_puts(t, "module-device-manager");
239 pa_tagstruct_putu32(t, SUBCOMMAND_RENAME);
240
241 pa_tagstruct_puts(t, device);
242 pa_tagstruct_puts(t, description);
243
244 pa_pstream_send_tagstruct(c->pstream, t);
245 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);
246
247 return o;
248 }
249
250 pa_operation *pa_ext_device_manager_delete(
251 pa_context *c,
252 const char *const s[],
253 pa_context_success_cb_t cb,
254 void *userdata) {
255
256 uint32_t tag;
257 pa_operation *o = NULL;
258 pa_tagstruct *t = NULL;
259 const char *const *k;
260
261 pa_assert(c);
262 pa_assert(PA_REFCNT_VALUE(c) >= 1);
263 pa_assert(s);
264
265 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
266 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
267 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
268
269 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
270
271 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
272 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
273 pa_tagstruct_puts(t, "module-device-manager");
274 pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
275
276 for (k = s; *k; k++) {
277 if (!*k || !**k)
278 goto fail;
279
280 pa_tagstruct_puts(t, *k);
281 }
282
283 pa_pstream_send_tagstruct(c->pstream, t);
284 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);
285
286 return o;
287
288 fail:
289 if (o) {
290 pa_operation_cancel(o);
291 pa_operation_unref(o);
292 }
293
294 if (t)
295 pa_tagstruct_free(t);
296
297 pa_context_set_error(c, PA_ERR_INVALID);
298 return NULL;
299 }
300
301 pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
302 pa_context *c,
303 int enable,
304 pa_context_success_cb_t cb,
305 void *userdata) {
306
307 uint32_t tag;
308 pa_operation *o = NULL;
309 pa_tagstruct *t = NULL;
310
311 pa_assert(c);
312 pa_assert(PA_REFCNT_VALUE(c) >= 1);
313
314 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
315 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
316 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
317
318 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
319
320 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
321 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
322 pa_tagstruct_puts(t, "module-device-manager");
323 pa_tagstruct_putu32(t, SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING);
324 pa_tagstruct_put_boolean(t, !!enable);
325
326 pa_pstream_send_tagstruct(c->pstream, t);
327 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);
328
329 return o;
330 }
331
332 pa_operation *pa_ext_device_manager_reorder_devices_for_role(
333 pa_context *c,
334 const char* role,
335 const char** devices,
336 pa_context_success_cb_t cb,
337 void *userdata) {
338
339 uint32_t tag, i;
340 pa_operation *o = NULL;
341 pa_tagstruct *t = NULL;
342
343 pa_assert(c);
344 pa_assert(PA_REFCNT_VALUE(c) >= 1);
345
346 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
347 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
348 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
349
350 pa_assert(role);
351 pa_assert(devices);
352
353 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
354
355 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
356 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
357 pa_tagstruct_puts(t, "module-device-manager");
358 pa_tagstruct_putu32(t, SUBCOMMAND_REORDER);
359 pa_tagstruct_puts(t, role);
360
361 i = 0; while (devices[i]) i++;
362 pa_tagstruct_putu32(t, i);
363
364 i = 0;
365 while (devices[i])
366 pa_tagstruct_puts(t, devices[i++]);
367
368 pa_pstream_send_tagstruct(c->pstream, t);
369 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);
370
371 return o;
372 }
373
374 pa_operation *pa_ext_device_manager_subscribe(
375 pa_context *c,
376 int enable,
377 pa_context_success_cb_t cb,
378 void *userdata) {
379
380 uint32_t tag;
381 pa_operation *o;
382 pa_tagstruct *t;
383
384 pa_assert(c);
385 pa_assert(PA_REFCNT_VALUE(c) >= 1);
386
387 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
388 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
389 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
390
391 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
392
393 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
394 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
395 pa_tagstruct_puts(t, "module-device-manager");
396 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
397 pa_tagstruct_put_boolean(t, enable);
398 pa_pstream_send_tagstruct(c->pstream, t);
399 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);
400
401 return o;
402 }
403
404 void pa_ext_device_manager_set_subscribe_cb(
405 pa_context *c,
406 pa_ext_device_manager_subscribe_cb_t cb,
407 void *userdata) {
408
409 pa_assert(c);
410 pa_assert(PA_REFCNT_VALUE(c) >= 1);
411
412 if (pa_detect_fork())
413 return;
414
415 c->ext_device_manager.callback = cb;
416 c->ext_device_manager.userdata = userdata;
417 }
418
419 void pa_ext_device_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
420 uint32_t subcommand;
421
422 pa_assert(c);
423 pa_assert(PA_REFCNT_VALUE(c) >= 1);
424 pa_assert(t);
425
426 if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
427 !pa_tagstruct_eof(t)) {
428
429 pa_context_fail(c, PA_ERR_PROTOCOL);
430 return;
431 }
432
433 if (subcommand != SUBCOMMAND_EVENT) {
434 pa_context_fail(c, PA_ERR_PROTOCOL);
435 return;
436 }
437
438 if (c->ext_device_manager.callback)
439 c->ext_device_manager.callback(c, c->ext_device_manager.userdata);
440 }