2 * module-agl-audio -- PulseAudio module for providing audio routing support
3 * (forked from "module-murphy-ivi" - https://github.com/otcshare )
4 * Copyright (c) 2012, Intel Corporation.
5 * Copyright (c) 2016, IoT.bzh
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU Lesser General Public License,
9 * version 2.1, as published by the Free Software Foundation.
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
27 agl_router *agl_router_init (struct userdata *u)
32 num_classes = agl_application_class_end;
34 router = pa_xnew0 (agl_router, 1);
35 router->rtgroups.input = pa_hashmap_new (pa_idxset_string_hash_func,
36 pa_idxset_string_compare_func);
37 router->rtgroups.output = pa_hashmap_new (pa_idxset_string_hash_func,
38 pa_idxset_string_compare_func);
39 router->maplen = num_classes;
40 router->priormap = pa_xnew0 (int, num_classes);
42 AGL_DLIST_INIT (router->nodlist);
43 AGL_DLIST_INIT (router->connlist);
48 void agl_router_done (struct userdata *u)
52 agl_connection *conn, *c;
57 if (u && (router = u->router)) {
58 AGL_DLIST_FOR_EACH_SAFE(agl_node, rtprilist, e,n, &router->nodlist)
59 AGL_DLIST_UNLINK(agl_node, rtprilist, e);
60 AGL_DLIST_FOR_EACH_SAFE(agl_connection, link, conn,c, &router->connlist) {
61 AGL_DLIST_UNLINK(agl_connection, link, conn);
65 PA_HASHMAP_FOREACH(rtg, router->rtgroups.input, state) {
66 rtgroup_destroy(u, rtg);
68 PA_HASHMAP_FOREACH(rtg, router->rtgroups.output, state) {
69 rtgroup_destroy(u, rtg);
71 pa_hashmap_free (router->rtgroups.input);
72 pa_hashmap_free (router->rtgroups.output);
74 for (i = 0; i < AGL_ZONE_MAX; i++) {
75 if ((map = router->classmap.input[i]))
77 if ((map = router->classmap.output[i]))
81 pa_xfree (router->priormap);
88 bool agl_router_default_accept (struct userdata *u, agl_rtgroup *rtg, agl_node *node)
94 bool agl_router_phone_accept (struct userdata *u, agl_rtgroup *rtg, agl_node *node)
100 int agl_router_default_compare (struct userdata *u, agl_rtgroup *rtg, agl_node *n1, agl_node *n2)
106 int agl_router_phone_compare (struct userdata *u, agl_rtgroup *rtg, agl_node *n1, agl_node *n2)
112 agl_rtgroup *agl_router_create_rtgroup (struct userdata *u, agl_direction type, const char *name, agl_rtgroup_accept_t accept, agl_rtgroup_compare_t compare)
119 pa_assert (type == agl_input || type == agl_output);
123 pa_assert_se (router = u->router);
125 if (type == agl_input)
126 table = router->rtgroups.input;
128 table = router->rtgroups.output;
131 rtg = pa_xnew0 (agl_rtgroup, 1);
132 rtg->name = pa_xstrdup (name);
133 rtg->accept = accept;
134 rtg->compare = compare;
135 AGL_DLIST_INIT(rtg->entries);
137 pa_hashmap_put (table, rtg->name, rtg);
139 pa_log_debug ("routing group '%s' created", name);
144 void agl_router_destroy_rtgroup (struct userdata *u, agl_direction type, const char *name)
152 pa_assert_se (router = u->router);
154 if (type == agl_input)
155 table = router->rtgroups.input;
157 table = router->rtgroups.output;
160 rtg = pa_hashmap_remove (table, name);
162 pa_log_debug ("can't destroy routing group '%s': not found", name);
164 //rtgroup_destroy (u, rtg);
165 pa_log_debug ("routing group '%s' destroyed", name);
169 bool agl_router_assign_class_to_rtgroup (struct userdata *u, agl_node_type class, uint32_t zone, agl_direction type, const char *name)
173 agl_rtgroup ***classmap;
174 agl_rtgroup **zonemap;
175 const char *classname;
176 const char *direction;
181 pa_assert (zone < AGL_ZONE_MAX);
182 pa_assert (type == agl_input || type == agl_output);
184 pa_assert_se (router = u->router);
186 if (type == agl_input) {
187 rtable = router->rtgroups.input;
188 classmap = router->classmap.input;
190 rtable = router->rtgroups.output;
191 classmap = router->classmap.output;
194 if (class < 0 || class >= router->maplen) {
195 pa_log_debug ("Cannot assign class to routing group '%s': "
196 "id %d out of range (0 - %d)",
197 name, class, router->maplen);
201 classname = agl_node_type_str (class); /* "Player", "Radio"... */
202 direction = agl_node_direction_str (type); /* "input", "output" */
204 rtg = pa_hashmap_get (rtable, name);
206 pa_log_debug ("Cannot assign class to routing group '%s': "
207 "router group not found", name);
211 zonemap = classmap[zone];
212 if (!zonemap) { /* THIS LOOKS LIKE A HACK TO IGNORE THE ERROR... */
213 zonemap = pa_xnew0 (agl_rtgroup *, router->maplen);
214 classmap[zone] = zonemap;
217 zonemap[class] = rtg;
219 /* try to get zone name for logging, if fails, only print id number */
220 rzone = agl_zoneset_get_zone_by_index (u, zone);
222 pa_log_debug ("class '%s'@'%s' assigned to routing group '%s'",
223 classname, rzone->name, name);
225 pa_log_debug ("class '%s'@zone%d assigned to routing group '%s'",
226 classname, zone, name);
232 void agl_router_assign_class_priority (struct userdata *u, agl_node_type class, int priority)
238 pa_assert_se (router = u->router);
239 pa_assert_se (priormap = router->priormap);
241 if (class > 0 && class < router->maplen) {
242 pa_log_debug ("assigning priority %d to class '%s'",
243 priority, agl_node_type_str (class));
244 priormap[class] = priority;
248 void agl_router_register_node (struct userdata *u, agl_node *node)
253 implement_default_route (u, node, NULL, agl_utils_new_stamp ());
256 void agl_router_unregister_node (struct userdata *u, agl_node *node)
261 remove_routes (u, node, NULL, agl_utils_new_stamp ());
264 agl_node *agl_router_make_prerouting (struct userdata *u, agl_node *data)
268 static bool done_prerouting;
270 agl_node *start, *end;
274 pa_assert_se (router = u->router);
275 pa_assert_se (data->implement == agl_stream);
277 //priority = node_priority (u, data);
279 done_prerouting = false;
281 stamp = agl_utils_new_stamp ();
283 //make_explicit_routes (u, stamp);
285 //pa_audiomgr_delete_default_routes(u);
287 AGL_DLIST_FOR_EACH_BACKWARDS(agl_node, rtprilist, start, &router->nodlist) {
288 //if ((start->implement == agl_device) &&
289 // (!start->loop)) /* only manage looped real devices */
292 /*if (priority >= node_priority (u, start)) {
293 target = find_default_route (u, data, stamp);
295 implement_preroute (u, data, target, stamp);
297 done_prerouting = true;
300 if (start->stamp >= stamp)
303 //end = find_default_route (u, start, stamp);
305 // implement_default_route(u, start, end, stamp);
308 if (!done_prerouting) {
309 pa_log_debug ("Prerouting failed, trying to find default route as last resort");
311 //target = find_default_route (u, data, stamp);
313 // implement_preroute (u, data, target, stamp);
319 void agl_router_make_routing (struct userdata *u)
322 static bool ongoing_routing; /* true while we are actively routing */
324 agl_node *start, *end;
327 pa_assert_se (router = u->router);
329 if (ongoing_routing) /* already routing, canceling */
331 ongoing_routing = true;
332 stamp = agl_utils_new_stamp ();
334 pa_log_debug("stamp for routing: %d", stamp);
336 // make_explicit_routes (u, stamp);
338 // pa_audiomgr_delete_default_routes (u);
340 AGL_DLIST_FOR_EACH_BACKWARDS(agl_node, rtprilist, start, &router->nodlist) {
341 //if ((start->implement == agl_device) &&
342 // (!start->loop)) /* only manage looped real devices */
345 if (start->stamp >= stamp)
348 end = find_default_route (u, start, stamp);
350 implement_default_route (u, start, end, stamp);
353 // pa_audiomgr_send_default_routes (u);
355 ongoing_routing = false;
358 void implement_default_route (struct userdata *u,
359 agl_node *start, agl_node *end,
362 if (start->direction == agl_input) {
363 agl_switch_setup_link (u, start, end, false);
364 //agl_volume_add_limiting_class(u, end, volume_class(start), stamp);
366 agl_switch_setup_link (u, end, start, false);
370 agl_node *find_default_route (struct userdata *u, agl_node *start, uint32_t stamp)
377 void remove_routes (struct userdata *u, agl_node *start, agl_node *end, uint32_t stamp)
379 if (start->direction == agl_input) {
380 agl_switch_teardown_link (u, start, end);
382 agl_switch_teardown_link (u, end, start);