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