release: updated changelog.
[profile/ivi/pulseaudio.git] / src / pulse / ext-node-manager.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2012 Jaska Uimonen
5   Copyright 2012 Janos Kovacs
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/xmalloc.h>
29 #include <pulse/fork-detect.h>
30 #include <pulse/operation.h>
31
32 #include <pulsecore/macro.h>
33 #include <pulsecore/pstream-util.h>
34
35 #include "internal.h"
36 #include "ext-node-manager.h"
37
38 enum {
39     SUBCOMMAND_TEST,
40     SUBCOMMAND_READ,
41     SUBCOMMAND_CONNECT,
42     SUBCOMMAND_DISCONNECT,
43     SUBCOMMAND_SUBSCRIBE,
44     SUBCOMMAND_EVENT
45 };
46
47 static void ext_node_manager_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
48     pa_operation *o = userdata;
49     uint32_t version = PA_INVALID_INDEX;
50
51     pa_assert(pd);
52     pa_assert(o);
53     pa_assert(PA_REFCNT_VALUE(o) >= 1);
54
55     if (!o->context)
56         goto finish;
57
58     if (command != PA_COMMAND_REPLY) {
59         if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
60             goto finish;
61
62     } else if (pa_tagstruct_getu32(t, &version) < 0 ||
63                !pa_tagstruct_eof(t)) {
64
65         pa_context_fail(o->context, PA_ERR_PROTOCOL);
66         goto finish;
67     }
68
69     if (o->callback) {
70         pa_ext_node_manager_test_cb_t cb = (pa_ext_node_manager_test_cb_t) o->callback;
71         cb(o->context, version, o->userdata);
72     }
73
74 finish:
75     pa_operation_done(o);
76     pa_operation_unref(o);
77 }
78
79 pa_operation *pa_ext_node_manager_test(
80         pa_context *c,
81         pa_ext_node_manager_test_cb_t cb,
82         void *userdata) {
83
84     uint32_t tag;
85     pa_operation *o;
86     pa_tagstruct *t;
87
88     pa_assert(c);
89     pa_assert(PA_REFCNT_VALUE(c) >= 1);
90
91     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
92     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
93     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
94
95     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
96
97     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
98     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
99     pa_tagstruct_puts(t, "module-murphy-ivi");
100     pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
101     pa_pstream_send_tagstruct(c->pstream, t);
102     pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_node_manager_test_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
103
104     return o;
105 }
106
107 static void ext_node_manager_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
108     pa_operation *o = userdata;
109     pa_ext_node_manager_info i;
110
111     pa_assert(pd);
112     pa_assert(o);
113     pa_assert(PA_REFCNT_VALUE(o) >= 1);
114
115     if (!o->context)
116         goto finish;
117
118     if (command != PA_COMMAND_REPLY) {
119         if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
120             goto finish;
121     } else {
122
123         while (!pa_tagstruct_eof(t)) {
124
125             memset(&i, 0, sizeof(i));
126
127             i.props = pa_proplist_new();
128
129             if (pa_tagstruct_gets(t, &i.name) < 0 ||
130                 pa_tagstruct_get_proplist(t, i.props) < 0) {
131
132                 pa_context_fail(o->context, PA_ERR_PROTOCOL);
133                 goto finish;
134             }
135
136             if (o->callback) {
137                 pa_ext_node_manager_read_cb_t cb = (pa_ext_node_manager_read_cb_t) o->callback;
138                 cb(o->context, &i, 0, o->userdata);
139             }
140
141             pa_proplist_free(i.props);
142         }
143
144         /* let's send end marker */
145         if (o->callback) {
146                 pa_ext_node_manager_read_cb_t cb = (pa_ext_node_manager_read_cb_t) o->callback;
147                 cb(o->context, &i, 1, o->userdata);
148             }
149     }
150
151 finish:
152     pa_operation_done(o);
153     pa_operation_unref(o);
154 }
155
156 pa_operation *pa_ext_node_manager_read_nodes(
157         pa_context *c,
158         pa_ext_node_manager_read_cb_t cb,
159         void *userdata) {
160
161     uint32_t tag;
162     pa_operation *o;
163     pa_tagstruct *t;
164
165     pa_assert(c);
166     pa_assert(PA_REFCNT_VALUE(c) >= 1);
167
168     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
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-murphy-ivi");
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_node_manager_read_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
180
181     return o;
182 }
183
184 static void ext_node_manager_connect_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
185     pa_operation *o = userdata;
186     uint32_t connection = PA_INVALID_INDEX;
187
188     pa_assert(pd);
189     pa_assert(o);
190     pa_assert(PA_REFCNT_VALUE(o) >= 1);
191
192     if (!o->context)
193         goto finish;
194
195     if (command != PA_COMMAND_REPLY) {
196         if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
197             goto finish;
198
199     } else if (pa_tagstruct_getu32(t, &connection) < 0 ||
200                !pa_tagstruct_eof(t)) {
201
202         pa_context_fail(o->context, PA_ERR_PROTOCOL);
203         goto finish;
204     }
205
206     if (o->callback) {
207         pa_ext_node_manager_connect_cb_t cb = (pa_ext_node_manager_connect_cb_t) o->callback;
208         cb(o->context, connection, o->userdata);
209     }
210
211 finish:
212     pa_operation_done(o);
213     pa_operation_unref(o);
214 }
215
216 pa_operation *pa_ext_node_manager_connect_nodes(
217         pa_context *c,
218         uint32_t source_node_id,
219         uint32_t sink_node_id,
220         pa_ext_node_manager_connect_cb_t cb,
221         void *userdata) {
222
223     uint32_t tag;
224     pa_operation *o = NULL;
225     pa_tagstruct *t = NULL;
226
227     pa_assert(c);
228     pa_assert(PA_REFCNT_VALUE(c) >= 1);
229
230     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
231     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
232     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
233
234     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
235
236     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
237     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
238     pa_tagstruct_puts(t, "module-murphy-ivi");
239     pa_tagstruct_putu32(t, SUBCOMMAND_CONNECT);
240
241     pa_tagstruct_putu32(t, source_node_id);
242     pa_tagstruct_putu32(t, sink_node_id);
243
244     pa_pstream_send_tagstruct(c->pstream, t);
245     pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_node_manager_connect_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
246
247     return o;
248 }
249
250 pa_operation *pa_ext_node_manager_disconnect_nodes(
251         pa_context *c,
252         uint32_t conn_id,
253         pa_context_success_cb_t cb,
254         void *userdata) {
255
256     uint32_t tag;
257     pa_operation *o = NULL;
258     pa_tagstruct *t = NULL;
259
260     pa_assert(c);
261     pa_assert(PA_REFCNT_VALUE(c) >= 1);
262
263     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
264     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
265     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
266
267     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
268
269     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
270     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
271     pa_tagstruct_puts(t, "module-murphy-ivi");
272     pa_tagstruct_putu32(t, SUBCOMMAND_DISCONNECT);
273
274     pa_tagstruct_putu32(t, conn_id);
275
276     pa_pstream_send_tagstruct(c->pstream, t);
277     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);
278
279     return o;
280 }
281
282 pa_operation *pa_ext_node_manager_subscribe(
283         pa_context *c,
284         int enable,
285         pa_context_success_cb_t cb,
286         void *userdata) {
287
288     uint32_t tag;
289     pa_operation *o;
290     pa_tagstruct *t;
291
292     pa_assert(c);
293     pa_assert(PA_REFCNT_VALUE(c) >= 1);
294
295     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
296     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
297     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
298
299     o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
300
301     t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
302     pa_tagstruct_putu32(t, PA_INVALID_INDEX);
303     pa_tagstruct_puts(t, "module-murphy-ivi");
304     pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
305     pa_tagstruct_put_boolean(t, enable);
306     pa_pstream_send_tagstruct(c->pstream, t);
307     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);
308
309     return o;
310 }
311
312 void pa_ext_node_manager_set_subscribe_cb(
313         pa_context *c,
314         pa_ext_node_manager_subscribe_cb_t cb,
315         void *userdata) {
316
317     pa_assert(c);
318     pa_assert(PA_REFCNT_VALUE(c) >= 1);
319
320     if (pa_detect_fork())
321         return;
322
323     c->ext_node_manager.callback = cb;
324     c->ext_node_manager.userdata = userdata;
325 }
326
327 void pa_ext_node_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
328     uint32_t subcommand;
329
330     pa_assert(c);
331     pa_assert(PA_REFCNT_VALUE(c) >= 1);
332     pa_assert(t);
333
334     if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
335         !pa_tagstruct_eof(t)) {
336
337         pa_context_fail(c, PA_ERR_PROTOCOL);
338         return;
339     }
340
341     if (subcommand != SUBCOMMAND_EVENT) {
342         pa_context_fail(c, PA_ERR_PROTOCOL);
343         return;
344     }
345
346     if (c->ext_node_manager.callback)
347         c->ext_node_manager.callback(c, c->ext_node_manager.userdata);
348 }