device-manager: Provide a way for clients to enable/disable role-based device-priorit...
[pulseaudio-mirror.git] / src / pulse / ext-device-manager.c
blob0603a89a54e311046d4f9e26771ff419eb68b2b5
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>
30 #include <pulsecore/macro.h>
31 #include <pulsecore/pstream-util.h>
33 #include "internal.h"
34 #include "operation.h"
35 #include "fork-detect.h"
37 #include "ext-device-manager.h"
39 enum {
40 SUBCOMMAND_TEST,
41 SUBCOMMAND_READ,
42 SUBCOMMAND_WRITE,
43 SUBCOMMAND_DELETE,
44 SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
45 SUBCOMMAND_SUBSCRIBE,
46 SUBCOMMAND_EVENT
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;
53 pa_assert(pd);
54 pa_assert(o);
55 pa_assert(PA_REFCNT_VALUE(o) >= 1);
57 if (!o->context)
58 goto finish;
60 if (command != PA_COMMAND_REPLY) {
61 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
62 goto finish;
64 } else if (pa_tagstruct_getu32(t, &version) < 0 ||
65 !pa_tagstruct_eof(t)) {
67 pa_context_fail(o->context, PA_ERR_PROTOCOL);
68 goto finish;
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);
76 finish:
77 pa_operation_done(o);
78 pa_operation_unref(o);
81 pa_operation *pa_ext_device_manager_test(
82 pa_context *c,
83 pa_ext_device_manager_test_cb_t cb,
84 void *userdata) {
86 uint32_t tag;
87 pa_operation *o;
88 pa_tagstruct *t;
90 pa_assert(c);
91 pa_assert(PA_REFCNT_VALUE(c) >= 1);
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);
97 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
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);
106 return o;
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;
113 pa_assert(pd);
114 pa_assert(o);
115 pa_assert(PA_REFCNT_VALUE(o) >= 1);
117 if (!o->context)
118 goto finish;
120 if (command != PA_COMMAND_REPLY) {
121 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
122 goto finish;
124 eol = -1;
125 } else {
127 while (!pa_tagstruct_eof(t)) {
128 pa_ext_device_manager_info i;
130 memset(&i, 0, sizeof(i));
132 if (pa_tagstruct_gets(t, &i.name) < 0 ||
133 pa_tagstruct_gets(t, &i.description) < 0) {
135 pa_context_fail(o->context, PA_ERR_PROTOCOL);
136 goto finish;
139 if (o->callback) {
140 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
141 cb(o->context, &i, 0, o->userdata);
146 if (o->callback) {
147 pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
148 cb(o->context, NULL, eol, o->userdata);
151 finish:
152 pa_operation_done(o);
153 pa_operation_unref(o);
156 pa_operation *pa_ext_device_manager_read(
157 pa_context *c,
158 pa_ext_device_manager_read_cb_t cb,
159 void *userdata) {
161 uint32_t tag;
162 pa_operation *o;
163 pa_tagstruct *t;
165 pa_assert(c);
166 pa_assert(PA_REFCNT_VALUE(c) >= 1);
168 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
169 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
170 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
172 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
174 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
175 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
176 pa_tagstruct_puts(t, "module-device-manager");
177 pa_tagstruct_putu32(t, SUBCOMMAND_READ);
178 pa_pstream_send_tagstruct(c->pstream, t);
179 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);
181 return o;
184 pa_operation *pa_ext_device_manager_write(
185 pa_context *c,
186 pa_update_mode_t mode,
187 const pa_ext_device_manager_info data[],
188 unsigned n,
189 int apply_immediately,
190 pa_context_success_cb_t cb,
191 void *userdata) {
193 uint32_t tag;
194 pa_operation *o = NULL;
195 pa_tagstruct *t = NULL;
197 pa_assert(c);
198 pa_assert(PA_REFCNT_VALUE(c) >= 1);
199 pa_assert(mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE || mode == PA_UPDATE_SET);
200 pa_assert(data);
202 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
203 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
204 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
206 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
208 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
209 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
210 pa_tagstruct_puts(t, "module-device-manager");
211 pa_tagstruct_putu32(t, SUBCOMMAND_WRITE);
213 pa_tagstruct_putu32(t, mode);
214 pa_tagstruct_put_boolean(t, apply_immediately);
216 for (; n > 0; n--, data++) {
217 if (!data->name || !*data->name)
218 goto fail;
220 pa_tagstruct_puts(t, data->name);
221 pa_tagstruct_puts(t, data->description);
224 pa_pstream_send_tagstruct(c->pstream, t);
225 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);
227 return o;
229 fail:
230 if (o) {
231 pa_operation_cancel(o);
232 pa_operation_unref(o);
235 if (t)
236 pa_tagstruct_free(t);
238 pa_context_set_error(c, PA_ERR_INVALID);
239 return NULL;
242 pa_operation *pa_ext_device_manager_delete(
243 pa_context *c,
244 const char *const s[],
245 pa_context_success_cb_t cb,
246 void *userdata) {
248 uint32_t tag;
249 pa_operation *o = NULL;
250 pa_tagstruct *t = NULL;
251 const char *const *k;
253 pa_assert(c);
254 pa_assert(PA_REFCNT_VALUE(c) >= 1);
255 pa_assert(s);
257 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
258 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
259 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
261 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
263 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
264 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
265 pa_tagstruct_puts(t, "module-device-manager");
266 pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
268 for (k = s; *k; k++) {
269 if (!*k || !**k)
270 goto fail;
272 pa_tagstruct_puts(t, *k);
275 pa_pstream_send_tagstruct(c->pstream, t);
276 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);
278 return o;
280 fail:
281 if (o) {
282 pa_operation_cancel(o);
283 pa_operation_unref(o);
286 if (t)
287 pa_tagstruct_free(t);
289 pa_context_set_error(c, PA_ERR_INVALID);
290 return NULL;
293 pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
294 pa_context *c,
295 int enable,
296 pa_context_success_cb_t cb,
297 void *userdata) {
299 uint32_t tag;
300 pa_operation *o = NULL;
301 pa_tagstruct *t = NULL;
303 pa_assert(c);
304 pa_assert(PA_REFCNT_VALUE(c) >= 1);
306 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
307 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
308 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
310 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
312 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
313 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
314 pa_tagstruct_puts(t, "module-device-manager");
315 pa_tagstruct_putu32(t, SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING);
316 pa_tagstruct_put_boolean(t, !!enable);
318 pa_pstream_send_tagstruct(c->pstream, t);
319 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);
321 return o;
324 pa_operation *pa_ext_device_manager_subscribe(
325 pa_context *c,
326 int enable,
327 pa_context_success_cb_t cb,
328 void *userdata) {
330 uint32_t tag;
331 pa_operation *o;
332 pa_tagstruct *t;
334 pa_assert(c);
335 pa_assert(PA_REFCNT_VALUE(c) >= 1);
337 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
338 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
339 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
341 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
343 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
344 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
345 pa_tagstruct_puts(t, "module-device-manager");
346 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
347 pa_tagstruct_put_boolean(t, enable);
348 pa_pstream_send_tagstruct(c->pstream, t);
349 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);
351 return o;
354 void pa_ext_device_manager_set_subscribe_cb(
355 pa_context *c,
356 pa_ext_device_manager_subscribe_cb_t cb,
357 void *userdata) {
359 pa_assert(c);
360 pa_assert(PA_REFCNT_VALUE(c) >= 1);
362 if (pa_detect_fork())
363 return;
365 c->ext_device_manager.callback = cb;
366 c->ext_device_manager.userdata = userdata;
369 void pa_ext_device_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
370 uint32_t subcommand;
372 pa_assert(c);
373 pa_assert(PA_REFCNT_VALUE(c) >= 1);
374 pa_assert(t);
376 if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
377 !pa_tagstruct_eof(t)) {
379 pa_context_fail(c, PA_ERR_PROTOCOL);
380 return;
383 if (subcommand != SUBCOMMAND_EVENT) {
384 pa_context_fail(c, PA_ERR_PROTOCOL);
385 return;
388 if (c->ext_device_manager.callback)
389 c->ext_device_manager.callback(c, c->ext_device_manager.userdata);