This allows routers to set the initial routing for new nodes without caring about their type. --- src/pulsecore/edge.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/edge.c b/src/pulsecore/edge.c index 931bee1..177ae3f 100644 --- a/src/pulsecore/edge.c +++ b/src/pulsecore/edge.c @@ -119,7 +119,9 @@ pa_edge *pa_edge_new(pa_node *input, pa_node *output, int *ret) { edge->output = output; edge->string = pa_sprintf_malloc("%s -> %s", input->name, output->name); - edge_put(edge); + r = edge_put(edge); + if (r < 0) + goto fail; return edge; @@ -133,15 +135,183 @@ fail: return NULL; } +static int connect_source_to_source_output(pa_source *source, pa_source_output *output) { + int r; + + pa_assert(source); + pa_assert(output); + + if (output->state == PA_SOURCE_OUTPUT_INIT) + r = pa_source_output_set_initial_source(output, source); + else + r = -PA_ERR_NOTSUPPORTED; + + return r; +} + +static int connect_port_to_source_output(pa_device_port *port, pa_source_output *output) { + pa_assert(port); + pa_assert(output); + + return connect_source_to_source_output(port->device, output); +} + +static int connect_port_monitor_to_source_output(pa_device_port *port, pa_source_output *output) { + pa_assert(port); + pa_assert(output); + + return connect_source_to_source_output(((pa_sink *) port->device)->monitor_source, output); +} + +static int connect_sink_input_to_sink(pa_sink_input *input, pa_sink *sink) { + int r; + + pa_assert(input); + pa_assert(sink); + + if (input->state == PA_SINK_INPUT_INIT) + r = pa_sink_input_set_initial_sink(input, sink); + else + r = -PA_ERR_NOTSUPPORTED; + + return r; +} + +static int connect_sink_input_to_port(pa_sink_input *input, pa_device_port *port) { + pa_assert(input); + pa_assert(port); + + return connect_sink_input_to_sink(input, port->device); +} + +static int connect_sink_input_to_source_output(pa_sink_input *input, pa_source_output *output) { + int r; + + pa_assert(input); + pa_assert(output); + + if (output->state == PA_SOURCE_OUTPUT_INIT) + r = pa_source_output_set_direct_on_input(output, input); + else { + pa_log_info("Connecting a linked source output to a sink input is not supported."); + r = -PA_ERR_NOTSUPPORTED; + } + + return r; +} + +static int connect_nodes(pa_edge *edge) { + int r = 0; + + pa_assert(edge); + + switch (edge->input->type) { + case PA_NODE_TYPE_PORT: + switch (edge->output->type) { + case PA_NODE_TYPE_SOURCE_OUTPUT: + r = connect_port_to_source_output(edge->input->owner, edge->output->owner); + break; + + case PA_NODE_TYPE_PORT: + case PA_NODE_TYPE_SINK: + goto not_supported; + + case PA_NODE_TYPE_PORT_MONITOR: + case PA_NODE_TYPE_SOURCE: + case PA_NODE_TYPE_SINK_INPUT: + pa_assert_not_reached(); + } + break; + + case PA_NODE_TYPE_PORT_MONITOR: + switch (edge->output->type) { + case PA_NODE_TYPE_SOURCE_OUTPUT: + r = connect_port_monitor_to_source_output(edge->input->owner, edge->output->owner); + break; + + case PA_NODE_TYPE_PORT: + case PA_NODE_TYPE_SINK: + goto not_supported; + + case PA_NODE_TYPE_PORT_MONITOR: + case PA_NODE_TYPE_SOURCE: + case PA_NODE_TYPE_SINK_INPUT: + pa_assert_not_reached(); + } + break; + + case PA_NODE_TYPE_SOURCE: + switch (edge->output->type) { + case PA_NODE_TYPE_SOURCE_OUTPUT: + r = connect_source_to_source_output(edge->input->owner, edge->output->owner); + break; + + case PA_NODE_TYPE_PORT: + case PA_NODE_TYPE_SINK: + goto not_supported; + + case PA_NODE_TYPE_PORT_MONITOR: + case PA_NODE_TYPE_SOURCE: + case PA_NODE_TYPE_SINK_INPUT: + pa_assert_not_reached(); + } + break; + + case PA_NODE_TYPE_SINK_INPUT: + switch (edge->output->type) { + case PA_NODE_TYPE_PORT: + r = connect_sink_input_to_port(edge->input->owner, edge->output->owner); + break; + + case PA_NODE_TYPE_SINK: + r = connect_sink_input_to_sink(edge->input->owner, edge->output->owner); + break; + + case PA_NODE_TYPE_SOURCE_OUTPUT: + r = connect_sink_input_to_source_output(edge->input->owner, edge->output->owner); + break; + + case PA_NODE_TYPE_PORT_MONITOR: + case PA_NODE_TYPE_SOURCE: + case PA_NODE_TYPE_SINK_INPUT: + pa_assert_not_reached(); + } + break; + + case PA_NODE_TYPE_SINK: + case PA_NODE_TYPE_SOURCE_OUTPUT: + pa_assert_not_reached(); + } + + return r; + +not_supported: + pa_log_info("Connecting node type %s to type %s is not supported.", pa_node_type_to_string(edge->input->type), + pa_node_type_to_string(edge->output->type)); + + return -PA_ERR_NOTSUPPORTED; +} + static int edge_put(pa_edge *edge) { + int r; + pa_assert(edge); pa_node_add_edge(edge->input, edge); pa_node_add_edge(edge->output, edge); + r = connect_nodes(edge); + if (r < 0) + goto fail; + pa_log_debug("Created edge %s.", edge->string); return 0; + +fail: + edge_unlink(edge); + + return r; } static void edge_unlink(pa_edge *edge) { -- 1.8.3.1