calssification: more heuristics to guess bluetooth device classes
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / multiplex.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 <stdio.h>
21 #include <stdlib.h>
22 #include <strings.h>
23
24 #include <pulsecore/pulsecore-config.h>
25
26 #include <pulse/def.h>
27 #include <pulsecore/thread.h>
28 #include <pulsecore/strlist.h>
29 #include <pulsecore/time-smoother.h>
30 #include <pulsecore/sink.h>
31 #include <pulsecore/sink-input.h>
32
33 #include <combine/userdata.h>
34
35 #include "multiplex.h"
36 #include "utils.h"
37
38 #ifndef DEFAULT_RESAMPLER
39 #define DEFAULT_RESAMPLER "speex-fixed-3"
40 #endif
41
42
43 static void copy_media_role_property(pa_sink *, pa_sink_input *);
44
45
46 pa_multiplex *pa_multiplex_init(void)
47 {
48     pa_multiplex *multiplex = pa_xnew0(pa_multiplex, 1);
49
50     return multiplex;
51 }
52
53
54 void pa_multiplex_done(pa_multiplex *multiplex, pa_core *core)
55 {
56     pa_muxnode *mux, *n;
57
58     PA_LLIST_FOREACH_SAFE(mux,n, multiplex->muxnodes) {
59         pa_module_unload_by_index(core, mux->module_index, FALSE);
60     }
61 }
62
63
64
65 pa_muxnode *pa_multiplex_create(pa_multiplex   *multiplex,
66                                 pa_core        *core,
67                                 uint32_t        sink_index,
68                                 pa_channel_map *chmap,
69                                 const char     *resampler,
70                                 const char     *media_role,
71                                 int             type)
72 {
73     static char *modnam = "module-combine-sink";
74
75     struct userdata *u;         /* combine's userdata! */
76     struct output   *o;
77     pa_muxnode      *mux;
78     pa_sink         *sink;
79     pa_sink_input   *sinp;
80     pa_module       *module;
81     char             args[512];
82     uint32_t         idx;
83     uint32_t         channels;
84
85     pa_assert(core);
86
87     if (!resampler)
88         resampler = DEFAULT_RESAMPLER;
89
90     if (!(sink = pa_idxset_get_by_index(core->sinks, sink_index))) {
91         pa_log_debug("can't find the primary sink (index %u) for multiplexer",
92                      sink_index);
93         return NULL;
94     }
95
96     channels = chmap->channels ? chmap->channels : sink->channel_map.channels;
97
98     snprintf(args, sizeof(args), "slaves=\"%s\" resample_method=\"%s\" "
99              "channels=%u", sink->name, resampler, channels);
100
101     if (!(module = pa_module_load(core, modnam, args))) {
102         pa_log("failed to load module '%s %s'. can't multiplex", modnam, args);
103         return NULL;
104     }
105
106     pa_assert_se((u = module->userdata));
107     pa_assert(u->sink);
108
109     u->no_reattach = TRUE;
110
111     mux = pa_xnew0(pa_muxnode, 1);
112     mux->module_index = module->index;
113     mux->sink_index = u->sink->index;
114     mux->defstream_index = PA_IDXSET_INVALID;
115
116     PA_LLIST_PREPEND(pa_muxnode, multiplex->muxnodes, mux);
117
118     if (!(o = pa_idxset_first(u->outputs, &idx)))
119         pa_log("can't find default multiplexer stream");
120     else {
121         if ((sinp = o->sink_input)) {
122             if (media_role)
123                 pa_proplist_sets(sinp->proplist,PA_PROP_MEDIA_ROLE,media_role);
124             pa_utils_set_stream_routing_properties(sinp->proplist, type, NULL);
125             mux->defstream_index = sinp->index;
126         }
127     }
128
129     pa_log_debug("multiplexer succesfully loaded");
130
131     return mux;
132 }
133
134
135 void pa_multiplex_destroy(pa_multiplex *multiplex,
136                           pa_core      *core,
137                           pa_muxnode   *mux)
138 {
139     pa_assert(multiplex);
140     pa_assert(core);
141
142     if (mux) {
143         PA_LLIST_REMOVE(pa_muxnode, multiplex->muxnodes, mux);
144         pa_module_unload_by_index(core, mux->module_index, FALSE);
145         pa_xfree(mux);
146     }
147 }
148
149
150 pa_muxnode *pa_multiplex_find(pa_multiplex *multiplex, uint32_t sink_index)
151 {
152     pa_muxnode *mux;
153
154     if (sink_index != PA_IDXSET_INVALID) {
155         PA_LLIST_FOREACH(mux, multiplex->muxnodes) {
156             if (sink_index == mux->sink_index) {
157                 pa_log_debug("muxnode found for sink %u", sink_index);
158                 return mux;
159             }
160         }
161     }
162
163     pa_log_debug("can't find muxnode for sink %u", sink_index);
164
165     return NULL;
166 }
167
168
169 pa_bool_t pa_multiplex_add_default_route(pa_core    *core,
170                                          pa_muxnode *mux,
171                                          pa_sink    *sink,
172                                          int         type)
173 {
174     pa_module *module;
175     pa_sink_input *sinp;
176     struct userdata *u;         /* combine's userdata! */
177
178     pa_assert(core);
179     pa_assert(mux);
180     pa_assert(sink);
181
182     if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
183         pa_log("module %u is gone", mux->module_index);
184     else {
185         pa_assert_se((u = module->userdata));
186
187         if (sink == u->sink) {
188             pa_log("%s: mux %d refuses to make a loopback to itself",
189                    __FILE__, mux->module_index);
190         }
191         else {
192             pa_log_debug("adding default route to mux %u", mux->module_index);
193
194             if (!(sinp = u->add_slave(u, sink))) {
195                 pa_log("failed to add new slave to mux %u", mux->module_index);
196                 return FALSE;
197             }
198
199             copy_media_role_property(u->sink, sinp);
200             pa_utils_set_stream_routing_properties(sinp->proplist, type, NULL);
201             mux->defstream_index = sinp->index;
202
203             return TRUE;
204         }
205     }
206
207     return FALSE;
208 }
209
210 pa_bool_t pa_multiplex_remove_default_route(pa_core *core,
211                                             pa_muxnode *mux,
212                                             pa_bool_t transfer_to_explicit)
213 {
214     pa_module       *module;
215     pa_sink_input   *sinp;
216     uint32_t         idx;
217     struct userdata *u;         /* combine's userdata! */
218
219     pa_assert(core);
220     pa_assert(mux);
221
222     if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
223         pa_log("module %u is gone", mux->module_index);
224     else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
225         pa_log_debug("mux %u do not have default stream", mux->module_index);
226     else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
227         pa_log("can't remove default route: sink-input %u is gone", idx);
228     else {
229         pa_assert_se((u = module->userdata));
230         mux->defstream_index = PA_IDXSET_INVALID;
231
232         if (transfer_to_explicit) {
233             pa_log_debug("converting default route sink-input.%u -> sink.%u "
234                          "to explicit", sinp->index, sinp->sink->index);
235             pa_utils_set_stream_routing_method_property(sinp->proplist, TRUE);
236             return TRUE;
237         }
238         else {
239             u->remove_slave(u, sinp, NULL);
240         }
241     }
242
243     return FALSE;
244 }
245
246 pa_bool_t pa_multiplex_change_default_route(pa_core    *core,
247                                             pa_muxnode *mux,
248                                             pa_sink    *sink)
249 {
250     pa_module       *module;
251     pa_sink_input   *sinp;
252     uint32_t         idx;
253     struct userdata *u;         /* combine's userdata! */
254
255     pa_assert(core);
256     pa_assert(mux);
257     pa_assert(sink);
258
259     if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
260         pa_log("module %u is gone", mux->module_index);
261     else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
262         pa_log_debug("mux %u do not have default stream", mux->module_index);
263     else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
264         pa_log("can't remove default route: sink-input %u is gone", idx);
265     else {
266         pa_assert_se((u = module->userdata));
267         if (!u->move_slave(u, sinp, sink))
268             pa_log_debug("failed to move default stream on mux %u", mux->module_index);
269         else {
270             pa_log_debug("default stream was successfully moved on mux %u",
271                          mux->module_index);
272             return TRUE;
273         }
274     }
275
276     return FALSE;
277 }
278
279
280 pa_bool_t pa_multiplex_add_explicit_route(pa_core    *core,
281                                           pa_muxnode *mux,
282                                           pa_sink    *sink,
283                                           int         type)
284 {
285     pa_module *module;
286     pa_sink_input *sinp;
287     struct userdata *u;         /* combine's userdata! */
288
289     pa_assert(core);
290     pa_assert(mux);
291     pa_assert(sink);
292
293     if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
294         pa_log("module %u is gone", mux->module_index);
295     else {
296         pa_assert_se((u = module->userdata));
297
298         if (sink == u->sink) {
299             pa_log("%s: mux %d refuses to make a loopback to itself",
300                    __FILE__, mux->module_index);
301         }
302         else {
303             pa_log_debug("adding explicit route to mux %u", mux->module_index);
304
305             if (!(sinp = u->add_slave(u, sink))) {
306                 pa_log("failed to add new slave to mux %u", mux->module_index);
307                 return FALSE;
308             }
309
310             copy_media_role_property(u->sink, sinp);
311             pa_utils_set_stream_routing_properties(sinp->proplist, type, sink);
312
313             return TRUE;
314         }
315     }
316
317     return FALSE;
318 }
319
320
321 pa_bool_t pa_multiplex_remove_explicit_route(pa_core    *core,
322                                              pa_muxnode *mux,
323                                              pa_sink    *sink)
324 {
325     pa_module *module;
326     struct userdata *u;         /* combine's userdata! */
327
328     pa_assert(core);
329     pa_assert(mux);
330     pa_assert(sink);
331
332     if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
333         pa_log("module %u is gone", mux->module_index);
334     else {
335         pa_assert_se((u = module->userdata));
336
337         u->remove_slave(u, NULL, sink);
338
339         pa_log_debug("link to sink.%u removed", sink->index);
340
341         return TRUE;
342     }
343
344     return FALSE;
345 }
346
347
348 pa_bool_t pa_multiplex_duplicate_route(pa_core       *core,
349                                        pa_muxnode    *mux,
350                                        pa_sink_input *sinp,
351                                        pa_sink       *sink)
352 {
353     pa_module       *module;
354     struct userdata *u;   /* combine's userdata! */
355     struct output   *o;
356     uint32_t         idx;
357     pa_sink_input   *i;
358
359     pa_assert(core);
360     pa_assert(mux);
361     pa_assert(sink);
362
363     pa_log_debug("check for duplicate route on mux %u",
364                  mux->module_index);
365
366     if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index)))
367         pa_log("module %u is gone", mux->module_index);
368     else {
369         pa_assert_se((u = module->userdata));
370
371         PA_IDXSET_FOREACH(o, u->outputs, idx) {
372             if (!(i = o->sink_input))
373                 continue;
374             if (sinp && i == sinp)
375                 continue;
376             if (i->sink == sink) {
377                 pa_log_debug("route sink-input.%u -> sink.%u is a duplicate",
378                              i->index, sink->index);
379                 return TRUE;
380             }
381         }
382
383         if (!sinp)
384             pa_log_debug("no duplicate route found to sink.%u", sink->index);
385         else {
386             pa_log_debug("no duplicate found for route sink-input.%u -> "
387                          "sink.%u", sinp->index, sink->index);
388         }
389     }
390         
391     return FALSE;
392 }
393
394 int pa_multiplex_no_of_routes(pa_core *core, pa_muxnode *mux)
395 {
396     pa_module       *module;
397     struct userdata *u;   /* combine's userdata! */
398
399     pa_assert(core);
400     pa_assert(mux);
401
402     if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index))) {
403         pa_log("module %u is gone", mux->module_index);
404         return -1;
405     }
406
407     pa_assert_se((u = module->userdata));
408
409     return (int)pa_idxset_size(u->outputs);
410 }
411
412
413 int pa_multiplex_print(pa_muxnode *mux, char *buf, int len)
414 {
415     char *p, *e;
416
417     pa_assert(buf);
418     pa_assert(len > 0);
419
420     e = (p = buf) + len;
421
422     if (!mux)
423         p += snprintf(p, e-p, "<not set>");
424     else {
425         p += snprintf(p, e-p, "module %u, sink %u, default stream %u",
426                       mux->module_index, mux->sink_index,mux->defstream_index);
427     }
428     
429     return p - buf;
430 }
431
432 static void copy_media_role_property(pa_sink *sink, pa_sink_input *to)
433 {
434     uint32_t index;
435     pa_sink_input *from;
436     const char *role;
437
438     pa_assert(to);
439
440     if (sink && (from = pa_idxset_first(sink->inputs, &index))) {
441         pa_assert(from->proplist);
442         pa_assert(to->proplist);
443
444         if ((role = pa_proplist_gets(from->proplist, PA_PROP_MEDIA_ROLE)) &&
445             pa_proplist_sets(to->proplist, PA_PROP_MEDIA_ROLE, role) == 0)
446         {
447             pa_log_debug("set media.role=\"%s\" on sink_input.%d",
448                          role, to->index);
449             return;
450         }
451     }
452
453     pa_log_debug("failed to set media.role on sink_input.%d", to->index);
454 }
455
456
457 /*
458  * Local Variables:
459  * c-basic-offset: 4
460  * indent-tabs-mode: nil
461  * End:
462  *
463  */
464