device-manager: Expose the priority lists in the protocol extension.
[pulseaudio-mirror.git] / src / pulse / ext-device-manager.c
blob01e4594b6eb7adc37fd7456807fa4e235126da2c
1 /***
2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
5 Copyright 2009 Colin Guthrie
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.
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.
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 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <pulse/context.h>
28 #include <pulse/gccmacro.h>
29 #include <pulse/xmalloc.h>
31 #include <pulsecore/macro.h>
32 #include <pulsecore/pstream-util.h>
34 #include "internal.h"
35 #include "operation.h"
36 #include "fork-detect.h"
38 #include "ext-device-manager.h"
40 enum {
41 SUBCOMMAND_TEST,
42 SUBCOMMAND_READ,
43 SUBCOMMAND_RENAME,
44 SUBCOMMAND_DELETE,
45 SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
46 SUBCOMMAND_PREFER_DEVICE,
47 SUBCOMMAND_DEFER_DEVICE,
48 SUBCOMMAND_SUBSCRIBE,
49 SUBCOMMAND_EVENT
52 static void ext_device_manager_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
53 pa_operation *o = userdata;
54 uint32_t version = PA_INVALID_INDEX;
56 pa_assert(pd);
57 pa_assert(o);
58 pa_assert(PA_REFCNT_VALUE(o) >= 1);
60 if (!o->context)
61 goto finish;
63 if (command != PA_COMMAND_REPLY) {
64 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
65 goto finish;
67 } else if (pa_tagstruct_getu32(t, &version) < 0 ||
68 !pa_tagstruct_eof(t)) {
70 pa_context_fail(o->context, PA_ERR_PROTOCOL);
71 goto finish;
74 if (o->callback) {
75 pa_ext_device_manager_test_cb_t cb = (pa_ext_device_manager_test_cb_t) o->callback;
76 cb(o->context, version, o->userdata);
79 finish:
80 pa_operation_done(o);
81 pa_operation_unref(o);
84 pa_operation *pa_ext_device_manager_test(
85 pa_context *c,
86 pa_ext_device_manager_test_cb_t cb,
87 void *userdata) {
89 uint32_t tag;
90 pa_operation *o;
91 pa_tagstruct *t;
93 pa_assert(c);
94 pa_assert(PA_REFCNT_VALUE(c) >= 1);
96 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
97 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
98 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
100 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
102 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
103 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
104 pa_tagstruct_puts(t, "module-device-manager");
105 pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
106 pa_pstream_send_tagstruct(c->pstream, t);
107 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);
109 return o;
112 static void ext_device_manager_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
113 pa_operation *o = userdata;
114 int eol = 1;
116 pa_assert(pd);
117 pa_assert(o);
118 pa_assert(PA_REFCNT_VALUE(o) >= 1);
120 if (!o->context)
121 goto finish;
123 if (command != PA_COMMAND_REPLY) {
124 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
125 goto finish;
127 eol = -1;
128 } else {
130 while (!pa_tagstruct_eof(t)) {
131 pa_ext_device_manager_info i;
132 pa_bool_t available;
134 memset(&i, 0, sizeof(i));
135 available = FALSE;
137 if (pa_tagstruct_gets(t, &i.name) < 0 ||
138 pa_tagstruct_gets(t, &i.description) < 0 ||
139 pa_tagstruct_gets(t, &i.icon) < 0 ||
140 pa_tagstruct_get_boolean(t, &available) < 0 ||
141 pa_tagstruct_getu32(t, &i.n_role_priorities) < 0) {
143 pa_context_fail(o->context, PA_ERR_PROTOCOL);
144 goto finish;
146 i.available = (uint8_t)available;
148 if (i.n_role_priorities > 0) {
149 uint32_t j;
150 i.role_priorities = pa_xnew0(pa_ext_device_manager_role_priority_info, i.n_role_priorities+1);
152 for (j = 0; j < i.n_role_priorities; j++) {
154 if (pa_tagstruct_gets(t, &i.role_priorities[j].role) < 0 ||
155 pa_tagstruct_getu32(t, &i.role_priorities[j].priority) < 0) {
157 pa_context_fail(o->context, PA_ERR_PROTOCOL);
158 pa_xfree(i.role_priorities);
159 goto finish;
163 /* Terminate with an extra NULL entry, just to make sure */
164 i.role_priorities[j].role = NULL;
165 i.role_priorities[j].priority = 0;
168 if (o->callback) {
169 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
170 cb(o->context, &i, 0, o->userdata);
173 pa_xfree(i.role_priorities);
177 if (o->callback) {
178 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
179 cb(o->context, NULL, eol, o->userdata);
182 finish:
183 pa_operation_done(o);
184 pa_operation_unref(o);
187 pa_operation *pa_ext_device_manager_read(
188 pa_context *c,
189 pa_ext_device_manager_read_cb_t cb,
190 void *userdata) {
192 uint32_t tag;
193 pa_operation *o;
194 pa_tagstruct *t;
196 pa_assert(c);
197 pa_assert(PA_REFCNT_VALUE(c) >= 1);
199 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
200 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
201 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
203 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
205 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
206 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
207 pa_tagstruct_puts(t, "module-device-manager");
208 pa_tagstruct_putu32(t, SUBCOMMAND_READ);
209 pa_pstream_send_tagstruct(c->pstream, t);
210 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);
212 return o;
215 pa_operation *pa_ext_device_manager_set_device_description(
216 pa_context *c,
217 const char* device,
218 const char* description,
219 pa_context_success_cb_t cb,
220 void *userdata) {
222 uint32_t tag;
223 pa_operation *o = NULL;
224 pa_tagstruct *t = NULL;
226 pa_assert(c);
227 pa_assert(PA_REFCNT_VALUE(c) >= 1);
228 pa_assert(device);
229 pa_assert(description);
231 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
232 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
233 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
235 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
237 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
238 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
239 pa_tagstruct_puts(t, "module-device-manager");
240 pa_tagstruct_putu32(t, SUBCOMMAND_RENAME);
242 pa_tagstruct_puts(t, device);
243 pa_tagstruct_puts(t, description);
245 pa_pstream_send_tagstruct(c->pstream, t);
246 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);
248 return o;
251 pa_operation *pa_ext_device_manager_delete(
252 pa_context *c,
253 const char *const s[],
254 pa_context_success_cb_t cb,
255 void *userdata) {
257 uint32_t tag;
258 pa_operation *o = NULL;
259 pa_tagstruct *t = NULL;
260 const char *const *k;
262 pa_assert(c);
263 pa_assert(PA_REFCNT_VALUE(c) >= 1);
264 pa_assert(s);
266 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
267 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
268 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
270 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
272 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
273 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
274 pa_tagstruct_puts(t, "module-device-manager");
275 pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
277 for (k = s; *k; k++) {
278 if (!*k || !**k)
279 goto fail;
281 pa_tagstruct_puts(t, *k);
284 pa_pstream_send_tagstruct(c->pstream, t);
285 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);
287 return o;
289 fail:
290 if (o) {
291 pa_operation_cancel(o);
292 pa_operation_unref(o);
295 if (t)
296 pa_tagstruct_free(t);
298 pa_context_set_error(c, PA_ERR_INVALID);
299 return NULL;
302 pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
303 pa_context *c,
304 int enable,
305 pa_context_success_cb_t cb,
306 void *userdata) {
308 uint32_t tag;
309 pa_operation *o = NULL;
310 pa_tagstruct *t = NULL;
312 pa_assert(c);
313 pa_assert(PA_REFCNT_VALUE(c) >= 1);
315 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
316 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
317 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
319 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
321 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
322 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
323 pa_tagstruct_puts(t, "module-device-manager");
324 pa_tagstruct_putu32(t, SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING);
325 pa_tagstruct_put_boolean(t, !!enable);
327 pa_pstream_send_tagstruct(c->pstream, t);
328 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);
330 return o;
333 pa_operation *pa_ext_device_manager_prefer_device(
334 pa_context *c,
335 const char* role,
336 const char* device,
337 pa_context_success_cb_t cb,
338 void *userdata) {
340 uint32_t tag;
341 pa_operation *o = NULL;
342 pa_tagstruct *t = NULL;
344 pa_assert(c);
345 pa_assert(PA_REFCNT_VALUE(c) >= 1);
347 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
348 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
349 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
351 pa_assert(role);
352 pa_assert(device);
354 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
356 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
357 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
358 pa_tagstruct_puts(t, "module-device-manager");
359 pa_tagstruct_putu32(t, SUBCOMMAND_PREFER_DEVICE);
360 pa_tagstruct_puts(t, role);
361 pa_tagstruct_puts(t, device);
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);
366 return o;
369 pa_operation *pa_ext_device_manager_defer_device(
370 pa_context *c,
371 const char* role,
372 const char* device,
373 pa_context_success_cb_t cb,
374 void *userdata) {
376 uint32_t tag;
377 pa_operation *o = NULL;
378 pa_tagstruct *t = NULL;
380 pa_assert(c);
381 pa_assert(PA_REFCNT_VALUE(c) >= 1);
383 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
384 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
385 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
387 pa_assert(role);
388 pa_assert(device);
390 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
392 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
393 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
394 pa_tagstruct_puts(t, "module-device-manager");
395 pa_tagstruct_putu32(t, SUBCOMMAND_DEFER_DEVICE);
396 pa_tagstruct_puts(t, role);
397 pa_tagstruct_puts(t, device);
399 pa_pstream_send_tagstruct(c->pstream, t);
400 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);
402 return o;
405 pa_operation *pa_ext_device_manager_subscribe(
406 pa_context *c,
407 int enable,
408 pa_context_success_cb_t cb,
409 void *userdata) {
411 uint32_t tag;
412 pa_operation *o;
413 pa_tagstruct *t;
415 pa_assert(c);
416 pa_assert(PA_REFCNT_VALUE(c) >= 1);
418 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
419 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
420 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
422 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
424 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
425 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
426 pa_tagstruct_puts(t, "module-device-manager");
427 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
428 pa_tagstruct_put_boolean(t, enable);
429 pa_pstream_send_tagstruct(c->pstream, t);
430 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);
432 return o;
435 void pa_ext_device_manager_set_subscribe_cb(
436 pa_context *c,
437 pa_ext_device_manager_subscribe_cb_t cb,
438 void *userdata) {
440 pa_assert(c);
441 pa_assert(PA_REFCNT_VALUE(c) >= 1);
443 if (pa_detect_fork())
444 return;
446 c->ext_device_manager.callback = cb;
447 c->ext_device_manager.userdata = userdata;
450 void pa_ext_device_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
451 uint32_t subcommand;
453 pa_assert(c);
454 pa_assert(PA_REFCNT_VALUE(c) >= 1);
455 pa_assert(t);
457 if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
458 !pa_tagstruct_eof(t)) {
460 pa_context_fail(c, PA_ERR_PROTOCOL);
461 return;
464 if (subcommand != SUBCOMMAND_EVENT) {
465 pa_context_fail(c, PA_ERR_PROTOCOL);
466 return;
469 if (c->ext_device_manager.callback)
470 c->ext_device_manager.callback(c, c->ext_device_manager.userdata);