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