+struct bt_connection *bt_graph_connect(struct bt_graph *graph,
+ struct bt_port *upstream_port,
+ struct bt_port *downstream_port)
+{
+ struct bt_connection *connection = NULL;
+ struct bt_graph *upstream_graph = NULL;
+ struct bt_graph *downstream_graph = NULL;
+ struct bt_component *upstream_component = NULL;
+ struct bt_component *downstream_component = NULL;
+ enum bt_component_status component_status;
+ bool components_added = false;
+
+ if (!graph || !upstream_port || !downstream_port) {
+ goto end;
+ }
+
+ if (bt_port_get_type(upstream_port) != BT_PORT_TYPE_OUTPUT) {
+ goto end;
+ }
+ if (bt_port_get_type(downstream_port) != BT_PORT_TYPE_INPUT) {
+ goto end;
+ }
+
+ /* Ensure the components are not already part of another graph. */
+ upstream_component = bt_port_get_component(upstream_port);
+ assert(upstream_component);
+ upstream_graph = bt_component_get_graph(upstream_component);
+ if (upstream_graph && (graph != upstream_graph)) {
+ fprintf(stderr, "Upstream component is already part of another graph\n");
+ goto error;
+ }
+
+ downstream_component = bt_port_get_component(downstream_port);
+ assert(downstream_component);
+ downstream_graph = bt_component_get_graph(downstream_component);
+ if (downstream_graph && (graph != downstream_graph)) {
+ fprintf(stderr, "Downstream component is already part of another graph\n");
+ goto error;
+ }
+
+ connection = bt_connection_create(graph, upstream_port,
+ downstream_port);
+ if (!connection) {
+ goto error;
+ }
+
+ /*
+ * Ownership of up/downstream_component and of the connection object is
+ * transferred to the graph.
+ */
+ g_ptr_array_add(graph->connections, connection);
+ g_ptr_array_add(graph->components, upstream_component);
+ g_ptr_array_add(graph->components, downstream_component);
+ if (bt_component_get_class_type(downstream_component) ==
+ BT_COMPONENT_CLASS_TYPE_SINK) {
+ g_queue_push_tail(graph->sinks_to_consume,
+ downstream_component);
+ }
+
+ /*
+ * The graph is now the parent of these components which garantees their
+ * existence for the duration of the graph's lifetime.
+ */
+ bt_component_set_graph(upstream_component, graph);
+ bt_put(upstream_component);
+ bt_component_set_graph(downstream_component, graph);
+ bt_put(downstream_component);
+
+ /* Rollback the connection from this point on. */
+ components_added = true;
+
+ /*
+ * The components and connection are added to the graph before invoking
+ * the new_connection method in order to make them visible to the
+ * components during the method's invocation.
+ */
+ component_status = bt_component_new_connection(upstream_component,
+ upstream_port, connection);
+ if (component_status != BT_COMPONENT_STATUS_OK) {
+ goto error;
+ }
+ component_status = bt_component_new_connection(downstream_component,
+ downstream_port, connection);
+ if (component_status != BT_COMPONENT_STATUS_OK) {
+ goto error;
+ }
+end:
+ bt_put(upstream_graph);
+ bt_put(downstream_graph);
+ return connection;
+error:
+ if (components_added) {
+ if (bt_component_get_class_type(downstream_component) ==
+ BT_COMPONENT_CLASS_TYPE_SINK) {
+ g_queue_pop_tail(graph->sinks_to_consume);
+ }
+ g_ptr_array_set_size(graph->connections,
+ graph->connections->len - 1);
+ g_ptr_array_set_size(graph->components,
+ graph->components->len - 2);
+ }
+ goto end;
+}
+
+static
+int get_component_port_counts(struct bt_component *component, int *input_count,
+ int *output_count)
+{
+ int ret = -1;
+
+ switch (bt_component_get_class_type(component)) {
+ case BT_COMPONENT_CLASS_TYPE_SOURCE:
+ ret = bt_component_source_get_output_port_count(component);
+ if (ret < 0) {
+ goto end;
+ }
+ *output_count = ret;
+ break;
+ case BT_COMPONENT_CLASS_TYPE_FILTER:
+ ret = bt_component_filter_get_output_port_count(component);
+ if (ret < 0) {
+ goto end;
+ }
+ *output_count = ret;
+ break;
+ ret = bt_component_filter_get_input_port_count(component);
+ if (ret < 0) {
+ goto end;
+ }
+ *input_count = ret;
+ break;
+ case BT_COMPONENT_CLASS_TYPE_SINK:
+ ret = bt_component_sink_get_input_port_count(component);
+ if (ret < 0) {
+ goto end;
+ }
+ *input_count = ret;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ ret = 0;
+end:
+ return ret;
+}
+
+static
+struct bt_port *get_input_port(struct bt_component *component, int index)