finer granularity of amname generation + audio manager registration filtering
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / router.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/module.h>
29
30 #include "router.h"
31 #include "zone.h"
32 #include "node.h"
33 #include "switch.h"
34 #include "constrain.h"
35 #include "volume.h"
36 #include "fader.h"
37 #include "utils.h"
38 #include "classify.h"
39 #include "audiomgr.h"
40
41 static void rtgroup_destroy(struct userdata *, mir_rtgroup *);
42 static int rtgroup_print(mir_rtgroup *, char *, int);
43 static void rtgroup_update_module_property(struct userdata *, mir_direction,
44                                            mir_rtgroup *);
45
46 static void add_rtentry(struct userdata *, mir_direction, mir_rtgroup *,
47                         mir_node *);
48 static void remove_rtentry(struct userdata *, mir_rtentry *);
49
50 static void make_explicit_routes(struct userdata *, uint32_t);
51 static mir_node *find_default_route(struct userdata *, mir_node *, uint32_t);
52 static void implement_preroute(struct userdata *, mir_node *, mir_node *,
53                                uint32_t);
54 static void implement_default_route(struct userdata *, mir_node *, mir_node *,
55                                     uint32_t);
56
57 static int uint32_cmp(uint32_t, uint32_t);
58
59 static int node_priority(struct userdata *, mir_node *);
60
61 static int volume_class(mir_node *);
62
63 static int print_routing_table(pa_hashmap *, const char *, char *, int);
64
65
66 static void pa_hashmap_rtgroup_free(void *rtg, void *u)
67 {
68     rtgroup_destroy(u, rtg);
69 }
70
71
72 pa_router *pa_router_init(struct userdata *u)
73 {
74     size_t num_classes = mir_application_class_end;
75     pa_router *router = pa_xnew0(pa_router, 1);
76     
77     router->rtgroups.input  = pa_hashmap_new(pa_idxset_string_hash_func,
78                                             pa_idxset_string_compare_func);
79     router->rtgroups.output = pa_hashmap_new(pa_idxset_string_hash_func,
80                                              pa_idxset_string_compare_func);
81
82     router->maplen = num_classes;
83
84     router->priormap = pa_xnew0(int, num_classes);
85
86     MIR_DLIST_INIT(router->nodlist);
87     MIR_DLIST_INIT(router->connlist);
88     
89     return router;
90 }
91
92 void pa_router_done(struct userdata *u)
93 {
94     pa_router      *router;
95     mir_connection *conn, *c;
96     mir_node       *e,*n;
97     void           *state;
98     mir_rtgroup    *rtg;
99     mir_rtgroup   **map;
100     int             i;
101
102     if (u && (router = u->router)) {
103         MIR_DLIST_FOR_EACH_SAFE(mir_node, rtprilist, e,n, &router->nodlist) {
104             MIR_DLIST_UNLINK(mir_node, rtprilist, e);
105         }
106
107         MIR_DLIST_FOR_EACH_SAFE(mir_connection,link, conn,c,&router->connlist){
108             MIR_DLIST_UNLINK(mir_connection, link, conn);
109             pa_xfree(conn);
110         }
111
112         PA_HASHMAP_FOREACH(rtg, router->rtgroups.input, state) {
113             rtgroup_destroy(u, rtg);
114         }
115
116         PA_HASHMAP_FOREACH(rtg, router->rtgroups.output, state) {
117             rtgroup_destroy(u, rtg);
118         }
119
120         pa_hashmap_free(router->rtgroups.input);
121         pa_hashmap_free(router->rtgroups.output);
122
123         for (i = 0;  i < MRP_ZONE_MAX;  i++) {
124             if ((map = router->classmap.input[i]))
125                 pa_xfree(map);
126
127             if ((map = router->classmap.output[i]))
128                 pa_xfree(map);
129         }
130
131         pa_xfree(router->priormap);
132         pa_xfree(router);
133
134         u->router = NULL;
135     }
136 }
137
138
139 void mir_router_assign_class_priority(struct userdata *u,
140                                       mir_node_type    class,
141                                       int              pri)
142 {
143     pa_router *router;
144     int *priormap;
145
146     pa_assert(u);
147     pa_assert_se((router = u->router));
148     pa_assert_se((priormap = router->priormap));
149
150     if (class >= 0 && class < router->maplen) {
151         pa_log_debug("assigning priority %d to class '%s'",
152                      pri, mir_node_type_str(class));
153         priormap[class] = pri;
154     }
155 }
156
157
158 mir_rtgroup *mir_router_create_rtgroup(struct userdata      *u,
159                                        mir_direction         type,
160                                        const char           *name,
161                                        mir_rtgroup_accept_t  accept,
162                                        mir_rtgroup_compare_t compare)
163 {
164     pa_router   *router;
165     pa_hashmap  *table;
166     mir_rtgroup *rtg;
167
168     pa_assert(u);
169     pa_assert(type == mir_input || type == mir_output);
170     pa_assert(name);
171     pa_assert(accept);
172     pa_assert(compare);
173     pa_assert_se((router = u->router));
174
175     if (type == mir_input)
176         table = router->rtgroups.input;
177     else
178         table = router->rtgroups.output;
179
180     pa_assert(table);
181
182     rtg = pa_xnew0(mir_rtgroup, 1);
183     rtg->name    = pa_xstrdup(name);
184     rtg->accept  = accept;
185     rtg->compare = compare;
186     MIR_DLIST_INIT(rtg->entries);
187
188     if (pa_hashmap_put(table, rtg->name, rtg) < 0) {
189         pa_xfree(rtg->name);
190         pa_xfree(rtg);
191         return NULL;
192     }
193
194     pa_log_debug("%s routing group '%s' created",
195                  mir_direction_str(type), name);
196
197     return rtg;
198 }
199
200 void mir_router_destroy_rtgroup(struct userdata *u,
201                                 mir_direction    type,
202                                 const char      *name)
203 {
204     pa_router   *router;
205     pa_hashmap  *table;
206     mir_rtgroup *rtg;
207
208     pa_assert(u);
209     pa_assert(name);
210     pa_assert_se((router = u->router));
211
212     if (type == mir_input)
213         table = router->rtgroups.input;
214     else
215         table = router->rtgroups.output;
216
217     pa_assert(table);
218
219     if (!(rtg = pa_hashmap_remove(table, name))) {
220         pa_log_debug("can't destroy %s routing group '%s': group not found",
221                      mir_direction_str(type), name);
222     }
223     else {
224         rtgroup_destroy(u, rtg);
225         pa_log_debug("routing group '%s' destroyed", name);
226     }
227 }
228
229
230 bool mir_router_assign_class_to_rtgroup(struct userdata *u,
231                                              mir_node_type    class,
232                                              uint32_t         zone,
233                                              mir_direction    type,
234                                              const char      *rtgrpnam)
235 {
236     pa_router *router;
237     pa_hashmap *rtable;
238     mir_rtgroup ***classmap;
239     mir_rtgroup **zonemap;
240     mir_rtgroup *rtg;
241     const char *clnam;
242     const char *direction;
243     mir_zone *z;
244
245     pa_assert(u);
246     pa_assert(zone < MRP_ZONE_MAX);
247     pa_assert(type == mir_input || type == mir_output);
248     pa_assert(rtgrpnam);
249     pa_assert_se((router = u->router));
250
251     if (type == mir_input) {
252         rtable   = router->rtgroups.input;
253         classmap = router->classmap.input;
254     }
255     else {
256         rtable   = router->rtgroups.output;
257         classmap = router->classmap.output;
258     }
259
260     if (class < 0 || class >= router->maplen) {
261         pa_log_debug("can't assign class (%d) to  routing group '%s': "
262                      "class id is out of range (0 - %d)",
263                      class, rtgrpnam, router->maplen);
264         return false;
265     }
266
267     clnam = mir_node_type_str(class);
268     direction = mir_direction_str(type);
269
270     if (!(rtg = pa_hashmap_get(rtable, rtgrpnam))) {
271         pa_log_debug("can't assign class '%s' to %s routing group '%s': "
272                      "router group not found", clnam, direction, rtgrpnam);
273     }
274
275     if (!(zonemap = classmap[zone])) {
276         zonemap = pa_xnew0(mir_rtgroup *, router->maplen);
277         classmap[zone] = zonemap;
278     }
279
280     zonemap[class] = rtg;
281
282     if ((z = pa_zoneset_get_zone_by_index(u, zone))) {
283         pa_log_debug("class '%s'@'%s' assigned to %s routing group '%s'",
284                      clnam, z->name, direction, rtgrpnam);
285     }
286     else {
287         pa_log_debug("class '%s'@zone%u assigned to %s routing group '%s'",
288                      clnam, zone, direction, rtgrpnam);
289     }
290
291     return true;
292 }
293
294
295
296 void mir_router_register_node(struct userdata *u, mir_node *node)
297 {
298     pa_router   *router;
299     mir_rtgroup *rtg;
300     void        *state;
301     int          priority;
302     mir_node    *before;
303
304     pa_assert(u);
305     pa_assert(node);
306     pa_assert_se((router = u->router));
307     
308     if (node->direction == mir_output) {
309         if (node->implement == mir_device) {
310             PA_HASHMAP_FOREACH(rtg, router->rtgroups.output, state) {
311                 add_rtentry(u, mir_output, rtg, node);
312             }
313         }
314         return;
315     }
316
317     
318     if (node->direction == mir_input) {
319 #if 0
320         if (node->implement == mir_device) &&
321             !pa_classify_loopback_stream(node))
322             return;
323 #endif
324
325         if (node->implement == mir_device) {
326             PA_HASHMAP_FOREACH(rtg, router->rtgroups.input, state) {
327                 add_rtentry(u, mir_input, rtg, node);
328             }
329
330             if (!pa_classify_loopback_stream(node))
331                 return;
332         }
333
334         priority = node_priority(u, node);
335             
336         MIR_DLIST_FOR_EACH(mir_node, rtprilist, before, &router->nodlist) {
337             if (priority < node_priority(u, before)) {
338                 MIR_DLIST_INSERT_BEFORE(mir_node, rtprilist, node,
339                                         &before->rtprilist);
340                 return;
341             }
342         }
343             
344         MIR_DLIST_APPEND(mir_node, rtprilist, node, &router->nodlist);
345
346         return;
347     }
348 }
349
350 void mir_router_unregister_node(struct userdata *u, mir_node *node)
351 {
352     pa_router *router;
353     mir_rtentry *rte, *n;
354     
355     pa_assert(u);
356     pa_assert(node);
357     pa_assert_se((router = u->router));
358
359     MIR_DLIST_FOR_EACH_SAFE(mir_rtentry,nodchain, rte,n, &node->rtentries) {
360         remove_rtentry(u, rte);
361     }
362
363     MIR_DLIST_UNLINK(mir_node, rtprilist, node);
364 }
365
366 mir_connection *mir_router_add_explicit_route(struct userdata *u,
367                                               uint16_t   amid,
368                                               mir_node  *from,
369                                               mir_node  *to)
370 {
371     pa_router *router;
372     mir_connection *conn;
373
374     pa_assert(u);
375     pa_assert(from);
376     pa_assert(to);
377     pa_assert_se((router = u->router));
378
379     conn = pa_xnew0(mir_connection, 1);
380     MIR_DLIST_INIT(conn->link);
381     conn->amid = amid;
382     conn->from = from->index;
383     conn->to = to->index;
384     
385     MIR_DLIST_APPEND(mir_connection, link, conn, &router->connlist);
386
387     mir_router_make_routing(u);
388
389     return conn;
390 }
391
392 void mir_router_remove_explicit_route(struct userdata *u, mir_connection *conn)
393 {
394     pa_core   *core;
395     pa_router *router;
396     mir_node  *from;
397     mir_node  *to;
398
399     pa_assert(u);
400     pa_assert(conn);
401     pa_assert_se((core = u->core));
402     pa_assert_se((router = u->router));
403
404     MIR_DLIST_UNLINK(mir_connection, link, conn);
405
406     if (!(from = mir_node_find_by_index(u, conn->from)) ||
407         !(to   = mir_node_find_by_index(u, conn->to))     )
408     {
409         pa_log_debug("can't remove explicit route: some node was not found");
410     }
411     else {
412         pa_log_debug("tear down link '%s' => '%s'", from->amname, to->amname);
413
414         if (!mir_switch_teardown_link(u, from, to)) {
415             pa_log_debug("can't remove explicit route: "
416                          "failed to teardown link");
417         }
418         else {
419             if (!conn->blocked)
420                 mir_router_make_routing(u);
421         }
422     }
423
424     pa_xfree(conn);
425 }
426
427
428 int mir_router_print_rtgroups(struct userdata *u, char *buf, int len)
429 {
430     pa_router *router;
431     char *p, *e;
432
433     pa_assert(u);
434     pa_assert(buf);
435     pa_assert(len > 0);
436     pa_assert_se((router = u->router));
437     pa_assert(router->rtgroups.input);
438     pa_assert(router->rtgroups.output);
439
440     e = (p = buf) + len;
441
442     if (p < e)
443         p += print_routing_table(router->rtgroups.input, "input", p, e-p);
444
445     if (p < e)
446         p += print_routing_table(router->rtgroups.output, "output", p, e-p);
447
448     return p - buf;
449 }
450
451
452 mir_node *mir_router_make_prerouting(struct userdata *u, mir_node *data)
453 {
454     pa_router     *router;
455     mir_node      *start;
456     mir_node      *end;
457     int            priority;
458     bool      done;
459     mir_node      *target;
460     uint32_t       stamp;
461
462     pa_assert(u);
463     pa_assert_se((router = u->router));
464     pa_assert_se((data->implement == mir_stream));
465
466     priority = node_priority(u, data);
467     done = false;
468     target = NULL;
469     stamp = pa_utils_new_stamp();
470
471     make_explicit_routes(u, stamp);
472
473     pa_audiomgr_delete_default_routes(u);
474
475     MIR_DLIST_FOR_EACH_BACKWARD(mir_node, rtprilist, start, &router->nodlist) {
476         if (start->implement == mir_device) {
477 #if 0
478             if (start->direction == mir_output)
479                 continue;       /* we should never get here */
480             if (!start->mux && !start->loop)
481                 continue;       /* skip not looped back input nodes */
482 #endif
483             if (!start->loop)
484                 continue;       /* only looped back devices routed here */
485         }
486
487         if (priority >= node_priority(u, start)) {
488             if ((target = find_default_route(u, data, stamp)))
489                 implement_preroute(u, data, target, stamp);
490             done = true;
491         }
492
493         if (start->stamp >= stamp)
494             continue;
495
496         if ((end = find_default_route(u, start, stamp)))
497             implement_default_route(u, start, end, stamp);
498     }    
499
500     if (!done && (target = find_default_route(u, data, stamp)))
501         implement_preroute(u, data, target, stamp);
502
503     return target;
504 }
505
506
507 void mir_router_make_routing(struct userdata *u)
508 {
509     static bool ongoing_routing;
510
511     pa_router  *router;
512     mir_node   *start;
513     mir_node   *end;
514     uint32_t    stamp;
515
516     pa_assert(u);
517     pa_assert_se((router = u->router));
518
519     if (ongoing_routing)
520         return;
521
522     ongoing_routing = true;
523     stamp = pa_utils_new_stamp();
524
525     make_explicit_routes(u, stamp);
526
527     pa_audiomgr_delete_default_routes(u);
528
529     MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtprilist, start, &router->nodlist) {
530         if (start->implement == mir_device) {
531 #if 0
532             if (start->direction == mir_output)
533                 continue;       /* we should never get here */
534             if (!start->mux && !start->loop)
535                 continue;       /* skip not looped back input nodes */
536 #endif
537             if (!start->loop)
538                 continue;       /* only looped back devices routed here */
539         }
540
541         if (start->stamp >= stamp)
542             continue;
543
544         if ((end = find_default_route(u, start, stamp)))
545             implement_default_route(u, start, end, stamp);
546     }    
547
548     pa_audiomgr_send_default_routes(u);
549
550     pa_fader_apply_volume_limits(u, stamp);
551
552     ongoing_routing = false;
553 }
554
555
556
557 bool mir_router_default_accept(struct userdata *u, mir_rtgroup *rtg,
558                                     mir_node *node)
559 {
560     pa_core *core;
561     pa_sink *sink;
562     pa_source *source;
563     pa_proplist *pl;
564     mir_node_type class;
565     bool accept;
566     const char *role, *excluded_role;
567
568     pa_assert(u);
569     pa_assert(rtg);
570     pa_assert(node);
571
572     class = node->type;
573
574     if (class == mir_bluetooth_carkit)
575         accept = false;
576     else if (class == mir_jack || class == mir_hdmi) {
577         pa_assert_se((core = u->core));
578             
579         if (node->direction == mir_input) {
580             source = pa_idxset_get_by_index(core->sources,node->paidx);
581             pl = source ? source->proplist : NULL;
582             excluded_role = "hfp_uplink";
583         }
584         else {
585             sink = pa_idxset_get_by_index(core->sinks, node->paidx);
586             pl = sink ? sink->proplist : NULL;
587             excluded_role = "hfp_downlink";
588         }
589         role = pl ? pa_proplist_gets(pl, PA_PROP_NODE_ROLE) : NULL;
590         accept = role ? strcmp(role, excluded_role) : true;
591     }
592     else {
593         accept = (class >= mir_device_class_begin &&
594                   class < mir_device_class_end);
595     }
596         
597     return accept;
598 }
599
600
601 bool mir_router_phone_accept(struct userdata *u, mir_rtgroup *rtg,
602                                   mir_node *node)
603 {
604     pa_core *core;
605     pa_sink *sink;
606     pa_source *source;
607     pa_proplist *pl;
608     mir_node_type class;
609     const char *role, *expected_role;
610
611     pa_assert(u);
612     pa_assert(rtg);
613     pa_assert(node);
614
615     class = node->type;
616
617     if (class >= mir_device_class_begin &&  class < mir_device_class_end) {
618         if (class != mir_bluetooth_a2dp   &&
619             class != mir_spdif            &&
620             class != mir_jack             &&
621             class != mir_bluetooth_source &&
622             class != mir_bluetooth_sink   &&
623             class != mir_bluetooth_carkit   )
624         {
625             return true;
626         }
627     }
628
629     return false;
630 }
631
632
633 int mir_router_default_compare(struct userdata *u, mir_rtgroup *rtg,
634                                mir_node *n1, mir_node *n2)
635 {
636     uint32_t p1, p2;
637
638     (void)u;
639     (void)rtg;
640
641     pa_assert(n1);
642     pa_assert(n2);
643
644     if (n1->type == mir_null)
645         return -1;
646     if (n2->type == mir_null)
647         return 1;
648
649     p1 = ((((n1->channels & 31) << 5) + n1->privacy) << 2) + n1->location;
650     p2 = ((((n2->channels & 31) << 5) + n2->privacy) << 2) + n2->location;
651
652     p1 = (p1 << 8) + ((n1->type - mir_device_class_begin) & 0xff);
653     p2 = (p2 << 8) + ((n2->type - mir_device_class_begin) & 0xff);
654
655     return uint32_cmp(p1,p2);
656 }
657
658
659 int mir_router_phone_compare(struct userdata *u, mir_rtgroup *rtg,
660                              mir_node *n1, mir_node *n2)
661 {
662     uint32_t p1, p2;
663
664     (void)u;
665     (void)rtg;
666
667     pa_assert(n1);
668     pa_assert(n2);
669
670     if (n1->type == mir_null)
671         return -1;
672     if (n2->type == mir_null)
673         return 1;
674
675     p1 = (n1->privacy << 8) + ((n1->type - mir_device_class_begin) & 0xff);
676     p2 = (n2->privacy << 8) + ((n2->type - mir_device_class_begin) & 0xff);
677
678     return uint32_cmp(p1,p2);
679 }
680
681
682 static void rtgroup_destroy(struct userdata *u, mir_rtgroup *rtg)
683 {
684     mir_rtentry *rte, *n;
685
686     pa_assert(u);
687     pa_assert(rtg);
688
689     MIR_DLIST_FOR_EACH_SAFE(mir_rtentry, link, rte,n, &rtg->entries) {
690         remove_rtentry(u, rte);
691     }
692
693     pa_xfree(rtg->name);
694     pa_xfree(rtg);
695 }
696
697 static int rtgroup_print(mir_rtgroup *rtg, char *buf, int len)
698 {
699     mir_rtentry *rte;
700     mir_node *node;
701     char *p, *e;
702
703     e = (p = buf) + len;
704
705     *buf = 0;
706
707     MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
708         node = rte->node;
709         if (p >= e)
710             break;
711         p += snprintf(p, e-p, " '%s'", node->amname);
712     }
713
714     return p - buf;
715 }
716
717 static void rtgroup_update_module_property(struct userdata *u,
718                                            mir_direction    type,
719                                            mir_rtgroup     *rtg)
720 {
721     pa_module *module;
722     char       key[64];
723     char       value[512];
724     int        ret;
725
726     pa_assert(u);
727     pa_assert(rtg);
728     pa_assert(rtg->name);
729     pa_assert_se((module = u->module));
730
731     snprintf(key, sizeof(key), PA_PROP_ROUTING_TABLE ".%s.%s",
732              mir_direction_str(type), rtg->name);
733     ret = rtgroup_print(rtg, value, sizeof(value));
734
735     if (!ret)
736         value[1] = 0;
737     
738     pa_proplist_sets(module->proplist, key, value+1); /* skip ' '@beginning */
739 }
740
741 static void add_rtentry(struct userdata *u,
742                         mir_direction    type,
743                         mir_rtgroup     *rtg,
744                         mir_node        *node)
745 {
746     pa_router *router;
747     mir_rtentry *rte, *before;
748
749     pa_assert(u);
750     pa_assert(rtg);
751     pa_assert(node);
752     pa_assert_se((router = u->router));
753
754     if (!rtg->accept(u, rtg, node)) {
755         pa_log_debug("refuse node '%s' registration to routing group '%s'",
756                      node->amname, rtg->name);
757         return;
758     }
759
760     rte = pa_xnew0(mir_rtentry, 1);
761
762     MIR_DLIST_APPEND(mir_rtentry, nodchain, rte, &node->rtentries);
763     rte->group = rtg;
764     rte->node  = node;
765
766     MIR_DLIST_FOR_EACH(mir_rtentry, link, before, &rtg->entries) {
767         if (rtg->compare(u, rtg, node, before->node) < 0) {
768             MIR_DLIST_INSERT_BEFORE(mir_rtentry, link, rte, &before->link);
769             goto added;
770         }
771     }
772
773     MIR_DLIST_APPEND(mir_rtentry, link, rte, &rtg->entries);
774
775  added:
776     rtgroup_update_module_property(u, type, rtg);
777     pa_log_debug("node '%s' added to routing group '%s'",
778                  node->amname, rtg->name);
779 }
780
781 static void remove_rtentry(struct userdata *u, mir_rtentry *rte)
782 {
783     mir_rtgroup *rtg;
784     mir_node    *node;
785
786     pa_assert(u);
787     pa_assert(rte);
788     pa_assert_se((rtg = rte->group));
789     pa_assert_se((node = rte->node));
790
791     MIR_DLIST_UNLINK(mir_rtentry, link, rte);
792     MIR_DLIST_UNLINK(mir_rtentry, nodchain, rte);
793
794     pa_xfree(rte);
795
796     rtgroup_update_module_property(u, node->direction, rtg);
797 }
798
799 static void make_explicit_routes(struct userdata *u, uint32_t stamp)
800 {
801     pa_router *router;
802     mir_connection *conn;
803     mir_node *from;
804     mir_node *to;
805
806     pa_assert(u);
807     pa_assert_se((router = u->router));
808
809     MIR_DLIST_FOR_EACH_BACKWARD(mir_connection,link, conn, &router->connlist) {
810         if (conn->blocked)
811             continue;
812         
813         if (!(from = mir_node_find_by_index(u, conn->from)) ||
814             !(to   = mir_node_find_by_index(u, conn->to))     )
815         {
816             pa_log_debug("ignoring explicit route %u: some of the nodes "
817                          "not found", conn->amid);
818             continue;
819         }
820
821         if (!mir_switch_setup_link(u, from, to, true))
822             continue;
823
824         if (from->implement == mir_stream)
825             from->stamp = stamp;
826
827         if (to->implement == mir_device)
828             mir_volume_add_limiting_class(u, to, volume_class(from), stamp);
829     }
830 }
831
832
833 static mir_node *find_default_route(struct userdata *u,
834                                     mir_node        *start,
835                                     uint32_t         stamp)
836 {
837     pa_router     *router = u->router;
838     mir_node_type  class  = pa_classify_guess_application_class(start);
839     mir_zone      *zone   = pa_zoneset_get_zone_by_name(u, start->zone);
840     mir_rtgroup ***cmap;
841     mir_rtgroup  **zmap;
842     mir_node      *end;
843     mir_rtgroup   *rtg;
844     mir_rtentry   *rte;
845
846     if (class < 0 || class > router->maplen) {
847         pa_log_debug("can't route '%s': class %d is out of range (0 - %d)",
848                      start->amname, class, router->maplen);
849         return NULL;
850     }
851
852     if (!zone) {
853         pa_log_debug("can't route '%s': zone '%s' is unknown",
854                      start->amname, start->zone);
855         return NULL;
856     }
857     
858     switch (start->direction) {
859     case mir_input:     cmap = router->classmap.output;     break;
860     case mir_output:    cmap = router->classmap.input;      break;
861     default:            cmap = NULL;                        break;
862     }
863
864     if (!cmap || !(zmap = cmap[zone->index]) || !(rtg = zmap[class])) {
865         pa_log_debug("node '%s' won't be routed beacuse its class '%s' "
866                      "is not assigned to any router group",
867                      start->amname, mir_node_type_str(class));
868         return NULL;
869     }
870     
871     pa_log_debug("using '%s' router group when routing '%s'",
872                  rtg->name, start->amname);
873
874         
875     MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
876         if (!(end = rte->node)) {
877             pa_log("   node was null in mir_rtentry");
878             continue;
879         }
880         
881         if (end->ignore) {
882             pa_log_debug("   '%s' ignored. Skipping...",end->amname);
883             continue;
884         }
885
886         if (!end->available) {
887             pa_log_debug("   '%s' not available. Skipping...", end->amname);
888             continue;
889         }
890
891         if (end->paidx == PA_IDXSET_INVALID && !end->paport) {
892             /* requires profile change. We do it only for BT headsets */
893             if (end->type != mir_bluetooth_a2dp &&
894                 end->type != mir_bluetooth_sco    )
895             {
896                 pa_log_debug("   '%s' has no sink. Skipping...", end->amname);
897                 continue;
898             }
899         }
900
901         if (rte->stamp < stamp)
902             mir_constrain_apply(u, end, stamp);
903         else {
904             if (rte->blocked) {
905                 pa_log_debug("   '%s' is blocked by constraints. Skipping...",
906                              end->amname);
907                 continue;
908             }
909         }
910         
911         pa_log_debug("routing '%s' => '%s'", start->amname, end->amname);
912
913         pa_audiomgr_add_default_route(u, start, end);
914         
915         return end;
916     }
917     
918     pa_log_debug("could not find route for '%s'", start->amname);
919
920     return NULL;
921 }
922
923 static void implement_preroute(struct userdata *u,
924                                mir_node        *data,
925                                mir_node        *target,
926                                uint32_t         stamp)
927 {
928     if (data->direction == mir_output)
929         mir_switch_setup_link(u, target, NULL, false);
930     else {
931         mir_switch_setup_link(u, NULL, target, false);
932         mir_volume_add_limiting_class(u, target, data->type, stamp);
933     }
934 }
935
936 static void implement_default_route(struct userdata *u,
937                                     mir_node        *start,
938                                     mir_node        *end,
939                                     uint32_t         stamp)
940 {
941     if (start->direction == mir_output)
942         mir_switch_setup_link(u, end, start, false);
943     else {
944         mir_switch_setup_link(u, start, end, false);
945         mir_volume_add_limiting_class(u, end, volume_class(start), stamp);
946     }
947 }
948
949
950 static int uint32_cmp(uint32_t v1, uint32_t v2)
951 {
952     if (v1 > v2)
953         return 1;
954     if (v1 < v2)
955         return -1;
956     return 0;
957 }
958
959 static int node_priority(struct userdata *u, mir_node *node)
960 {
961     pa_router *router;
962     int class;
963
964     pa_assert(u);
965     pa_assert(node);
966     pa_assert_se((router = u->router));
967     pa_assert(router->priormap);
968
969     class = pa_classify_guess_application_class(node);
970
971     if (class < 0 || class >= router->maplen)
972         return 0;
973
974     return router->priormap[class];
975 }
976
977 static int volume_class(mir_node *node)
978 {
979     int device_class[mir_device_class_end - mir_device_class_begin] = {
980         [ mir_bluetooth_carkit - mir_device_class_begin ] = mir_phone,
981         [ mir_bluetooth_source - mir_device_class_begin ] = mir_player,
982     };
983
984     int t;
985
986     pa_assert(node);
987
988     t = node->type;
989
990     if (t >= mir_application_class_begin && t < mir_application_class_end)
991         return t;
992
993     if (t >= mir_device_class_begin && t < mir_device_class_end)
994         return device_class[t - mir_device_class_begin];
995
996     return mir_node_type_unknown;
997 }
998
999
1000 static int print_routing_table(pa_hashmap  *table,
1001                                const char  *type,
1002                                char        *buf,
1003                                int          len)
1004 {
1005     mir_rtgroup *rtg;
1006     void *state;
1007     char *p, *e;
1008     int n;
1009
1010     pa_assert(table);
1011     pa_assert(type);
1012     pa_assert(buf);
1013
1014     e = (p = buf) + len;
1015     n = 0;
1016
1017     if (len > 0) {
1018         p += snprintf(p, e-p, "%s routing table:\n", type);
1019
1020         state = NULL;
1021
1022         if (p < e) {
1023             PA_HASHMAP_FOREACH(rtg, table, state) {
1024                 n++;
1025
1026                 if (p >= e) break;
1027                 p += snprintf(p, e-p, "   %s:", rtg->name);
1028                 
1029                 if (p >= e) break;
1030                 p += rtgroup_print(rtg, p, e-p);
1031                 
1032                 if (p >= e) break;
1033                 p += snprintf(p, e-p, "\n");
1034             }
1035
1036             if (!n && p < e)
1037                 p += snprintf(p, e-p, "   <empty>\n");
1038         }
1039     }
1040
1041     return p - buf;
1042 }
1043
1044
1045 /*
1046  * Local Variables:
1047  * c-basic-offset: 4
1048  * indent-tabs-mode: nil
1049  * End:
1050  *
1051  */