summaryrefslogtreecommitdiffstats
path: root/switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'switch.c')
-rw-r--r--switch.c267
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;
+}