[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