routing: set media.role property on multiplex streams
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / constrain.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 <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <pulsecore/pulsecore-config.h>
26
27 #include <pulse/proplist.h>
28 #include <pulsecore/core-util.h>
29 #include <pulsecore/module.h>
30
31 #include "constrain.h"
32 #include "router.h"
33 #include "node.h"
34
35
36 static mir_constr_def *cstrdef_create(struct userdata *, const char *,
37                                       mir_constrain_func_t, const char *);
38 static void cstrdef_destroy(struct userdata *, mir_constr_def *);
39
40 static mir_constr_link *cstrlink_create(struct userdata *, mir_constr_def *,
41                                         mir_node *);
42 static void cstrlink_destroy(struct userdata *, mir_constr_link *);
43
44
45 static void pa_hashmap_constrdef_free(void *cd, void *u)
46 {
47     cstrdef_destroy(u, cd);
48 }
49
50
51 pa_constrain *pa_constrain_init(struct userdata *u)
52 {
53     pa_constrain *constrain = pa_xnew0(pa_constrain, 1);
54     
55     constrain->defs = pa_hashmap_new(pa_idxset_string_hash_func,
56                                      pa_idxset_string_compare_func);    
57     return constrain;
58 }
59
60 void pa_constrain_done(struct userdata *u)
61 {
62     pa_constrain   *constrain;
63
64     if (u && (constrain = u->constrain)) {
65         pa_hashmap_free(constrain->defs, pa_hashmap_constrdef_free, u);
66
67         pa_xfree(constrain);
68
69         u->constrain = NULL;
70     }
71 }
72
73
74 mir_constr_def *mir_constrain_create(struct userdata *u, const char *name,
75                                      mir_constrain_func_t func,
76                                      const char *key)
77 {
78     pa_constrain *constrain;
79     mir_constr_def *cd;
80
81     pa_assert(u);
82     pa_assert(name);
83     pa_assert(func);
84     pa_assert(key);
85     pa_assert_se((constrain = u->constrain));
86
87     if ((cd = mir_constrain_find(u, key))) {
88         if (pa_streq(name, cd->name) && func == cd->func)
89             return cd;
90         else {
91             pa_log_debug("attempt to redefine constrain %s/%s => %s/%s",
92                          cd->name,cd->key, name,key);
93             return NULL;
94         }
95     }
96
97     cd = cstrdef_create(u, name, func, key);
98
99     if (pa_hashmap_put(constrain->defs, cd->key, cd) < 0) {
100         pa_xfree(cd->key);
101         pa_xfree(cd->name);
102         pa_xfree(cd);
103         return NULL;
104     }
105
106     pa_log_debug("constrain %s/%s created", cd->name, cd->key);
107
108     return cd;
109 }
110
111 void mir_constrain_destroy(struct userdata *u, const char *key)
112 {
113     pa_constrain *constrain;
114     mir_constr_def *cd;
115
116     pa_assert(u);
117     pa_assert(key);
118     pa_assert_se((constrain = u->constrain));
119
120     if ((cd = pa_hashmap_remove(constrain->defs, key))) {
121         pa_log_debug("destroying constrain %s/%s", cd->name, cd->key);
122         cstrdef_destroy(u, cd);
123     }
124 }
125
126 mir_constr_def *mir_constrain_find(struct userdata *u, const char *key)
127 {
128     pa_constrain *constrain;
129     mir_constr_def *cd;
130
131     pa_assert(u);
132     pa_assert(key);
133     pa_assert_se((constrain = u->constrain));
134
135     cd = pa_hashmap_get(constrain->defs, key);
136
137     return cd;
138 }
139
140
141 void mir_constrain_add_node(struct userdata *u,
142                             mir_constr_def  *cd,
143                             mir_node        *node)
144 {
145     mir_constr_link *cl;
146
147     pa_assert(u);
148     pa_assert(node);
149
150     if (cd) {
151         cl = cstrlink_create(u, cd, node);
152
153         MIR_DLIST_APPEND(mir_constr_link, link, cl, &cd->nodes);
154         MIR_DLIST_APPEND(mir_constr_link, nodchain, cl, &node->constrains);
155         
156         pa_log_debug("node '%s' added to constrain %s/%s",
157                      node->amname, cd->name, cd->key);
158     }
159 }
160
161 void mir_constrain_remove_node(struct userdata *u, mir_node *node)
162 {
163     mir_constr_def  *cd;
164     mir_constr_link *cl, *n;
165
166     pa_assert(u);
167     pa_assert(node);
168
169     MIR_DLIST_FOR_EACH_SAFE(mir_constr_link,nodchain, cl,n, &node->constrains){
170         pa_assert_se((cd = cl->def));
171
172         pa_log_debug("node '%s' removed from constrain %s/%s",
173                      node->amname, cd->name, cd->key);
174
175         cstrlink_destroy(u, cl);
176     }
177 }
178
179
180 void mir_constrain_apply(struct userdata *u, mir_node *node, uint32_t stamp)
181 {
182     mir_constr_link *cl;
183     mir_constr_def  *cd;
184     mir_constr_link *c;
185     mir_node        *n;
186     mir_rtentry     *rte;
187     mir_rtgroup     *rtg;
188     pa_bool_t        blocked;
189
190     pa_assert(u);
191     pa_assert(node);
192
193     MIR_DLIST_FOR_EACH(mir_constr_link, nodchain, cl, &node->constrains) {
194         pa_assert(node == cl->node);
195         pa_assert_se((cd = cl->def));
196
197         pa_log_debug("applying constrain %s/%s", cd->name, cd->key);
198
199         MIR_DLIST_FOR_EACH(mir_constr_link, link, c, &cd->nodes) {
200             n = c->node;
201             blocked = cd->func(u, cd, node, n);
202
203             MIR_DLIST_FOR_EACH(mir_rtentry, nodchain, rte, &n->rtentries) {
204                 pa_assert_se((rtg = rte->group));
205
206                 rte->blocked = blocked;
207                 rte->stamp   = stamp;
208
209                 pa_log_debug("   %sblocking '%s' in table '%s'",
210                              blocked ? "":"un", n->amname, rtg->name);
211             }
212         }
213     }
214
215
216 int mir_constrain_print(mir_node *node, char *buf, int len)
217 {
218     mir_constr_def  *cd;
219     mir_constr_link *cl;
220     char *p, *e, *s;
221
222     pa_assert(node);
223     pa_assert(buf);
224     pa_assert(len > 0);
225
226     buf[0] = '\0';
227
228     e = (p = buf) + len;
229     s = "";
230
231     MIR_DLIST_FOR_EACH(mir_constr_link, nodchain, cl, &node->constrains) {
232         if (p >= e)
233             break;
234
235         cd = cl->def;
236
237         p += snprintf(p, e-p, "%s'%s'", s, cd->name);
238         s  = " ";
239     }
240
241     return p - buf;
242 }
243
244 pa_bool_t mir_constrain_port(struct userdata *u,
245                              mir_constr_def  *cd,
246                              mir_node        *active,
247                              mir_node        *node)
248 {
249     char *active_port;
250     char *node_port;
251     pa_bool_t block;
252
253     pa_assert(u);
254     pa_assert(cd);
255     pa_assert(active);
256     pa_assert(node);
257
258     pa_assert_se((active_port = active->paport));
259     pa_assert_se((node_port = node->paport));
260
261     block = !pa_streq(active_port, node_port);
262
263     return block;
264 }
265
266 pa_bool_t mir_constrain_profile(struct userdata *u,
267                                 mir_constr_def  *cd,
268                                 mir_node        *active,
269                                 mir_node        *node)
270 {
271     char *active_profile;
272     char *node_profile;
273     pa_bool_t block;
274
275     pa_assert(u);
276     pa_assert(cd);
277     pa_assert(active);
278     pa_assert(node);
279
280     pa_assert_se((active_profile = active->pacard.profile));
281     pa_assert_se((node_profile = node->pacard.profile));
282
283     block = !pa_streq(active_profile, node_profile);
284
285     return block;
286 }
287
288 static mir_constr_def *cstrdef_create(struct userdata     *u,
289                                       const char          *name,
290                                       mir_constrain_func_t func,
291                                       const char          *key)
292 {
293     mir_constr_def *cd;
294
295     pa_assert(u);
296     pa_assert(name);
297     pa_assert(func);
298     pa_assert(key);
299
300     cd = pa_xnew0(mir_constr_def, 1);
301     cd->key  = pa_xstrdup(key);
302     cd->name = pa_xstrdup(name);
303     cd->func = func;
304     MIR_DLIST_INIT(cd->nodes);
305
306     return cd;
307 }
308
309 static void cstrdef_destroy(struct userdata *u, mir_constr_def *cd)
310 {
311     mir_constr_link *cl, *n;
312
313     pa_assert(u);
314     pa_assert(cd);
315
316     MIR_DLIST_FOR_EACH_SAFE(mir_constr_link, link, cl,n, &cd->nodes) {
317         cstrlink_destroy(u, cl);
318     }
319
320     pa_xfree(cd->name);
321     pa_xfree(cd);
322 }
323
324
325 static mir_constr_link *cstrlink_create(struct userdata *u,
326                                         mir_constr_def  *cd,
327                                         mir_node        *node)
328 {
329     mir_constr_link *cl;
330
331     pa_assert(u);
332     pa_assert(cd);
333     pa_assert(node);
334
335     cl = pa_xnew0(mir_constr_link, 1);
336     cl->def  = cd;
337     cl->node = node;
338     MIR_DLIST_INIT(cl->link);
339     MIR_DLIST_INIT(cl->nodchain);
340
341     return cl;
342 }
343
344 static void cstrlink_destroy(struct userdata *u, mir_constr_link *cl)
345 {
346     pa_assert(u);
347     pa_assert(cl);
348
349     MIR_DLIST_UNLINK(mir_constr_link, link, cl);
350     MIR_DLIST_UNLINK(mir_constr_link, nodchain, cl);
351
352     pa_xfree(cl);
353 }
354
355
356 /*
357  * Local Variables:
358  * c-basic-offset: 4
359  * indent-tabs-mode: nil
360  * End:
361  *
362  */