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