26fc0d9041d317362a4c0f97d0bd2a830522f36b
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / tracker.c
1 /*
2  * module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU Lesser General Public License,
7  * version 2.1, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <pulsecore/pulsecore-config.h>
21
22 #include <pulse/def.h>
23 #include <pulsecore/sink.h>
24 #include <pulsecore/card.h>
25
26 #include "tracker.h"
27 #include "utils.h"
28 #include "discover.h"
29 #include "router.h"
30 #include "node.h"
31
32
33 struct pa_card_hooks {
34     pa_hook_slot    *put;
35     pa_hook_slot    *unlink;
36     pa_hook_slot    *profchg;
37 };
38
39 struct pa_port_hooks {
40     pa_hook_slot    *avail;
41 };
42
43 struct pa_sink_hooks {
44     pa_hook_slot    *put;
45     pa_hook_slot    *unlink;
46     pa_hook_slot    *portchg;
47 };
48
49 struct pa_source_hooks {
50     pa_hook_slot    *put;
51     pa_hook_slot    *unlink;
52     pa_hook_slot    *portchg;
53 };
54
55 struct pa_sink_input_hooks {
56     pa_hook_slot    *neew;
57     pa_hook_slot    *put;
58     pa_hook_slot    *unlink;
59 };
60
61 struct pa_source_output_hooks {
62     pa_hook_slot    *neew;
63     pa_hook_slot    *put;
64     pa_hook_slot    *unlink;
65 };
66
67
68 struct pa_tracker {
69     pa_card_hooks           card;
70     pa_port_hooks           port;
71     pa_sink_hooks           sink;
72     pa_source_hooks         source;
73     pa_sink_input_hooks     sink_input;
74     pa_source_output_hooks  source_output;
75 };
76
77
78 static pa_hook_result_t card_put(void *, void *, void *);
79 static pa_hook_result_t card_unlink(void *, void *, void *);
80 static pa_hook_result_t card_profile_changed(void *, void *, void *);
81
82 static pa_hook_result_t port_available_changed(void *, void *, void *);
83
84 static pa_hook_result_t sink_put(void *, void *, void *);
85 static pa_hook_result_t sink_unlink(void *, void *, void *);
86 static pa_hook_result_t sink_port_changed(void *, void *, void *);
87
88 static pa_hook_result_t source_put(void *, void *, void *);
89 static pa_hook_result_t source_unlink(void *, void *, void *);
90 static pa_hook_result_t source_port_changed(void *, void *, void *);
91
92 static pa_hook_result_t sink_input_new(void *, void *, void *);
93 static pa_hook_result_t sink_input_put(void *, void *, void *);
94 static pa_hook_result_t sink_input_unlink(void *, void *, void *);
95
96 static pa_hook_result_t source_output_new(void *, void *, void *);
97 static pa_hook_result_t source_output_put(void *, void *, void *);
98 static pa_hook_result_t source_output_unlink(void *, void *, void *);
99
100
101 pa_tracker *pa_tracker_init(struct userdata *u)
102 {
103     pa_core                *core;
104     pa_hook                *hooks;
105     pa_tracker             *tracker;
106     pa_card_hooks          *card;
107     pa_port_hooks          *port;
108     pa_sink_hooks          *sink;
109     pa_source_hooks        *source;
110     pa_sink_input_hooks    *sinp;
111     pa_source_output_hooks *sout;
112
113     pa_assert(u);
114     pa_assert_se((core = u->core));
115     pa_assert_se((hooks = core->hooks));
116
117     tracker = pa_xnew0(pa_tracker, 1);
118     card   = &tracker->card;
119     port   = &tracker->port;
120     sink   = &tracker->sink;
121     source = &tracker->source;
122     sinp   = &tracker->sink_input;
123     sout   = &tracker->source_output;
124
125     /* card */
126     card->put     = pa_hook_connect(
127                         hooks + PA_CORE_HOOK_CARD_PUT,
128                         PA_HOOK_LATE, card_put, u
129                     );
130     card->unlink  = pa_hook_connect(
131                         hooks + PA_CORE_HOOK_CARD_UNLINK,
132                         PA_HOOK_LATE, card_unlink, u
133                     );
134     card->profchg = pa_hook_connect(
135                         hooks + PA_CORE_HOOK_CARD_PROFILE_CHANGED,
136                         PA_HOOK_LATE, card_profile_changed, u
137                     );
138     /* port */
139     port->avail = pa_hook_connect(
140                       hooks + PA_CORE_HOOK_PORT_AVAILABLE_CHANGED,
141                       PA_HOOK_LATE, port_available_changed, u
142                   );
143     /* sink */
144     sink->put     = pa_hook_connect(
145                         hooks + PA_CORE_HOOK_SINK_PUT,
146                         PA_HOOK_LATE, sink_put, u
147                     );
148     sink->unlink  = pa_hook_connect(
149                         hooks + PA_CORE_HOOK_SINK_UNLINK,
150                         PA_HOOK_LATE, sink_unlink, u
151                     );
152     sink->portchg = pa_hook_connect(
153                         hooks + PA_CORE_HOOK_SINK_PORT_CHANGED,
154                         PA_HOOK_LATE, sink_port_changed, u
155                     );
156     /* source */
157     source->put     = pa_hook_connect(
158                           hooks + PA_CORE_HOOK_SOURCE_PUT,
159                           PA_HOOK_LATE, source_put, u
160                       );
161     source->unlink  = pa_hook_connect(
162                           hooks + PA_CORE_HOOK_SOURCE_UNLINK,
163                           PA_HOOK_LATE, source_unlink, u
164                       );
165     source->portchg = pa_hook_connect(
166                           hooks + PA_CORE_HOOK_SOURCE_PORT_CHANGED,
167                           PA_HOOK_LATE, source_port_changed, u
168                       );
169     /* sink-input */
170     sinp->neew   = pa_hook_connect(
171                        hooks + PA_CORE_HOOK_SINK_INPUT_NEW,
172                        PA_HOOK_EARLY, sink_input_new, u
173                    );
174     sinp->put    = pa_hook_connect(
175                        hooks + PA_CORE_HOOK_SINK_INPUT_PUT,
176                        PA_HOOK_LATE, sink_input_put, u
177                    );
178     sinp->unlink = pa_hook_connect(
179                        hooks + PA_CORE_HOOK_SINK_INPUT_UNLINK,
180                        PA_HOOK_LATE, sink_input_unlink, u
181                    );
182     
183     /* source-output */
184     sout->neew   = pa_hook_connect(
185                        hooks + PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
186                        PA_HOOK_EARLY, source_output_new, u
187                    );
188     sout->put    = pa_hook_connect(
189                        hooks + PA_CORE_HOOK_SOURCE_OUTPUT_PUT,
190                        PA_HOOK_LATE, source_output_put, u
191                    );
192     sout->unlink = pa_hook_connect(
193                        hooks + PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK,
194                        PA_HOOK_LATE, source_output_unlink, u
195                    );
196     
197     return tracker;
198 }
199
200 void pa_tracker_done(struct userdata *u)
201 {
202     pa_tracker          *tracker;
203     pa_card_hooks       *card;
204     pa_port_hooks       *port;
205     pa_sink_hooks       *sink;
206     pa_source_hooks     *source;
207     pa_sink_input_hooks *sinp;
208
209     if (u && (tracker = u->tracker)) {
210
211         card = &tracker->card;
212         pa_hook_slot_free(card->put);
213         pa_hook_slot_free(card->unlink);
214         pa_hook_slot_free(card->profchg);
215
216         port = &tracker->port;
217         pa_hook_slot_free(port->avail);
218         
219         sink = &tracker->sink;
220         pa_hook_slot_free(sink->put);
221         pa_hook_slot_free(sink->unlink);
222         pa_hook_slot_free(sink->portchg);
223         
224         source = &tracker->source;
225         pa_hook_slot_free(source->put);
226         pa_hook_slot_free(source->unlink);
227         pa_hook_slot_free(source->portchg);
228         
229         sinp = &tracker->sink_input;
230         pa_hook_slot_free(sinp->neew);
231         pa_hook_slot_free(sinp->put);
232         pa_hook_slot_free(sinp->unlink);
233
234         pa_xfree(tracker);
235         
236         u->tracker = NULL;
237     }
238 }
239
240 void pa_tracker_synchronize(struct userdata *u)
241 {
242     pa_core          *core;
243     pa_card          *card;
244     pa_sink          *sink;
245     pa_source        *source;
246     pa_sink_input    *sinp;
247     pa_source_output *sout;
248     uint32_t          index;
249
250     pa_assert(u);
251     pa_assert_se((core = u->core));
252
253
254     PA_IDXSET_FOREACH(card, core->cards, index) {
255         pa_discover_add_card(u, card);
256     }
257
258     PA_IDXSET_FOREACH(sink, core->sinks, index) {
259         pa_discover_add_sink(u, sink, FALSE);
260     }
261
262     PA_IDXSET_FOREACH(source, core->sources, index) {
263         pa_discover_add_source(u, source);
264     }
265
266     /* Hmm... we should first collect all sink-inputs & source-outputs, assign
267        priority to them, sort them, and call pa_discover_register_sink_input()
268        in reverse priority order. Until than we may experience sound leaks
269        unnecessary profile changes etc ... */
270
271     PA_IDXSET_FOREACH(sinp, core->sink_inputs, index) {
272         pa_discover_register_sink_input(u, sinp);
273     }
274
275     PA_IDXSET_FOREACH(sout, core->source_outputs, index) {
276         pa_discover_register_source_output(u, sout);
277     }
278
279     mir_router_make_routing(u);
280 }
281
282
283 static pa_hook_result_t card_put(void *hook_data,
284                                  void *call_data,
285                                  void *slot_data)
286 {
287     pa_card *card = (pa_card *)call_data;
288     struct userdata *u = (struct userdata *)slot_data;
289
290     pa_assert(u);
291     pa_assert(card);
292
293     pa_discover_add_card(u, card);
294
295     return PA_HOOK_OK;
296 }
297
298 static pa_hook_result_t card_unlink(void *hook_data,
299                                     void *call_data,
300                                     void *slot_data)
301 {
302     pa_card  *card = (pa_card *)call_data;
303     struct userdata *u = (struct userdata *)slot_data;
304     char buf[4096];
305
306     pa_assert(u);
307     pa_assert(card);
308
309     pa_discover_remove_card(u, card);
310
311     mir_router_print_rtgroups(u, buf, sizeof(buf));
312     pa_log_debug("%s", buf);
313
314     mir_router_make_routing(u);
315
316     return PA_HOOK_OK;
317 }
318
319
320 static pa_hook_result_t card_profile_changed(void *hook_data,
321                                              void *call_data,
322                                              void *slot_data)
323 {
324     pa_card  *card = (pa_card *)call_data;
325     struct userdata *u = (struct userdata *)slot_data;
326
327     pa_assert(u);
328     pa_assert(card);
329
330     pa_discover_profile_changed(u, card);
331
332     return PA_HOOK_OK;
333 }
334
335
336 static pa_hook_result_t port_available_changed(void *hook_data,
337                                                void *call_data,
338                                                void *slot_data)
339 {
340     pa_device_port *port = (pa_device_port *)call_data;
341     struct userdata *u = (struct userdata *)slot_data;
342
343     pa_assert(u);
344     pa_assert(port);
345
346     pa_discover_port_available_changed(u, port);
347
348     return PA_HOOK_OK;
349 }
350
351
352
353 static pa_hook_result_t sink_put(void *hook_data,
354                                  void *call_data,
355                                  void *slot_data)
356 {
357     pa_sink *sink = (pa_sink *)call_data;
358     struct userdata *u = (struct userdata *)slot_data;
359
360     pa_assert(u);
361     pa_assert(sink);
362
363     pa_discover_add_sink(u, sink, TRUE);
364
365     return PA_HOOK_OK;
366 }
367
368
369 static pa_hook_result_t sink_unlink(void *hook_data,
370                                     void *call_data,
371                                     void *slot_data)
372 {
373     pa_sink *sink = (pa_sink *)call_data;
374     struct userdata *u = (struct userdata *)slot_data;
375
376     pa_assert(u);
377     pa_assert(sink);
378
379     pa_discover_remove_sink(u, sink);
380
381     return PA_HOOK_OK;
382 }
383
384
385 static pa_hook_result_t sink_port_changed(void *hook_data,
386                                           void *call_data,
387                                           void *slot_data)
388 {
389     pa_sink *sink = (pa_sink *)call_data;
390     struct userdata *u = (struct userdata *)slot_data;
391
392     pa_assert(u);
393     pa_assert(sink);
394
395     return PA_HOOK_OK;
396 }
397
398
399
400 static pa_hook_result_t source_put(void *hook_data,
401                                    void *call_data,
402                                    void *slot_data)
403 {
404     pa_source *source = (pa_source *)call_data;
405     struct userdata *u = (struct userdata *)slot_data;
406
407     pa_assert(u);
408     pa_assert(source);
409
410     pa_discover_add_source(u, source);
411
412     return PA_HOOK_OK;
413 }
414
415
416 static pa_hook_result_t source_unlink(void *hook_data,
417                                       void *call_data,
418                                       void *slot_data)
419 {
420     pa_source *source = (pa_source *)call_data;
421     struct userdata *u = (struct userdata *)slot_data;
422
423     pa_assert(u);
424     pa_assert(source);
425
426     pa_discover_remove_source(u, source);
427
428     return PA_HOOK_OK;
429 }
430
431
432 static pa_hook_result_t source_port_changed(void *hook_data,
433                                             void *call_data,
434                                             void *slot_data)
435 {
436     pa_source *source = (pa_source *)call_data;
437     struct userdata *u = (struct userdata *)slot_data;
438
439     pa_assert(u);
440     pa_assert(source);
441
442     return PA_HOOK_OK;
443 }
444
445
446
447 static pa_hook_result_t sink_input_new(void *hook_data,
448                                        void *call_data,
449                                        void *slot_data)
450 {
451     pa_sink_input_new_data *data = (pa_sink_input_new_data *)call_data;
452     struct userdata *u = (struct userdata *)slot_data;
453
454     pa_assert(u);
455     pa_assert(data);
456
457     pa_discover_preroute_sink_input(u, data);
458
459     return PA_HOOK_OK;
460 }
461
462 static pa_hook_result_t sink_input_put(void *hook_data,
463                                        void *call_data,
464                                        void *slot_data)
465 {
466     pa_sink_input *sinp = (pa_sink_input *)call_data;
467     struct userdata *u = (struct userdata *)slot_data;
468
469     pa_assert(u);
470     pa_assert(sinp);
471
472     pa_discover_add_sink_input(u, sinp);
473
474     return PA_HOOK_OK;
475 }
476
477
478 static pa_hook_result_t sink_input_unlink(void *hook_data,
479                                           void *call_data,
480                                           void *slot_data)
481 {
482     struct pa_sink_input *sinp = (pa_sink_input *)call_data;
483     struct userdata *u = (struct userdata *)slot_data;
484
485     pa_assert(u);
486     pa_assert(sinp);
487
488     pa_discover_remove_sink_input(u, sinp);
489
490     return PA_HOOK_OK;
491 }
492
493
494 static pa_hook_result_t source_output_new(void *hook_data,
495                                           void *call_data,
496                                           void *slot_data)
497 {
498     pa_source_output_new_data *data = (pa_source_output_new_data *)call_data;
499     struct userdata *u = (struct userdata *)slot_data;
500
501     pa_assert(u);
502     pa_assert(data);
503
504     pa_discover_preroute_source_output(u, data);
505
506     return PA_HOOK_OK;
507 }
508
509 static pa_hook_result_t source_output_put(void *hook_data,
510                                           void *call_data,
511                                           void *slot_data)
512 {
513     pa_source_output *sout = (pa_source_output *)call_data;
514     struct userdata *u = (struct userdata *)slot_data;
515
516     pa_assert(u);
517     pa_assert(sout);
518
519     pa_discover_add_source_output(u, sout);
520
521     return PA_HOOK_OK;
522 }
523
524
525 static pa_hook_result_t source_output_unlink(void *hook_data,
526                                              void *call_data,
527                                              void *slot_data)
528 {
529     struct pa_source_output *sout = (pa_source_output *)call_data;
530     struct userdata *u = (struct userdata *)slot_data;
531
532     pa_assert(u);
533     pa_assert(sout);
534
535     pa_discover_remove_source_output(u, sout);
536
537     return PA_HOOK_OK;
538 }
539
540
541 /*
542  * Local Variables:
543  * c-basic-offset: 4
544  * indent-tabs-mode: nil
545  * End:
546  *
547  */
548