2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
5 Copyright 2011 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
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>
34 #include <pulsecore/macro.h>
35 #include <pulsecore/pstream-util.h>
38 #include "ext-device-restore.h"
40 /* Protocol extension commands */
45 SUBCOMMAND_READ_FORMATS_ALL,
46 SUBCOMMAND_READ_FORMATS,
47 SUBCOMMAND_SAVE_FORMATS
50 static void ext_device_restore_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
51 pa_operation *o = userdata;
52 uint32_t version = PA_INVALID_INDEX;
56 pa_assert(PA_REFCNT_VALUE(o) >= 1);
61 if (command != PA_COMMAND_REPLY) {
62 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
65 } else if (pa_tagstruct_getu32(t, &version) < 0 ||
66 !pa_tagstruct_eof(t)) {
68 pa_context_fail(o->context, PA_ERR_PROTOCOL);
73 pa_ext_device_restore_test_cb_t cb = (pa_ext_device_restore_test_cb_t) o->callback;
74 cb(o->context, version, o->userdata);
79 pa_operation_unref(o);
82 pa_operation *pa_ext_device_restore_test(
84 pa_ext_device_restore_test_cb_t cb,
92 pa_assert(PA_REFCNT_VALUE(c) >= 1);
94 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
95 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
96 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
98 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
100 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
101 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
102 pa_tagstruct_puts(t, "module-device-restore");
103 pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
104 pa_pstream_send_tagstruct(c->pstream, t);
105 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);
110 pa_operation *pa_ext_device_restore_subscribe(
113 pa_context_success_cb_t cb,
121 pa_assert(PA_REFCNT_VALUE(c) >= 1);
123 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
124 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
125 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
127 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
129 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
130 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
131 pa_tagstruct_puts(t, "module-device-restore");
132 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
133 pa_tagstruct_put_boolean(t, enable);
134 pa_pstream_send_tagstruct(c->pstream, t);
135 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);
140 void pa_ext_device_restore_set_subscribe_cb(
142 pa_ext_device_restore_subscribe_cb_t cb,
146 pa_assert(PA_REFCNT_VALUE(c) >= 1);
148 if (pa_detect_fork())
151 c->ext_device_restore.callback = cb;
152 c->ext_device_restore.userdata = userdata;
155 static void ext_device_restore_read_device_formats_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
156 pa_operation *o = userdata;
161 pa_assert(PA_REFCNT_VALUE(o) >= 1);
166 if (command != PA_COMMAND_REPLY) {
167 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
174 while (!pa_tagstruct_eof(t)) {
175 pa_ext_device_restore_info i;
178 if (pa_tagstruct_getu32(t, &i.type) < 0 ||
179 pa_tagstruct_getu32(t, &i.index) < 0 ||
180 pa_tagstruct_getu8(t, &i.n_formats) < 0) {
182 pa_context_fail(o->context, PA_ERR_PROTOCOL);
186 if (PA_DEVICE_TYPE_SINK != i.type && PA_DEVICE_TYPE_SOURCE != i.type) {
187 pa_context_fail(o->context, PA_ERR_PROTOCOL);
191 if (i.index == PA_INVALID_INDEX) {
192 pa_context_fail(o->context, PA_ERR_PROTOCOL);
196 if (i.n_formats > 0) {
197 i.formats = pa_xnew0(pa_format_info*, i.n_formats);
199 for (j = 0; j < i.n_formats; j++) {
201 pa_format_info *f = i.formats[j] = pa_format_info_new();
202 if (pa_tagstruct_get_format_info(t, f) < 0) {
205 pa_context_fail(o->context, PA_ERR_PROTOCOL);
206 for (k = 0; k < j+1; k++)
207 pa_format_info_free(i.formats[k]);
215 pa_ext_device_restore_read_device_formats_cb_t cb = (pa_ext_device_restore_read_device_formats_cb_t) o->callback;
216 cb(o->context, &i, 0, o->userdata);
219 for (j = 0; j < i.n_formats; j++)
220 pa_format_info_free(i.formats[j]);
226 pa_ext_device_restore_read_device_formats_cb_t cb = (pa_ext_device_restore_read_device_formats_cb_t) o->callback;
227 cb(o->context, NULL, eol, o->userdata);
231 pa_operation_done(o);
232 pa_operation_unref(o);
235 pa_operation *pa_ext_device_restore_read_formats_all(
237 pa_ext_device_restore_read_device_formats_cb_t cb,
245 pa_assert(PA_REFCNT_VALUE(c) >= 1);
247 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
248 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
249 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
251 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
253 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
254 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
255 pa_tagstruct_puts(t, "module-device-restore");
256 pa_tagstruct_putu32(t, SUBCOMMAND_READ_FORMATS_ALL);
257 pa_pstream_send_tagstruct(c->pstream, t);
258 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);
263 pa_operation *pa_ext_device_restore_read_formats(
265 pa_device_type_t type,
267 pa_ext_device_restore_read_device_formats_cb_t cb,
275 pa_assert(PA_REFCNT_VALUE(c) >= 1);
276 pa_assert(idx != PA_INVALID_INDEX);
278 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
279 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
280 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
282 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
284 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
285 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
286 pa_tagstruct_puts(t, "module-device-restore");
287 pa_tagstruct_putu32(t, SUBCOMMAND_READ_FORMATS);
288 pa_tagstruct_putu32(t, type);
289 pa_tagstruct_putu32(t, idx);
290 pa_pstream_send_tagstruct(c->pstream, t);
291 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);
296 pa_operation *pa_ext_device_restore_save_formats(
298 pa_device_type_t type,
301 pa_format_info **formats,
302 pa_context_success_cb_t cb,
311 pa_assert(PA_REFCNT_VALUE(c) >= 1);
312 pa_assert(idx != PA_INVALID_INDEX);
313 pa_assert(n_formats > 0);
314 pa_assert(formats && *formats);
316 PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
317 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
318 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
320 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
322 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
323 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
324 pa_tagstruct_puts(t, "module-device-restore");
325 pa_tagstruct_putu32(t, SUBCOMMAND_SAVE_FORMATS);
327 pa_tagstruct_putu32(t, type);
328 pa_tagstruct_putu32(t, idx);
329 pa_tagstruct_putu8(t, n_formats);
330 for (j = 0; j < n_formats; j++)
331 pa_tagstruct_put_format_info(t, formats[j]);
333 pa_pstream_send_tagstruct(c->pstream, t);
334 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);
339 /* Command function defined in internal.h */
340 void pa_ext_device_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
342 pa_device_type_t type;
346 pa_assert(PA_REFCNT_VALUE(c) >= 1);
349 if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
350 pa_tagstruct_getu32(t, &type) < 0 ||
351 pa_tagstruct_getu32(t, &idx) < 0 ||
352 !pa_tagstruct_eof(t)) {
354 pa_context_fail(c, PA_ERR_PROTOCOL);
358 if (subcommand != SUBCOMMAND_EVENT) {
359 pa_context_fail(c, PA_ERR_PROTOCOL);
363 if (PA_DEVICE_TYPE_SINK != type && PA_DEVICE_TYPE_SOURCE != type) {
364 pa_context_fail(c, PA_ERR_PROTOCOL);
368 if (idx == PA_INVALID_INDEX) {
369 pa_context_fail(c, PA_ERR_PROTOCOL);
373 if (c->ext_device_restore.callback)
374 c->ext_device_restore.callback(c, type, idx, c->ext_device_restore.userdata);