config: fixup type for demo effect
[staging/agl-audio-plugin.git] / router.c
1 /*
2  * module-agl-audio -- PulseAudio module for providing audio routing support
3  * (forked from "module-murphy-ivi" - https://github.com/otcshare )
4  * Copyright (c) 2012, Intel Corporation.
5  * Copyright (c) 2016, IoT.bzh
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU Lesser General Public License,
9  * version 2.1, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
19  * MA 02110-1301 USA.
20  *
21  */
22 #include "router.h"
23 #include "switch.h"
24 #include "zone.h"
25 #include "utils.h"
26
27 agl_router *agl_router_init (struct userdata *u)
28 {
29         agl_router *router;
30         size_t num_classes;
31
32         num_classes = agl_application_class_end;
33
34         router = pa_xnew0 (agl_router, 1);
35         router->rtgroups.input = pa_hashmap_new (pa_idxset_string_hash_func,
36                                                  pa_idxset_string_compare_func);
37         router->rtgroups.output = pa_hashmap_new (pa_idxset_string_hash_func,
38                                                   pa_idxset_string_compare_func);
39         router->maplen = num_classes;
40         router->priormap = pa_xnew0 (int, num_classes);
41
42         AGL_DLIST_INIT (router->nodlist);
43         AGL_DLIST_INIT (router->connlist);
44
45         return router;
46 }
47
48 void agl_router_done (struct userdata *u)
49 {
50         agl_router *router;
51         agl_node *e,*n;
52         agl_connection *conn, *c;
53         agl_rtgroup *rtg;
54         agl_rtgroup **map;
55         int i;
56
57         if (u && (router = u->router)) {
58                 AGL_DLIST_FOR_EACH_SAFE(agl_node, rtprilist, e,n, &router->nodlist)
59                         AGL_DLIST_UNLINK(agl_node, rtprilist, e);
60                 AGL_DLIST_FOR_EACH_SAFE(agl_connection, link, conn,c, &router->connlist) {
61                         AGL_DLIST_UNLINK(agl_connection, link, conn);
62                         pa_xfree (conn);
63                 }
64                 /*
65                 PA_HASHMAP_FOREACH(rtg, router->rtgroups.input, state) {
66                         rtgroup_destroy(u, rtg);
67                 }
68                 PA_HASHMAP_FOREACH(rtg, router->rtgroups.output, state) {
69                         rtgroup_destroy(u, rtg);
70                 }*/
71                 pa_hashmap_free (router->rtgroups.input);
72                 pa_hashmap_free (router->rtgroups.output);
73
74                 for (i = 0;  i < AGL_ZONE_MAX;  i++) {
75                         if ((map = router->classmap.input[i]))
76                                 pa_xfree(map);
77                         if ((map = router->classmap.output[i]))
78                                 pa_xfree(map);
79                 }
80
81                 pa_xfree (router->priormap);
82                 pa_xfree (router);
83
84                 u->router = NULL;
85         }
86 }
87
88 bool agl_router_default_accept (struct userdata *u, agl_rtgroup *rtg, agl_node *node)
89 {
90         /* TODO */
91         return true;
92 }
93
94 bool agl_router_phone_accept (struct userdata *u, agl_rtgroup *rtg, agl_node *node)
95 {
96         /* TODO */
97         return true;
98 }
99
100 int agl_router_default_effect (struct userdata *u, agl_rtgroup *rtg, agl_node *node, bool new)
101 {
102         /* TODO */
103         return 1;
104 }
105
106 int agl_router_phone_effect (struct userdata *u, agl_rtgroup *rtg, agl_node *node, bool new)
107 {
108         pa_assert (u);
109         pa_assert (node);
110
111         if (new)
112                 agl_utils_volume_ramp (u, node->nullsink, false);
113         else
114                 agl_utils_volume_ramp (u, node->nullsink, true);
115
116         return 1;
117 }
118
119 agl_rtgroup *agl_router_create_rtgroup (struct userdata *u, agl_direction type, const char *name, const char *node_desc, agl_rtgroup_accept_t accept, agl_rtgroup_effect_t effect)
120 {
121         agl_router *router;
122         agl_rtgroup *rtg;
123         agl_nodeset *nodeset;
124         agl_node *node;
125         pa_hashmap *table;
126
127         pa_assert (u);
128         pa_assert (type == agl_input || type == agl_output);
129         pa_assert (name);
130         pa_assert_se (router = u->router);
131         pa_assert_se (nodeset = u->nodeset);
132
133         if (type == agl_input)
134                 table = router->rtgroups.input;
135         else
136                 table = router->rtgroups.output;
137         pa_assert (table);
138
139         rtg = pa_xnew0 (agl_rtgroup, 1);
140         rtg->name = pa_xstrdup (name);
141         rtg->accept = accept;
142         rtg->effect = effect;
143         AGL_DLIST_INIT(rtg->entries);
144         /* associate an agl_output node for an agl_input routing group */
145         if (type == agl_input) {
146                 node = agl_node_create (u, NULL);
147                 node->direction = agl_output;
148                 node->implement = agl_device;
149                 node->visible = true;
150                 node->available = true;
151                 node->paname = pa_xstrdup (node_desc);
152                  /* add to global nodeset */
153                 pa_idxset_put (nodeset->nodes, node, &node->index);
154                 rtg->node = node;
155         } else {
156                 rtg->node = NULL;
157         }
158         
159
160         pa_hashmap_put (table, rtg->name, rtg);
161
162         pa_log_debug ("routing group '%s' created", name);
163
164         return rtg;
165 }
166
167 void agl_router_destroy_rtgroup (struct userdata *u, agl_direction type, const char *name)
168 {
169         agl_router *router;
170         agl_rtgroup *rtg;
171         pa_hashmap *table;
172
173         pa_assert (u);
174         pa_assert (name);
175         pa_assert_se (router = u->router);
176
177         if (type == agl_input)
178                 table = router->rtgroups.input;
179         else
180                 table = router->rtgroups.output;
181         pa_assert (table);
182
183         rtg = pa_hashmap_remove (table, name);
184         if (!rtg) {
185                 pa_log_debug ("can't destroy routing group '%s': not found", name);
186         } else {
187                 //rtgroup_destroy (u, rtg);
188                 pa_log_debug ("routing group '%s' destroyed", name);
189         }
190 }
191
192 bool agl_router_assign_class_to_rtgroup (struct userdata *u, agl_node_type class, uint32_t zone, agl_direction type, const char *name)
193 {
194         agl_router *router;
195         pa_hashmap *rtable;
196         agl_rtgroup ***classmap;
197         agl_rtgroup **zonemap;
198         const char *classname;
199         const char *direction;
200         agl_rtgroup *rtg;
201         agl_zone *rzone;
202
203         pa_assert (u);
204         pa_assert (zone < AGL_ZONE_MAX);
205         pa_assert (type == agl_input || type == agl_output);
206         pa_assert (name);
207         pa_assert_se (router = u->router);
208
209         if (type == agl_input) {
210                 rtable = router->rtgroups.input;
211                 classmap = router->classmap.input;
212         } else {
213                 rtable = router->rtgroups.output;
214                 classmap = router->classmap.output;
215         }
216
217         if (class < 0 || class >= router->maplen) {
218                 pa_log_debug ("Cannot assign class to routing group '%s': "
219                               "id %d out of range (0 - %d)",
220                               name, class, router->maplen);
221                 return false;
222         }
223
224         classname = agl_node_type_str (class); /* "Player", "Radio"... */
225         direction = agl_node_direction_str (type); /* "input", "output" */
226
227         rtg = pa_hashmap_get (rtable, name);
228         if (!rtg) {
229                 pa_log_debug ("Cannot assign class to routing group '%s': "
230                               "router group not found", name);
231                 return false;
232         }
233
234         zonemap = classmap[zone];
235         if (!zonemap) {
236                 zonemap = pa_xnew0 (agl_rtgroup *, router->maplen);
237                 classmap[zone] = zonemap;
238         }
239
240         zonemap[class] = rtg;
241
242          /* try to get zone name for logging, if fails, only print id number */
243         rzone = agl_zoneset_get_zone_by_index (u, zone);
244         if (rzone) {
245                 pa_log_debug ("class '%s'@'%s' assigned to routing group '%s'",
246                               classname, rzone->name, name); 
247         } else {
248                 pa_log_debug ("class '%s'@zone%d assigned to routing group '%s'",
249                               classname, zone, name);
250         }
251
252         return true;
253 }
254
255 agl_rtgroup * agl_router_get_rtgroup_from_class (struct userdata *u, agl_node_type class, uint32_t zone, agl_direction type)
256 {
257         agl_router *router;
258         pa_hashmap *rtable;
259         agl_rtgroup ***classmap;
260         agl_rtgroup **zonemap;
261         agl_rtgroup * rtg;
262
263         pa_assert (u);
264         pa_assert_se (router = u->router);
265         pa_assert (class >= 0 && class < router->maplen);
266         pa_assert (zone < AGL_ZONE_MAX);
267         pa_assert (type == agl_input || type == agl_output);
268
269         if (type == agl_input) {
270                 rtable = router->rtgroups.input;
271                 classmap = router->classmap.input;
272         } else {
273                 rtable = router->rtgroups.output;
274                 classmap = router->classmap.output;
275         }
276
277         zonemap = classmap[zone];
278         rtg = zonemap[class];
279
280         return rtg;
281 }
282
283 void agl_router_assign_class_priority (struct userdata *u, agl_node_type class, int priority)
284 {
285         agl_router *router;
286         int *priormap;
287
288         pa_assert (u);
289         pa_assert_se (router = u->router);
290         pa_assert_se (priormap = router->priormap);
291
292         if (class > 0 && class < router->maplen) {
293                 pa_log_debug ("assigning priority %d to class '%s'",
294                               priority, agl_node_type_str (class));
295                 priormap[class] = priority;
296         }
297 }
298
299 int agl_router_get_node_priority (struct userdata *u, agl_node *node)
300 {
301         agl_router *router;
302         int class;
303
304         pa_assert (u);
305         pa_assert (node);
306         pa_assert_se (router = u->router);
307
308         class = node->type;
309
310         if (class < 0 || class >= (int)router->maplen)
311                 return 0;
312
313         return router->priormap[class];
314 }
315
316 bool agl_router_apply_node_priority_effect (struct userdata *u, agl_node *node, bool new)
317 {
318         agl_router *router;
319         agl_rtgroup *rtg;
320         agl_nodeset *nodeset;
321         agl_node *n;
322         pa_sink *sink;
323         int priority;
324         uint32_t index;
325
326         pa_assert (u);
327         pa_assert (node);
328         pa_assert_se (router = u->router);
329         pa_assert_se (nodeset = u->nodeset);
330
331         rtg = agl_router_get_rtgroup_from_class(u, node->type, 0, node->direction);
332
333         /* now let us compare priorities, and apply effect if needed */
334         /* "new" case */
335         if (new) {
336                 priority = agl_router_get_node_priority (u, node);
337                 PA_IDXSET_FOREACH(n, nodeset->nodes, index) {
338                         if (n->nullsink && (priority > agl_router_get_node_priority (u, n))) {
339                                 sink = agl_utils_get_null_sink (u, n->nullsink);
340                                 if (sink) {
341                                         /* do we have a custom effect ? otherwise, just mute it */
342                                         if (rtg && rtg->effect)
343                                                 rtg->effect (u, rtg, n, new);
344                                         else
345                                                 pa_sink_set_mute (sink, new, false);
346                                 }
347                         }
348                 }
349         } else {
350         /* "old" case */
351                 if (!agl_node_has_highest_priority (u, node))
352                         return true;
353                 PA_IDXSET_FOREACH(n, nodeset->nodes, index) {
354                         if (n->nullsink) {
355                                 sink = agl_utils_get_null_sink (u, n->nullsink);
356                                 if (sink) {
357                                         /* do we have a custom effect ? otherwise, just unmute it */
358                                         if (rtg && rtg->effect)
359                                                 rtg->effect (u, rtg, n, new);
360                                         else
361                                                 pa_sink_set_mute (sink, new, false);
362                                 }
363                         }
364                 }
365         }
366
367         return true;
368 }
369
370 void agl_router_register_node (struct userdata *u, agl_node *node)
371 {
372         agl_router *router;
373         agl_rtgroup *rtg;
374
375         pa_assert (u);
376         pa_assert (node);
377         pa_assert_se (router = u->router);
378
379         /* we try to discover node routing group from the configuration, "Phone" for instance,
380          * see defaults in "config.c. Otherwise we just say NULL, a.k.a. default */
381         rtg = agl_router_get_rtgroup_from_class(u, node->type, 0, node->direction);
382
383         if (node->direction == agl_input) {
384                 if (rtg)
385                         implement_default_route (u, node, rtg->node, agl_utils_new_stamp ());
386                 else
387                         implement_default_route (u, node, NULL, agl_utils_new_stamp ());
388         } else {
389                 if (rtg)
390                         implement_default_route (u, rtg->node, node, agl_utils_new_stamp ());
391                 else
392                         implement_default_route (u, NULL, node, agl_utils_new_stamp ());
393         }
394 }
395
396 void agl_router_unregister_node (struct userdata *u, agl_node *node)
397 {
398         pa_assert (u);
399         pa_assert (node);
400
401         remove_routes (u, node, NULL, agl_utils_new_stamp ());
402 }
403
404 agl_node *agl_router_make_prerouting (struct userdata *u, agl_node *data)
405 {
406         agl_router *router;
407         int priority;
408         static bool done_prerouting;
409         uint32_t stamp;
410         agl_node *start, *end;
411         agl_node *target;
412
413         pa_assert (u);
414         pa_assert_se (router = u->router);
415         pa_assert_se (data->implement == agl_stream);
416
417         //priority = node_priority (u, data);
418
419         done_prerouting = false;
420         target = NULL;
421         stamp = agl_utils_new_stamp ();
422
423         //make_explicit_routes (u, stamp);
424
425         //pa_audiomgr_delete_default_routes(u);
426
427         AGL_DLIST_FOR_EACH_BACKWARDS(agl_node, rtprilist, start, &router->nodlist) {
428                 //if ((start->implement == agl_device) &&
429                 //    (!start->loop))   /* only manage looped real devices */
430                 //      continue;
431
432                 /*if (priority >= node_priority (u, start)) {
433                         target = find_default_route (u, data, stamp);
434                         if (target)
435                                 implement_preroute (u, data, target, stamp);
436                         else
437                                 done_prerouting = true;
438                 }*/
439
440                 if (start->stamp >= stamp)
441                         continue;
442
443                 //end = find_default_route (u, start, stamp);
444                 //if (end)
445                 //      implement_default_route(u, start, end, stamp);
446         }
447
448         if (!done_prerouting) {
449                 pa_log_debug ("Prerouting failed, trying to find default route as last resort");
450
451                 //target = find_default_route (u, data, stamp);
452                 //if (target)
453                 //      implement_preroute (u, data, target, stamp);
454         }
455
456         return target;
457 }
458
459 void agl_router_make_routing (struct userdata *u)
460 {
461         agl_router *router;
462         static bool ongoing_routing;    /* true while we are actively routing */
463         uint32_t stamp;
464         agl_node *start, *end;
465
466         pa_assert (u);
467         pa_assert_se (router = u->router);
468
469         if (ongoing_routing)            /* already routing, canceling */
470                 return;
471         ongoing_routing = true;
472         stamp = agl_utils_new_stamp ();
473
474         pa_log_debug("stamp for routing: %d", stamp);
475
476         // make_explicit_routes (u, stamp);
477
478         // pa_audiomgr_delete_default_routes (u);
479
480         AGL_DLIST_FOR_EACH_BACKWARDS(agl_node, rtprilist, start, &router->nodlist) {
481                 //if ((start->implement == agl_device) &&
482                 //   (!start->loop))    /* only manage looped real devices */
483                 //      continue;
484
485                 if (start->stamp >= stamp)
486                         continue;
487
488                 end = find_default_route (u, start, stamp);
489                 if (end)
490                         implement_default_route (u, start, end, stamp);
491         }
492
493         // pa_audiomgr_send_default_routes (u);
494
495         ongoing_routing = false;
496 }
497
498 void implement_default_route (struct userdata *u,
499                               agl_node *start, agl_node *end,
500                               uint32_t stamp)
501 {
502         if (start->direction == agl_input)
503                 agl_switch_setup_link (u, start, end, false);
504         else
505                 agl_switch_setup_link (u, end, start, false);
506 }
507
508 agl_node *find_default_route (struct userdata *u, agl_node *start, uint32_t stamp)
509 {
510         /* TODO */
511
512         return NULL;
513 }
514
515 void remove_routes (struct userdata *u, agl_node *start, agl_node *end, uint32_t stamp)
516 {
517         if (start->direction == agl_input) {
518                 agl_switch_teardown_link (u, start, end);
519         } else {
520                 agl_switch_teardown_link (u, end, start);
521         }
522 }