domain-controller: add basic murphy interfacing
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / murphyif.c
1 /*
2  * module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU Lesser General Public License,
7  * version 2.1, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <pulsecore/pulsecore-config.h>
21 #include <pulsecore/module.h>
22
23 #ifdef WITH_MURPHYIF
24 #include <murphy/common/macros.h>
25 #include <murphy/common/mainloop.h>
26 #include <murphy/pulse/pulse-glue.h>
27 #endif
28
29 #include "murphyif.h"
30
31
32 struct pa_domctl {
33     const char           *addr;
34 #ifdef WITH_MURPHYIF
35     mrp_mainloop_t       *ml;
36     mrp_domctl_t         *ctl;
37     int                   ntable;
38     mrp_domctl_table_t   *tables;
39     int                   nwatch;
40     mrp_domctl_watch_t   *watches;
41     pa_murphyif_watch_cb  watchcb;
42 #endif
43 };
44
45
46 #ifdef WITH_MURPHYIF
47 static void connect_notify(mrp_domctl_t *, int, int, const char *, void *);
48 static void watch_notify(mrp_domctl_t *, mrp_domctl_data_t *, int, void *);
49 static void dump_data(mrp_domctl_data_t *);
50 #endif
51
52
53
54 pa_domctl *pa_murphyif_init(struct userdata *u, const char *addr)
55 {
56     pa_domctl *domctl;
57 #ifdef WITH_MURPHYIF
58     mrp_mainloop_t *ml;
59
60     if (!(ml = mrp_mainloop_pulse_get(u->core->mainloop))) {
61         pa_log_error("Failed to set up murphy mainloop.");
62         return NULL;
63     }
64 #endif
65
66     domctl = pa_xnew0(pa_domctl, 1);
67     domctl->addr = pa_xstrdup(addr ? addr : MRP_DEFAULT_DOMCTL_ADDRESS);
68 #ifdef WITH_MURPHYIF
69     domctl->ml = ml;
70 #endif
71
72     return domctl;
73 }
74
75
76 void pa_murphyif_done(struct userdata *u)
77 {
78     pa_domctl *domctl;
79
80     if (u && (domctl = u->domctl)) {
81 #ifdef WITH_MURPHYIF
82         mrp_domctl_table_t *t;
83         mrp_domctl_watch_t *w;
84         int i;
85
86         mrp_domctl_destroy(domctl->ctl);
87         mrp_mainloop_destroy(domctl->ml);
88
89         if (domctl->ntable > 0 && domctl->tables) {
90             for (i = 0;  i < domctl->ntable;  i++) {
91                 t = domctl->tables + i;
92                 pa_xfree((void *)t->table);
93                 pa_xfree((void *)t->mql_columns);
94                 pa_xfree((void *)t->mql_index);
95             }
96             pa_xfree(domctl->tables);
97         }
98
99         if (domctl->nwatch > 0 && domctl->watches) {
100             for (i = 0;  i < domctl->nwatch;  i++) {
101                 w = domctl->watches + i;
102                 pa_xfree((void *)w->table);
103                 pa_xfree((void *)w->mql_columns);
104                 pa_xfree((void *)w->mql_where);
105             }
106             pa_xfree(domctl->watches);
107         }
108 #endif
109         pa_xfree((void *)domctl->addr);
110
111         pa_xfree(domctl);
112     }
113 }
114
115 void pa_murphyif_add_table(struct userdata *u,
116                            const char *table,
117                            const char *columns,
118                            const char *index)
119 {
120     pa_domctl *domctl;
121     mrp_domctl_table_t *t;
122     size_t size;
123     size_t idx;
124     
125     pa_assert(u);
126     pa_assert(table);
127     pa_assert(columns);
128     pa_assert_se((domctl = u->domctl));
129
130     idx = domctl->ntable++;
131     size = sizeof(mrp_domctl_table_t) * domctl->ntable;
132     t = (domctl->tables = pa_xrealloc(domctl->tables, size)) + idx;
133
134     t->table = pa_xstrdup(table);
135     t->mql_columns = pa_xstrdup(columns);
136     t->mql_index = index ? pa_xstrdup(index) : NULL;
137 }
138
139 void pa_murphyif_add_watch(struct userdata *u,
140                            const char *table,
141                            const char *columns,
142                            const char *where,
143                            int max_rows)
144 {
145     pa_domctl *domctl;
146     mrp_domctl_watch_t *w;
147     size_t size;
148     size_t idx;
149     
150     pa_assert(u);
151     pa_assert(table);
152     pa_assert(columns);
153     pa_assert(max_rows > 0 && max_rows < MQI_QUERY_RESULT_MAX);
154     pa_assert_se((domctl = u->domctl));
155
156     idx = domctl->nwatch++;
157     size = sizeof(mrp_domctl_watch_t) * domctl->nwatch;
158     w = (domctl->watches = pa_xrealloc(domctl->watches, size)) + idx;
159
160     w->table = pa_xstrdup(table);
161     w->mql_columns = pa_xstrdup(columns);
162     w->mql_where = where ? pa_xstrdup(where) : NULL;
163     w->max_rows = max_rows;
164 }
165
166 void pa_murphyif_setup_domainctl(struct userdata *u, pa_murphyif_watch_cb wcb)
167 {
168     static const char *name = "pulse";
169
170     pa_domctl *domctl;
171
172     pa_assert(u);
173     pa_assert(wcb);
174     pa_assert_se((domctl = u->domctl));
175
176 #ifdef WITH_MURPHYIF
177     if (domctl->ntable || domctl->nwatch) {
178         domctl->ctl = mrp_domctl_create(name, domctl->ml,
179                                         domctl->tables, domctl->ntable,
180                                         domctl->watches, domctl->nwatch,
181                                         connect_notify, watch_notify, u);
182         if (!domctl->ctl) {
183             pa_log("failed to create '%s' domain controller", name);
184             return;
185         }
186
187         if (!mrp_domctl_connect(domctl->ctl, domctl->addr, 0)) {
188             pa_log("failed to conect to murphyd");
189             return;
190         }
191
192         domctl->watchcb = wcb;
193         pa_log_info("'%s' domain controller sucessfully created", name);
194     }
195 #endif
196 }
197
198 #ifdef WITH_MURPHYIF
199 static void connect_notify(mrp_domctl_t *dc, int connected, int errcode,
200                            const char *errmsg, void *user_data)
201 {
202     MRP_UNUSED(dc);
203     MRP_UNUSED(user_data);
204
205     if (connected) {
206         pa_log_info("Successfully registered to Murphy.");
207     }
208     else
209         pa_log_error("Connection to Murphy failed (%d: %s).", errcode, errmsg);
210 }
211
212 static void watch_notify(mrp_domctl_t *dc, mrp_domctl_data_t *tables,
213                          int ntable, void *user_data)
214 {
215     struct userdata *u = (struct userdata *)user_data;
216     pa_domctl *domctl;
217     mrp_domctl_data_t *t;
218     mrp_domctl_watch_t *w;
219     int i;
220
221     MRP_UNUSED(dc);
222
223     pa_assert(tables);
224     pa_assert(ntable > 0);
225     pa_assert(u);
226     pa_assert_se((domctl = u->domctl));
227
228     pa_log_info("Received change notification for %d tables.", ntable);
229
230     for (i = 0; i < ntable; i++) {
231         t = tables + i;
232
233         dump_data(t);
234
235         pa_assert(t->id >= 0);
236         pa_assert(t->id < domctl->nwatch);
237
238         w = domctl->watches + t->id;
239
240         domctl->watchcb(u, w->table, t->nrow, t->rows);
241     }
242 }
243
244 static void dump_data(mrp_domctl_data_t *table)
245 {
246     mrp_domctl_value_t *row;
247     int                 i, j;
248     char                buf[1024], *p;
249     const char         *t;
250     int                 n, l;
251
252     pa_log_debug("Table #%d: %d rows x %d columns", table->id,
253            table->nrow, table->ncolumn);
254
255     for (i = 0; i < table->nrow; i++) {
256         row = table->rows[i];
257         p   = buf;
258         n   = sizeof(buf);
259
260         for (j = 0, t = ""; j < table->ncolumn; j++, t = ", ") {
261             switch (row[j].type) {
262             case MRP_DOMCTL_STRING:
263                 l  = snprintf(p, n, "%s'%s'", t, row[j].str);
264                 p += l;
265                 n -= l;
266                 break;
267             case MRP_DOMCTL_INTEGER:
268                 l  = snprintf(p, n, "%s%d", t, row[j].s32);
269                 p += l;
270                 n -= l;
271                 break;
272             case MRP_DOMCTL_UNSIGNED:
273                 l  = snprintf(p, n, "%s%u", t, row[j].u32);
274                 p += l;
275                 n -= l;
276                 break;
277             case MRP_DOMCTL_DOUBLE:
278                 l  = snprintf(p, n, "%s%f", t, row[j].dbl);
279                 p += l;
280                 n -= l;
281                 break;
282             default:
283                 l  = snprintf(p, n, "%s<invalid column 0x%x>",
284                               t, row[j].type);
285                 p += l;
286                 n -= l;
287             }
288         }
289
290         pa_log_debug("row #%d: { %s }", i, buf);
291     }
292 }
293 #endif
294
295 /*
296  * Local Variables:
297  * c-basic-offset: 4
298  * indent-tabs-mode: nil
299  * End:
300  *
301  */