0e13dde95539889384e64472a3ad099b233548d2
[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     router->classmap.output[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     pa_assert_se((data->direction == mir_input));
440
441     priority = node_priority(u, data);
442     done = FALSE;
443     target = NULL;
444     stamp = pa_utils_new_stamp();
445
446     make_explicit_routes(u, stamp);
447
448     MIR_DLIST_FOR_EACH_BACKWARD(mir_node, rtentries, start, &router->nodlist) {
449         if (start->implement == mir_device) {
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         }
455
456         if (priority >= node_priority(u, start)) {
457             if ((target = find_default_route(u, data, stamp)))
458                 implement_preroute(u, data, target, stamp);
459             done = TRUE;
460         }
461
462         if (start->stamp >= stamp)
463             continue;
464
465         if ((end = find_default_route(u, start, stamp)))
466             implement_default_route(u, start, end, stamp);
467     }    
468
469     if (!done && (target = find_default_route(u, data, stamp)))
470         implement_preroute(u, data, target, stamp);
471
472     return target;
473 }
474
475
476 void mir_router_make_routing(struct userdata *u)
477 {
478     static pa_bool_t ongoing_routing;
479
480     pa_router  *router;
481     mir_node   *start;
482     mir_node   *end;
483     uint32_t    stamp;
484
485     pa_assert(u);
486     pa_assert_se((router = u->router));
487
488     if (ongoing_routing)
489         return;
490
491     ongoing_routing = TRUE;
492     stamp = pa_utils_new_stamp();
493
494     make_explicit_routes(u, stamp);
495
496     MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, start, &router->nodlist) {
497         if (start->implement == mir_device) {
498             if (start->direction == mir_output)
499                 continue;       /* we should never get here */
500             if (!start->mux && !start->loop)
501                 continue;       /* skip not looped back input nodes */
502         }
503
504         if (start->stamp >= stamp)
505             continue;
506
507         if ((end = find_default_route(u, start, stamp)))
508             implement_default_route(u, start, end, stamp);
509     }    
510
511     pa_fader_apply_volume_limits(u, stamp);
512
513     ongoing_routing = FALSE;
514 }
515
516
517
518 pa_bool_t mir_router_default_accept(struct userdata *u, mir_rtgroup *rtg,
519                                     mir_node *node)
520 {
521     pa_bool_t accept;
522
523     pa_assert(u);
524     pa_assert(rtg);
525     pa_assert(node);
526
527     if (node->type == mir_bluetooth_carkit)
528         accept = FALSE;
529     else
530         accept = (node->type >= mir_device_class_begin &&
531                   node->type < mir_device_class_end);
532         
533     return accept;
534 }
535
536
537 pa_bool_t mir_router_phone_accept(struct userdata *u, mir_rtgroup *rtg,
538                                   mir_node *node)
539 {
540     mir_node_type class;
541
542     pa_assert(u);
543     pa_assert(rtg);
544     pa_assert(node);
545
546     class = node->type;
547
548     if (class >= mir_device_class_begin &&  class < mir_device_class_end) {
549         if (class != mir_bluetooth_a2dp   &&
550             class != mir_usb_headphone    &&
551             class != mir_wired_headphone  &&
552             class != mir_jack             &&
553             class != mir_hdmi             &&
554             class != mir_spdif            &&
555             class != mir_bluetooth_carkit   )
556         {
557             return TRUE;
558         }
559     }
560
561     return FALSE;
562 }
563
564
565 int mir_router_default_compare(struct userdata *u, mir_node *n1, mir_node *n2)
566 {
567     uint32_t p1, p2;
568
569     (void)u;
570
571     pa_assert(n1);
572     pa_assert(n2);
573
574     if (n1->type == mir_null)
575         return -1;
576     if (n2->type == mir_null)
577         return 1;
578
579     p1 = ((((n1->channels & 31) << 5) + n1->privacy) << 2) + n1->location;
580     p2 = ((((n2->channels & 31) << 5) + n2->privacy) << 2) + n2->location;
581
582     p1 = (p1 << 8) + ((n1->type - mir_device_class_begin) & 0xff);
583     p2 = (p2 << 8) + ((n2->type - mir_device_class_begin) & 0xff);
584
585     return uint32_cmp(p1,p2);
586 }
587
588
589 int mir_router_phone_compare(struct userdata *u, mir_node *n1, mir_node *n2)
590 {
591     uint32_t p1, p2;
592
593     (void)u;
594
595     pa_assert(n1);
596     pa_assert(n2);
597
598     if (n1->type == mir_null)
599         return -1;
600     if (n2->type == mir_null)
601         return 1;
602
603     p1 = (n1->privacy << 8) + ((n1->type - mir_device_class_begin) & 0xff);
604     p2 = (n2->privacy << 8) + ((n2->type - mir_device_class_begin) & 0xff);
605
606     return uint32_cmp(p1,p2);
607 }
608
609
610 static void rtgroup_destroy(struct userdata *u, mir_rtgroup *rtg)
611 {
612     mir_rtentry *rte, *n;
613
614     pa_assert(u);
615     pa_assert(rtg);
616
617     MIR_DLIST_FOR_EACH_SAFE(mir_rtentry, link, rte,n, &rtg->entries) {
618         remove_rtentry(u, rte);
619     }
620
621     pa_xfree(rtg->name);
622     pa_xfree(rtg);
623 }
624
625 static int rtgroup_print(mir_rtgroup *rtg, char *buf, int len)
626 {
627     mir_rtentry *rte;
628     mir_node *node;
629     char *p, *e;
630
631     e = (p = buf) + len;
632
633     MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
634         node = rte->node;
635         if (p >= e)
636             break;
637         p += snprintf(p, e-p, " '%s'", node->amname);
638     }
639
640     return p - buf;
641 }
642
643 static void rtgroup_update_module_property(struct userdata *u,
644                                            mir_direction    type,
645                                            mir_rtgroup     *rtg)
646 {
647     pa_module *module;
648     char       key[64];
649     char       value[512];
650
651     pa_assert(u);
652     pa_assert(rtg);
653     pa_assert_se((module = u->module));
654
655     snprintf(key, sizeof(key), PA_PROP_ROUTING_TABLE ".%s.%s",
656              mir_direction_str(type), rtg->name);
657     rtgroup_print(rtg, value, sizeof(value));
658
659     pa_proplist_sets(module->proplist, key, value+1); /* skip ' '@beginning */
660 }
661
662 static void add_rtentry(struct userdata *u,
663                         mir_direction    type,
664                         mir_rtgroup     *rtg,
665                         mir_node        *node)
666 {
667     pa_router *router;
668     mir_rtentry *rte, *before;
669
670     pa_assert(u);
671     pa_assert(rtg);
672     pa_assert(node);
673     pa_assert_se((router = u->router));
674
675     if (!rtg->accept(u, rtg, node)) {
676         pa_log_debug("refuse node '%s' registration to routing group '%s'",
677                      node->amname, rtg->name);
678         return;
679     }
680
681     rte = pa_xnew0(mir_rtentry, 1);
682
683     MIR_DLIST_APPEND(mir_rtentry, nodchain, rte, &node->rtentries);
684     rte->group = rtg;
685     rte->node  = node;
686
687     MIR_DLIST_FOR_EACH(mir_rtentry, link, before, &rtg->entries) {
688         if (rtg->compare(u, node, before->node) < 0) {
689             MIR_DLIST_INSERT_BEFORE(mir_rtentry, link, rte, &before->link);
690             goto added;
691         }
692     }
693
694     MIR_DLIST_APPEND(mir_rtentry, link, rte, &rtg->entries);
695
696  added:
697     rtgroup_update_module_property(u, type, rtg);
698     pa_log_debug("node '%s' added to routing group '%s'",
699                  node->amname, rtg->name);
700 }
701
702 static void remove_rtentry(struct userdata *u, mir_rtentry *rte)
703 {
704     pa_assert(u);
705     pa_assert(rte);
706
707     MIR_DLIST_UNLINK(mir_rtentry, link, rte);
708     MIR_DLIST_UNLINK(mir_rtentry, nodchain, rte);
709
710     pa_xfree(rte);
711 }
712
713 static void make_explicit_routes(struct userdata *u, uint32_t stamp)
714 {
715     pa_router *router;
716     mir_connection *conn;
717     mir_node *from;
718     mir_node *to;
719
720     pa_assert(u);
721     pa_assert_se((router = u->router));
722
723     MIR_DLIST_FOR_EACH_BACKWARD(mir_connection,link, conn, &router->connlist) {
724         if (conn->blocked)
725             continue;
726         
727         if (!(from = mir_node_find_by_index(u, conn->from)) ||
728             !(to   = mir_node_find_by_index(u, conn->to))     )
729         {
730             pa_log_debug("ignoring explicit route %u: some of the nodes "
731                          "not found", conn->amid);
732             continue;
733         }
734
735         if (!mir_switch_setup_link(u, from, to, TRUE))
736             continue;
737
738         if (from->implement == mir_stream)
739             from->stamp = stamp;
740
741         if (to->implement == mir_device)
742             mir_volume_add_limiting_class(u, to, from->type, stamp);
743     }
744 }
745
746
747 static mir_node *find_default_route(struct userdata *u,
748                                     mir_node        *start,
749                                     uint32_t         stamp)
750 {
751     pa_router     *router = u->router;
752     mir_node_type  class  = pa_classify_guess_application_class(start);
753     mir_rtgroup  **classmap;
754     mir_node      *end;
755     mir_rtgroup   *rtg;
756     mir_rtentry   *rte;
757
758     if (class < 0 || class > router->maplen) {
759         pa_log_debug("can't route '%s': class %d is out of range (0 - %d)",
760                      start->amname, class, router->maplen);
761         return NULL;
762     }
763     
764     switch (start->direction) {
765     case mir_input:     classmap = router->classmap.output;     break;
766     case mir_output:    classmap = router->classmap.input;      break;
767     default:            classmap = NULL;                        break;
768     }
769
770     if (!classmap || !(rtg = classmap[class])) {
771         pa_log_debug("node '%s' won't be routed beacuse its class '%s' "
772                      "is not assigned to any router group",
773                      start->amname, mir_node_type_str(class));
774         return NULL;
775     }
776     
777     pa_log_debug("using '%s' router group when routing '%s'",
778                  rtg->name, start->amname);
779
780         
781     MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
782         if (!(end = rte->node)) {
783             pa_log("   node was null in mir_rtentry");
784             continue;
785         }
786         
787         if (end->ignore) {
788             pa_log_debug("   '%s' ignored. Skipping...",end->amname);
789             continue;
790         }
791
792         if (!end->available) {
793             pa_log_debug("   '%s' not available. Skipping...", end->amname);
794             continue;
795         }
796
797         if (end->paidx == PA_IDXSET_INVALID && !end->paport) {
798             /* requires profile change. We do it only for BT headsets */
799             if (end->type != mir_bluetooth_a2dp &&
800                 end->type != mir_bluetooth_sco    )
801             {
802                 pa_log_debug("   '%s' has no sink. Skipping...", end->amname);
803                 continue;
804             }
805         }
806
807         if (rte->stamp < stamp)
808             mir_constrain_apply(u, end, stamp);
809         else {
810             if (rte->blocked) {
811                 pa_log_debug("   '%s' is blocked by constraints. Skipping...",
812                              end->amname);
813                 continue;
814             }
815         }
816         
817         pa_log_debug("routing '%s' => '%s'", start->amname, end->amname);
818
819         return end;
820     }
821     
822     pa_log_debug("could not find route for '%s'", start->amname);
823
824     return NULL;
825 }
826
827 static void implement_preroute(struct userdata *u,
828                                mir_node        *data,
829                                mir_node        *target,
830                                uint32_t         stamp)
831 {
832     if (data->direction == mir_output)
833         mir_switch_setup_link(u, target, NULL, FALSE);
834     else {
835         mir_switch_setup_link(u, NULL, target, FALSE);
836         mir_volume_add_limiting_class(u, target, data->type, stamp);
837     }
838 }
839
840 static void implement_default_route(struct userdata *u,
841                                     mir_node        *start,
842                                     mir_node        *end,
843                                     uint32_t         stamp)
844 {
845     if (start->direction == mir_output)
846         mir_switch_setup_link(u, end, start, FALSE);
847     else {
848         mir_switch_setup_link(u, start, end, FALSE);
849         mir_volume_add_limiting_class(u, end, start->type, stamp);
850     }
851 }
852
853
854 static int uint32_cmp(uint32_t v1, uint32_t v2)
855 {
856     if (v1 > v2)
857         return 1;
858     if (v1 < v2)
859         return -1;
860     return 0;
861 }
862
863
864 static int node_priority(struct userdata *u, mir_node *node)
865 {
866     pa_router *router;
867     mir_node_type type;
868     int class;
869
870     pa_assert(u);
871     pa_assert(node);
872     pa_assert_se((router = u->router));
873     pa_assert(router->priormap);
874
875     class = pa_classify_guess_application_class(node);
876
877     if (class < 0 || class >= router->maplen)
878         return 0;
879
880     return router->priormap[class];
881 }
882
883 static int print_routing_table(pa_hashmap  *table,
884                                const char  *type,
885                                char        *buf,
886                                int          len)
887 {
888     mir_rtgroup *rtg;
889     void *state;
890     char *p, *e;
891     int n;
892
893     pa_assert(table);
894     pa_assert(type);
895     pa_assert(buf);
896
897     e = (p = buf) + len;
898     n = 0;
899
900     if (len > 0) {
901         p += snprintf(p, e-p, "%s routing table:\n", type);
902
903         if (p < e) {
904             PA_HASHMAP_FOREACH(rtg, table, state) {
905                 n++;
906
907                 if (p >= e) break;
908                 p += snprintf(p, e-p, "   %s:", rtg->name);
909                 
910                 if (p >= e) break;
911                 p += rtgroup_print(rtg, p, e-p);
912                 
913                 if (p >= e) break;
914                 p += snprintf(p, e-p, "\n");
915             }
916
917             if (!n && p < e)
918                 p += snprintf(p, e-p, "   <empty>\n");
919         }
920     }
921
922     return p - buf;
923 }
924
925
926 /*
927  * Local Variables:
928  * c-basic-offset: 4
929  * indent-tabs-mode: nil
930  * End:
931  *
932  */