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_LLIST_REMOVE(pa_muxnode, multiplex->muxnodes, mux);
144 pa_module_unload_by_index(core, mux->module_index, FALSE);
150 pa_muxnode *pa_multiplex_find(pa_multiplex *multiplex, uint32_t sink_index)
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);
169 pa_bool_t pa_multiplex_add_default_route(pa_core *core,
176 struct userdata *u; /* combine's userdata! */
182 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
183 pa_log("module %u is gone", mux->module_index);
185 pa_assert_se((u = module->userdata));
187 if (sink == u->sink) {
188 pa_log("%s: mux %d refuses to make a loopback to itself",
189 __FILE__, mux->module_index);
192 pa_log_debug("adding default route to mux %u", mux->module_index);
194 if (!(sinp = u->add_slave(u, sink))) {
195 pa_log("failed to add new slave to mux %u", mux->module_index);
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;
210 pa_bool_t pa_multiplex_remove_default_route(pa_core *core,
212 pa_bool_t transfer_to_explicit)
217 struct userdata *u; /* combine's userdata! */
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);
229 pa_assert_se((u = module->userdata));
230 mux->defstream_index = PA_IDXSET_INVALID;
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);
239 u->remove_slave(u, sinp, NULL);
246 pa_bool_t pa_multiplex_change_default_route(pa_core *core,
253 struct userdata *u; /* combine's userdata! */
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);
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);
270 pa_log_debug("default stream was successfully moved on mux %u",
280 pa_bool_t pa_multiplex_add_explicit_route(pa_core *core,
287 struct userdata *u; /* combine's userdata! */
293 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
294 pa_log("module %u is gone", mux->module_index);
296 pa_assert_se((u = module->userdata));
298 if (sink == u->sink) {
299 pa_log("%s: mux %d refuses to make a loopback to itself",
300 __FILE__, mux->module_index);
303 pa_log_debug("adding explicit route to mux %u", mux->module_index);
305 if (!(sinp = u->add_slave(u, sink))) {
306 pa_log("failed to add new slave to mux %u", mux->module_index);
310 copy_media_role_property(u->sink, sinp);
311 pa_utils_set_stream_routing_properties(sinp->proplist, type, sink);
321 pa_bool_t pa_multiplex_remove_explicit_route(pa_core *core,
326 struct userdata *u; /* combine's userdata! */
332 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
333 pa_log("module %u is gone", mux->module_index);
335 pa_assert_se((u = module->userdata));
337 u->remove_slave(u, NULL, sink);
339 pa_log_debug("link to sink.%u removed", sink->index);
348 pa_bool_t pa_multiplex_duplicate_route(pa_core *core,
354 struct userdata *u; /* combine's userdata! */
363 pa_log_debug("check for duplicate route on mux %u",
366 if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index)))
367 pa_log("module %u is gone", mux->module_index);
369 pa_assert_se((u = module->userdata));
371 PA_IDXSET_FOREACH(o, u->outputs, idx) {
372 if (!(i = o->sink_input))
374 if (sinp && i == sinp)
376 if (i->sink == sink) {
377 pa_log_debug("route sink-input.%u -> sink.%u is a duplicate",
378 i->index, sink->index);
384 pa_log_debug("no duplicate route found to sink.%u", sink->index);
386 pa_log_debug("no duplicate found for route sink-input.%u -> "
387 "sink.%u", sinp->index, sink->index);
394 int pa_multiplex_no_of_routes(pa_core *core, pa_muxnode *mux)
397 struct userdata *u; /* combine's userdata! */
402 if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index))) {
403 pa_log("module %u is gone", mux->module_index);
407 pa_assert_se((u = module->userdata));
409 return (int)pa_idxset_size(u->outputs);
413 int pa_multiplex_print(pa_muxnode *mux, char *buf, int len)
423 p += snprintf(p, e-p, "<not set>");
425 p += snprintf(p, e-p, "module %u, sink %u, default stream %u",
426 mux->module_index, mux->sink_index,mux->defstream_index);
432 static void copy_media_role_property(pa_sink *sink, pa_sink_input *to)
440 if (sink && (from = pa_idxset_first(sink->inputs, &index))) {
441 pa_assert(from->proplist);
442 pa_assert(to->proplist);
444 if ((role = pa_proplist_gets(from->proplist, PA_PROP_MEDIA_ROLE)) &&
445 pa_proplist_sets(to->proplist, PA_PROP_MEDIA_ROLE, role) == 0)
447 pa_log_debug("set media.role=\"%s\" on sink_input.%d",
453 pa_log_debug("failed to set media.role on sink_input.%d", to->index);
460 * indent-tabs-mode: nil