release: updated changelog.
[profile/ivi/pulseaudio.git] / 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.1 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/fork-detect.h>
28 #include <pulse/operation.h>
29
30 #include <pulsecore/macro.h>
31 #include <pulsecore/pstream-util.h>
32
33 #include "internal.h"
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, !pa_detect_fork(), PA_ERR_FORKED);
90     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
91     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
92
93     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
94
95     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
96     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
97     pa_tagstruct_puts(t, "module-stream-restore");
98     pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
99     pa_pstream_send_tagstruct(c->pstream, t);
100     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);
101
102     return o;
103 }
104
105 static void ext_stream_restore_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
106     pa_operation *o = userdata;
107     int eol = 1;
108
109     pa_assert(pd);
110     pa_assert(o);
111     pa_assert(PA_REFCNT_VALUE(o) >= 1);
112
113     if (!o->context)
114         goto finish;
115
116     if (command != PA_COMMAND_REPLY) {
117         if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
118             goto finish;
119
120         eol = -1;
121     } else {
122
123         while (!pa_tagstruct_eof(t)) {
124             pa_ext_stream_restore_info i;
125             pa_bool_t mute = FALSE;
126
127             memset(&i, 0, sizeof(i));
128
129             if (pa_tagstruct_gets(t, &i.name) < 0 ||
130                 pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 ||
131                 pa_tagstruct_get_cvolume(t, &i.volume) < 0 ||
132                 pa_tagstruct_gets(t, &i.device) < 0 ||
133                 pa_tagstruct_get_boolean(t, &mute) < 0) {
134
135                 pa_context_fail(o->context, PA_ERR_PROTOCOL);
136                 goto finish;
137             }
138
139             i.mute = (int) mute;
140
141             if (o->callback) {
142                 pa_ext_stream_restore_read_cb_t cb = (pa_ext_stream_restore_read_cb_t) o->callback;
143                 cb(o->context, &i, 0, o->userdata);
144             }
145         }
146     }
147
148     if (o->callback) {
149         pa_ext_stream_restore_read_cb_t cb = (pa_ext_stream_restore_read_cb_t) o->callback;
150         cb(o->context, NULL, eol, o->userdata);
151     }
152
153 finish:
154     pa_operation_done(o);
155     pa_operation_unref(o);
156 }
157
158 pa_operation *pa_ext_stream_restore_read(
159         pa_context *c,
160         pa_ext_stream_restore_read_cb_t cb,
161         void *userdata) {
162
163     uint32_t tag;
164     pa_operation *o;
165     pa_tagstruct *t;
166
167     pa_assert(c);
168     pa_assert(PA_REFCNT_VALUE(c) >= 1);
169
170     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
171     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
172     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
173
174     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
175
176     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
177     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
178     pa_tagstruct_puts(t, "module-stream-restore");
179     pa_tagstruct_putu32(t, SUBCOMMAND_READ);
180     pa_pstream_send_tagstruct(c->pstream, t);
181     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);
182
183     return o;
184 }
185
186 pa_operation *pa_ext_stream_restore_write(
187         pa_context *c,
188         pa_update_mode_t mode,
189         const pa_ext_stream_restore_info data[],
190         unsigned n,
191         int apply_immediately,
192         pa_context_success_cb_t cb,
193         void *userdata) {
194
195     uint32_t tag;
196     pa_operation *o = NULL;
197     pa_tagstruct *t = NULL;
198
199     pa_assert(c);
200     pa_assert(PA_REFCNT_VALUE(c) >= 1);
201     pa_assert(mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE || mode == PA_UPDATE_SET);
202     pa_assert(data);
203
204     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
205     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
206     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
207
208     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
209
210     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
211     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
212     pa_tagstruct_puts(t, "module-stream-restore");
213     pa_tagstruct_putu32(t, SUBCOMMAND_WRITE);
214
215     pa_tagstruct_putu32(t, mode);
216     pa_tagstruct_put_boolean(t, apply_immediately);
217
218     for (; n > 0; n--, data++) {
219         if (!data->name || !*data->name)
220             goto fail;
221
222         pa_tagstruct_puts(t, data->name);
223
224         if (data->volume.channels > 0 &&
225             !pa_cvolume_compatible_with_channel_map(&data->volume, &data->channel_map))
226             goto fail;
227
228         pa_tagstruct_put_channel_map(t, &data->channel_map);
229         pa_tagstruct_put_cvolume(t, &data->volume);
230         pa_tagstruct_puts(t, data->device);
231         pa_tagstruct_put_boolean(t, data->mute);
232     }
233
234     pa_pstream_send_tagstruct(c->pstream, t);
235     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);
236
237     return o;
238
239 fail:
240     pa_operation_cancel(o);
241     pa_operation_unref(o);
242
243     pa_tagstruct_free(t);
244
245     pa_context_set_error(c, PA_ERR_INVALID);
246     return NULL;
247 }
248
249 pa_operation *pa_ext_stream_restore_delete(
250         pa_context *c,
251         const char *const s[],
252         pa_context_success_cb_t cb,
253         void *userdata) {
254
255     uint32_t tag;
256     pa_operation *o = NULL;
257     pa_tagstruct *t = NULL;
258     const char *const *k;
259
260     pa_assert(c);
261     pa_assert(PA_REFCNT_VALUE(c) >= 1);
262     pa_assert(s);
263
264     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
265     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
266     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
267
268     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
269
270     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
271     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
272     pa_tagstruct_puts(t, "module-stream-restore");
273     pa_tagstruct_putu32(t, SUBCOMMAND_DELETE);
274
275     for (k = s; *k; k++) {
276         if (!*k || !**k)
277             goto fail;
278
279         pa_tagstruct_puts(t, *k);
280     }
281
282     pa_pstream_send_tagstruct(c->pstream, t);
283     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);
284
285     return o;
286
287 fail:
288     pa_operation_cancel(o);
289     pa_operation_unref(o);
290
291     pa_tagstruct_free(t);
292
293     pa_context_set_error(c, PA_ERR_INVALID);
294     return NULL;
295 }
296
297 pa_operation *pa_ext_stream_restore_subscribe(
298         pa_context *c,
299         int enable,
300         pa_context_success_cb_t cb,
301         void *userdata) {
302
303     uint32_t tag;
304     pa_operation *o;
305     pa_tagstruct *t;
306
307     pa_assert(c);
308     pa_assert(PA_REFCNT_VALUE(c) >= 1);
309
310     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
311     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
312     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
313
314     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
315
316     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
317     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
318     pa_tagstruct_puts(t, "module-stream-restore");
319     pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
320     pa_tagstruct_put_boolean(t, enable);
321     pa_pstream_send_tagstruct(c->pstream, t);
322     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);
323
324     return o;
325 }
326
327 void pa_ext_stream_restore_set_subscribe_cb(
328         pa_context *c,
329         pa_ext_stream_restore_subscribe_cb_t cb,
330         void *userdata) {
331
332     pa_assert(c);
333     pa_assert(PA_REFCNT_VALUE(c) >= 1);
334
335     if (pa_detect_fork())
336         return;
337
338     c->ext_stream_restore.callback = cb;
339     c->ext_stream_restore.userdata = userdata;
340 }
341
342 void pa_ext_stream_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
343     uint32_t subcommand;
344
345     pa_assert(c);
346     pa_assert(PA_REFCNT_VALUE(c) >= 1);
347     pa_assert(t);
348
349     if (pa_tagstruct_getu32(t, &subcommand) < 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 (c->ext_stream_restore.callback)
362         c->ext_stream_restore.callback(c, c->ext_stream_restore.userdata);
363 }