switch: explicit route support
[staging/agl-audio-plugin.git] / switch.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 <pulsecore/pulsecore-config.h> /* required for headers below */
23 #include <pulsecore/core-util.h>        /* requred for "pa_streq" */
24 #include <pulsecore/namereg.h>          /* for PA_NAMEREG_SOURCE */
25
26 #include "utils.h"
27 #include "switch.h"
28 #include "node.h"
29
30 bool agl_switch_setup_link (struct userdata *u, agl_node *from, agl_node *to)
31 {
32         pa_core *core;
33         pa_sink *sink;
34         pa_source *source;
35
36         pa_assert (u);
37         pa_assert_se (core = u->core);
38
39         /* EXPLICIT ROUTES/DEFAULT ROUTES */
40
41         /* 1) EXPLICIT ROUTES : "FROM" AND "TO" ARE DEFINED */
42         if (from && to) {
43                 pa_assert (from);
44                 pa_assert (to);
45
46                 switch (from->implement) {
47                         /* STREAM SOURCE */
48                         case agl_stream:
49                         switch (to->implement) {
50                                 /* STREAM TO STREAM : NOT IMPLEMENTED */
51                                 case agl_stream:
52                                         pa_log_debug ("routing to streams not implemented");
53                                         break;
54                                 /* STREAM TO DEVICE : OK */
55                                 case agl_device:
56                                         //if (!setup_explicit_stream2dev_link (u, from, to))
57                                         //      return false;
58                                         sink = agl_utils_get_alsa_sink (u, to->paname);
59                                         if (!sink) {
60                                                 pa_log("sink output not found!!!!");
61                                                 sink = agl_utils_get_primary_alsa_sink (u);
62                                                 //break;
63                                         }
64                                         source = agl_utils_get_null_source (u, from->nullsink);
65                                         from->loopnode = agl_loopnode_create (u, AGL_LOOPNODE_SINK, from->index, source->index, sink->index);
66                                         break;
67                                 /* DEFAULT */
68                                 default:
69                                         pa_log ("can't setup link: invalid sink node");
70                                         return false;
71                         }
72                         break;
73
74                         /* DEVICE SOURCE : NOT IMPLEMENTED */
75                         case agl_device:
76                                 pa_log_debug("input device routing is not implemented yet");
77                                 break;
78
79                         /* DEFAULT */
80                         default:
81                                 pa_log ("can't setup link: invalid sink node");
82                                 return false;
83                 }
84         }
85
86         /* 2) DEFAULT ROUTES : EITHER ONE OF "FROM" AND "TO" ARE DEFINED */
87         else {
88                 pa_assert (from || to);
89
90                 /* "TO" IS DEFINED */
91                 if (to) {
92                         switch (to->implement) {
93                                 /* STREAM DESTINATION */
94                                 case agl_stream:
95                                 switch (from->implement) {
96                                         /* STREAM TO STREAM : NOT IMPLEMENTED */
97                                         case agl_stream:
98                                                 pa_log_debug ("routing to streams not implemented");
99                                                 break;
100                                         /* DEVICE TO STREAM : OK */
101                                         case agl_device:
102                                                 //if (!setup_default_dev2stream_link(u, from, to))
103                                                 //      return false;
104                                                 break;
105                                         /* DEFAULT */
106                                         default:
107                                                 pa_log ("can't setup link: invalid sink node");
108                                                 return false;
109                                 }
110                                 break;
111
112                                 /* DEVICE DESTINATION */
113                                 case agl_device:
114                                 switch (from->implement) {
115                                         /* STREAM TO DEVICE : OK */
116                                         case agl_stream:
117                                                 sink = agl_utils_get_alsa_sink (u, to->paname);
118                                                 if (!sink) break;
119                                                 source = agl_utils_get_null_source (u, from->nullsink);
120
121                                                 from->loopnode = agl_loopnode_create (u, AGL_LOOPNODE_SINK, from->index, source->index, sink->index);
122                                                 break;
123                                         /* DEVICE TO DEVICE : OK */
124                                         case agl_device:
125                                                 //if (!setup_default_dev2dev_link (u, from, to))
126                                                 //      return false;
127                                                 break;
128                                         /* DEFAULT */
129                                         default:
130                                                 pa_log ("can't setup link: invalid source node");
131                                                 return false;
132                                 }
133                                 break;
134                                 /* } */
135
136                                 /* DEFAULT DESTINATION : NULL */
137                                 default:
138                                         pa_log ("can't setup link");
139                                         return false;
140                         }
141                 }
142
143                 /* ONLY "FROM" IS DEFINED */
144                 else {
145                         /* only works with a stream, use default input prerouting */
146                         if (from->implement == agl_device) {
147                                 pa_log_debug ("default routing for a device input is not supported yet");
148                                 return false;
149                         }
150                         /* (the rest supposes "from->implement == agl_stream") */
151                         /* refuse unknown node types for default routing */
152                         if (from->type == agl_node_type_unknown) {
153                                 pa_log_debug ("default routing for unknown node type is refused");
154                                 return false;
155                         }
156
157                         sink = agl_utils_get_primary_alsa_sink (u);
158                         source = agl_utils_get_null_source (u, from->nullsink);
159                         from->loopnode = agl_loopnode_create (u, AGL_LOOPNODE_SINK, from->index, source->index, sink->index);
160                 }
161         }
162
163         //pa_log_debug ("link %s => %s is established", from->amname, to->amname);
164
165         return true;
166 }
167
168 bool agl_switch_teardown_link (struct userdata *u, agl_node *from, agl_node *to)
169 {
170         pa_core *core;
171
172         pa_assert (u);
173         pa_assert_se (core = u->core);
174
175         pa_assert (from || to);
176
177         /* "TO" IS DEFINED */
178         if (to) {
179
180         }
181         /* ONLY "FROM" IS DEFINED */
182         else {
183                 /* only works with a stream */
184                 if (from->implement == agl_device) {
185                         pa_log_debug ("default routing for a device input is not supported");
186                         return false;
187                 }
188                 /* (the rest supposes "from->implement == agl_stream") */
189                 if (from->loopnode)
190                         agl_loopnode_destroy (u, from->loopnode);
191                 if (from->nullsink)
192                         agl_utils_destroy_null_sink (u, from->nullsink);
193         }
194
195         //pa_log_debug("link %s => %s is torn down", from->amname, to->amname);
196
197         return true;
198 }
199
200
201 bool set_port (struct userdata *u, agl_node *node)
202 {
203         pa_core *core;
204         pa_sink *sink;
205         pa_source *source;
206         pa_device_port *port;
207         void *data = NULL;
208         uint32_t paidx = PA_IDXSET_INVALID;
209
210         pa_assert (u);
211         pa_assert (node);
212         pa_assert (node->paname);
213         pa_assert_se (core = u->core);
214
215         if (node->direction != agl_input && node->direction != agl_output)
216                 return false;
217         if (node->implement != agl_device)
218                 return true;
219         if (!node->paport)
220                 return true;
221
222         if (node->direction == agl_input) {
223                 source = pa_namereg_get (core, node->paname, PA_NAMEREG_SOURCE);
224                 if (!source) {
225                         pa_log ("cannot set port for node '%s': source not found", node->paname);
226                         return false;
227                 }
228
229                 port = source->active_port;
230                 /* active port and wanted port already match */
231                 if (pa_streq (node->paport, port->name))
232                         return true;
233
234                 /* ACTIVE CODE */
235                 if (pa_source_set_port (source, node->paport, false) < 0)
236                         return false;
237
238                 data = source;
239                 paidx = source->index;
240         }
241
242         if (node->direction == agl_output) {
243                 sink = pa_namereg_get (core, node->paname, PA_NAMEREG_SINK);
244                 if (!sink) {
245                         pa_log ("cannot set port for node '%s': source not found", node->paname);
246                         return false;
247                 }
248
249                 port = sink->active_port;
250                 /* active port and wanted port already match */
251                 if (pa_streq (node->paport, port->name))
252                         return true;
253
254                 /* ACTIVE CODE */
255                 if (pa_sink_set_port (sink, node->paport, false) < 0)
256                         return false;
257
258                 data = sink;
259                 paidx = sink->index;
260         }
261
262         return true;
263 }