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