[pulseaudio-discuss] [PATCH 10/30] node: Implement fallback routing of new streams

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Thu Jan 16 07:02:36 PST 2014


This doesn't add any new functionality, this only makes it possible to
remove the fallback routing logic from sink-input.c and
source-output.c (it's better to centralize all routing logic at the
node level).
---
 src/pulsecore/node.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/pulsecore/node.h |   2 +
 2 files changed, 213 insertions(+), 1 deletion(-)

diff --git a/src/pulsecore/node.c b/src/pulsecore/node.c
index b1dc841..155ff4b 100644
--- a/src/pulsecore/node.c
+++ b/src/pulsecore/node.c
@@ -30,6 +30,19 @@
 
 #include "node.h"
 
+const char *pa_node_type_to_string(pa_node_type_t type) {
+    switch (type) {
+        case PA_NODE_TYPE_PORT:          return "port";
+        case PA_NODE_TYPE_PORT_MONITOR:  return "monitor port";
+        case PA_NODE_TYPE_SINK:          return "sink";
+        case PA_NODE_TYPE_SOURCE:        return "source";
+        case PA_NODE_TYPE_SINK_INPUT:    return "sink input";
+        case PA_NODE_TYPE_SOURCE_OUTPUT: return "source output";
+    }
+
+    pa_assert_not_reached();
+}
+
 pa_node_new_data *pa_node_new_data_init(pa_node_new_data *data) {
     pa_assert(data);
 
@@ -152,6 +165,200 @@ void pa_node_free(pa_node *node) {
     pa_xfree(node);
 }
 
+static void set_initial_routing_fallback(pa_node_set_initial_routing_hook_data *data) {
+    int r;
+    pa_node *node;
+    pa_sink_input *sink_input;
+    pa_source_output *source_output;
+    pa_sink *sink;
+    pa_source *source;
+    pa_node *other_node;
+    pa_device_port *port;
+
+    pa_assert(data);
+
+    node = data->node;
+
+    if (node->type != PA_NODE_TYPE_SINK_INPUT && node->type != PA_NODE_TYPE_SOURCE_OUTPUT) {
+        if (data->n_requested_connections == 0)
+            data->ret = 0;
+        else {
+            pa_log_info("Can't set initial routing for node %s, operation not supported for node type %s.", node->name,
+                        pa_node_type_to_string(node->type));
+            data->ret = -PA_ERR_NOTSUPPORTED;
+        }
+
+        return;
+    }
+
+    if (node->type == PA_NODE_TYPE_SINK_INPUT)
+        sink_input = node->owner;
+    else
+        source_output = node->owner;
+
+    if (data->n_requested_connections > 1) {
+        pa_log_info("Can't set initial routing for node %s, multiple connections not supported.", node->name);
+        data->ret = -PA_ERR_NOTSUPPORTED;
+        return;
+    }
+
+    if (data->n_requested_connections == 0) {
+        if (node->type == PA_NODE_TYPE_SINK_INPUT) {
+            sink = pa_namereg_get_default_sink(node->core);
+            if (!sink) {
+                pa_log_info("Can't set initial routing for node %s, no sinks available.", node->name);
+                data->ret = -PA_ERR_NOENTITY;
+                return;
+            }
+
+            r = pa_sink_input_set_initial_sink(sink_input, sink);
+            if (r < 0) {
+                pa_log_info("Can't set initial routing for node %s, format negotiation with the default sink (%s) failed.",
+                            node->name, sink->name);
+                data->ret = r;
+                return;
+            }
+
+            data->ret = 0;
+            return;
+        } else {
+            source = pa_namereg_get_default_source(node->core);
+            if (!source) {
+                pa_log_info("Can't set initial routing for node %s, no sources available.", node->name);
+                data->ret = -PA_ERR_NOENTITY;
+                return;
+            }
+
+            r = pa_source_output_set_initial_source(source_output, source);
+            if (r < 0) {
+                pa_log_info("Can't set initial routing for node %s, format negotiation with the default source (%s) failed.",
+                            node->name, source->name);
+                data->ret = r;
+                return;
+            }
+
+            data->ret = 0;
+            return;
+        }
+    }
+
+    pa_assert(data->n_requested_connections == 1);
+    other_node = data->requested_connections[0];
+
+    if (node->type == PA_NODE_TYPE_SINK_INPUT) {
+        if (other_node->direction != PA_DIRECTION_OUTPUT) {
+            pa_log_info("Can't connect %s to %s, both are input nodes.", node->name, other_node->name);
+            data->ret = -PA_ERR_INVALID;
+            return;
+        }
+
+        if (other_node->type == PA_NODE_TYPE_SINK) {
+            sink = other_node->owner;
+
+            r = pa_sink_input_set_initial_sink(sink_input, sink);
+            if (r < 0) {
+                pa_log_info("Can't connect %s to %s, pa_sink_input_set_initial_sink() failed.", node->name, other_node->name);
+                data->ret = r;
+                return;
+            }
+
+            data->ret = 0;
+            return;
+        }
+
+        if (other_node->type == PA_NODE_TYPE_PORT) {
+            port = other_node->owner;
+
+            sink = port->device;
+            if (!sink || sink->active_port != port) {
+                pa_log_info("Can't connect %s to %s, port %s is not active.", node->name, other_node->name, port->name);
+                data->ret = -PA_ERR_NOTSUPPORTED;
+                return;
+            }
+
+            r = pa_sink_input_set_initial_sink(sink_input, sink);
+            if (r < 0) {
+                pa_log_info("Can't connect %s to %s, pa_sink_input_set_initial_sink() failed.", node->name, other_node->name);
+                data->ret = r;
+                return;
+            }
+
+            data->ret = 0;
+            return;
+        }
+
+        pa_log_info("Can't connect %s to %s, connections from type %s to type %s are not supported.", node->name,
+                    other_node->name, pa_node_type_to_string(node->type), pa_node_type_to_string(other_node->type));
+        data->ret = -PA_ERR_NOTSUPPORTED;
+        return;
+    }
+
+    if (node->type == PA_NODE_TYPE_SOURCE_OUTPUT) {
+        if (other_node->direction != PA_DIRECTION_INPUT) {
+            pa_log_info("Can't connect %s to %s, both are output nodes.", node->name, other_node->name);
+            data->ret = -PA_ERR_INVALID;
+            return;
+        }
+
+        if (other_node->type == PA_NODE_TYPE_SOURCE) {
+            source = other_node->owner;
+
+            r = pa_source_output_set_initial_source(source_output, source);
+            if (r < 0) {
+                pa_log_info("Can't connect %s to %s, pa_source_output_set_initial_source() failed.", node->name,
+                            other_node->name);
+                data->ret = r;
+                return;
+            }
+
+            data->ret = 0;
+            return;
+        }
+
+        if (other_node->type == PA_NODE_TYPE_PORT || other_node->type == PA_NODE_TYPE_PORT_MONITOR) {
+            bool port_is_active = false;
+
+            port = other_node->owner;
+
+            if (other_node->type == PA_NODE_TYPE_PORT)
+                source = port->device;
+                if (source && source->active_port == port)
+                    port_is_active = true;
+            else if (other_node->type == PA_NODE_TYPE_PORT_MONITOR) {
+                sink = port->device;
+                if (sink && sink->active_port == port) {
+                    port_is_active = true;
+                    source = sink->monitor_source;
+                }
+            }
+
+            if (!port_is_active) {
+                pa_log_info("Can't connect %s to %s, port %s is not active.", node->name, other_node->name, port->name);
+                data->ret = -PA_ERR_NOTSUPPORTED;
+                return;
+            }
+
+            r = pa_source_output_set_initial_source(source_output, source);
+            if (r < 0) {
+                pa_log_info("Can't connect %s to %s, pa_source_output_set_initial_source() failed.", node->name,
+                            other_node->name);
+                data->ret = r;
+                return;
+            }
+
+            data->ret = 0;
+            return;
+        }
+
+        pa_log_info("Can't connect %s to %s, connections from type %s to type %s are not supported.", node->name,
+                    other_node->name, pa_node_type_to_string(node->type), pa_node_type_to_string(other_node->type));
+        data->ret = -PA_ERR_NOTSUPPORTED;
+        return;
+    }
+
+    pa_assert_not_reached();
+}
+
 int pa_node_put(pa_node *node, pa_node **requested_connections, unsigned n_requested_connections) {
     pa_node_set_initial_routing_hook_data data = {
         .node = node,
@@ -174,7 +381,10 @@ int pa_node_put(pa_node *node, pa_node **requested_connections, unsigned n_reque
 
     pa_hook_fire(&node->core->hooks[PA_CORE_HOOK_NODE_SET_INITIAL_ROUTING], &data);
 
-    if (data.ret_valid && data.ret < 0) {
+    if (!data.ret_valid)
+        set_initial_routing_fallback(&data);
+
+    if (data.ret < 0) {
         pa_log_info("Setting initial routing for node %s failed.", node->name);
         return data.ret;
     }
diff --git a/src/pulsecore/node.h b/src/pulsecore/node.h
index 395609e..306096a 100644
--- a/src/pulsecore/node.h
+++ b/src/pulsecore/node.h
@@ -38,6 +38,8 @@ typedef enum {
     PA_NODE_TYPE_SOURCE_OUTPUT  /* owner: pa_source_output */
 } pa_node_type_t;
 
+const char *pa_node_type_to_string(pa_node_type_t type);
+
 typedef enum {
     PA_NODE_STATE_INIT,
     PA_NODE_STATE_LINKED,
-- 
1.8.3.1



More information about the pulseaudio-discuss mailing list