6 #include <pulsecore/pulsecore-config.h>
8 #include <pulse/proplist.h>
9 #include <pulsecore/module.h>
16 static void rtgroup_destroy(struct userdata *, mir_rtgroup *);
17 static int rtgroup_print(mir_rtgroup *, char *, int);
18 static void rtgroup_update_module_property(struct userdata *, mir_rtgroup *);
20 static void add_rtentry(struct userdata *, mir_rtgroup *, mir_node *);
21 static void remove_rtentry(struct userdata *, mir_rtentry *);
23 static void make_explicit_routes(struct userdata *, uint32_t);
24 static mir_node *find_default_route(struct userdata *, mir_node *);
27 static int uint32_cmp(uint32_t, uint32_t);
29 static int node_priority(struct userdata *, mir_node *);
32 static void pa_hashmap_rtgroup_free(void *rtg, void *u)
34 rtgroup_destroy(u, rtg);
38 pa_router *pa_router_init(struct userdata *u)
40 size_t num_classes = mir_application_class_end;
41 pa_router *router = pa_xnew0(pa_router, 1);
43 router->rtgroups = pa_hashmap_new(pa_idxset_string_hash_func,
44 pa_idxset_string_compare_func);
45 router->maplen = num_classes;
46 router->classmap = pa_xnew0(mir_rtgroup *, num_classes);
47 router->priormap = pa_xnew0(int, num_classes);
48 MIR_DLIST_INIT(router->nodlist);
49 MIR_DLIST_INIT(router->connlist);
54 void pa_router_done(struct userdata *u)
57 mir_connection *conn, *c;
60 if (u && (router = u->router)) {
61 MIR_DLIST_FOR_EACH_SAFE(mir_node, rtentries, e,n, &router->nodlist) {
62 MIR_DLIST_UNLINK(mir_node, rtentries, e);
65 MIR_DLIST_FOR_EACH_SAFE(mir_connection,link, conn,c,&router->connlist){
66 MIR_DLIST_UNLINK(mir_connection, link, conn);
70 pa_hashmap_free(router->rtgroups, pa_hashmap_rtgroup_free,u);
72 pa_xfree(router->classmap);
73 pa_xfree(router->priormap);
81 pa_bool_t mir_router_create_rtgroup(struct userdata *u,
83 mir_rtgroup_accept_t accept,
84 mir_rtgroup_compare_t compare)
93 pa_assert_se((router = u->router));
95 rtg = pa_xnew0(mir_rtgroup, 1);
96 rtg->name = pa_xstrdup(name);
98 rtg->compare = compare;
99 MIR_DLIST_INIT(rtg->entries);
101 if (pa_hashmap_put(router->rtgroups, rtg->name, rtg) < 0) {
107 pa_log_debug("routing group '%s' created", name);
112 void mir_router_destroy_rtgroup(struct userdata *u, const char *name)
119 pa_assert_se((router = u->router));
121 if (!(rtg = pa_hashmap_remove(router->rtgroups, name)))
122 pa_log_debug("can't destroy routing group '%s': group not found",name);
124 rtgroup_destroy(u, rtg);
125 pa_log_debug("routing group '%s' destroyed", name);
130 pa_bool_t mir_router_assign_class_to_rtgroup(struct userdata *u,
132 const char *rtgrpnam)
140 pa_assert_se((router = u->router));
142 if (class < 0 || class >= router->maplen) {
143 pa_log_debug("can't assign class (%d) to routing group '%s': "
144 "class id is out of range (0 - %d)",
145 class, rtgrpnam, router->maplen);
149 clnam = mir_node_type_str(class);
151 if (!(rtg = pa_hashmap_get(router->rtgroups, rtgrpnam))) {
152 pa_log_debug("can't assign class '%s' to routing group '%s': "
153 "router group not found", clnam, rtgrpnam);
156 router->classmap[class] = rtg;
158 pa_log_debug("class '%s' assigned to routing group '%s'", clnam, rtgrpnam);
164 void mir_router_register_node(struct userdata *u, mir_node *node)
174 pa_assert_se((router = u->router));
176 if (node->implement == mir_device) {
177 if (node->direction == mir_output) {
178 PA_HASHMAP_FOREACH(rtg, router->rtgroups, state) {
179 add_rtentry(u, rtg, node);
185 if (node->implement == mir_stream) {
186 if (node->direction == mir_input) {
187 priority = node_priority(u, node);
189 MIR_DLIST_FOR_EACH(mir_node, rtentries, before, &router->nodlist) {
190 if (priority < node_priority(u, before)) {
191 MIR_DLIST_INSERT_BEFORE(mir_node, rtentries, node,
197 MIR_DLIST_APPEND(mir_node, rtentries, node, &router->nodlist);
203 void mir_router_unregister_node(struct userdata *u, mir_node *node)
206 mir_rtentry *rte, *n;
210 pa_assert_se((router = u->router));
212 if (node->implement == mir_device && node->direction == mir_output) {
213 MIR_DLIST_FOR_EACH_SAFE(mir_rtentry,nodchain, rte,n, &node->rtentries){
214 remove_rtentry(u, rte);
219 if (node->implement == mir_stream && node->direction == mir_input) {
220 MIR_DLIST_UNLINK(mir_node, rtentries, node);
225 mir_connection *mir_router_add_explicit_route(struct userdata *u,
231 mir_connection *conn;
236 pa_assert_se((router = u->router));
238 conn = pa_xnew0(mir_connection, 1);
239 MIR_DLIST_INIT(conn->link);
241 conn->from = from->index;
242 conn->to = to->index;
244 MIR_DLIST_APPEND(mir_connection, link, conn, &router->connlist);
246 mir_router_make_routing(u);
251 void mir_router_remove_explicit_route(struct userdata *u, mir_connection *conn)
260 pa_assert_se((core = u->core));
261 pa_assert_se((router = u->router));
263 MIR_DLIST_UNLINK(mir_connection, link, conn);
265 if (!(from = mir_node_find_by_index(u, conn->from)) ||
266 !(to = mir_node_find_by_index(u, conn->to)) )
268 pa_log_debug("can't remove explicit route: some node was not found");
271 pa_log_debug("tear down link '%s' => '%s'", from->amname, to->amname);
273 if (!mir_switch_teardown_link(u, from, to)) {
274 pa_log_debug("can't remove explicit route: "
275 "failed to teardown link");
279 mir_router_make_routing(u);
286 int mir_router_print_rtgroups(struct userdata *u, char *buf, int len)
296 pa_assert_se((router = u->router));
297 pa_assert(router->rtgroups);
302 p += snprintf(p, e-p, "routing table:\n");
305 PA_HASHMAP_FOREACH(rtg, router->rtgroups, state) {
307 p += snprintf(p, e-p, " %s:", rtg->name);
310 p += rtgroup_print(rtg, p, e-p);
313 p += snprintf(p, e-p, "\n");
322 mir_node *mir_router_make_prerouting(struct userdata *u, mir_node *data)
333 pa_assert_se((router = u->router));
334 pa_assert_se((data->implement == mir_stream));
335 pa_assert_se((data->direction == mir_input));
337 priority = node_priority(u, data);
340 stamp = pa_utils_new_stamp();
342 make_explicit_routes(u, stamp);
344 MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, from, &router->nodlist) {
345 if (priority >= node_priority(u, from)) {
346 if ((target = find_default_route(u, data)))
347 mir_switch_setup_link(u, NULL, target, FALSE);
351 if (from->stamp >= stamp)
354 if ((to = find_default_route(u, from)))
355 mir_switch_setup_link(u, from, to, FALSE);
358 if (!done && (target = find_default_route(u, data)))
359 mir_switch_setup_link(u, NULL, target, FALSE);
365 void mir_router_make_routing(struct userdata *u)
367 static pa_bool_t ongoing_routing;
375 pa_assert_se((router = u->router));
380 ongoing_routing = TRUE;
381 stamp = pa_utils_new_stamp();
383 make_explicit_routes(u, stamp);
385 MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, from, &router->nodlist) {
386 if (from->stamp >= stamp)
389 if ((to = find_default_route(u, from)))
390 mir_switch_setup_link(u, from, to, FALSE);
393 ongoing_routing = FALSE;
398 pa_bool_t mir_router_default_accept(struct userdata *u, mir_rtgroup *rtg,
407 accept = (node->type >= mir_device_class_begin &&
408 node->type < mir_device_class_end);
414 pa_bool_t mir_router_phone_accept(struct userdata *u, mir_rtgroup *rtg,
425 if (class >= mir_device_class_begin && class < mir_device_class_end) {
426 if (class != mir_bluetooth_a2dp &&
427 class != mir_usb_headphone &&
428 class != mir_wired_headphone &&
440 int mir_router_default_compare(struct userdata *u, mir_node *n1, mir_node *n2)
449 if (n1->type == mir_null)
451 if (n2->type == mir_null)
454 p1 = ((((n1->channels & 31) << 5) + n1->privacy) << 2) + n1->location;
455 p2 = ((((n2->channels & 31) << 5) + n2->privacy) << 2) + n2->location;
457 p1 = (p1 << 8) + ((n1->type - mir_device_class_begin) & 0xff);
458 p2 = (p2 << 8) + ((n2->type - mir_device_class_begin) & 0xff);
460 return uint32_cmp(p1,p2);
464 int mir_router_phone_compare(struct userdata *u, mir_node *n1, mir_node *n2)
473 if (n1->type == mir_null)
475 if (n2->type == mir_null)
478 p1 = (n1->privacy << 8) + ((n1->type - mir_device_class_begin) & 0xff);
479 p2 = (n2->privacy << 8) + ((n2->type - mir_device_class_begin) & 0xff);
481 return uint32_cmp(p1,p2);
485 static void rtgroup_destroy(struct userdata *u, mir_rtgroup *rtg)
487 mir_rtentry *rte, *n;
492 MIR_DLIST_FOR_EACH_SAFE(mir_rtentry, link, rte,n, &rtg->entries) {
493 remove_rtentry(u, rte);
500 static int rtgroup_print(mir_rtgroup *rtg, char *buf, int len)
508 MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
512 p += snprintf(p, e-p, " '%s'", node->amname);
518 static void rtgroup_update_module_property(struct userdata *u,mir_rtgroup *rtg)
526 pa_assert_se((module = u->module));
528 snprintf(key, sizeof(key), PA_PROP_ROUTING_TABLE ".%s", rtg->name);
529 rtgroup_print(rtg, value, sizeof(value));
531 pa_proplist_sets(module->proplist, key, value+1); /* skip ' '@beginning */
534 static void add_rtentry(struct userdata *u, mir_rtgroup *rtg, mir_node *node)
537 mir_rtentry *rte, *before;
542 pa_assert_se((router = u->router));
544 if (!rtg->accept(u, rtg, node)) {
545 pa_log_debug("refuse node '%s' registration to routing group '%s'",
546 node->amname, rtg->name);
550 rte = pa_xnew0(mir_rtentry, 1);
552 MIR_DLIST_APPEND(mir_rtentry, nodchain, rte, &node->rtentries);
555 MIR_DLIST_FOR_EACH(mir_rtentry, link, before, &rtg->entries) {
556 if (rtg->compare(u, node, before->node) < 0) {
557 MIR_DLIST_INSERT_BEFORE(mir_rtentry, link, rte, &before->link);
562 MIR_DLIST_APPEND(mir_rtentry, link, rte, &rtg->entries);
565 rtgroup_update_module_property(u, rtg);
566 pa_log_debug("node '%s' added to routing group '%s'",
567 node->amname, rtg->name);
570 static void remove_rtentry(struct userdata *u, mir_rtentry *rte)
575 MIR_DLIST_UNLINK(mir_rtentry, link, rte);
576 MIR_DLIST_UNLINK(mir_rtentry, nodchain, rte);
581 static void make_explicit_routes(struct userdata *u, uint32_t stamp)
584 mir_connection *conn;
589 pa_assert_se((router = u->router));
591 MIR_DLIST_FOR_EACH_BACKWARD(mir_connection,link, conn, &router->connlist) {
595 if (!(from = mir_node_find_by_index(u, conn->from)) ||
596 !(to = mir_node_find_by_index(u, conn->to)) )
598 pa_log_debug("ignoring explicit route %u: some of the nodes "
599 "not found", conn->amid);
603 if (!mir_switch_setup_link(u, from, to, TRUE))
606 if (from->implement == mir_stream)
612 static mir_node *find_default_route(struct userdata *u, mir_node *from)
614 pa_router *router = u->router;
615 mir_node_type class = from->type;
621 if (class < 0 || class > router->maplen) {
622 pa_log_debug("can't route '%s': class %d is out of range (0 - %d)",
623 from->amname, class, router->maplen);
627 if (!(rtg = router->classmap[class])) {
628 pa_log_debug("node '%s' won't be routed beacuse its class '%s' "
629 "is not assigned to any router group",
630 from->amname, mir_node_type_str(class));
634 pa_log_debug("using '%s' router group when routing '%s'",
635 rtg->name, from->amname);
638 MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
639 if (!(to = rte->node)) {
640 pa_log(" node was null in mir_rtentry");
645 pa_log_debug(" '%s' ignored. Skipping...",to->amname);
649 if (!to->available) {
650 pa_log_debug(" '%s' not available. Skipping...", to->amname);
654 if (to->paidx == PA_IDXSET_INVALID) {
655 if (to->type != mir_bluetooth_a2dp &&
656 to->type != mir_bluetooth_sco)
658 pa_log_debug(" '%s' has no to. Skipping...", to->amname);
663 pa_log_debug("routing '%s' => '%s'", from->amname, to->amname);
668 pa_log_debug("could not find route for '%s'", from->amname);
675 static int uint32_cmp(uint32_t v1, uint32_t v2)
685 static int node_priority(struct userdata *u, mir_node *node)
692 pa_assert_se((router = u->router));
693 pa_assert(router->priormap);
697 if (type < 0 || type >= router->maplen)
700 return router->priormap[type];
707 * indent-tabs-mode: nil