95c5f0a520820cf8c5c636b6a50c2a215e97bc23
[staging/agl-audio-plugin.git] / tracker.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 "tracker.h"
23 #include "discover.h"
24 #include "router.h"
25 #include "utils.h"
26
27 struct pa_card_hooks {
28     pa_hook_slot    *put;
29     pa_hook_slot    *unlink;
30     pa_hook_slot    *profchg;
31 };
32
33 struct pa_port_hooks {
34     pa_hook_slot    *avail;
35 };
36
37 struct pa_sink_hooks {
38     pa_hook_slot    *put;
39     pa_hook_slot    *unlink;
40     pa_hook_slot    *portchg;
41 };
42
43 struct pa_source_hooks {
44     pa_hook_slot    *put;
45     pa_hook_slot    *unlink;
46     pa_hook_slot    *portchg;
47 };
48
49 struct pa_sink_input_hooks {
50     pa_hook_slot    *neew;
51     pa_hook_slot    *put;
52     pa_hook_slot    *unlink;
53 };
54
55 struct pa_source_output_hooks {
56     pa_hook_slot    *neew;
57     pa_hook_slot    *put;
58     pa_hook_slot    *unlink;
59 };
60
61 struct pa_tracker {
62     pa_card_hooks           card;
63     pa_port_hooks           port;
64     pa_sink_hooks           sink;
65     pa_source_hooks         source;
66     pa_sink_input_hooks     sink_input;
67     pa_source_output_hooks  source_output;
68 };
69
70
71 static pa_hook_result_t card_put (void *, void *, void *);
72 static pa_hook_result_t card_unlink (void *, void *, void *);
73 static pa_hook_result_t card_profile_changed (void *, void *, void *);
74
75 static pa_hook_result_t port_available_changed (void *, void *, void *);
76
77 static pa_hook_result_t sink_put (void *, void *, void *);
78 static pa_hook_result_t sink_unlink (void *, void *, void *);
79 static pa_hook_result_t sink_port_changed (void *, void *, void *);
80
81 static pa_hook_result_t source_put (void *, void *, void *);
82 static pa_hook_result_t source_unlink (void *, void *, void *);
83 static pa_hook_result_t source_port_changed (void *, void *, void *);
84
85 static pa_hook_result_t sink_input_new (void *, void *, void *);
86 static pa_hook_result_t sink_input_put (void *, void *, void *);
87 static pa_hook_result_t sink_input_unlink (void *, void *, void *);
88
89 static pa_hook_result_t source_output_new (void *, void *, void *);
90 static pa_hook_result_t source_output_put (void *, void *, void *);
91 static pa_hook_result_t source_output_unlink (void *, void *, void *);
92
93
94 pa_tracker *pa_tracker_init (struct userdata *u)
95 {
96         pa_core *core;
97         pa_hook *hooks;
98         pa_tracker *tracker;
99         pa_card_hooks *card;
100         pa_port_hooks *port;
101         pa_sink_hooks *sink;
102         pa_source_hooks *source;
103         pa_sink_input_hooks *sinp;
104         pa_source_output_hooks *sout;
105
106         pa_assert (u);
107         pa_assert_se (core = u->core);
108         pa_assert_se (hooks = core->hooks);
109
110         tracker = pa_xnew0 (pa_tracker, 1);
111         card = &tracker->card;
112         port = &tracker->port;
113         sink = &tracker->sink;
114         source = &tracker->source;
115         sinp = &tracker->sink_input;
116         sout = &tracker->source_output;
117
118          /* card */
119         card->put = pa_hook_connect (hooks + PA_CORE_HOOK_CARD_PUT,
120                                      PA_HOOK_LATE, card_put, u);
121         card->unlink = pa_hook_connect (hooks + PA_CORE_HOOK_CARD_UNLINK,
122                                         PA_HOOK_LATE, card_unlink, u);
123         card->profchg = pa_hook_connect (hooks + PA_CORE_HOOK_CARD_PROFILE_CHANGED,
124                                          PA_HOOK_LATE, card_profile_changed, u);
125
126          /* port */
127         port->avail = pa_hook_connect (hooks + PA_CORE_HOOK_PORT_AVAILABLE_CHANGED,
128                                        PA_HOOK_LATE, port_available_changed, u);
129
130          /* sink */
131         sink->put = pa_hook_connect (hooks + PA_CORE_HOOK_SINK_PUT,
132                                      PA_HOOK_LATE, sink_put, u);
133         sink->unlink = pa_hook_connect (hooks + PA_CORE_HOOK_SINK_UNLINK,
134                                         PA_HOOK_LATE, sink_unlink, u);
135         sink->portchg = pa_hook_connect (hooks + PA_CORE_HOOK_SINK_PORT_CHANGED,
136                                          PA_HOOK_LATE, sink_port_changed, u);
137
138          /* source */
139         source->put = pa_hook_connect (hooks + PA_CORE_HOOK_SOURCE_PUT,
140                                        PA_HOOK_LATE, source_put, u);
141         source->unlink = pa_hook_connect (hooks + PA_CORE_HOOK_SOURCE_UNLINK,
142                                           PA_HOOK_LATE, source_unlink, u);
143         source->portchg = pa_hook_connect (hooks + PA_CORE_HOOK_SOURCE_PORT_CHANGED,
144                                           PA_HOOK_LATE, source_port_changed, u);
145
146          /* sink-input */
147         sinp->neew = pa_hook_connect (hooks + PA_CORE_HOOK_SINK_INPUT_NEW,
148                                       PA_HOOK_EARLY, sink_input_new, u);
149         sinp->put = pa_hook_connect (hooks + PA_CORE_HOOK_SINK_INPUT_PUT,
150                                      PA_HOOK_LATE, sink_input_put, u);
151         sinp->unlink = pa_hook_connect (hooks + PA_CORE_HOOK_SINK_INPUT_UNLINK,
152                                         PA_HOOK_LATE, sink_input_unlink, u);
153
154          /* source-output */
155         sout->neew = pa_hook_connect (hooks + PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
156                                       PA_HOOK_EARLY, source_output_new, u);
157         sout->put = pa_hook_connect (hooks + PA_CORE_HOOK_SOURCE_OUTPUT_PUT,
158                                      PA_HOOK_LATE, source_output_put, u);
159         sout->unlink = pa_hook_connect (hooks + PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK,
160                                         PA_HOOK_LATE, source_output_unlink, u);
161
162         return tracker; 
163 }
164
165 void pa_tracker_done (struct userdata *u)
166 {
167         pa_tracker *tracker;    
168         pa_card_hooks *card;
169         pa_port_hooks *port;
170         pa_sink_hooks *sink;
171         pa_source_hooks *source;
172         pa_sink_input_hooks *sinp;
173
174         if (u && (tracker = u->tracker)) {
175
176                 card = &tracker->card;
177                 pa_hook_slot_free (card->put);
178                 pa_hook_slot_free (card->unlink);
179                 pa_hook_slot_free (card->profchg);
180
181                 port = &tracker->port;
182                 pa_hook_slot_free (port->avail);
183
184                 sink = &tracker->sink;
185                 pa_hook_slot_free (sink->put);
186                 pa_hook_slot_free (sink->unlink);
187                 pa_hook_slot_free (sink->portchg);
188
189                 source = &tracker->source;
190                 pa_hook_slot_free (source->put);
191                 pa_hook_slot_free (source->unlink);
192                 pa_hook_slot_free (source->portchg);
193
194                 sinp = &tracker->sink_input;
195                 pa_hook_slot_free (sinp->neew);
196                 pa_hook_slot_free (sinp->put);
197                 pa_hook_slot_free (sinp->unlink);
198
199                 pa_xfree(tracker);
200         
201                 u->tracker = NULL;
202         }
203 }
204
205  /* main logic initialization function */
206 void pa_tracker_synchronize (struct userdata *u)
207 {
208         pa_core *core;
209         pa_card *card;
210         pa_sink *sink;
211         pa_source *source;
212         pa_sink_input *sinp;
213         pa_source_output *sout;
214         uint32_t index;
215
216         pa_assert (u);
217         pa_assert_se (core = u->core);
218
219          /* initialize "stamp" incremental card property to 0 */
220         pa_utils_init_stamp ();
221
222          /* discover.c : add each valid USB/PCI/Platform ALSA sound card */
223         PA_IDXSET_FOREACH (card, core->cards, index) {
224                 pa_discover_add_card (u, card);
225         }
226
227         PA_IDXSET_FOREACH (sink, core->sinks, index) {
228                 pa_discover_add_sink (u, sink, false);
229         }
230
231         PA_IDXSET_FOREACH (source, core->sources, index) {
232                 pa_discover_add_source (u, source);
233         }
234
235         PA_IDXSET_FOREACH(sinp, core->sink_inputs, index) {
236                 pa_discover_register_sink_input (u, sinp);
237         }
238
239         PA_IDXSET_FOREACH(sout, core->source_outputs, index) {
240                 pa_discover_register_source_output (u, sout);
241         }
242
243         agl_router_make_routing (u);
244 }
245
246
247  /* HOOK IMPLEMENTATIONS */
248 static pa_hook_result_t card_put (void *hook_data,
249                                   void *call_data,
250                                   void *slot_data)
251 {
252         return PA_HOOK_OK;
253 }
254
255 static pa_hook_result_t card_unlink (void *hook_data,
256                                      void *call_data,
257                                      void *slot_data)
258 {
259         return PA_HOOK_OK;
260 }
261
262 static pa_hook_result_t card_profile_changed (void *hook_data,
263                                               void *call_data,
264                                               void *slot_data)
265 {
266         return PA_HOOK_OK;
267 }
268
269 static pa_hook_result_t port_available_changed (void *hook_data,
270                                                 void *call_data,
271                                                 void *slot_data)
272 {
273         return PA_HOOK_OK;
274 }
275
276 static pa_hook_result_t sink_put (void *hook_data,
277                                   void *call_data,
278                                   void *slot_data)
279 {
280         return PA_HOOK_OK;
281 }
282
283 static pa_hook_result_t sink_unlink (void *hook_data,
284                                      void *call_data,
285                                      void *slot_data)
286 {
287         return PA_HOOK_OK;
288 }
289
290 static pa_hook_result_t sink_port_changed (void *hook_data,
291                                            void *call_data,
292                                            void *slot_data)
293 {
294         return PA_HOOK_OK;
295 }
296
297 static pa_hook_result_t source_put (void *hook_data,
298                                     void *call_data,
299                                     void *slot_data)
300 {
301         return PA_HOOK_OK;
302 }
303
304 static pa_hook_result_t source_unlink (void *hook_data,
305                                        void *call_data,
306                                        void *slot_data)
307 {
308         return PA_HOOK_OK;
309 }
310
311 static pa_hook_result_t source_port_changed (void *hook_data,
312                                              void *call_data,
313                                              void *slot_data)
314 {
315         return PA_HOOK_OK;
316 }
317
318 static pa_hook_result_t sink_input_new (void *hook_data,
319                                         void *call_data,
320                                         void *slot_data)
321 {
322         /* main hook, called by each client in its 1st phase */
323         pa_sink_input_new_data *data = (pa_sink_input_new_data *)call_data;
324         struct userdata *u = (struct userdata *)slot_data;
325         bool success;
326
327         success = pa_discover_preroute_sink_input (u, data);
328
329         return success ? PA_HOOK_OK : PA_HOOK_CANCEL;
330 }
331
332 static pa_hook_result_t sink_input_put (void *hook_data,
333                                         void *call_data,
334                                         void *slot_data)
335 {
336         /* called by each client in its 2nd phase */
337         pa_sink_input *sinp = (pa_sink_input *)call_data;
338         struct userdata *u = (struct userdata *)slot_data;
339
340         pa_discover_add_sink_input (u, sinp);
341
342         return PA_HOOK_OK;
343 }
344
345 static pa_hook_result_t sink_input_unlink (void *hook_data,
346                                            void *call_data,
347                                            void *slot_data)
348 {
349         /* called by each client when stopping sound */
350         pa_sink_input *sinp = (pa_sink_input *)call_data;
351         struct userdata *u = (struct userdata *)slot_data;
352
353         pa_discover_remove_sink_input (u, sinp);
354
355         return PA_HOOK_OK;
356 }
357
358 static pa_hook_result_t source_output_new (void *hook_data,
359                                            void *call_data,
360                                            void *slot_data)
361 {
362         return PA_HOOK_OK;
363 }
364
365 static pa_hook_result_t source_output_put (void *hook_data,
366                                            void *call_data,
367                                            void *slot_data)
368 {
369         return PA_HOOK_OK;
370 }
371
372 static pa_hook_result_t source_output_unlink (void *hook_data,
373                                               void *call_data,
374                                               void *slot_data)
375 {
376         return PA_HOOK_OK;
377 }