]> code.delx.au - pulseaudio/blob - src/pulse/ext-stream-restore.c
Merge branch 'master' of git://git.0pointer.de/pulseaudio
[pulseaudio] / src / pulse / ext-stream-restore.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2008 Lennart Poettering
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <pulse/context.h>
27 #include <pulse/gccmacro.h>
28
29 #include <pulsecore/macro.h>
30 #include <pulsecore/pstream-util.h>
31
32 #include "internal.h"
33
34 #include "ext-stream-restore.h"
35
36 enum {
37 SUBCOMMAND_TEST,
38 SUBCOMMAND_READ,
39 SUBCOMMAND_WRITE,
40 SUBCOMMAND_DELETE,
41 SUBCOMMAND_SUBSCRIBE,
42 SUBCOMMAND_EVENT
43 };
44
45 static void ext_stream_restore_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
46 pa_operation *o = userdata;
47 uint32_t version = PA_INVALID_INDEX;
48
49 pa_assert(pd);
50 pa_assert(o);
51 pa_assert(PA_REFCNT_VALUE(o) >= 1);
52
53 if (!o->context)
54 goto finish;
55
56 if (command != PA_COMMAND_REPLY) {
57 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
58 goto finish;
59
60 } else if (pa_tagstruct_getu32(t, &version) < 0 ||
61 !pa_tagstruct_eof(t)) {
62
63 pa_context_fail(o->context, PA_ERR_PROTOCOL);
64 goto finish;
65 }
66
67 if (o->callback) {
68 pa_ext_stream_restore_test_cb_t cb = (pa_ext_stream_restore_test_cb_t) o->callback;
69 cb(o->context, version, o->userdata);
70 }
71
72 finish:
73 pa_operation_done(o);
74 pa_operation_unref(o);
75 }
76
77 pa_operation *pa_ext_stream_restore_test(
78 pa_context *c,
79 pa_ext_stream_restore_test_cb_t cb,
80 void *userdata) {
81
82 uint32_t tag;
83 pa_operation *o;
84 pa_tagstruct *t;
85
86 pa_assert(c);
87 pa_assert(PA_REFCNT_VALUE(c) >= 1);
88
89 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
90 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
91
92 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
93
94 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
95 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
96 pa_tagstruct_puts(t, "module-stream-restore");
97 pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
98 pa_pstream_send_tagstruct(c->pstream, t);
99 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_stream_restore_test_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
100
101 return o;
102 }
103
104 static void ext_stream_restore_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
105 pa_operation *o = userdata;
106 int eol = 1;
107
108 pa_assert(pd);
109 pa_assert(o);
110 pa_assert(PA_REFCNT_VALUE(o) >= 1);
111
112 if (!o->context)
113 goto finish;
114
115 if (command != PA_COMMAND_REPLY) {
116 if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
117 goto finish;
118
119 eol = -1;
120 } else {
121
122 while (!pa_tagstruct_eof(t)) {
123 pa_ext_stream_restore_info i;
124 pa_bool_t mute = FALSE;
125
126 memset(&i, 0, sizeof(i));
127
128 if (pa_tagstruct_gets(t, &i.name) < 0 ||
129 pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 ||
130 pa_tagstruct_get_cvolume(t, &i.volume) < 0 ||
131 pa_tagstruct_gets(t, &i.device) < 0 ||
132 pa_tagstruct_get_boolean(t, &mute) < 0) {
133
134 pa_context_fail(o->context, PA_ERR_PROTOCOL);
135 goto finish;
136 }
137
138 i.mute = (int) mute;
139
140 if (o->callback) {
141 pa_ext_stream_restore_read_cb_t cb = (pa_ext_stream_restore_read_cb_t) o->callback;
142 cb(o->context, &i, 0, o->userdata);
143 }
144 }
145 }
146
147 if (o->callback) {
148 pa_ext_stream_restore_read_cb_t cb = (pa_ext_stream_restore_read_cb_t) o->callback;
149 cb(o->context, NULL, eol, o->userdata);
150 }
151
152 finish:
153 pa_operation_done(o);
154 pa_operation_unref(o);
155 }
156
157 pa_operation *pa_ext_stream_restore_read(
158 pa_context *c,
159 pa_ext_stream_restore_read_cb_t cb,
160 void *userdata) {
161
162 uint32_t tag;
163 pa_operation *o;
164 pa_tagstruct *t;
165
166 pa_assert(c);
167 pa_assert(PA_REFCNT_VALUE(c) >= 1);
168
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);
171
172 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
173
174 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
175 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
176 pa_tagstruct_puts(t, "module-stream-restore");
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_stream_restore_read_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
180
181 return o;
182 }
183
184 pa_operation *pa_ext_stream_restore_write(
185 pa_context *c,
186 pa_update_mode_t mode,
187 const pa_ext_stream_restore_info data[],
188 unsigned n,
189 int apply_immediately,
190 pa_context_success_cb_t cb,
191 void *userdata) {
192
193 uint32_t tag;
194 pa_operation *o;
195 pa_tagstruct *t;
196
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);
201
202 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
203 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
204
205 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
206
207 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
208 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
209 pa_tagstruct_puts(t, "module-stream-restore");
210 pa_tagstruct_putu32(t, SUBCOMMAND_WRITE);
211
212 pa_tagstruct_putu32(t, mode);
213 pa_tagstruct_put_boolean(t, apply_immediately);
214
215 for (; n > 0; n--, data++) {
216 pa_tagstruct_puts(t, data->name);
217 pa_tagstruct_put_channel_map(t, &data->channel_map);
218 pa_tagstruct_put_cvolume(t, &data->volume);
219 pa_tagstruct_puts(t, data->device);
220 pa_tagstruct_put_boolean(t, data->mute);
221 }
222
223 pa_pstream_send_tagstruct(c->pstream, t);
224 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);
225
226 return o;
227 }
228
229 pa_operation *pa_ext_stream_restore_delete(
230 pa_context *c,
231 const char *const s[],
232 pa_context_success_cb_t cb,
233 void *userdata) {
234
235 uint32_t tag;
236 pa_operation *o;
237 pa_tagstruct *t;
238 const char *const *k;
239
240 pa_assert(c);
241 pa_assert(PA_REFCNT_VALUE(c) >= 1);
242 pa_assert(s);
243
244 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
245 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
246
247 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
248
249 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
250 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
251 pa_tagstruct_puts(t, "module-stream-restore");
252 pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
253
254 for (k = s; *k; k++)
255 pa_tagstruct_puts(t, *k);
256
257 pa_pstream_send_tagstruct(c->pstream, t);
258 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);
259
260 return o;
261 }
262
263 pa_operation *pa_ext_stream_restore_subscribe(
264 pa_context *c,
265 int enable,
266 pa_context_success_cb_t cb,
267 void *userdata) {
268
269 uint32_t tag;
270 pa_operation *o;
271 pa_tagstruct *t;
272
273 pa_assert(c);
274 pa_assert(PA_REFCNT_VALUE(c) >= 1);
275
276 PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
277 PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
278
279 o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
280
281 t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
282 pa_tagstruct_putu32(t, PA_INVALID_INDEX);
283 pa_tagstruct_puts(t, "module-stream-restore");
284 pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
285 pa_tagstruct_put_boolean(t, enable);
286 pa_pstream_send_tagstruct(c->pstream, t);
287 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);
288
289 return o;
290 }
291
292 void pa_ext_stream_restore_set_subscribe_cb(
293 pa_context *c,
294 pa_ext_stream_restore_subscribe_cb_t cb,
295 void *userdata) {
296
297 pa_assert(c);
298 pa_assert(PA_REFCNT_VALUE(c) >= 1);
299
300 c->ext_stream_restore.callback = cb;
301 c->ext_stream_restore.userdata = userdata;
302 }
303
304 void pa_ext_stream_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
305 uint32_t subcommand;
306
307 pa_assert(c);
308 pa_assert(PA_REFCNT_VALUE(c) >= 1);
309 pa_assert(t);
310
311 if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
312 !pa_tagstruct_eof(t)) {
313
314 pa_context_fail(c, PA_ERR_PROTOCOL);
315 return;
316 }
317
318 if (subcommand != SUBCOMMAND_EVENT) {
319 pa_context_fail(c, PA_ERR_PROTOCOL);
320 return;
321 }
322
323 if (c->ext_stream_restore.callback)
324 c->ext_stream_restore.callback(c, c->ext_stream_restore.userdata);
325
326 }