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