+ const struct bt_component_class_filter *comp_cls,
+ const char *name, const struct bt_value *params,
+ void *init_method_data,
+ const struct bt_component_filter **component)
+{
+ BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+ return add_component_with_init_method_data(graph,
+ (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
+ name, params, init_method_data, (void *) component);
+}
+
+enum bt_graph_status bt_graph_add_filter_component(
+ struct bt_graph *graph,
+ const struct bt_component_class_filter *comp_cls,
+ const char *name, const struct bt_value *params,
+ const struct bt_component_filter **component)
+{
+ return bt_graph_add_filter_component_with_init_method_data(
+ graph, comp_cls, name, params, NULL, component);
+}
+
+enum bt_graph_status
+bt_graph_add_sink_component_with_init_method_data(
+ struct bt_graph *graph,
+ const struct bt_component_class_sink *comp_cls,
+ const char *name, const struct bt_value *params,
+ void *init_method_data,
+ const struct bt_component_sink **component)
+{
+ BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+ return add_component_with_init_method_data(graph,
+ (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
+ name, params, init_method_data, (void *) component);
+}
+
+enum bt_graph_status bt_graph_add_sink_component(
+ struct bt_graph *graph,
+ const struct bt_component_class_sink *comp_cls,
+ const char *name, const struct bt_value *params,
+ const struct bt_component_sink **component)
+{
+ return bt_graph_add_sink_component_with_init_method_data(
+ graph, comp_cls, name, params, NULL, component);
+}
+
+BT_HIDDEN
+int bt_graph_remove_unconnected_component(struct bt_graph *graph,
+ struct bt_component *component)
+{
+ bool init_can_consume;
+ uint64_t count;
+ uint64_t i;
+ int ret = 0;
+
+ BT_ASSERT(graph);
+ BT_ASSERT(component);
+ BT_ASSERT(component->base.ref_count == 0);
+ BT_ASSERT(bt_component_borrow_graph(component) == graph);
+
+ init_can_consume = graph->can_consume;
+ count = bt_component_get_input_port_count(component);
+
+ for (i = 0; i < count; i++) {
+ struct bt_port *port = (void *)
+ bt_component_borrow_input_port_by_index(component, i);
+
+ BT_ASSERT(port);
+
+ if (bt_port_is_connected(port)) {
+ BT_LIB_LOGW("Cannot remove component from graph: "
+ "an input port is connected: "
+ "%![graph-]+g, %![comp-]+c, %![port-]+p",
+ graph, component, port);
+ goto error;
+ }
+ }
+
+ count = bt_component_get_output_port_count(component);
+
+ for (i = 0; i < count; i++) {
+ struct bt_port *port = (void *)
+ bt_component_borrow_output_port_by_index(component, i);
+
+ BT_ASSERT(port);
+
+ if (bt_port_is_connected(port)) {
+ BT_LIB_LOGW("Cannot remove component from graph: "
+ "an output port is connected: "
+ "%![graph-]+g, %![comp-]+c, %![port-]+p",
+ graph, component, port);
+ goto error;
+ }
+ }
+
+ bt_graph_set_can_consume(graph, false);
+
+ /* Possibly remove from sinks to consume */
+ (void) g_queue_remove(graph->sinks_to_consume, component);
+
+ if (graph->sinks_to_consume->length == 0) {
+ graph->has_sink = false;
+ }
+
+ /*
+ * This calls bt_object_try_spec_release() on the component, and
+ * since its reference count is 0, its destructor is called. Its
+ * destructor calls the user's finalization method (if set).
+ */
+ g_ptr_array_remove(graph->components, component);
+ goto end;
+
+error:
+ ret = -1;
+
+end:
+ (void) init_can_consume;
+ bt_graph_set_can_consume(graph, init_can_consume);
+ return ret;
+}
+
+BT_HIDDEN
+void bt_graph_add_message(struct bt_graph *graph,
+ struct bt_message *msg)
+{
+ BT_ASSERT(graph);
+ BT_ASSERT(msg);
+
+ /*
+ * It's okay not to take a reference because, when a
+ * message's reference count drops to 0, either:
+ *
+ * * It is recycled back to one of this graph's pool.
+ * * It is destroyed because it doesn't have any link to any
+ * graph, which means the original graph is already destroyed.
+ */
+ g_ptr_array_add(graph->messages, msg);
+}
+
+void bt_graph_get_ref(const struct bt_graph *graph)
+{
+ bt_object_get_ref(graph);
+}
+
+void bt_graph_put_ref(const struct bt_graph *graph)