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