Fix invalid sink input treatment after module-loopback
[staging/agl-audio-plugin.git] / router.c
1 /*
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
6  *
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.
10  *
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.
15  *
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,
19  * MA 02110-1301 USA.
20  *
21  */
22 #include "router.h"
23 #include "switch.h"
24 #include "utils.h"
25
26 pa_router *pa_router_init (struct userdata *u)
27 {
28         pa_router *router;
29         size_t num_classes;
30
31         num_classes = agl_application_class_end;
32
33         router = pa_xnew0 (pa_router, 1);
34         router->rtgroups.input = pa_hashmap_new (pa_idxset_string_hash_func,
35                                                  pa_idxset_string_compare_func);
36         router->rtgroups.output = pa_hashmap_new (pa_idxset_string_hash_func,
37                                                   pa_idxset_string_compare_func);
38         router->maplen = num_classes;
39         router->priormap = pa_xnew0 (int, num_classes);
40
41         AGL_DLIST_INIT (router->nodlist);
42         AGL_DLIST_INIT (router->connlist);
43
44         return router;
45 }
46
47 void pa_router_done (struct userdata *u)
48 {
49         pa_router *router;
50         agl_node *e,*n;
51         agl_connection *conn, *c;
52         agl_rtgroup *rtg;
53         agl_rtgroup **map;
54         int i;
55
56         if (u && (router = u->router)) {
57                 AGL_DLIST_FOR_EACH_SAFE(agl_node, rtprilist, e,n, &router->nodlist)
58                         AGL_DLIST_UNLINK(agl_node, rtprilist, e);
59                 AGL_DLIST_FOR_EACH_SAFE(agl_connection, link, conn,c, &router->connlist) {
60                         AGL_DLIST_UNLINK(agl_connection, link, conn);
61                         pa_xfree (conn);
62                 }
63                 /*
64                 PA_HASHMAP_FOREACH(rtg, router->rtgroups.input, state) {
65                         rtgroup_destroy(u, rtg);
66                 }
67                 PA_HASHMAP_FOREACH(rtg, router->rtgroups.output, state) {
68                         rtgroup_destroy(u, rtg);
69                 }*/
70                 pa_hashmap_free (router->rtgroups.input);
71                 pa_hashmap_free (router->rtgroups.output);
72
73                 for (i = 0;  i < AGL_ZONE_MAX;  i++) {
74                         if ((map = router->classmap.input[i]))
75                                 pa_xfree(map);
76                         if ((map = router->classmap.output[i]))
77                                 pa_xfree(map);
78                 }
79
80                 pa_xfree (router->priormap);
81                 pa_xfree (router);
82
83                 u->router = NULL;
84         }
85 }
86
87 agl_node *agl_router_make_prerouting (struct userdata *u, agl_node *data)
88 {
89         pa_router *router;
90         int priority;
91         static bool done_prerouting;
92         uint32_t stamp;
93         agl_node *start, *end;
94         agl_node *target;
95
96         pa_assert (u);
97         pa_assert_se (router = u->router);
98         pa_assert_se (data->implement == agl_stream);
99
100         //priority = node_priority (u, data);
101
102         done_prerouting = false;
103         target = NULL;
104         stamp = pa_utils_new_stamp ();
105
106         //make_explicit_routes (u, stamp);
107
108         //pa_audiomgr_delete_default_routes(u);
109
110         AGL_DLIST_FOR_EACH_BACKWARDS(agl_node, rtprilist, start, &router->nodlist) {
111                 //if ((start->implement == agl_device) &&
112                 //    (!start->loop))   /* only manage looped real devices */
113                 //      continue;
114
115                 /*if (priority >= node_priority (u, start)) {
116                         target = find_default_route (u, data, stamp);
117                         if (target)
118                                 implement_preroute (u, data, target, stamp);
119                         else
120                                 done_prerouting = true;
121                 }*/
122
123                 if (start->stamp >= stamp)
124                         continue;
125
126                 //end = find_default_route (u, start, stamp);
127                 //if (end)
128                 //      implement_default_route(u, start, end, stamp);
129         }
130
131         if (!done_prerouting) {
132                 pa_log_debug ("Prerouting failed, trying to find default route as last resort");
133
134                 //target = find_default_route (u, data, stamp);
135                 //if (target)
136                 //      implement_preroute (u, data, target, stamp);
137         }
138
139         return target;
140 }
141
142 void agl_router_make_routing (struct userdata *u)
143 {
144         pa_router *router;
145         static bool ongoing_routing;    /* true while we are actively routing */
146         uint32_t stamp;
147         agl_node *start, *end;
148
149         pa_assert (u);
150         pa_assert_se (router = u->router);
151
152         if (ongoing_routing)            /* already routing, canceling */
153                 return;
154         ongoing_routing = true;
155         stamp = pa_utils_new_stamp ();
156
157         pa_log_debug("stamp for routing: %d", stamp);
158
159         // make_explicit_routes (u, stamp);
160
161         // pa_audiomgr_delete_default_routes (u);
162
163         AGL_DLIST_FOR_EACH_BACKWARDS(agl_node, rtprilist, start, &router->nodlist) {
164                 //if ((start->implement == agl_device) &&
165                 //   (!start->loop))    /* only manage looped real devices */
166                 //      continue;
167
168                 if (start->stamp >= stamp)
169                         continue;
170
171                 end = find_default_route (u, start, stamp);
172                 if (end)
173                         implement_default_route (u, start, end, stamp);
174         }
175
176         // pa_audiomgr_send_default_routes (u);
177
178         ongoing_routing = false;
179 }
180
181 void implement_default_route (struct userdata *u,
182                               agl_node *start, agl_node *end,
183                               uint32_t stamp)
184 {
185         if (start->direction == agl_input) {
186                 agl_switch_setup_link (u, start, end, false);
187                 //agl_volume_add_limiting_class(u, end, volume_class(start), stamp);
188         } else {
189                 agl_switch_setup_link (u, end, start, false);
190         }
191 }
192
193 agl_node *find_default_route (struct userdata *u, agl_node *start, uint32_t stamp)
194 {
195         /* TODO */
196
197         return NULL;
198 }