Clean up node status after sink_input unlink
[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 void agl_router_register_node (struct userdata *u, agl_node *node)
88 {
89         pa_assert (u);
90         pa_assert (node);
91
92         implement_default_route (u, node, NULL, pa_utils_new_stamp ());
93 }
94
95 void agl_router_unregister_node (struct userdata *u, agl_node *node)
96 {
97         pa_assert (u);
98         pa_assert (node);
99
100         remove_routes (u, node, NULL, pa_utils_new_stamp ());
101 }
102
103 agl_node *agl_router_make_prerouting (struct userdata *u, agl_node *data)
104 {
105         pa_router *router;
106         int priority;
107         static bool done_prerouting;
108         uint32_t stamp;
109         agl_node *start, *end;
110         agl_node *target;
111
112         pa_assert (u);
113         pa_assert_se (router = u->router);
114         pa_assert_se (data->implement == agl_stream);
115
116         //priority = node_priority (u, data);
117
118         done_prerouting = false;
119         target = NULL;
120         stamp = pa_utils_new_stamp ();
121
122         //make_explicit_routes (u, stamp);
123
124         //pa_audiomgr_delete_default_routes(u);
125
126         AGL_DLIST_FOR_EACH_BACKWARDS(agl_node, rtprilist, start, &router->nodlist) {
127                 //if ((start->implement == agl_device) &&
128                 //    (!start->loop))   /* only manage looped real devices */
129                 //      continue;
130
131                 /*if (priority >= node_priority (u, start)) {
132                         target = find_default_route (u, data, stamp);
133                         if (target)
134                                 implement_preroute (u, data, target, stamp);
135                         else
136                                 done_prerouting = true;
137                 }*/
138
139                 if (start->stamp >= stamp)
140                         continue;
141
142                 //end = find_default_route (u, start, stamp);
143                 //if (end)
144                 //      implement_default_route(u, start, end, stamp);
145         }
146
147         if (!done_prerouting) {
148                 pa_log_debug ("Prerouting failed, trying to find default route as last resort");
149
150                 //target = find_default_route (u, data, stamp);
151                 //if (target)
152                 //      implement_preroute (u, data, target, stamp);
153         }
154
155         return target;
156 }
157
158 void agl_router_make_routing (struct userdata *u)
159 {
160         pa_router *router;
161         static bool ongoing_routing;    /* true while we are actively routing */
162         uint32_t stamp;
163         agl_node *start, *end;
164
165         pa_assert (u);
166         pa_assert_se (router = u->router);
167
168         if (ongoing_routing)            /* already routing, canceling */
169                 return;
170         ongoing_routing = true;
171         stamp = pa_utils_new_stamp ();
172
173         pa_log_debug("stamp for routing: %d", stamp);
174
175         // make_explicit_routes (u, stamp);
176
177         // pa_audiomgr_delete_default_routes (u);
178
179         AGL_DLIST_FOR_EACH_BACKWARDS(agl_node, rtprilist, start, &router->nodlist) {
180                 //if ((start->implement == agl_device) &&
181                 //   (!start->loop))    /* only manage looped real devices */
182                 //      continue;
183
184                 if (start->stamp >= stamp)
185                         continue;
186
187                 end = find_default_route (u, start, stamp);
188                 if (end)
189                         implement_default_route (u, start, end, stamp);
190         }
191
192         // pa_audiomgr_send_default_routes (u);
193
194         ongoing_routing = false;
195 }
196
197 void implement_default_route (struct userdata *u,
198                               agl_node *start, agl_node *end,
199                               uint32_t stamp)
200 {
201         if (start->direction == agl_input) {
202                 agl_switch_setup_link (u, start, end, false);
203                 //agl_volume_add_limiting_class(u, end, volume_class(start), stamp);
204         } else {
205                 agl_switch_setup_link (u, end, start, false);
206         }
207 }
208
209 agl_node *find_default_route (struct userdata *u, agl_node *start, uint32_t stamp)
210 {
211         /* TODO */
212
213         return NULL;
214 }
215
216 void remove_routes (struct userdata *u, agl_node *start, agl_node *end, uint32_t stamp)
217 {
218         if (start->direction == agl_input) {
219                 agl_switch_teardown_link (u, start, end);
220         } else {
221                 agl_switch_teardown_link (u, end, start);
222         }
223 }