]> code.delx.au - pulseaudio/blob - src/pulse/ext-device-manager.c
libpulse: introduce pa_context_get_tile_size() call
[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
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 pa_tagstruct_gets(t, &i.icon) < 0 ||
137 pa_tagstruct_getu32(t, &i.index) < 0 ||
138 pa_tagstruct_getu32(t, &i.n_role_priorities) < 0) {
139
140 pa_context_fail(o->context, PA_ERR_PROTOCOL);
141 goto finish;
142 }
143
144 if (i.n_role_priorities > 0) {
145 uint32_t j;
146 i.role_priorities = pa_xnew0(pa_ext_device_manager_role_priority_info, i.n_role_priorities+1);
147
148 for (j = 0; j < i.n_role_priorities; j++) {
149
150 if (pa_tagstruct_gets(t, &i.role_priorities[j].role) < 0 ||
151 pa_tagstruct_getu32(t, &i.role_priorities[j].priority) < 0) {
152
153 pa_context_fail(o->context, PA_ERR_PROTOCOL);
154 pa_xfree(i.role_priorities);
155 goto finish;
156 }
157 }
158
159 /* Terminate with an extra NULL entry, just to make sure */
160 i.role_priorities[j].role = NULL;
161 i.role_priorities[j].priority = 0;
162 }
163
164 if (o->callback) {
165 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
166 cb(o->context, &i, 0, o->userdata);
167 }
168
169 pa_xfree(i.role_priorities);
170 }
171 }
172
173 if (o->callback) {
174 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
175 cb(o->context, NULL, eol, o->userdata);
176 }
177
178 finish:
179 pa_operation_done(o);
180 pa_operation_unref(o);
181 }
182
183 pa_operation *pa_ext_device_manager_read(
184 pa_context *c,
185 pa_ext_device_manager_read_cb_t cb,
186 void *userdata) {
187
188 uint32_t tag;
189 pa_operation *o;
190 pa_tagstruct *t;
191
192 pa_assert(c);
193 pa_assert(PA_REFCNT_VALUE(c) >= 1);
194
195 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
196 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
197 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
198
199 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
200
201 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
202 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
203 pa_tagstruct_puts(t, "module-device-manager");
204 pa_tagstruct_putu32(t, SUBCOMMAND_READ);
205 pa_pstream_send_tagstruct(c->pstream, t);
206 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);
207
208 return o;
209 }
210
211 pa_operation *pa_ext_device_manager_set_device_description(
212 pa_context *c,
213 const char* device,
214 const char* description,
215 pa_context_success_cb_t cb,
216 void *userdata) {
217
218 uint32_t tag;
219 pa_operation *o = NULL;
220 pa_tagstruct *t = NULL;
221
222 pa_assert(c);
223 pa_assert(PA_REFCNT_VALUE(c) >= 1);
224 pa_assert(device);
225 pa_assert(description);
226
227 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
228 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
229 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
230
231 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
232
233 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
234 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
235 pa_tagstruct_puts(t, "module-device-manager");
236 pa_tagstruct_putu32(t, SUBCOMMAND_RENAME);
237
238 pa_tagstruct_puts(t, device);
239 pa_tagstruct_puts(t, description);
240
241 pa_pstream_send_tagstruct(c->pstream, t);
242 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);
243
244 return o;
245 }
246
247 pa_operation *pa_ext_device_manager_delete(
248 pa_context *c,
249 const char *const s[],
250 pa_context_success_cb_t cb,
251 void *userdata) {
252
253 uint32_t tag;
254 pa_operation *o = NULL;
255 pa_tagstruct *t = NULL;
256 const char *const *k;
257
258 pa_assert(c);
259 pa_assert(PA_REFCNT_VALUE(c) >= 1);
260 pa_assert(s);
261
262 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
263 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
264 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
265
266 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
267
268 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
269 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
270 pa_tagstruct_puts(t, "module-device-manager");
271 pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
272
273 for (k = s; *k; k++) {
274 if (!*k || !**k)
275 goto fail;
276
277 pa_tagstruct_puts(t, *k);
278 }
279
280 pa_pstream_send_tagstruct(c->pstream, t);
281 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);
282
283 return o;
284
285 fail:
286 if (o) {
287 pa_operation_cancel(o);
288 pa_operation_unref(o);
289 }
290
291 if (t)
292 pa_tagstruct_free(t);
293
294 pa_context_set_error(c, PA_ERR_INVALID);
295 return NULL;
296 }
297
298 pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
299 pa_context *c,
300 int enable,
301 pa_context_success_cb_t cb,
302 void *userdata) {
303
304 uint32_t tag;
305 pa_operation *o = NULL;
306 pa_tagstruct *t = NULL;
307
308 pa_assert(c);
309 pa_assert(PA_REFCNT_VALUE(c) >= 1);
310
311 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
312 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
313 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
314
315 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
316
317 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
318 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
319 pa_tagstruct_puts(t, "module-device-manager");
320 pa_tagstruct_putu32(t, SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING);
321 pa_tagstruct_put_boolean(t, !!enable);
322
323 pa_pstream_send_tagstruct(c->pstream, t);
324 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);
325
326 return o;
327 }
328
329 pa_operation *pa_ext_device_manager_reorder_devices_for_role(
330 pa_context *c,
331 const char* role,
332 const char** devices,
333 pa_context_success_cb_t cb,
334 void *userdata) {
335
336 uint32_t tag, i;
337 pa_operation *o = NULL;
338 pa_tagstruct *t = NULL;
339
340 pa_assert(c);
341 pa_assert(PA_REFCNT_VALUE(c) >= 1);
342
343 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
344 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
345 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
346
347 pa_assert(role);
348 pa_assert(devices);
349
350 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
351
352 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
353 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
354 pa_tagstruct_puts(t, "module-device-manager");
355 pa_tagstruct_putu32(t, SUBCOMMAND_REORDER);
356 pa_tagstruct_puts(t, role);
357
358 i = 0; while (devices[i]) i++;
359 pa_tagstruct_putu32(t, i);
360
361 i = 0;
362 while (devices[i])
363 pa_tagstruct_puts(t, devices[i++]);
364
365 pa_pstream_send_tagstruct(c->pstream, t);
366 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);
367
368 return o;
369 }
370
371 pa_operation *pa_ext_device_manager_subscribe(
372 pa_context *c,
373 int enable,
374 pa_context_success_cb_t cb,
375 void *userdata) {
376
377 uint32_t tag;
378 pa_operation *o;
379 pa_tagstruct *t;
380
381 pa_assert(c);
382 pa_assert(PA_REFCNT_VALUE(c) >= 1);
383
384 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
385 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
386 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
387
388 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
389
390 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
391 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
392 pa_tagstruct_puts(t, "module-device-manager");
393 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
394 pa_tagstruct_put_boolean(t, enable);
395 pa_pstream_send_tagstruct(c->pstream, t);
396 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);
397
398 return o;
399 }
400
401 void pa_ext_device_manager_set_subscribe_cb(
402 pa_context *c,
403 pa_ext_device_manager_subscribe_cb_t cb,
404 void *userdata) {
405
406 pa_assert(c);
407 pa_assert(PA_REFCNT_VALUE(c) >= 1);
408
409 if (pa_detect_fork())
410 return;
411
412 c->ext_device_manager.callback = cb;
413 c->ext_device_manager.userdata = userdata;
414 }
415
416 void pa_ext_device_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
417 uint32_t subcommand;
418
419 pa_assert(c);
420 pa_assert(PA_REFCNT_VALUE(c) >= 1);
421 pa_assert(t);
422
423 if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
424 !pa_tagstruct_eof(t)) {
425
426 pa_context_fail(c, PA_ERR_PROTOCOL);
427 return;
428 }
429
430 if (subcommand != SUBCOMMAND_EVENT) {
431 pa_context_fail(c, PA_ERR_PROTOCOL);
432 return;
433 }
434
435 if (c->ext_device_manager.callback)
436 c->ext_device_manager.callback(c, c->ext_device_manager.userdata);
437 }