1 # SPDX-License-Identifier: MIT
3 # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
5 from bt2
import native_bt
6 from bt2
import object as bt2_object
7 from bt2
import utils
as bt2_utils
8 from bt2
import interrupter
as bt2_interrupter
9 from bt2
import connection
as bt2_connection
10 from bt2
import component
as bt2_component
12 from bt2
import port
as bt2_port
13 from bt2
import logging
as bt2_logging
17 def _graph_port_added_listener_from_native(
18 user_listener
, component_ptr
, component_type
, port_ptr
, port_type
20 component
= bt2_component
._create
_component
_from
_const
_ptr
_and
_get
_ref
(
21 component_ptr
, component_type
23 port
= bt2_port
._create
_from
_const
_ptr
_and
_get
_ref
(port_ptr
, port_type
)
24 user_listener(component
, port
)
27 class Graph(bt2_object
._SharedObject
):
30 native_bt
.graph_get_ref(ptr
)
34 native_bt
.graph_put_ref(ptr
)
36 def __init__(self
, mip_version
=0):
37 bt2_utils
._check
_uint
64(mip_version
)
39 if mip_version
> bt2
.get_maximal_mip_version():
40 raise ValueError("unknown MIP version {}".format(mip_version
))
42 ptr
= native_bt
.graph_create(mip_version
)
45 raise bt2
._MemoryError("cannot create graph object")
49 # list of listener partials to keep a reference as long as
51 self
._listener
_partials
= []
59 logging_level
=bt2_logging
.LoggingLevel
.NONE
,
61 if isinstance(component_class
, bt2_component
._SourceComponentClassConst
):
62 cc_ptr
= component_class
._ptr
63 add_fn
= native_bt
.bt2_graph_add_source_component
64 cc_type
= native_bt
.COMPONENT_CLASS_TYPE_SOURCE
65 elif isinstance(component_class
, bt2_component
._FilterComponentClassConst
):
66 cc_ptr
= component_class
._ptr
67 add_fn
= native_bt
.bt2_graph_add_filter_component
68 cc_type
= native_bt
.COMPONENT_CLASS_TYPE_FILTER
69 elif isinstance(component_class
, bt2_component
._SinkComponentClassConst
):
70 cc_ptr
= component_class
._ptr
71 add_fn
= native_bt
.bt2_graph_add_sink_component
72 cc_type
= native_bt
.COMPONENT_CLASS_TYPE_SINK
73 elif issubclass(component_class
, bt2_component
._UserSourceComponent
):
74 cc_ptr
= component_class
._bt
_cc
_ptr
75 add_fn
= native_bt
.bt2_graph_add_source_component
76 cc_type
= native_bt
.COMPONENT_CLASS_TYPE_SOURCE
77 elif issubclass(component_class
, bt2_component
._UserSinkComponent
):
78 cc_ptr
= component_class
._bt
_cc
_ptr
79 add_fn
= native_bt
.bt2_graph_add_sink_component
80 cc_type
= native_bt
.COMPONENT_CLASS_TYPE_SINK
81 elif issubclass(component_class
, bt2_component
._UserFilterComponent
):
82 cc_ptr
= component_class
._bt
_cc
_ptr
83 add_fn
= native_bt
.bt2_graph_add_filter_component
84 cc_type
= native_bt
.COMPONENT_CLASS_TYPE_FILTER
87 "'{}' is not a component class".format(
88 component_class
.__class
__.__name
__
92 bt2_utils
._check
_str
(name
)
93 bt2_utils
._check
_log
_level
(logging_level
)
94 base_cc_ptr
= component_class
._bt
_component
_class
_ptr
()
96 if obj
is not None and not native_bt
.bt2_is_python_component_class(base_cc_ptr
):
97 raise ValueError("cannot pass a Python object to a non-Python component")
99 if params
is not None and not isinstance(params
, (dict, bt2
.MapValue
)):
100 raise TypeError("'params' parameter is not a 'dict' or a 'bt2.MapValue'.")
102 params
= bt2
.create_value(params
)
104 params_ptr
= params
._ptr
if params
is not None else None
106 status
, comp_ptr
= add_fn(
107 self
._ptr
, cc_ptr
, name
, params_ptr
, obj
, logging_level
109 bt2_utils
._handle
_func
_status
(status
, "cannot add component to graph")
111 return bt2_component
._create
_component
_from
_const
_ptr
_and
_get
_ref
(
115 def connect_ports(self
, upstream_port
, downstream_port
):
116 bt2_utils
._check
_type
(upstream_port
, bt2_port
._OutputPortConst
)
117 bt2_utils
._check
_type
(downstream_port
, bt2_port
._InputPortConst
)
118 status
, conn_ptr
= native_bt
.graph_connect_ports(
119 self
._ptr
, upstream_port
._ptr
, downstream_port
._ptr
121 bt2_utils
._handle
_func
_status
(
122 status
, "cannot connect component ports within graph"
125 return bt2_connection
._ConnectionConst
._create
_from
_ptr
_and
_get
_ref
(conn_ptr
)
127 def add_port_added_listener(self
, listener
):
128 if not callable(listener
):
129 raise TypeError("'listener' parameter is not callable")
131 fn
= native_bt
.bt2_graph_add_port_added_listener
132 listener_from_native
= functools
.partial(
133 _graph_port_added_listener_from_native
, listener
136 listener_ids
= fn(self
._ptr
, listener_from_native
)
137 if listener_ids
is None:
138 raise bt2
._Error("cannot add listener to graph object")
140 # keep the partial's reference
141 self
._listener
_partials
.append(listener_from_native
)
144 status
= native_bt
.graph_run_once(self
._ptr
)
145 bt2_utils
._handle
_func
_status
(status
, "graph object could not run once")
148 status
= native_bt
.graph_run(self
._ptr
)
149 bt2_utils
._handle
_func
_status
(status
, "graph object stopped running")
151 def add_interrupter(self
, interrupter
):
152 bt2_utils
._check
_type
(interrupter
, bt2_interrupter
.Interrupter
)
153 native_bt
.graph_add_interrupter(self
._ptr
, interrupter
._ptr
)
156 def default_interrupter(self
):
157 ptr
= native_bt
.graph_borrow_default_interrupter(self
._ptr
)
158 return bt2_interrupter
.Interrupter
._create
_from
_ptr
_and
_get
_ref
(ptr
)