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