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 pa_multiplex *pa_multiplex_init(void)
45 pa_multiplex *multiplex = pa_xnew0(pa_multiplex, 1);
51 void pa_multiplex_done(pa_multiplex *multiplex, pa_core *core)
55 PA_LLIST_FOREACH_SAFE(mux,n, multiplex->muxnodes) {
56 pa_module_unload_by_index(core, mux->module_index, FALSE);
62 pa_muxnode *pa_multiplex_create(pa_multiplex *multiplex,
65 pa_channel_map *chmap,
66 const char *resampler,
69 static char *modnam = "module-combine-sink";
71 struct userdata *u; /* combine's userdata! */
83 resampler = DEFAULT_RESAMPLER;
85 if (!(sink = pa_idxset_get_by_index(core->sinks, sink_index))) {
86 pa_log_debug("can't find the primary sink (index %u) for multiplexer",
91 snprintf(args, sizeof(args), "slaves=\"%s\" resample_method=\"%s\" "
92 "channels=%u", sink->name, resampler, chmap->channels);
94 if (!(module = pa_module_load(core, modnam, args))) {
95 pa_log("failed to load module '%s %s'. can't multiplex", modnam, args);
99 pa_assert_se((u = module->userdata));
102 u->no_reattach = TRUE;
104 mux = pa_xnew0(pa_muxnode, 1);
105 mux->module_index = module->index;
106 mux->sink_index = u->sink->index;
107 mux->defstream_index = PA_IDXSET_INVALID;
109 PA_LLIST_PREPEND(pa_muxnode, multiplex->muxnodes, mux);
111 if (!(o = pa_idxset_first(u->outputs, &idx)))
112 pa_log("can't find default multiplexer stream");
114 if ((sinp = o->sink_input)) {
115 pa_utils_set_stream_routing_properties(sinp->proplist, type, NULL);
116 mux->defstream_index = sinp->index;
120 pa_log_debug("multiplexer succesfully loaded");
126 void pa_multiplex_destroy(pa_multiplex *multiplex,
130 pa_assert(multiplex);
134 PA_LLIST_REMOVE(pa_muxnode, multiplex->muxnodes, mux);
135 pa_module_unload_by_index(core, mux->module_index, FALSE);
141 pa_muxnode *pa_multiplex_find(pa_multiplex *multiplex, uint32_t sink_index)
145 PA_LLIST_FOREACH(mux, multiplex->muxnodes) {
146 if (sink_index == mux->sink_index) {
147 pa_log_debug("muxnode found for sink %u", sink_index);
152 pa_log_debug("can't find muxnode for sink %u", sink_index);
158 pa_bool_t pa_multiplex_add_default_route(pa_core *core,
165 struct userdata *u; /* combine's userdata! */
171 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
172 pa_log("module %u is gone", mux->module_index);
174 pa_assert_se((u = module->userdata));
176 if (sink == u->sink) {
177 pa_log("%s: mux %d refuses to make a loopback to itself",
178 __FILE__, mux->module_index);
181 pa_log_debug("adding default route to mux %u", mux->module_index);
183 if (!(sinp = u->add_slave(u, sink))) {
184 pa_log("failed to add new slave to mux %u", mux->module_index);
188 pa_utils_set_stream_routing_properties(sinp->proplist, type, NULL);
189 mux->defstream_index = sinp->index;
198 pa_bool_t pa_multiplex_remove_default_route(pa_core *core,
200 pa_bool_t transfer_to_explicit)
205 struct userdata *u; /* combine's userdata! */
210 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
211 pa_log("module %u is gone", mux->module_index);
212 else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
213 pa_log_debug("mux %u do not have default stream", mux->module_index);
214 else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
215 pa_log("can't remove default route: sink-input %u is gone", idx);
217 pa_assert_se((u = module->userdata));
218 mux->defstream_index = PA_IDXSET_INVALID;
220 if (transfer_to_explicit) {
221 pa_log_debug("converting default route sink-input.%u -> sink.%u "
222 "to explicit", sinp->index, sinp->sink->index);
223 pa_utils_set_stream_routing_method_property(sinp->proplist, TRUE);
227 u->remove_slave(u, sinp, NULL);
234 pa_bool_t pa_multiplex_change_default_route(pa_core *core,
241 struct userdata *u; /* combine's userdata! */
247 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
248 pa_log("module %u is gone", mux->module_index);
249 else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
250 pa_log_debug("mux %u do not have default stream", mux->module_index);
251 else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
252 pa_log("can't remove default route: sink-input %u is gone", idx);
254 pa_assert_se((u = module->userdata));
255 if (!u->move_slave(u, sinp, sink))
256 pa_log_debug("failed to move default stream on mux %u", mux->module_index);
258 pa_log_debug("default stream was successfully moved on mux %u",
268 pa_bool_t pa_multiplex_add_explicit_route(pa_core *core,
275 struct userdata *u; /* combine's userdata! */
281 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
282 pa_log("module %u is gone", mux->module_index);
284 pa_assert_se((u = module->userdata));
286 if (sink == u->sink) {
287 pa_log("%s: mux %d refuses to make a loopback to itself",
288 __FILE__, mux->module_index);
291 pa_log_debug("adding explicit route to mux %u", mux->module_index);
293 if (!(sinp = u->add_slave(u, sink))) {
294 pa_log("failed to add new slave to mux %u", mux->module_index);
298 pa_utils_set_stream_routing_properties(sinp->proplist, type, sink);
308 pa_bool_t pa_multiplex_remove_explicit_route(pa_core *core,
313 struct userdata *u; /* combine's userdata! */
319 if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
320 pa_log("module %u is gone", mux->module_index);
322 pa_assert_se((u = module->userdata));
324 u->remove_slave(u, NULL, sink);
326 pa_log_debug("link to sink.%u removed", sink->index);
335 pa_bool_t pa_multiplex_duplicate_route(pa_core *core,
341 struct userdata *u; /* combine's userdata! */
350 pa_log_debug("check for duplicate route on mux %u",
353 if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index)))
354 pa_log("module %u is gone", mux->module_index);
356 pa_assert_se((u = module->userdata));
358 PA_IDXSET_FOREACH(o, u->outputs, idx) {
359 if (!(i = o->sink_input))
361 if (sinp && i == sinp)
363 if (i->sink == sink) {
364 pa_log_debug("route sink-input.%u -> sink.%u is a duplicate",
365 i->index, sink->index);
371 pa_log_debug("no duplicate route found to sink.%u", sink->index);
373 pa_log_debug("no duplicate found for route sink-input.%u -> "
374 "sink.%u", sinp->index, sink->index);
381 int pa_multiplex_no_of_routes(pa_core *core, pa_muxnode *mux)
384 struct userdata *u; /* combine's userdata! */
389 if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index))) {
390 pa_log("module %u is gone", mux->module_index);
394 pa_assert_se((u = module->userdata));
396 return (int)pa_idxset_size(u->outputs);
400 int pa_multiplex_print(pa_muxnode *mux, char *buf, int len)
410 p += snprintf(p, e-p, "<not set>");
412 p += snprintf(p, e-p, "module %u, sink %u, default stream %u",
413 mux->module_index, mux->sink_index,mux->defstream_index);
423 * indent-tabs-mode: nil