+ struct bt_port *upstream_port,
+ struct bt_port *downstream_port)
+{
+ uint64_t i;
+ GArray *listeners;
+
+ BT_ASSERT(graph);
+ BT_ASSERT(upstream_comp);
+ BT_ASSERT(downstream_comp);
+ BT_ASSERT(upstream_port);
+ BT_ASSERT(downstream_port);
+ BT_LIB_LOGV("Notifying graph listeners that ports were disconnected: "
+ "%![graph-]+g, %![up-port-]+p, %![down-port-]+p, "
+ "%![up-comp-]+c, %![down-comp-]+c",
+ graph, upstream_port, downstream_port, upstream_comp,
+ downstream_comp);
+
+ switch (upstream_comp->class->type) {
+ case BT_COMPONENT_CLASS_TYPE_SOURCE:
+ {
+ switch (downstream_comp->class->type) {
+ case BT_COMPONENT_CLASS_TYPE_FILTER:
+ listeners =
+ graph->listeners.source_filter_ports_disconnected;
+ break;
+ case BT_COMPONENT_CLASS_TYPE_SINK:
+ listeners =
+ graph->listeners.source_sink_ports_disconnected;
+ break;
+ default:
+ abort();
+ }
+
+ break;
+ }
+ case BT_COMPONENT_CLASS_TYPE_FILTER:
+ {
+ switch (downstream_comp->class->type) {
+ case BT_COMPONENT_CLASS_TYPE_SINK:
+ listeners =
+ graph->listeners.filter_sink_ports_disconnected;
+ break;
+ default:
+ abort();
+ }
+
+ break;
+ }
+ default:
+ abort();
+ }
+
+ for (i = 0; i < listeners->len; i++) {
+ struct bt_graph_listener_ports_disconnected *listener =
+ &g_array_index(listeners,
+ struct bt_graph_listener_ports_disconnected, i);
+
+ BT_ASSERT(listener->func);
+ listener->func(upstream_comp, downstream_comp,
+ upstream_port, downstream_port, listener->base.data);
+ }
+}
+
+enum bt_graph_status bt_graph_cancel(
+ struct bt_graph *graph)
+{
+
+ BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+ graph->canceled = true;
+ BT_LIB_LOGV("Canceled graph: %!+i", graph);
+ return BT_GRAPH_STATUS_OK;
+}
+
+bt_bool bt_graph_is_canceled(const struct bt_graph *graph)
+{
+ BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+ return graph->canceled ? BT_TRUE : BT_FALSE;
+}
+
+BT_HIDDEN
+void bt_graph_remove_connection(struct bt_graph *graph,
+ struct bt_connection *connection)
+{
+ BT_ASSERT(graph);
+ BT_ASSERT(connection);
+ BT_LIB_LOGV("Removing graph's connection: %![graph-]+g, %![conn-]+x",
+ graph, connection);
+ g_ptr_array_remove(graph->connections, connection);
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool component_name_exists(struct bt_graph *graph, const char *name)
+{
+ bool exists = false;
+ uint64_t i;
+
+ for (i = 0; i < graph->components->len; i++) {
+ struct bt_component *other_comp = graph->components->pdata[i];
+
+ if (strcmp(name, bt_component_get_name(other_comp)) == 0) {
+ BT_ASSERT_PRE_MSG("Another component with the same name already exists in the graph: "
+ "%![other-comp-]+c, name=\"%s\"",
+ other_comp, name);
+ exists = true;
+ goto end;
+ }
+ }
+
+end:
+ return exists;
+}
+
+static
+enum bt_graph_status add_component_with_init_method_data(
+ struct bt_graph *graph,
+ struct bt_component_class *comp_cls,
+ comp_init_method_t init_method,
+ const char *name, const struct bt_value *params,
+ void *init_method_data, struct bt_component **user_component)
+{
+ enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
+ enum bt_self_component_status comp_status;
+ struct bt_component *component = NULL;
+ int ret;
+ bool init_can_consume;
+ struct bt_value *new_params = NULL;
+
+ BT_ASSERT(comp_cls);
+ BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+ BT_ASSERT_PRE_NON_NULL(name, "Name");
+ BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
+ BT_ASSERT_PRE(!component_name_exists(graph, name),
+ "Duplicate component name: %!+g, name=\"%s\"", graph, name);
+ BT_ASSERT_PRE(!params || bt_value_is_map(params),
+ "Parameter value is not a map value: %!+v", params);
+ init_can_consume = graph->can_consume;
+ bt_graph_set_can_consume(graph, false);
+ BT_LIB_LOGD("Adding component to graph: "
+ "%![graph-]+g, %![cc-]+C, name=\"%s\", %![params-]+v, "
+ "init-method-data-addr=%p",
+ graph, comp_cls, name, params, init_method_data);
+
+ if (!params) {
+ new_params = bt_value_map_create();
+ if (!new_params) {
+ BT_LOGE_STR("Cannot create map value object.");
+ graph_status = BT_GRAPH_STATUS_NOMEM;
+ goto end;
+ }
+
+ params = new_params;
+ }
+
+ ret = bt_component_create(comp_cls, name, &component);
+ if (ret) {
+ BT_LOGE("Cannot create empty component object: ret=%d",
+ ret);
+ graph_status = BT_GRAPH_STATUS_NOMEM;
+ goto end;
+ }
+
+ /*
+ * The user's initialization method needs to see that this
+ * component is part of the graph. If the user method fails, we
+ * immediately remove the component from the graph's components.
+ */
+ g_ptr_array_add(graph->components, component);
+ bt_component_set_graph(component, graph);
+
+ if (init_method) {
+ BT_LOGD_STR("Calling user's initialization method.");
+ comp_status = init_method(component, params, init_method_data);
+ BT_LOGD("User method returned: status=%s",
+ bt_self_component_status_string(comp_status));
+ if (comp_status != BT_SELF_COMPONENT_STATUS_OK) {
+ BT_LOGW_STR("Initialization method failed.");
+ graph_status = (int) comp_status;
+ bt_component_set_graph(component, NULL);
+ g_ptr_array_remove_fast(graph->components, component);
+ goto end;
+ }
+ }
+
+ /*
+ * Mark the component as initialized so that its finalization
+ * method is called when it is destroyed.
+ */
+ component->initialized = true;
+
+ /*
+ * If it's a sink component, it needs to be part of the graph's
+ * sink queue to be consumed by bt_graph_consume().
+ */
+ if (bt_component_is_sink(component)) {
+ graph->has_sink = true;
+ g_queue_push_tail(graph->sinks_to_consume, component);
+ }
+
+ /*
+ * Freeze the component class now that it's instantiated at
+ * least once.
+ */
+ BT_LOGD_STR("Freezing component class.");
+ bt_component_class_freeze(comp_cls);
+ BT_LIB_LOGD("Added component to graph: "
+ "%![graph-]+g, %![cc-]+C, name=\"%s\", %![params-]+v, "
+ "init-method-data-addr=%p, %![comp-]+c",
+ graph, comp_cls, name, params, init_method_data, component);
+
+ if (user_component) {
+ /* Move reference to user */
+ *user_component = component;
+ component = NULL;
+ }
+
+end:
+ bt_object_put_ref(component);
+ bt_object_put_ref(new_params);
+ (void) init_can_consume;
+ bt_graph_set_can_consume(graph, init_can_consume);
+ return graph_status;
+}
+
+enum bt_graph_status
+bt_graph_add_source_component_with_init_method_data(
+ struct bt_graph *graph,
+ const struct bt_component_class_source *comp_cls,
+ const char *name, const struct bt_value *params,
+ void *init_method_data,
+ const struct bt_component_source **component)