]> code.delx.au - pulseaudio/blob - src/pulse/ext-device-manager.c
device-manager: Provide a method for prefering/defering a device.
[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
30 #include <pulsecore/macro.h>
31 #include <pulsecore/pstream-util.h>
32
33 #include "internal.h"
34 #include "operation.h"
35 #include "fork-detect.h"
36
37 #include "ext-device-manager.h"
38
39 enum {
40 SUBCOMMAND_TEST,
41 SUBCOMMAND_READ,
42 SUBCOMMAND_WRITE,
43 SUBCOMMAND_DELETE,
44 SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
45 SUBCOMMAND_PREFER_DEVICE,
46 SUBCOMMAND_DEFER_DEVICE,
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
132 memset(&i, 0, sizeof(i));
133
134 if (pa_tagstruct_gets(t, &i.name) < 0 ||
135 pa_tagstruct_gets(t, &i.description) < 0) {
136
137 pa_context_fail(o->context, PA_ERR_PROTOCOL);
138 goto finish;
139 }
140
141 if (o->callback) {
142 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
143 cb(o->context, &i, 0, o->userdata);
144 }
145 }
146 }
147
148 if (o->callback) {
149 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
150 cb(o->context, NULL, eol, o->userdata);
151 }
152
153 finish:
154 pa_operation_done(o);
155 pa_operation_unref(o);
156 }
157
158 pa_operation *pa_ext_device_manager_read(
159 pa_context *c,
160 pa_ext_device_manager_read_cb_t cb,
161 void *userdata) {
162
163 uint32_t tag;
164 pa_operation *o;
165 pa_tagstruct *t;
166
167 pa_assert(c);
168 pa_assert(PA_REFCNT_VALUE(c) >= 1);
169
170 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
171 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
172 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
173
174 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
175
176 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
177 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
178 pa_tagstruct_puts(t, "module-device-manager");
179 pa_tagstruct_putu32(t, SUBCOMMAND_READ);
180 pa_pstream_send_tagstruct(c->pstream, t);
181 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);
182
183 return o;
184 }
185
186 pa_operation *pa_ext_device_manager_write(
187 pa_context *c,
188 pa_update_mode_t mode,
189 const pa_ext_device_manager_info data[],
190 unsigned n,
191 int apply_immediately,
192 pa_context_success_cb_t cb,
193 void *userdata) {
194
195 uint32_t tag;
196 pa_operation *o = NULL;
197 pa_tagstruct *t = NULL;
198
199 pa_assert(c);
200 pa_assert(PA_REFCNT_VALUE(c) >= 1);
201 pa_assert(mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE || mode == PA_UPDATE_SET);
202 pa_assert(data);
203
204 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
205 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
206 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
207
208 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
209
210 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
211 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
212 pa_tagstruct_puts(t, "module-device-manager");
213 pa_tagstruct_putu32(t, SUBCOMMAND_WRITE);
214
215 pa_tagstruct_putu32(t, mode);
216 pa_tagstruct_put_boolean(t, apply_immediately);
217
218 for (; n > 0; n--, data++) {
219 if (!data->name || !*data->name)
220 goto fail;
221
222 pa_tagstruct_puts(t, data->name);
223 pa_tagstruct_puts(t, data->description);
224 }
225
226 pa_pstream_send_tagstruct(c->pstream, t);
227 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);
228
229 return o;
230
231 fail:
232 if (o) {
233 pa_operation_cancel(o);
234 pa_operation_unref(o);
235 }
236
237 if (t)
238 pa_tagstruct_free(t);
239
240 pa_context_set_error(c, PA_ERR_INVALID);
241 return NULL;
242 }
243
244 pa_operation *pa_ext_device_manager_delete(
245 pa_context *c,
246 const char *const s[],
247 pa_context_success_cb_t cb,
248 void *userdata) {
249
250 uint32_t tag;
251 pa_operation *o = NULL;
252 pa_tagstruct *t = NULL;
253 const char *const *k;
254
255 pa_assert(c);
256 pa_assert(PA_REFCNT_VALUE(c) >= 1);
257 pa_assert(s);
258
259 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
260 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
261 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
262
263 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
264
265 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
266 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
267 pa_tagstruct_puts(t, "module-device-manager");
268 pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
269
270 for (k = s; *k; k++) {
271 if (!*k || !**k)
272 goto fail;
273
274 pa_tagstruct_puts(t, *k);
275 }
276
277 pa_pstream_send_tagstruct(c->pstream, t);
278 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);
279
280 return o;
281
282 fail:
283 if (o) {
284 pa_operation_cancel(o);
285 pa_operation_unref(o);
286 }
287
288 if (t)
289 pa_tagstruct_free(t);
290
291 pa_context_set_error(c, PA_ERR_INVALID);
292 return NULL;
293 }
294
295 pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
296 pa_context *c,
297 int enable,
298 pa_context_success_cb_t cb,
299 void *userdata) {
300
301 uint32_t tag;
302 pa_operation *o = NULL;
303 pa_tagstruct *t = NULL;
304
305 pa_assert(c);
306 pa_assert(PA_REFCNT_VALUE(c) >= 1);
307
308 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
309 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
310 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
311
312 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
313
314 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
315 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
316 pa_tagstruct_puts(t, "module-device-manager");
317 pa_tagstruct_putu32(t, SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING);
318 pa_tagstruct_put_boolean(t, !!enable);
319
320 pa_pstream_send_tagstruct(c->pstream, t);
321 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);
322
323 return o;
324 }
325
326 pa_operation *pa_ext_device_manager_prefer_device(
327 pa_context *c,
328 const char* role,
329 const char* device,
330 pa_context_success_cb_t cb,
331 void *userdata) {
332
333 uint32_t tag;
334 pa_operation *o = NULL;
335 pa_tagstruct *t = NULL;
336
337 pa_assert(c);
338 pa_assert(PA_REFCNT_VALUE(c) >= 1);
339
340 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
341 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
342 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
343
344 pa_assert(role);
345 pa_assert(device);
346
347 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
348
349 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
350 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
351 pa_tagstruct_puts(t, "module-device-manager");
352 pa_tagstruct_putu32(t, SUBCOMMAND_PREFER_DEVICE);
353 pa_tagstruct_puts(t, role);
354 pa_tagstruct_puts(t, device);
355
356 pa_pstream_send_tagstruct(c->pstream, t);
357 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);
358
359 return o;
360 }
361
362 pa_operation *pa_ext_device_manager_defer_device(
363 pa_context *c,
364 const char* role,
365 const char* device,
366 pa_context_success_cb_t cb,
367 void *userdata) {
368
369 uint32_t tag;
370 pa_operation *o = NULL;
371 pa_tagstruct *t = NULL;
372
373 pa_assert(c);
374 pa_assert(PA_REFCNT_VALUE(c) >= 1);
375
376 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
377 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
378 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
379
380 pa_assert(role);
381 pa_assert(device);
382
383 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
384
385 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
386 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
387 pa_tagstruct_puts(t, "module-device-manager");
388 pa_tagstruct_putu32(t, SUBCOMMAND_DEFER_DEVICE);
389 pa_tagstruct_puts(t, role);
390 pa_tagstruct_puts(t, device);
391
392 pa_pstream_send_tagstruct(c->pstream, t);
393 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);
394
395 return o;
396 }
397
398 pa_operation *pa_ext_device_manager_subscribe(
399 pa_context *c,
400 int enable,
401 pa_context_success_cb_t cb,
402 void *userdata) {
403
404 uint32_t tag;
405 pa_operation *o;
406 pa_tagstruct *t;
407
408 pa_assert(c);
409 pa_assert(PA_REFCNT_VALUE(c) >= 1);
410
411 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
412 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
413 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
414
415 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
416
417 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
418 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
419 pa_tagstruct_puts(t, "module-device-manager");
420 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
421 pa_tagstruct_put_boolean(t, enable);
422 pa_pstream_send_tagstruct(c->pstream, t);
423 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);
424
425 return o;
426 }
427
428 void pa_ext_device_manager_set_subscribe_cb(
429 pa_context *c,
430 pa_ext_device_manager_subscribe_cb_t cb,
431 void *userdata) {
432
433 pa_assert(c);
434 pa_assert(PA_REFCNT_VALUE(c) >= 1);
435
436 if (pa_detect_fork())
437 return;
438
439 c->ext_device_manager.callback = cb;
440 c->ext_device_manager.userdata = userdata;
441 }
442
443 void pa_ext_device_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
444 uint32_t subcommand;
445
446 pa_assert(c);
447 pa_assert(PA_REFCNT_VALUE(c) >= 1);
448 pa_assert(t);
449
450 if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
451 !pa_tagstruct_eof(t)) {
452
453 pa_context_fail(c, PA_ERR_PROTOCOL);
454 return;
455 }
456
457 if (subcommand != SUBCOMMAND_EVENT) {
458 pa_context_fail(c, PA_ERR_PROTOCOL);
459 return;
460 }
461
462 if (c->ext_device_manager.callback)
463 c->ext_device_manager.callback(c, c->ext_device_manager.userdata);
464 }