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,
25 #include <pulsecore/pulsecore-config.h>
26 #include <pulsecore/core-util.h>
27 #include <pulsecore/namereg.h>
29 #include <pulsecore/card.h>
30 #include <pulsecore/sink.h>
31 #include <pulsecore/device-port.h>
32 #include <pulsecore/source.h>
33 #include <pulsecore/sink-input.h>
34 #include <pulsecore/source-output.h>
38 #include "multiplex.h"
44 static pa_bool_t setup_explicit_link_from_stream_to_device(struct userdata *,
47 static pa_bool_t teardown_explicit_link_from_stream_to_device(struct userdata*,
51 static pa_bool_t setup_default_link_from_stream_to_device(struct userdata *,
54 static pa_bool_t setup_default_link_from_device_to_device(struct userdata *,
58 static pa_sink *setup_device_output(struct userdata *, mir_node *);
60 static pa_bool_t set_profile(struct userdata *, mir_node *);
61 static pa_bool_t set_port(struct userdata *, mir_node *);
64 pa_bool_t mir_switch_setup_link(struct userdata *u,
73 pa_assert_se((core = u->core));
74 pa_assert(!from || from->direction == mir_input);
75 pa_assert(to->direction == mir_output);
79 * links for explic routes
83 switch (from->implement) {
86 switch (to->implement) {
89 pa_log_debug("routing to streams is not implemented yet");
93 if (!setup_explicit_link_from_stream_to_device(u, from, to))
98 pa_log("%s: can't setup link: invalid sink node "
99 "implement", __FILE__);
105 pa_log_debug("input device routing is not implemented yet");
109 pa_log("%s: can't setup link: invalid source node "
110 "implement", __FILE__);
116 * links for default routes
118 switch (to->implement) {
121 pa_log_debug("routing to a stream is not implemented yet");
125 if (!from) /* prerouting */
126 return (!explicit && setup_device_output(u, to) != NULL);
128 switch (from->implement) {
131 if (!setup_default_link_from_stream_to_device(u, from, to))
136 if (!setup_default_link_from_device_to_device(u, from, to))
141 pa_log("%s: can't setup link: invalid source node "
142 "implement", __FILE__);
149 pa_log("%s: can't setup link: invalid sink node "
150 "implement", __FILE__);
155 pa_log_debug("link %s => %s is established", from->amname, to->amname);
160 pa_bool_t mir_switch_teardown_link(struct userdata *u,
169 pa_assert_se((core = u->core));
170 pa_assert(from->direction == mir_input);
171 pa_assert(to->direction == mir_output);
174 switch (from->implement) {
177 switch (to->implement) {
179 case mir_stream: /* stream -> stream */
180 pa_log_debug("routing to streams is not implemented yet");
183 case mir_device: /* stream -> device */
184 if (!teardown_explicit_link_from_stream_to_device(u, from, to))
189 pa_log("%s: can't teardown link: invalid sink node "
190 "implement", __FILE__);
195 case mir_device: /* device -> stream | device->device */
196 pa_log_debug("input device routing is not implemented yet");
200 pa_log("%s: can't teardown link: invalid source node "
201 "implement", __FILE__);
205 pa_log_debug("link %s => %s is torn down", from->amname, to->amname);
210 static pa_bool_t setup_explicit_link_from_stream_to_device(struct userdata *u,
222 pa_assert((core = u->core));
224 if (!(sink = setup_device_output(u, to)))
227 if (!set_profile(u, from) || !set_port(u, from)) {
228 pa_log("can't route from '%s'", from->amname);
232 if ((mux = from->mux)) {
233 sinp = pa_idxset_get_by_index(core->sink_inputs, mux->defstream_index);
235 if (sinp && sinp->sink == sink) {
236 if (!pa_multiplex_remove_default_route(core, mux, TRUE))
239 else if (pa_multiplex_duplicate_route(core, mux, NULL, sink)) {
240 pa_log_debug("multiplex route %s => %s already exists",
241 from->amname, to->amname);
245 if (!pa_multiplex_add_explicit_route(core, mux, sink, from->type))
250 if ((sinp = pa_idxset_get_by_index(core->sink_inputs, from->paidx))) {
251 if (sinp->sink == sink)
252 pa_log_debug("direct route already exists. nothing to do");
254 pa_log_debug("direct route: sink-input.%u -> sink.%u",
255 sinp->index, sink->index);
257 if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
263 pa_log_debug("link %s => %s is established", from->amname, to->amname);
269 static pa_bool_t teardown_explicit_link_from_stream_to_device(struct userdata *u,
281 pa_assert((core = u->core));
283 if ((mux = from->mux)) {
284 if (!(sink = pa_idxset_get_by_index(core->sinks, to->paidx))) {
285 pa_log_debug("can't find sink.%u", to->paidx);
289 if (!pa_multiplex_remove_explicit_route(core, mux, sink)) {
290 pa_log_debug("can't remove multiplex route on mux %u", mux->module_index);
295 if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, from->paidx))) {
296 pa_log_debug("can't find source.%u", from->paidx);
300 if (!(sink = pa_utils_get_null_sink(u))) {
301 pa_log_debug("can't remove direct route: no null sink");
305 if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
309 pa_log_debug("link %s => %s is torn down", from->amname, to->amname);
315 static pa_bool_t setup_default_link_from_stream_to_device(struct userdata *u,
328 pa_assert((core = u->core));
330 if (!(sink = setup_device_output(u, to)))
333 if (!set_profile(u, from) || !set_port(u, from)) {
334 pa_log("can't route from '%s'", from->amname);
338 if ((mux = from->mux)) {
339 if (mux->defstream_index == PA_IDXSET_INVALID) {
340 if ((n = pa_multiplex_no_of_routes(core, mux)) < 0)
343 pa_log_debug("currently mux %u has no default route",
350 sinp = pa_idxset_get_by_index(core->sink_inputs,
351 mux->defstream_index);
356 * we supposed to have a default stream but the sink-input
357 * on the combine side is not existing any more. This can
358 * happen, for instance, if the sink, where it was connected,
359 * died for some reason.
361 pa_log_debug("supposed to have a default stream on multiplex "
362 "%u but non was found. Trying to make one",
364 if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
365 pa_log_debug("the default stream on mux %u would be a "
366 "duplicate to an explicit route. "
367 "Removing it ...", mux->module_index);
368 mux->defstream_index = PA_IDXSET_INVALID;
369 return TRUE; /* the routing is a success */
372 if (!pa_multiplex_add_default_route(core, mux,sink, from->type)) {
373 pa_log_debug("failed to add default route on mux %d",
375 mux->defstream_index = PA_IDXSET_INVALID;
379 else if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
380 pa_log_debug("the default stream on mux %u would be a duplicate "
381 "to an explicit route. Removing it ...",
383 return TRUE; /* the routing is a success */
387 pa_log_debug("multiplex route: sink-input.%d -> (sink.%d - "
388 "sink-input.%d) -> sink.%d", from->paidx,
389 mux->sink_index, sinp->index, sink->index);
392 pa_log_debug("multiplex route: sink-input.%d -> (sink.%d - "
393 "sink-input) -> sink.%d", from->paidx,
394 mux->sink_index, sink->index);
397 if (!pa_multiplex_change_default_route(core, mux, sink))
401 if (from->paidx == PA_IDXSET_INVALID) {
402 pa_log_debug("can't route '%s': no sink-input", to->amname);
406 if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, from->paidx))) {
407 pa_log_debug("can't find sink input for '%s'", from->amname);
411 pa_log_debug("direct route: sink-input.%d -> sink.%d",
412 sinp->index, sink->index);
414 if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
421 static pa_bool_t setup_default_link_from_device_to_device(struct userdata *u,
436 pa_assert((core = u->core));
438 if (!(loop = from->loop)) {
439 pa_log_debug("source is not looped back");
443 if (!(sink = setup_device_output(u, to)))
446 if ((mux = from->mux)) {
447 if (mux->defstream_index == PA_IDXSET_INVALID) {
448 if ((n = pa_multiplex_no_of_routes(core, mux)) < 0)
451 pa_log_debug("currently mux %u has no default route",
458 sinp = pa_idxset_get_by_index(core->sink_inputs,
459 mux->defstream_index);
464 * we supposed to have a default stream but the sink-input
465 * on the combine side is not existing any more. This can
466 * happen, for instance, if the sink, where it was connected,
467 * died for some reason.
469 pa_log_debug("supposed to have a default stream on multiplex "
470 "%u but non was found. Trying to make one",
472 if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
473 pa_log_debug("the default stream on mux %u would be a "
474 "duplicate to an explicit route. "
475 "Removing it ...", mux->module_index);
476 mux->defstream_index = PA_IDXSET_INVALID;
477 return TRUE; /* the routing is a success */
480 type = pa_classify_guess_application_class(from);
482 if (!pa_multiplex_add_default_route(core, mux,sink, type)) {
483 pa_log_debug("failed to add default route on mux %d",
485 mux->defstream_index = PA_IDXSET_INVALID;
489 else if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
490 pa_log_debug("the default stream on mux %u would be a duplicate "
491 "to an explicit route. Removing it ...",
493 return TRUE; /* the routing is a success */
497 pa_log_debug("multiplex route: source.%d -> "
498 "(source-output - sink-input %d) -> (sink.%d - "
499 "sink-input.%d) -> sink.%d", from->paidx,
500 loop->sink_input_index,
501 mux->sink_index, sinp->index, sink->index);
504 pa_log_debug("multiplex route: source.%d -> "
505 "(source-output - sink-input.%d) -> (sink.%d - "
506 "sink-input) -> sink.%d", from->paidx,
507 loop->sink_input_index,
508 mux->sink_index, sink->index);
511 if (!pa_multiplex_change_default_route(core, mux, sink))
515 sinp = pa_idxset_get_by_index(core->sink_inputs,
516 loop->sink_input_index);
519 pa_log_debug("can't find looped back sink input for '%s'",
524 pa_log_debug("loopback route: source.%d -> (source-output - "
525 "sink-input.%d) -> sink.%d",
526 from->paidx, sinp->index, sink->index);
528 if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
535 static pa_sink *setup_device_output(struct userdata *u, mir_node *node)
542 pa_assert_se((core = u->core));
544 if (!set_profile(u, node) || !set_port(u, node)) {
545 pa_log("can't route to '%s'", node->amname);
549 if (node->paidx == PA_IDXSET_INVALID) {
550 pa_log_debug("can't route to '%s': no sink", node->amname);
554 if (!(sink = pa_idxset_get_by_index(core->sinks, node->paidx))) {
555 pa_log_debug("can't route to '%s': cant find sink", node->amname);
563 static pa_bool_t set_profile(struct userdata *u, mir_node *node)
567 pa_card_profile *prof;
571 pa_assert_se((core = u->core));
573 if (node->implement != mir_device)
576 if (node->type == mir_bluetooth_a2dp ||
577 node->type == mir_bluetooth_sco)
579 card = pa_idxset_get_by_index(core->cards, node->pacard.index);
582 pa_log("can't find card for '%s'", node->amname);
586 pa_assert_se(prof = card->active_profile);
588 if (!pa_streq(node->pacard.profile, prof->name)) {
589 pa_log_debug("changing profile '%s' => '%s'",
590 prof->name, node->pacard.profile);
592 if (u->state.profile) {
593 pa_log("nested profile setting is not allowed. won't change "
594 "'%s' => '%s'", prof->name, node->pacard.profile);
598 u->state.profile = node->pacard.profile;
600 pa_card_set_profile(card, node->pacard.profile, FALSE);
602 u->state.profile = NULL;
611 static pa_bool_t set_port(struct userdata *u, mir_node *node)
616 pa_device_port *port;
619 uint32_t paidx = PA_IDXSET_INVALID;
623 pa_assert(node->paname);
624 pa_assert_se((core = u->core));
626 if (node->direction != mir_input && node->direction != mir_output)
629 if (node->implement != mir_device)
635 if (node->direction == mir_input) {
636 source = pa_namereg_get(core, node->paname, PA_NAMEREG_SOURCE);
638 if (!(data = source)) {
639 pa_log("can't set port for '%s': source not found",
644 if ((port = source->active_port) && pa_streq(node->paport, port->name))
647 if (pa_source_set_port(source, node->paport, FALSE) < 0)
650 paidx = source->index;
653 if (node->direction == mir_output) {
654 sink = pa_namereg_get(core, node->paname, PA_NAMEREG_SINK);
656 if (!(data = sink)) {
657 pa_log("can't set port for '%s': sink not found",
662 if ((port = sink->active_port) && pa_streq(node->paport, port->name))
665 if (pa_sink_set_port(sink, node->paport, FALSE) < 0)
671 if ((oldnode = pa_discover_remove_node_from_ptr_hash(u, data)))
672 oldnode->paidx = PA_IDXSET_INVALID;
675 pa_discover_add_node_to_ptr_hash(u, data, node);
686 * indent-tabs-mode: nil