6 #include <pulsecore/pulsecore-config.h>
13 static void rtgroup_destroy(struct userdata *, mir_rtgroup *);
14 static int rtgroup_print(mir_rtgroup *, char *, int);
16 static void add_rtentry(struct userdata *, mir_rtgroup *, mir_node *);
17 static void remove_rtentry(struct userdata *, mir_rtentry *);
19 static mir_node *route_stream(struct userdata *, mir_node *);
22 static int uint32_cmp(uint32_t, uint32_t);
24 static int node_priority(struct userdata *, mir_node *);
27 static void pa_hashmap_rtgroup_free(void *rtg, void *u)
29 rtgroup_destroy(u, rtg);
33 pa_router *pa_router_init(struct userdata *u)
35 size_t num_classes = mir_application_class_end;
36 pa_router *router = pa_xnew0(pa_router, 1);
38 router->rtgroups = pa_hashmap_new(pa_idxset_string_hash_func,
39 pa_idxset_string_compare_func);
40 router->maplen = num_classes;
41 router->classmap = pa_xnew0(mir_rtgroup *, num_classes);
42 router->priormap = pa_xnew0(int, num_classes);
43 MIR_DLIST_INIT(router->nodlist);
48 void pa_router_done(struct userdata *u)
53 if (u && (router = u->router)) {
54 MIR_DLIST_FOR_EACH_SAFE(mir_node, rtentries, e,n, &router->nodlist) {
55 MIR_DLIST_UNLINK(mir_node, rtentries, e);
58 pa_hashmap_free(router->rtgroups, pa_hashmap_rtgroup_free,u);
60 pa_xfree(router->classmap);
61 pa_xfree(router->priormap);
69 pa_bool_t mir_router_create_rtgroup(struct userdata *u,
71 mir_rtgroup_accept_t accept,
72 mir_rtgroup_compare_t compare)
81 pa_assert_se((router = u->router));
83 rtg = pa_xnew0(mir_rtgroup, 1);
84 rtg->name = pa_xstrdup(name);
86 rtg->compare = compare;
87 MIR_DLIST_INIT(rtg->entries);
89 if (pa_hashmap_put(router->rtgroups, rtg->name, rtg) < 0) {
95 pa_log_debug("routing group '%s' created", name);
100 void mir_router_destroy_rtgroup(struct userdata *u, const char *name)
107 pa_assert_se((router = u->router));
109 if (!(rtg = pa_hashmap_remove(router->rtgroups, name)))
110 pa_log_debug("can't destroy routing group '%s': group not found",name);
112 rtgroup_destroy(u, rtg);
113 pa_log_debug("routing group '%s' destroyed", name);
118 pa_bool_t mir_router_assign_class_to_rtgroup(struct userdata *u,
120 const char *rtgrpnam)
128 pa_assert_se((router = u->router));
130 if (class < 0 || class >= router->maplen) {
131 pa_log_debug("can't assign class (%d) to routing group '%s': "
132 "class id is out of range (0 - %d)",
133 class, rtgrpnam, router->maplen);
137 clnam = mir_node_type_str(class);
139 if (!(rtg = pa_hashmap_get(router->rtgroups, rtgrpnam))) {
140 pa_log_debug("can't assign class '%s' to routing group '%s': "
141 "router group not found", clnam, rtgrpnam);
144 router->classmap[class] = rtg;
146 pa_log_debug("class '%s' assigned to routing group '%s'", clnam, rtgrpnam);
152 void mir_router_register_node(struct userdata *u, mir_node *node)
162 pa_assert_se((router = u->router));
164 if (node->implement == mir_device) {
165 if (node->direction == mir_output) {
166 PA_HASHMAP_FOREACH(rtg, router->rtgroups, state) {
167 add_rtentry(u, rtg, node);
173 if (node->implement == mir_stream) {
174 if (node->direction == mir_input) {
175 priority = node_priority(u, node);
177 MIR_DLIST_FOR_EACH(mir_node, rtentries, before, &router->nodlist) {
178 if (priority < node_priority(u, before)) {
179 MIR_DLIST_INSERT_BEFORE(mir_node, rtentries, node,
185 MIR_DLIST_APPEND(mir_node, rtentries, node, &router->nodlist);
191 void mir_router_unregister_node(struct userdata *u, mir_node *node)
194 mir_rtentry *rte, *n;
198 pa_assert_se((router = u->router));
200 if (node->implement == mir_device && node->direction == mir_output) {
201 MIR_DLIST_FOR_EACH_SAFE(mir_rtentry,nodchain, rte,n, &node->rtentries){
202 remove_rtentry(u, rte);
207 if (node->implement == mir_stream && node->direction == mir_input) {
208 MIR_DLIST_UNLINK(mir_node, rtentries, node);
213 int mir_router_print_rtgroups(struct userdata *u, char *buf, int len)
223 pa_assert_se((router = u->router));
224 pa_assert(router->rtgroups);
229 p += snprintf(p, e-p, "routing table:\n");
232 PA_HASHMAP_FOREACH(rtg, router->rtgroups, state) {
234 p += snprintf(p, e-p, " %s:", rtg->name);
237 p += rtgroup_print(rtg, p, e-p);
240 p += snprintf(p, e-p, "\n");
249 mir_node *mir_router_make_prerouting(struct userdata *u, mir_node *data)
259 pa_assert_se((router = u->router));
261 priority = node_priority(u, data);
265 MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, source, &router->nodlist) {
266 if (priority >= node_priority(u, source)) {
267 if ((target = route_stream(u, data)))
268 mir_switch_setup_link(u, NULL, target, TRUE);
272 if ((sink = route_stream(u, source)))
273 mir_switch_setup_link(u, source, sink, FALSE);
276 if (!done && (target = route_stream(u, data)))
277 mir_switch_setup_link(u, NULL, target, TRUE);
283 void mir_router_make_routing(struct userdata *u)
285 static pa_bool_t ongoing_routing;
292 pa_assert_se((router = u->router));
297 ongoing_routing = TRUE;
299 MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, source, &router->nodlist) {
300 if ((sink = route_stream(u, source)))
301 mir_switch_setup_link(u, source, sink, FALSE);
304 ongoing_routing = FALSE;
309 pa_bool_t mir_router_default_accept(struct userdata *u, mir_rtgroup *rtg,
318 accept = (node->type >= mir_device_class_begin &&
319 node->type < mir_device_class_end);
324 int mir_router_default_compare(struct userdata *u, mir_node *n1, mir_node *n2)
333 if (n1->type == mir_null)
335 if (n2->type == mir_null)
338 p1 = ((((n1->channels & 31) << 5) + n1->privacy) << 2) + n1->location;
339 p2 = ((((n2->channels & 31) << 5) + n2->privacy) << 2) + n2->location;
341 p1 = (p1 << 8) + ((n1->type - mir_device_class_begin) & 0xff);
342 p2 = (p2 << 8) + ((n2->type - mir_device_class_begin) & 0xff);
344 return uint32_cmp(p1,p2);
348 static void rtgroup_destroy(struct userdata *u, mir_rtgroup *rtg)
350 mir_rtentry *rte, *n;
355 MIR_DLIST_FOR_EACH_SAFE(mir_rtentry, link, rte,n, &rtg->entries) {
356 remove_rtentry(u, rte);
363 static int rtgroup_print(mir_rtgroup *rtg, char *buf, int len)
371 MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
375 p += snprintf(p, e-p, " '%s'", node->amname);
381 static void add_rtentry(struct userdata *u, mir_rtgroup *rtg, mir_node *node)
384 mir_rtentry *rte, *before;
389 pa_assert_se((router = u->router));
391 if (!rtg->accept(u, rtg, node)) {
392 pa_log_debug("refuse node '%s' registration to routing group '%s'",
393 node->amname, rtg->name);
397 rte = pa_xnew0(mir_rtentry, 1);
399 MIR_DLIST_APPEND(mir_rtentry, nodchain, rte, &node->rtentries);
402 MIR_DLIST_FOR_EACH(mir_rtentry, link, before, &rtg->entries) {
403 if (rtg->compare(u, node, before->node) < 0) {
404 MIR_DLIST_INSERT_BEFORE(mir_rtentry, link, rte, &before->link);
409 MIR_DLIST_APPEND(mir_rtentry, link, rte, &rtg->entries);
412 pa_log_debug("node '%s' added to routing group '%s'",
413 node->amname, rtg->name);
416 static void remove_rtentry(struct userdata *u, mir_rtentry *rte)
421 MIR_DLIST_UNLINK(mir_rtentry, link, rte);
422 MIR_DLIST_UNLINK(mir_rtentry, nodchain, rte);
428 static mir_node *route_stream(struct userdata *u, mir_node *source)
430 pa_router *router = u->router;
431 mir_node_type class = source->type;
437 if (class < 0 || class > router->maplen) {
438 pa_log_debug("can't route '%s': class %d is out of range (0 - %d)",
439 source->amname, class, router->maplen);
443 if (!(rtg = router->classmap[class])) {
444 pa_log_debug("node '%s' won't be routed beacuse its class '%s' "
445 "is not assigned to any router group",
446 source->amname, mir_node_type_str(class));
450 pa_log_debug("using '%s' router group when routing '%s'",
451 rtg->name, source->amname);
454 MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
455 if (!(sink = rte->node)) {
456 pa_log(" node was null in mir_rtentry");
461 pa_log_debug(" '%s' should be ignored", sink->amname);
465 if (!sink->available) {
466 pa_log_debug(" '%s' not available", sink->amname);
470 if (sink->paidx == PA_IDXSET_INVALID) {
471 if (sink->type != mir_bluetooth_a2dp &&
472 sink->type != mir_bluetooth_sco)
474 pa_log_debug(" '%s' has no sink", sink->amname);
479 pa_log_debug("routing '%s' => '%s'", source->amname, sink->amname);
484 pa_log_debug("could not find route for '%s'", source->amname);
491 static int uint32_cmp(uint32_t v1, uint32_t v2)
501 static int node_priority(struct userdata *u, mir_node *node)
508 pa_assert_se((router = u->router));
509 pa_assert(router->priormap);
513 if (type < 0 || type >= router->maplen)
516 return router->priormap[type];
523 * indent-tabs-mode: nil