50d44e8d93feef776a6f9d64823f67a67a81b0d3
[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
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 };
68
69
70 static pa_hook_result_t card_put(void *, void *, void *);
71 static pa_hook_result_t card_unlink(void *, void *, void *);
72 static pa_hook_result_t card_profile_changed(void *, void *, void *);
73
74 static pa_hook_result_t port_available_changed(void *, void *, void *);
75
76 static pa_hook_result_t sink_put(void *, void *, void *);
77 static pa_hook_result_t sink_unlink(void *, void *, void *);
78 static pa_hook_result_t sink_port_changed(void *, void *, void *);
79
80 static pa_hook_result_t source_put(void *, void *, void *);
81 static pa_hook_result_t source_unlink(void *, void *, void *);
82 static pa_hook_result_t source_port_changed(void *, void *, void *);
83
84 static pa_hook_result_t sink_input_new(void *, void *, void *);
85 static pa_hook_result_t sink_input_put(void *, void *, void *);
86 static pa_hook_result_t sink_input_unlink(void *, void *, void *);
87
88
89 pa_tracker *pa_tracker_init(struct userdata *u)
90 {
91     pa_core             *core;
92     pa_hook             *hooks;
93     pa_tracker          *tracker;
94     pa_card_hooks       *card;
95     pa_port_hooks       *port;
96     pa_sink_hooks       *sink;
97     pa_source_hooks     *source;
98     pa_sink_input_hooks *sinp;
99
100     pa_assert(u);
101     pa_assert_se((core = u->core));
102     pa_assert_se((hooks = core->hooks));
103
104     tracker = pa_xnew0(pa_tracker, 1);
105     card   = &tracker->card;
106     port   = &tracker->port;
107     sink   = &tracker->sink;
108     source = &tracker->source;
109     sinp   = &tracker->sink_input;
110
111     /* card */
112     card->put     = pa_hook_connect(
113                         hooks + PA_CORE_HOOK_CARD_PUT,
114                         PA_HOOK_LATE, card_put, u
115                     );
116     card->unlink  = pa_hook_connect(
117                         hooks + PA_CORE_HOOK_CARD_UNLINK,
118                         PA_HOOK_LATE, card_unlink, u
119                     );
120     card->profchg = pa_hook_connect(
121                         hooks + PA_CORE_HOOK_CARD_PROFILE_CHANGED,
122                         PA_HOOK_LATE, card_profile_changed, u
123                     );
124     /* port */
125     port->avail = pa_hook_connect(
126                       hooks + PA_CORE_HOOK_PORT_AVAILABLE_CHANGED,
127                       PA_HOOK_LATE, port_available_changed, u
128                   );
129     /* sink */
130     sink->put     = pa_hook_connect(
131                         hooks + PA_CORE_HOOK_SINK_PUT,
132                         PA_HOOK_LATE, sink_put, u
133                     );
134     sink->unlink  = pa_hook_connect(
135                         hooks + PA_CORE_HOOK_SINK_UNLINK,
136                         PA_HOOK_LATE, sink_unlink, u
137                     );
138     sink->portchg = pa_hook_connect(
139                         hooks + PA_CORE_HOOK_SINK_PORT_CHANGED,
140                         PA_HOOK_LATE, sink_port_changed, u
141                     );
142     /* source */
143     source->put     = pa_hook_connect(
144                           hooks + PA_CORE_HOOK_SOURCE_PUT,
145                           PA_HOOK_LATE, source_put, u
146                       );
147     source->unlink  = pa_hook_connect(
148                           hooks + PA_CORE_HOOK_SOURCE_UNLINK,
149                           PA_HOOK_LATE, source_unlink, u
150                       );
151     source->portchg = pa_hook_connect(
152                           hooks + PA_CORE_HOOK_SOURCE_PORT_CHANGED,
153                           PA_HOOK_LATE, source_port_changed, u
154                       );
155     /* sink-input */
156     sinp->neew   = pa_hook_connect(
157                        hooks + PA_CORE_HOOK_SINK_INPUT_NEW,
158                        PA_HOOK_EARLY, sink_input_new, u
159                    );
160     sinp->put    = pa_hook_connect(
161                        hooks + PA_CORE_HOOK_SINK_INPUT_PUT,
162                        PA_HOOK_LATE, sink_input_put, u
163                    );
164     sinp->unlink = pa_hook_connect(
165                        hooks + PA_CORE_HOOK_SINK_INPUT_UNLINK,
166                        PA_HOOK_LATE, sink_input_unlink, u
167                    );
168     
169     return tracker;
170 }
171
172 void pa_tracker_done(struct userdata *u)
173 {
174     pa_tracker          *tracker;
175     pa_card_hooks       *card;
176     pa_port_hooks       *port;
177     pa_sink_hooks       *sink;
178     pa_source_hooks     *source;
179     pa_sink_input_hooks *sinp;
180
181     if (u && (tracker = u->tracker)) {
182
183         card = &tracker->card;
184         pa_hook_slot_free(card->put);
185         pa_hook_slot_free(card->unlink);
186         pa_hook_slot_free(card->profchg);
187
188         port = &tracker->port;
189         pa_hook_slot_free(port->avail);
190         
191         sink = &tracker->sink;
192         pa_hook_slot_free(sink->put);
193         pa_hook_slot_free(sink->unlink);
194         pa_hook_slot_free(sink->portchg);
195         
196         source = &tracker->source;
197         pa_hook_slot_free(source->put);
198         pa_hook_slot_free(source->unlink);
199         pa_hook_slot_free(source->portchg);
200         
201         sinp = &tracker->sink_input;
202         pa_hook_slot_free(sinp->neew);
203         pa_hook_slot_free(sinp->put);
204         pa_hook_slot_free(sinp->unlink);
205
206         pa_xfree(tracker);
207         
208         u->tracker = NULL;
209     }
210 }
211
212 void pa_tracker_synchronize(struct userdata *u)
213 {
214     pa_core       *core;
215     pa_card       *card;
216     pa_sink       *sink;
217     pa_source     *source;
218     pa_sink_input *sinp;
219     uint32_t       index;
220
221     pa_assert(u);
222     pa_assert_se((core = u->core));
223
224
225     PA_IDXSET_FOREACH(card, core->cards, index) {
226         pa_discover_add_card(u, card);
227     }
228
229     PA_IDXSET_FOREACH(sink, core->sinks, index) {
230         pa_discover_add_sink(u, sink, FALSE);
231     }
232
233     PA_IDXSET_FOREACH(source, core->sources, index) {
234         pa_discover_add_source(u, source);
235     }
236
237     /* Hmm... we should first collect all sink-inputs, assign
238        priority to them, sort them, and call pa_discover_register_sink_input()
239        in reverse priority order. Until than we may experience sound leaks
240        unnecessary profile changes etc ... */
241
242     PA_IDXSET_FOREACH(sinp, core->sink_inputs, index) {
243         pa_discover_register_sink_input(u, sinp);
244     }
245
246     mir_router_make_routing(u);
247 }
248
249
250 static pa_hook_result_t card_put(void *hook_data,
251                                  void *call_data,
252                                  void *slot_data)
253 {
254     pa_card *card = (pa_card *)call_data;
255     struct userdata *u = (struct userdata *)slot_data;
256
257     pa_assert(u);
258     pa_assert(card);
259
260     pa_discover_add_card(u, card);
261
262     return PA_HOOK_OK;
263 }
264
265 static pa_hook_result_t card_unlink(void *hook_data,
266                                     void *call_data,
267                                     void *slot_data)
268 {
269     pa_card  *card = (pa_card *)call_data;
270     struct userdata *u = (struct userdata *)slot_data;
271     char buf[4096];
272
273     pa_assert(u);
274     pa_assert(card);
275
276     pa_discover_remove_card(u, card);
277
278     mir_router_print_rtgroups(u, buf, sizeof(buf));
279     pa_log_debug("%s", buf);
280
281     mir_router_make_routing(u);
282
283     return PA_HOOK_OK;
284 }
285
286
287 static pa_hook_result_t card_profile_changed(void *hook_data,
288                                              void *call_data,
289                                              void *slot_data)
290 {
291     pa_card  *card = (pa_card *)call_data;
292     struct userdata *u = (struct userdata *)slot_data;
293
294     pa_assert(u);
295     pa_assert(card);
296
297     pa_discover_profile_changed(u, card);
298
299     return PA_HOOK_OK;
300 }
301
302
303 static pa_hook_result_t port_available_changed(void *hook_data,
304                                                void *call_data,
305                                                void *slot_data)
306 {
307     pa_device_port *port = (pa_device_port *)call_data;
308     struct userdata *u = (struct userdata *)slot_data;
309
310     pa_assert(u);
311     pa_assert(port);
312
313     pa_discover_port_available_changed(u, port);
314
315     return PA_HOOK_OK;
316 }
317
318
319
320 static pa_hook_result_t sink_put(void *hook_data,
321                                  void *call_data,
322                                  void *slot_data)
323 {
324     pa_sink *sink = (pa_sink *)call_data;
325     struct userdata *u = (struct userdata *)slot_data;
326
327     pa_assert(u);
328     pa_assert(sink);
329
330     pa_discover_add_sink(u, sink, TRUE);
331
332     return PA_HOOK_OK;
333 }
334
335
336 static pa_hook_result_t sink_unlink(void *hook_data,
337                                     void *call_data,
338                                     void *slot_data)
339 {
340     pa_sink *sink = (pa_sink *)call_data;
341     struct userdata *u = (struct userdata *)slot_data;
342
343     pa_assert(u);
344     pa_assert(sink);
345
346     pa_discover_remove_sink(u, sink);
347
348     return PA_HOOK_OK;
349 }
350
351
352 static pa_hook_result_t sink_port_changed(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     return PA_HOOK_OK;
363 }
364
365
366
367 static pa_hook_result_t source_put(void *hook_data,
368                                    void *call_data,
369                                    void *slot_data)
370 {
371     pa_source *source = (pa_source *)call_data;
372     struct userdata *u = (struct userdata *)slot_data;
373
374     pa_assert(u);
375     pa_assert(source);
376
377     pa_discover_add_source(u, source);
378
379     return PA_HOOK_OK;
380 }
381
382
383 static pa_hook_result_t source_unlink(void *hook_data,
384                                       void *call_data,
385                                       void *slot_data)
386 {
387     pa_source *source = (pa_source *)call_data;
388     struct userdata *u = (struct userdata *)slot_data;
389
390     pa_assert(u);
391     pa_assert(source);
392
393     pa_discover_remove_source(u, source);
394
395     return PA_HOOK_OK;
396 }
397
398
399 static pa_hook_result_t source_port_changed(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     return PA_HOOK_OK;
410 }
411
412
413
414 static pa_hook_result_t sink_input_new(void *hook_data,
415                                        void *call_data,
416                                        void *slot_data)
417 {
418     pa_sink_input_new_data *data = (pa_sink_input_new_data *)call_data;
419     struct userdata *u = (struct userdata *)slot_data;
420
421     pa_assert(u);
422     pa_assert(data);
423
424     pa_discover_preroute_sink_input(u, data);
425
426     return PA_HOOK_OK;
427 }
428
429 static pa_hook_result_t sink_input_put(void *hook_data,
430                                        void *call_data,
431                                        void *slot_data)
432 {
433     pa_sink_input *sinp = (pa_sink_input *)call_data;
434     struct userdata *u = (struct userdata *)slot_data;
435
436     pa_assert(u);
437     pa_assert(sinp);
438
439     pa_discover_add_sink_input(u, sinp);
440
441     return PA_HOOK_OK;
442 }
443
444
445 static pa_hook_result_t sink_input_unlink(void *hook_data,
446                                           void *call_data,
447                                           void *slot_data)
448 {
449     struct pa_sink_input *sinp = (pa_sink_input *)call_data;
450     struct userdata *u = (struct userdata *)slot_data;
451
452     pa_assert(u);
453     pa_assert(sinp);
454
455     pa_discover_remove_sink_input(u, sinp);
456
457     return PA_HOOK_OK;
458 }
459
460
461 /*
462  * Local Variables:
463  * c-basic-offset: 4
464  * indent-tabs-mode: nil
465  * End:
466  *
467  */
468