diff options
Diffstat (limited to 'switch.c')
-rw-r--r-- | switch.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/switch.c b/switch.c new file mode 100644 index 0000000..5b77180 --- /dev/null +++ b/switch.c @@ -0,0 +1,267 @@ +/* + * module-agl-audio -- PulseAudio module for providing audio routing support + * (forked from "module-murphy-ivi" - https://github.com/otcshare ) + * Copyright (c) 2012, Intel Corporation. + * Copyright (c) 2016, IoT.bzh + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, + * MA 02110-1301 USA. + * + */ +#include <pulsecore/pulsecore-config.h> /* required for headers below */ +#include <pulsecore/core-util.h> /* requred for "pa_streq" */ +#include <pulsecore/namereg.h> /* for PA_NAMEREG_SOURCE */ + +#include "utils.h" +#include "switch.h" +#include "node.h" + +bool agl_switch_setup_link (struct userdata *u, agl_node *from, agl_node *to, bool explicit) +{ + pa_core *core; + pa_sink *sink; + pa_source *source; + + pa_assert (u); + pa_assert_se (core = u->core); + + /* EXPLICIT ROUTES/DEFAULT ROUTES */ + + /* 1) EXPLICIT ROUTES : "FROM" AND "TO" ARE DEFINED */ + if (explicit) { + pa_assert (from); + pa_assert (to); + + switch (from->implement) { + /* STREAM SOURCE */ + case agl_stream: + switch (to->implement) { + /* STREAM TO STREAM : NOT IMPLEMENTED */ + case agl_stream: + pa_log_debug ("routing to streams not implemented"); + break; + /* STREAM TO DEVICE : OK */ + case agl_device: + //if (!setup_explicit_stream2dev_link (u, from, to)) + // return false; + break; + /* DEFAULT */ + default: + pa_log ("can't setup link: invalid sink node"); + return false; + } + break; + + /* DEVICE SOURCE : NOT IMPLEMENTED */ + case agl_device: + pa_log_debug("input device routing is not implemented yet"); + break; + + /* DEFAULT */ + default: + pa_log ("can't setup link: invalid sink node"); + return false; + } + } + + /* 2) DEFAULT ROUTES : EITHER ONE OF "FROM" AND "TO" ARE DEFINED */ + else { + pa_assert (from || to); + + /* "TO" IS DEFINED */ + if (to) { + switch (to->implement) { + /* STREAM DESTINATION */ + case agl_stream: + switch (from->implement) { + /* STREAM TO STREAM : NOT IMPLEMENTED */ + case agl_stream: + pa_log_debug ("routing to streams not implemented"); + break; + /* DEVICE TO STREAM : OK */ + case agl_device: + //if (!setup_default_dev2stream_link(u, from, to)) + // return false; + break; + /* DEFAULT */ + default: + pa_log ("can't setup link: invalid sink node"); + return false; + } + break; + + /* DEVICE DESTINATION */ + case agl_device: + /* IF THERE IS NO SOURCE : DEFAULT OUTPUT PREROUTE */ + /* if (!from) + return setup_device_output(u, to) != NULL; + else { */ + switch (from->implement) { + /* STREAM TO DEVICE : OK */ + case agl_stream: + //if (!setup_default_stream2dev_link (u, from, to)) + // return false; + break; + /* DEVICE TO DEVICE : OK */ + case agl_device: + //if (!setup_default_dev2dev_link (u, from, to)) + // return false; + break; + /* DEFAULT */ + default: + pa_log ("can't setup link: invalid source node"); + return false; + } + break; + /* } */ + + /* DEFAULT DESTINATION : NULL */ + default: + pa_log ("can't setup link"); + return false; + } + } + + /* ONLY "FROM" IS DEFINED */ + else { + /* only works with a device, use default input prerouting - TODO */ + if (from->implement == agl_device) { + pa_log_debug ("default routing for a device input is not supported yet"); + return false; + } + /* (the rest supposes "from->implement == agl_stream") */ + /* refuse unknown node types for default routing */ + if (from->type == agl_node_type_unknown) { + pa_log_debug ("default routing for unknown node type is refused"); + return false; + } + + sink = pa_utils_get_primary_alsa_sink (u); + source = pa_utils_get_null_source (u, from->nullsink); + + from->loopnode = pa_loopnode_create (u, PA_LOOPNODE_SINK, from->index, source->index, sink->index); + } + } + + //pa_log_debug ("link %s => %s is established", from->amname, to->amname); + + return true; +} + +bool agl_switch_teardown_link (struct userdata *u, agl_node *from, agl_node *to) +{ + pa_core *core; + + pa_assert (u); + pa_assert_se (core = u->core); + pa_assert (from || from->direction == agl_input); + pa_assert (to || to->direction == agl_output); + + switch (from->implement) { + case agl_stream: + switch (to->implement) { + /* STREAM TO STREAM : NOT IMPLEMENTED */ + case agl_stream: + pa_log_debug ("routing to streams is not implemented yet"); + break; + /* STREAM TO DEVICE : NOT OK */ + case agl_device: + //if (!teardown_explicit_stream2dev_link (u, from, to)) + // return false; + break; + default: + pa_log ("can't teardown link: invalid sink node"); + return false; + } + break; + + case agl_device: + /* DEVICE TO STREAM OR DEVICE TO DEVICE : NOT HANDLED */ + pa_log_debug ("input device routing is not implemented yet"); + break; + + default: + pa_log ("can't teardown link: invalid source node"); + return false; + } + + pa_log_debug("link %s => %s is torn down", from->amname, to->amname); + + return true; +} + + +bool set_port (struct userdata *u, agl_node *node) +{ + pa_core *core; + pa_sink *sink; + pa_source *source; + pa_device_port *port; + void *data = NULL; + uint32_t paidx = PA_IDXSET_INVALID; + + pa_assert (u); + pa_assert (node); + pa_assert (node->paname); + pa_assert_se (core = u->core); + + if (node->direction != agl_input && node->direction != agl_output) + return false; + if (node->implement != agl_device) + return true; + if (!node->paport) + return true; + + if (node->direction == agl_input) { + source = pa_namereg_get (core, node->paname, PA_NAMEREG_SOURCE); + if (!source) { + pa_log ("cannot set port for node '%s': source not found", node->paname); + return false; + } + + port = source->active_port; + /* active port and wanted port already match */ + if (pa_streq (node->paport, port->name)) + return true; + + /* ACTIVE CODE */ + if (pa_source_set_port (source, node->paport, false) < 0) + return false; + + data = source; + paidx = source->index; + } + + if (node->direction == agl_output) { + sink = pa_namereg_get (core, node->paname, PA_NAMEREG_SINK); + if (!sink) { + pa_log ("cannot set port for node '%s': source not found", node->paname); + return false; + } + + port = sink->active_port; + /* active port and wanted port already match */ + if (pa_streq (node->paport, port->name)) + return true; + + /* ACTIVE CODE */ + if (pa_sink_set_port (sink, node->paport, false) < 0) + return false; + + data = sink; + paidx = sink->index; + } + + return true; +} |