Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2008 Lennart Poettering
5 : : Copyright 2011 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 : : #include <pulse/fork-detect.h>
31 : : #include <pulse/operation.h>
32 : : #include <pulse/format.h>
33 : :
34 : : #include <pulsecore/macro.h>
35 : : #include <pulsecore/pstream-util.h>
36 : :
37 : : #include "internal.h"
38 : : #include "ext-device-restore.h"
39 : :
40 : : /* Protocol extension commands */
41 : : enum {
42 : : SUBCOMMAND_TEST,
43 : : SUBCOMMAND_SUBSCRIBE,
44 : : SUBCOMMAND_EVENT,
45 : : SUBCOMMAND_READ_FORMATS_ALL,
46 : : SUBCOMMAND_READ_FORMATS,
47 : : SUBCOMMAND_SAVE_FORMATS
48 : : };
49 : :
50 : 0 : static void ext_device_restore_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
51 : 0 : pa_operation *o = userdata;
52 : 0 : uint32_t version = PA_INVALID_INDEX;
53 : :
54 [ # # ]: 0 : pa_assert(pd);
55 [ # # ]: 0 : pa_assert(o);
56 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(o) >= 1);
57 : :
58 [ # # ]: 0 : if (!o->context)
59 : : goto finish;
60 : :
61 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
62 [ # # ]: 0 : if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
63 : : goto finish;
64 : :
65 [ # # # # ]: 0 : } else if (pa_tagstruct_getu32(t, &version) < 0 ||
66 : 0 : !pa_tagstruct_eof(t)) {
67 : :
68 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
69 : 0 : goto finish;
70 : : }
71 : :
72 [ # # ]: 0 : if (o->callback) {
73 : 0 : pa_ext_device_restore_test_cb_t cb = (pa_ext_device_restore_test_cb_t) o->callback;
74 : 0 : cb(o->context, version, o->userdata);
75 : : }
76 : :
77 : : finish:
78 : 0 : pa_operation_done(o);
79 : 0 : pa_operation_unref(o);
80 : 0 : }
81 : :
82 : 0 : pa_operation *pa_ext_device_restore_test(
83 : : pa_context *c,
84 : : pa_ext_device_restore_test_cb_t cb,
85 : : void *userdata) {
86 : :
87 : : uint32_t tag;
88 : : pa_operation *o;
89 : : pa_tagstruct *t;
90 : :
91 [ # # ]: 0 : pa_assert(c);
92 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
93 : :
94 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
95 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
96 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
97 : :
98 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
99 : :
100 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
101 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
102 : 0 : pa_tagstruct_puts(t, "module-device-restore");
103 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
104 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
105 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_device_restore_test_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
106 : :
107 : 0 : return o;
108 : : }
109 : :
110 : 0 : pa_operation *pa_ext_device_restore_subscribe(
111 : : pa_context *c,
112 : : int enable,
113 : : pa_context_success_cb_t cb,
114 : : void *userdata) {
115 : :
116 : : uint32_t tag;
117 : : pa_operation *o;
118 : : pa_tagstruct *t;
119 : :
120 [ # # ]: 0 : pa_assert(c);
121 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
122 : :
123 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
124 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
125 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
126 : :
127 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
128 : :
129 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
130 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
131 : 0 : pa_tagstruct_puts(t, "module-device-restore");
132 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
133 : 0 : pa_tagstruct_put_boolean(t, enable);
134 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
135 : 0 : 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);
136 : :
137 : 0 : return o;
138 : : }
139 : :
140 : 0 : void pa_ext_device_restore_set_subscribe_cb(
141 : : pa_context *c,
142 : : pa_ext_device_restore_subscribe_cb_t cb,
143 : : void *userdata) {
144 : :
145 [ # # ]: 0 : pa_assert(c);
146 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
147 : :
148 [ # # ]: 0 : if (pa_detect_fork())
149 : 0 : return;
150 : :
151 : 0 : c->ext_device_restore.callback = cb;
152 : 0 : c->ext_device_restore.userdata = userdata;
153 : : }
154 : :
155 : 0 : static void ext_device_restore_read_device_formats_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
156 : 0 : pa_operation *o = userdata;
157 : 0 : int eol = 1;
158 : :
159 [ # # ]: 0 : pa_assert(pd);
160 [ # # ]: 0 : pa_assert(o);
161 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(o) >= 1);
162 : :
163 [ # # ]: 0 : if (!o->context)
164 : : goto finish;
165 : :
166 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
167 [ # # ]: 0 : if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
168 : : goto finish;
169 : :
170 : : eol = -1;
171 : : } else {
172 : : uint8_t j;
173 : :
174 [ # # ]: 0 : while (!pa_tagstruct_eof(t)) {
175 : : pa_ext_device_restore_info i;
176 : : pa_zero(i);
177 : :
178 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &i.type) < 0 ||
179 [ # # ]: 0 : pa_tagstruct_getu32(t, &i.index) < 0 ||
180 : 0 : pa_tagstruct_getu8(t, &i.n_formats) < 0) {
181 : :
182 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
183 : 0 : goto finish;
184 : : }
185 : :
186 [ # # ]: 0 : if (PA_DEVICE_TYPE_SINK != i.type && PA_DEVICE_TYPE_SOURCE != i.type) {
187 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
188 : 0 : goto finish;
189 : : }
190 : :
191 [ # # ]: 0 : if (i.index == PA_INVALID_INDEX) {
192 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
193 : 0 : goto finish;
194 : : }
195 : :
196 [ # # ]: 0 : if (i.n_formats > 0) {
197 : 0 : i.formats = pa_xnew0(pa_format_info*, i.n_formats);
198 : :
199 [ # # ]: 0 : for (j = 0; j < i.n_formats; j++) {
200 : :
201 : 0 : pa_format_info *f = i.formats[j] = pa_format_info_new();
202 [ # # ]: 0 : if (pa_tagstruct_get_format_info(t, f) < 0) {
203 : : uint8_t k;
204 : :
205 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
206 [ # # ]: 0 : for (k = 0; k < j+1; k++)
207 : 0 : pa_format_info_free(i.formats[k]);
208 : 0 : pa_xfree(i.formats);
209 : 0 : goto finish;
210 : : }
211 : : }
212 : : }
213 : :
214 [ # # ]: 0 : if (o->callback) {
215 : 0 : pa_ext_device_restore_read_device_formats_cb_t cb = (pa_ext_device_restore_read_device_formats_cb_t) o->callback;
216 : 0 : cb(o->context, &i, 0, o->userdata);
217 : : }
218 : :
219 [ # # ]: 0 : for (j = 0; j < i.n_formats; j++)
220 : 0 : pa_format_info_free(i.formats[j]);
221 : 0 : pa_xfree(i.formats);
222 : : }
223 : : }
224 : :
225 [ # # ]: 0 : if (o->callback) {
226 : 0 : pa_ext_device_restore_read_device_formats_cb_t cb = (pa_ext_device_restore_read_device_formats_cb_t) o->callback;
227 : 0 : cb(o->context, NULL, eol, o->userdata);
228 : : }
229 : :
230 : : finish:
231 : 0 : pa_operation_done(o);
232 : 0 : pa_operation_unref(o);
233 : 0 : }
234 : :
235 : 0 : pa_operation *pa_ext_device_restore_read_formats_all(
236 : : pa_context *c,
237 : : pa_ext_device_restore_read_device_formats_cb_t cb,
238 : : void *userdata) {
239 : :
240 : : uint32_t tag;
241 : : pa_operation *o;
242 : : pa_tagstruct *t;
243 : :
244 [ # # ]: 0 : pa_assert(c);
245 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
246 : :
247 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
248 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
249 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
250 : :
251 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
252 : :
253 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
254 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
255 : 0 : pa_tagstruct_puts(t, "module-device-restore");
256 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_READ_FORMATS_ALL);
257 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
258 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_device_restore_read_device_formats_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
259 : :
260 : 0 : return o;
261 : : }
262 : :
263 : 0 : pa_operation *pa_ext_device_restore_read_formats(
264 : : pa_context *c,
265 : : pa_device_type_t type,
266 : : uint32_t idx,
267 : : pa_ext_device_restore_read_device_formats_cb_t cb,
268 : : void *userdata) {
269 : :
270 : : uint32_t tag;
271 : : pa_operation *o;
272 : : pa_tagstruct *t;
273 : :
274 [ # # ]: 0 : pa_assert(c);
275 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
276 [ # # ]: 0 : pa_assert(idx != PA_INVALID_INDEX);
277 : :
278 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
279 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
280 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
281 : :
282 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
283 : :
284 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
285 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
286 : 0 : pa_tagstruct_puts(t, "module-device-restore");
287 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_READ_FORMATS);
288 : 0 : pa_tagstruct_putu32(t, type);
289 : 0 : pa_tagstruct_putu32(t, idx);
290 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
291 : 0 : pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_device_restore_read_device_formats_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
292 : :
293 : 0 : return o;
294 : : }
295 : :
296 : 0 : pa_operation *pa_ext_device_restore_save_formats(
297 : : pa_context *c,
298 : : pa_device_type_t type,
299 : : uint32_t idx,
300 : : uint8_t n_formats,
301 : : pa_format_info **formats,
302 : : pa_context_success_cb_t cb,
303 : : void *userdata) {
304 : :
305 : : uint32_t tag;
306 : : pa_operation *o;
307 : : pa_tagstruct *t;
308 : : uint8_t j;
309 : :
310 [ # # ]: 0 : pa_assert(c);
311 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
312 [ # # ]: 0 : pa_assert(idx != PA_INVALID_INDEX);
313 [ # # ]: 0 : pa_assert(n_formats > 0);
314 [ # # ][ # # ]: 0 : pa_assert(formats && *formats);
315 : :
316 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
317 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
318 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
319 : :
320 : 0 : o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
321 : :
322 : 0 : t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
323 : 0 : pa_tagstruct_putu32(t, PA_INVALID_INDEX);
324 : 0 : pa_tagstruct_puts(t, "module-device-restore");
325 : 0 : pa_tagstruct_putu32(t, SUBCOMMAND_SAVE_FORMATS);
326 : :
327 : 0 : pa_tagstruct_putu32(t, type);
328 : 0 : pa_tagstruct_putu32(t, idx);
329 : 0 : pa_tagstruct_putu8(t, n_formats);
330 [ # # ]: 0 : for (j = 0; j < n_formats; j++)
331 : 0 : pa_tagstruct_put_format_info(t, formats[j]);
332 : :
333 : 0 : pa_pstream_send_tagstruct(c->pstream, t);
334 : 0 : 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);
335 : :
336 : 0 : return o;
337 : : }
338 : :
339 : : /* Command function defined in internal.h */
340 : 0 : void pa_ext_device_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
341 : : uint32_t subcommand;
342 : : pa_device_type_t type;
343 : : uint32_t idx;
344 : :
345 [ # # ]: 0 : pa_assert(c);
346 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
347 [ # # ]: 0 : pa_assert(t);
348 : :
349 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
350 [ # # ]: 0 : pa_tagstruct_getu32(t, &type) < 0 ||
351 [ # # ]: 0 : pa_tagstruct_getu32(t, &idx) < 0 ||
352 : 0 : !pa_tagstruct_eof(t)) {
353 : :
354 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
355 : 0 : return;
356 : : }
357 : :
358 [ # # ]: 0 : if (subcommand != SUBCOMMAND_EVENT) {
359 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
360 : 0 : return;
361 : : }
362 : :
363 [ # # ]: 0 : if (PA_DEVICE_TYPE_SINK != type && PA_DEVICE_TYPE_SOURCE != type) {
364 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
365 : 0 : return;
366 : : }
367 : :
368 [ # # ]: 0 : if (idx == PA_INVALID_INDEX) {
369 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
370 : 0 : return;
371 : : }
372 : :
373 [ # # ]: 0 : if (c->ext_device_restore.callback)
374 : 0 : c->ext_device_restore.callback(c, type, idx, c->ext_device_restore.userdata);
375 : : }
|