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