Commit | Line | Data |
---|---|---|
f6a5e476 PP |
1 | # The MIT License (MIT) |
2 | # | |
3 | # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com> | |
4 | # | |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | # of this software and associated documentation files (the "Software"), to deal | |
7 | # in the Software without restriction, including without limitation the rights | |
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | # copies of the Software, and to permit persons to whom the Software is | |
10 | # furnished to do so, subject to the following conditions: | |
11 | # | |
12 | # The above copyright notice and this permission notice shall be included in | |
13 | # all copies or substantial portions of the Software. | |
14 | # | |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
21 | # THE SOFTWARE. | |
22 | ||
23 | from bt2 import native_bt, object, utils | |
24 | import bt2.connection | |
25 | import bt2.component | |
26 | import functools | |
27 | import bt2.port | |
cc81b5ab | 28 | import bt2.logging |
f6a5e476 PP |
29 | import bt2 |
30 | ||
31 | ||
871a292a SM |
32 | def _graph_port_added_listener_from_native(user_listener, |
33 | component_ptr, component_type, | |
34 | port_ptr, port_type): | |
35 | component = bt2.component._create_component_from_ptr_and_get_ref(component_ptr, component_type) | |
36 | port = bt2.port._create_from_ptr_and_get_ref(port_ptr, port_type) | |
37 | user_listener(component, port) | |
f6a5e476 PP |
38 | |
39 | ||
40 | def _graph_ports_connected_listener_from_native(user_listener, | |
871a292a | 41 | upstream_component_ptr, upstream_component_type, |
f6a5e476 | 42 | upstream_port_ptr, |
871a292a | 43 | downstream_component_ptr, downstream_component_type, |
f6a5e476 | 44 | downstream_port_ptr): |
871a292a SM |
45 | upstream_component = bt2.component._create_component_from_ptr_and_get_ref( |
46 | upstream_component_ptr, upstream_component_type) | |
47 | upstream_port = bt2.port._create_from_ptr_and_get_ref( | |
48 | upstream_port_ptr, native_bt.PORT_TYPE_OUTPUT) | |
49 | downstream_component = bt2.component._create_component_from_ptr_and_get_ref( | |
50 | downstream_component_ptr, downstream_component_type) | |
51 | downstream_port = bt2.port._create_from_ptr_and_get_ref( | |
52 | downstream_port_ptr, native_bt.PORT_TYPE_INPUT) | |
53 | user_listener(upstream_component, upstream_port, downstream_component, downstream_port) | |
f6a5e476 PP |
54 | |
55 | ||
c3044a97 | 56 | class Graph(object._SharedObject): |
a49e2cc3 PP |
57 | _get_ref = staticmethod(native_bt.graph_get_ref) |
58 | _put_ref = staticmethod(native_bt.graph_put_ref) | |
bbb3650f | 59 | |
f6a5e476 PP |
60 | def __init__(self): |
61 | ptr = native_bt.graph_create() | |
62 | ||
63 | if ptr is None: | |
64 | raise bt2.CreationError('cannot create graph object') | |
65 | ||
66 | super().__init__(ptr) | |
67 | ||
68 | def _handle_status(self, status, gen_error_msg): | |
aa23edf1 | 69 | if status == native_bt.GRAPH_STATUS_CANCELED: |
f6a5e476 PP |
70 | raise bt2.GraphCanceled |
71 | elif status == native_bt.GRAPH_STATUS_END: | |
72 | raise bt2.Stop | |
73 | elif status == native_bt.GRAPH_STATUS_AGAIN: | |
74 | raise bt2.TryAgain | |
f6a5e476 PP |
75 | elif status < 0: |
76 | raise bt2.Error(gen_error_msg) | |
77 | ||
cc81b5ab PP |
78 | def add_component(self, component_class, name, params=None, |
79 | logging_level=bt2.logging.LoggingLevel.NONE): | |
871a292a SM |
80 | if isinstance(component_class, bt2.component._GenericSourceComponentClass): |
81 | cc_ptr = component_class._ptr | |
bc5c9924 SM |
82 | add_fn = native_bt.graph_add_source_component |
83 | cc_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE | |
871a292a SM |
84 | elif isinstance(component_class, bt2.component._GenericFilterComponentClass): |
85 | cc_ptr = component_class._ptr | |
bc5c9924 SM |
86 | add_fn = native_bt.graph_add_filter_component |
87 | cc_type = native_bt.COMPONENT_CLASS_TYPE_FILTER | |
871a292a SM |
88 | elif isinstance(component_class, bt2.component._GenericSinkComponentClass): |
89 | cc_ptr = component_class._ptr | |
90 | add_fn = native_bt.graph_add_sink_component | |
91 | cc_type = native_bt.COMPONENT_CLASS_TYPE_SINK | |
92 | elif issubclass(component_class, bt2.component._UserSourceComponent): | |
93 | cc_ptr = component_class._cc_ptr | |
94 | add_fn = native_bt.graph_add_source_component | |
95 | cc_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE | |
bc5c9924 SM |
96 | elif issubclass(component_class, bt2.component._UserSinkComponent): |
97 | cc_ptr = component_class._cc_ptr | |
98 | add_fn = native_bt.graph_add_sink_component | |
99 | cc_type = native_bt.COMPONENT_CLASS_TYPE_SINK | |
871a292a SM |
100 | elif issubclass(component_class, bt2.component._UserFilterComponent): |
101 | cc_ptr = component_class._cc_ptr | |
102 | add_fn = native_bt.graph_add_filter_component | |
103 | cc_type = native_bt.COMPONENT_CLASS_TYPE_FILTER | |
f6a5e476 | 104 | else: |
bc5c9924 | 105 | raise TypeError("'{}' is not a component class".format( |
bbb3650f | 106 | component_class.__class__.__name__)) |
f6a5e476 PP |
107 | |
108 | utils._check_str(name) | |
cc81b5ab | 109 | utils._check_log_level(logging_level) |
f6a5e476 PP |
110 | params = bt2.create_value(params) |
111 | ||
bbb3650f | 112 | params_ptr = params._ptr if params is not None else None |
f6a5e476 | 113 | |
cc81b5ab PP |
114 | status, comp_ptr = add_fn(self._ptr, cc_ptr, name, |
115 | params_ptr, logging_level) | |
bc5c9924 SM |
116 | self._handle_status(status, 'cannot add component to graph') |
117 | assert comp_ptr | |
118 | return bt2.component._create_component_from_ptr(comp_ptr, cc_type) | |
f6a5e476 PP |
119 | |
120 | def connect_ports(self, upstream_port, downstream_port): | |
121 | utils._check_type(upstream_port, bt2.port._OutputPort) | |
122 | utils._check_type(downstream_port, bt2.port._InputPort) | |
123 | status, conn_ptr = native_bt.graph_connect_ports(self._ptr, | |
124 | upstream_port._ptr, | |
125 | downstream_port._ptr) | |
126 | self._handle_status(status, 'cannot connect component ports within graph') | |
127 | assert(conn_ptr) | |
128 | return bt2.connection._Connection._create_from_ptr(conn_ptr) | |
129 | ||
871a292a SM |
130 | def add_port_added_listener(self, listener): |
131 | if not callable(listener): | |
f6a5e476 PP |
132 | raise TypeError("'listener' parameter is not callable") |
133 | ||
871a292a SM |
134 | fn = native_bt.py3_graph_add_port_added_listener |
135 | listener_from_native = functools.partial(_graph_port_added_listener_from_native, | |
136 | listener) | |
f6a5e476 | 137 | |
871a292a SM |
138 | listener_ids = fn(self._ptr, listener_from_native) |
139 | if listener_ids is None: | |
140 | utils._raise_bt2_error('cannot add listener to graph object') | |
141 | return bt2._ListenerHandle(listener_ids, self) | |
142 | ||
143 | def add_ports_connected_listener(self, listener): | |
144 | if not callable(listener): | |
145 | raise TypeError("'listener' parameter is not callable") | |
146 | ||
147 | fn = native_bt.py3_graph_add_ports_connected_listener | |
148 | listener_from_native = functools.partial(_graph_ports_connected_listener_from_native, | |
149 | listener) | |
150 | ||
151 | listener_ids = fn(self._ptr, listener_from_native) | |
152 | if listener_ids is None: | |
153 | utils._raise_bt2_error('cannot add listener to graph object') | |
154 | return bt2._ListenerHandle(listener_ids, self) | |
f6a5e476 PP |
155 | |
156 | def run(self): | |
157 | status = native_bt.graph_run(self._ptr) | |
158 | ||
159 | if status == native_bt.GRAPH_STATUS_END: | |
160 | return | |
161 | ||
162 | self._handle_status(status, 'graph object stopped running because of an unexpected error') | |
163 | ||
164 | def cancel(self): | |
165 | status = native_bt.graph_cancel(self._ptr) | |
166 | self._handle_status(status, 'cannot cancel graph object') | |
167 | ||
168 | @property | |
169 | def is_canceled(self): | |
170 | is_canceled = native_bt.graph_is_canceled(self._ptr) | |
171 | assert(is_canceled >= 0) | |
172 | return is_canceled > 0 | |
173 | ||
27d97a3f SM |
174 | def create_output_port_message_iterator(self, output_port): |
175 | utils._check_type(output_port, bt2.port._OutputPort) | |
176 | msg_iter_ptr = native_bt.port_output_message_iterator_create(self._ptr, output_port._ptr) | |
177 | ||
178 | if msg_iter_ptr is None: | |
179 | raise bt2.CreationError('cannot create output port message iterator') | |
180 | ||
181 | return bt2.message_iterator._OutputPortMessageIterator(msg_iter_ptr) |