2 * module-murphy-ivi -- PulseAudio module for providing audio routing support
3 * Copyright (c) 2012, Intel Corporation.
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.
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.
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,
24 #include <pulsecore/pulsecore-config.h>
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>
33 #include <combine/userdata.h>
35 #include "multiplex.h"
38 #ifndef DEFAULT_RESAMPLER
39 #define DEFAULT_RESAMPLER "speex-fixed-3"
43 static void copy_media_role_property(pa_sink *, pa_sink_input *);
46 pa_multiplex *pa_multiplex_init(void)
48 pa_multiplex *multiplex = pa_xnew0(pa_multiplex, 1);
54 void pa_multiplex_done(pa_multiplex *multiplex, pa_core *core)
58 PA_LLIST_FOREACH_SAFE(mux,n, multiplex->muxnodes) {
59 pa_module_unload_by_index(core, mux->module_index, false);
65 pa_muxnode *pa_multiplex_create(pa_multiplex *multiplex,
68 pa_channel_map *chmap,
69 const char *resampler,
70 const char *media_role,
73 static char *modnam = "module-combine-sink";
75 struct userdata *u; /* combine's userdata! */
88 resampler = DEFAULT_RESAMPLER;
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",
96 channels = chmap->channels ? chmap->channels : sink->channel_map.channels;
98 snprintf(args, sizeof(args), "slaves=\"%s\" resample_method=\"%s\" "
99 "channels=%u", sink->name, resampler, channels);
101 if (!(module = pa_module_load(core, modnam, args))) {
102 pa_log("failed to load module '%s %s'. can't multiplex", modnam, args);
106 pa_assert_se((u = module->userdata));
109 u->no_reattach = true;
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;
116 PA_LLIST_PREPEND(pa_muxnode, multiplex->muxnodes, mux);
118 if (!(o = pa_idxset_first(u->outputs, &idx)))
119 pa_log("can't find default multiplexer stream");
121 if ((sinp = o->sink_input)) {
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;
129 pa_log_debug("multiplexer succesfully loaded");
135 void pa_multiplex_destroy(pa_multiplex *multiplex,
139 pa_assert(multiplex);
143 pa_module_unload_by_index(core, mux->module_index, false);
144 PA_LLIST_REMOVE(pa_muxnode, multiplex->muxnodes, mux);
149 pa_muxnode *pa_multiplex_find_by_sink(pa_multiplex *multiplex,
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);
163 pa_log_debug("can't find muxnode for sink %u", sink_index);
168 pa_muxnode *pa_multiplex_find_by_module(pa_multiplex *multiplex,
171 uint32_t module_index;
174 pa_assert(multiplex);
177 module_index = module->index;
179 PA_LLIST_FOREACH(mux, multiplex->muxnodes) {
180 if (mux->module_index != PA_IDXSET_INVALID && module_index == mux->module_index)
188 bool pa_multiplex_sink_input_remove(pa_multiplex *multiplex,
194 pa_assert(multiplex);
197 if ((mux = pa_multiplex_find_by_module(multiplex, sinp->module))) {
198 name = pa_utils_get_sink_input_name(sinp);
200 pa_log_debug("multiplex (module %u) found for sink-input "
201 "(name %s)", mux->module_index, name);
203 if (sinp->index == mux->defstream_index) {
204 pa_log_debug("reseting default route on multiplex (module %u)",
206 mux->defstream_index = PA_IDXSET_INVALID;
209 pa_log_debug("reseting explicit route on multiplex (module %u)",
219 bool pa_multiplex_add_default_route(pa_core *core,
226 struct userdata *u; /* combine's userdata! */
232 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
233 pa_log_debug("module %u is gone", mux->module_index);
235 pa_assert_se((u = module->userdata));
237 if (sink == u->sink) {
238 pa_log("%s: mux %d refuses to make a loopback to itself",
239 __FILE__, mux->module_index);
242 pa_log_debug("adding default route to mux %u", mux->module_index);
244 if (!(sinp = u->add_slave(u, sink))) {
245 pa_log("failed to add new slave to mux %u", mux->module_index);
249 copy_media_role_property(u->sink, sinp);
250 pa_utils_set_stream_routing_properties(sinp->proplist, type, NULL);
251 mux->defstream_index = sinp->index;
260 bool pa_multiplex_remove_default_route(pa_core *core,
262 bool transfer_to_explicit)
267 struct userdata *u; /* combine's userdata! */
272 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
273 pa_log_debug("module %u is gone", mux->module_index);
274 else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
275 pa_log_debug("mux %u do not have default stream", mux->module_index);
276 else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
277 pa_log("can't remove default route: sink-input %u is gone", idx);
279 pa_assert_se((u = module->userdata));
280 mux->defstream_index = PA_IDXSET_INVALID;
282 if (transfer_to_explicit) {
283 pa_log_debug("converting default route sink-input.%u -> sink.%u "
284 "to explicit", sinp->index, sinp->sink->index);
285 pa_utils_set_stream_routing_method_property(sinp->proplist, true);
289 u->remove_slave(u, sinp, NULL);
296 bool pa_multiplex_change_default_route(pa_core *core,
303 struct userdata *u; /* combine's userdata! */
309 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
310 pa_log_debug("module %u is gone", mux->module_index);
311 else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
312 pa_log_debug("mux %u do not have default stream", mux->module_index);
313 else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
314 pa_log("can't remove default route: sink-input %u is gone", idx);
316 pa_assert_se((u = module->userdata));
317 if (u->move_slave(u, sinp, sink) < 0)
318 pa_log_debug("failed to move default stream on mux %u", mux->module_index);
320 pa_log_debug("default stream was successfully moved on mux %u",
330 bool pa_multiplex_add_explicit_route(pa_core *core,
337 struct userdata *u; /* combine's userdata! */
343 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
344 pa_log_debug("module %u is gone", mux->module_index);
346 pa_assert_se((u = module->userdata));
348 if (sink == u->sink) {
349 pa_log("%s: mux %d refuses to make a loopback to itself",
350 __FILE__, mux->module_index);
353 pa_log_debug("adding explicit route to mux %u", mux->module_index);
355 if (!(sinp = u->add_slave(u, sink))) {
356 pa_log("failed to add new slave to mux %u", mux->module_index);
360 copy_media_role_property(u->sink, sinp);
361 pa_utils_set_stream_routing_properties(sinp->proplist, type, sink);
371 bool pa_multiplex_remove_explicit_route(pa_core *core,
376 struct userdata *u; /* combine's userdata! */
382 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
383 pa_log_debug("module %u is gone", mux->module_index);
385 pa_assert_se((u = module->userdata));
387 u->remove_slave(u, NULL, sink);
389 pa_log_debug("link to sink.%u removed", sink->index);
398 bool pa_multiplex_duplicate_route(pa_core *core,
404 struct userdata *u; /* combine's userdata! */
413 pa_log_debug("check for duplicate route on mux %u",
416 if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index)))
417 pa_log_debug("module %u is gone", mux->module_index);
419 pa_assert_se((u = module->userdata));
421 PA_IDXSET_FOREACH(o, u->outputs, idx) {
422 if (!(i = o->sink_input))
424 if (sinp && i == sinp)
426 if (i->sink == sink) {
427 pa_log_debug("route sink-input.%u -> sink.%u is a duplicate",
428 i->index, sink->index);
434 pa_log_debug("no duplicate route found to sink.%u", sink->index);
436 pa_log_debug("no duplicate found for route sink-input.%u -> "
437 "sink.%u", sinp->index, sink->index);
444 int pa_multiplex_no_of_routes(pa_core *core, pa_muxnode *mux)
447 struct userdata *u; /* combine's userdata! */
452 if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index))) {
453 pa_log_debug("module %u is gone", mux->module_index);
457 pa_assert_se((u = module->userdata));
459 return (int)pa_idxset_size(u->outputs);
463 int pa_multiplex_print(pa_muxnode *mux, char *buf, int len)
473 p += snprintf(p, e-p, "<not set>");
475 p += snprintf(p, e-p, "module %u, sink %u, default stream %u",
476 mux->module_index, mux->sink_index,mux->defstream_index);
482 static void copy_media_role_property(pa_sink *sink, pa_sink_input *to)
490 if (sink && (from = pa_idxset_first(sink->inputs, &index))) {
491 pa_assert(from->proplist);
492 pa_assert(to->proplist);
494 if ((role = pa_proplist_gets(from->proplist, PA_PROP_MEDIA_ROLE)) &&
495 pa_proplist_sets(to->proplist, PA_PROP_MEDIA_ROLE, role) == 0)
497 pa_log_debug("set media.role=\"%s\" on sink_input.%d",
503 pa_log_debug("failed to set media.role on sink_input.%d", to->index);
510 * indent-tabs-mode: nil