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