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-float-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! */
87 resampler = DEFAULT_RESAMPLER;
89 if (!(sink = pa_idxset_get_by_index(core->sinks, sink_index))) {
90 pa_log_debug("can't find the primary sink (index %u) for multiplexer",
95 snprintf(args, sizeof(args), "slaves=\"%s\" resample_method=\"%s\" "
96 "channels=%u", sink->name, resampler, chmap->channels);
98 if (!(module = pa_module_load(core, modnam, args))) {
99 pa_log("failed to load module '%s %s'. can't multiplex", modnam, args);
103 pa_assert_se((u = module->userdata));
106 u->no_reattach = TRUE;
108 mux = pa_xnew0(pa_muxnode, 1);
109 mux->module_index = module->index;
110 mux->sink_index = u->sink->index;
111 mux->defstream_index = PA_IDXSET_INVALID;
113 PA_LLIST_PREPEND(pa_muxnode, multiplex->muxnodes, mux);
115 if (!(o = pa_idxset_first(u->outputs, &idx)))
116 pa_log("can't find default multiplexer stream");
118 if ((sinp = o->sink_input)) {
120 pa_proplist_sets(sinp->proplist,PA_PROP_MEDIA_ROLE,media_role);
121 pa_utils_set_stream_routing_properties(sinp->proplist, type, NULL);
122 mux->defstream_index = sinp->index;
126 pa_log_debug("multiplexer succesfully loaded");
132 void pa_multiplex_destroy(pa_multiplex *multiplex,
136 pa_assert(multiplex);
140 PA_LLIST_REMOVE(pa_muxnode, multiplex->muxnodes, mux);
141 pa_module_unload_by_index(core, mux->module_index, FALSE);
147 pa_muxnode *pa_multiplex_find(pa_multiplex *multiplex, uint32_t sink_index)
151 if (sink_index != PA_IDXSET_INVALID) {
152 PA_LLIST_FOREACH(mux, multiplex->muxnodes) {
153 if (sink_index == mux->sink_index) {
154 pa_log_debug("muxnode found for sink %u", sink_index);
160 pa_log_debug("can't find muxnode for sink %u", sink_index);
166 pa_bool_t pa_multiplex_add_default_route(pa_core *core,
173 struct userdata *u; /* combine's userdata! */
179 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
180 pa_log("module %u is gone", mux->module_index);
182 pa_assert_se((u = module->userdata));
184 if (sink == u->sink) {
185 pa_log("%s: mux %d refuses to make a loopback to itself",
186 __FILE__, mux->module_index);
189 pa_log_debug("adding default route to mux %u", mux->module_index);
191 if (!(sinp = u->add_slave(u, sink))) {
192 pa_log("failed to add new slave to mux %u", mux->module_index);
196 copy_media_role_property(u->sink, sinp);
197 pa_utils_set_stream_routing_properties(sinp->proplist, type, NULL);
198 mux->defstream_index = sinp->index;
207 pa_bool_t pa_multiplex_remove_default_route(pa_core *core,
209 pa_bool_t transfer_to_explicit)
214 struct userdata *u; /* combine's userdata! */
219 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
220 pa_log("module %u is gone", mux->module_index);
221 else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
222 pa_log_debug("mux %u do not have default stream", mux->module_index);
223 else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
224 pa_log("can't remove default route: sink-input %u is gone", idx);
226 pa_assert_se((u = module->userdata));
227 mux->defstream_index = PA_IDXSET_INVALID;
229 if (transfer_to_explicit) {
230 pa_log_debug("converting default route sink-input.%u -> sink.%u "
231 "to explicit", sinp->index, sinp->sink->index);
232 pa_utils_set_stream_routing_method_property(sinp->proplist, TRUE);
236 u->remove_slave(u, sinp, NULL);
243 pa_bool_t pa_multiplex_change_default_route(pa_core *core,
250 struct userdata *u; /* combine's userdata! */
256 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
257 pa_log("module %u is gone", mux->module_index);
258 else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
259 pa_log_debug("mux %u do not have default stream", mux->module_index);
260 else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
261 pa_log("can't remove default route: sink-input %u is gone", idx);
263 pa_assert_se((u = module->userdata));
264 if (!u->move_slave(u, sinp, sink))
265 pa_log_debug("failed to move default stream on mux %u", mux->module_index);
267 pa_log_debug("default stream was successfully moved on mux %u",
277 pa_bool_t pa_multiplex_add_explicit_route(pa_core *core,
284 struct userdata *u; /* combine's userdata! */
290 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
291 pa_log("module %u is gone", mux->module_index);
293 pa_assert_se((u = module->userdata));
295 if (sink == u->sink) {
296 pa_log("%s: mux %d refuses to make a loopback to itself",
297 __FILE__, mux->module_index);
300 pa_log_debug("adding explicit route to mux %u", mux->module_index);
302 if (!(sinp = u->add_slave(u, sink))) {
303 pa_log("failed to add new slave to mux %u", mux->module_index);
307 copy_media_role_property(u->sink, sinp);
308 pa_utils_set_stream_routing_properties(sinp->proplist, type, sink);
318 pa_bool_t pa_multiplex_remove_explicit_route(pa_core *core,
323 struct userdata *u; /* combine's userdata! */
329 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
330 pa_log("module %u is gone", mux->module_index);
332 pa_assert_se((u = module->userdata));
334 u->remove_slave(u, NULL, sink);
336 pa_log_debug("link to sink.%u removed", sink->index);
345 pa_bool_t pa_multiplex_duplicate_route(pa_core *core,
351 struct userdata *u; /* combine's userdata! */
360 pa_log_debug("check for duplicate route on mux %u",
363 if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index)))
364 pa_log("module %u is gone", mux->module_index);
366 pa_assert_se((u = module->userdata));
368 PA_IDXSET_FOREACH(o, u->outputs, idx) {
369 if (!(i = o->sink_input))
371 if (sinp && i == sinp)
373 if (i->sink == sink) {
374 pa_log_debug("route sink-input.%u -> sink.%u is a duplicate",
375 i->index, sink->index);
381 pa_log_debug("no duplicate route found to sink.%u", sink->index);
383 pa_log_debug("no duplicate found for route sink-input.%u -> "
384 "sink.%u", sinp->index, sink->index);
391 int pa_multiplex_no_of_routes(pa_core *core, pa_muxnode *mux)
394 struct userdata *u; /* combine's userdata! */
399 if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index))) {
400 pa_log("module %u is gone", mux->module_index);
404 pa_assert_se((u = module->userdata));
406 return (int)pa_idxset_size(u->outputs);
410 int pa_multiplex_print(pa_muxnode *mux, char *buf, int len)
420 p += snprintf(p, e-p, "<not set>");
422 p += snprintf(p, e-p, "module %u, sink %u, default stream %u",
423 mux->module_index, mux->sink_index,mux->defstream_index);
429 static void copy_media_role_property(pa_sink *sink, pa_sink_input *to)
437 if (sink && (from = pa_idxset_first(sink->inputs, &index))) {
438 pa_assert(from->proplist);
439 pa_assert(to->proplist);
441 if ((role = pa_proplist_gets(from->proplist, PA_PROP_MEDIA_ROLE)) &&
442 pa_proplist_sets(to->proplist, PA_PROP_MEDIA_ROLE, role) == 0)
444 pa_log_debug("set media.role=\"%s\" on sink_input.%d",
450 pa_log_debug("failed to set media.role on sink_input.%d", to->index);
457 * indent-tabs-mode: nil