Commit | Line | Data |
---|---|---|
811644b8 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 | |
28 | import bt2 | |
29 | ||
30 | ||
5f25509b SM |
31 | def _graph_port_added_listener_from_native(user_listener, |
32 | component_ptr, component_type, | |
33 | port_ptr, port_type): | |
34 | component = bt2.component._create_component_from_ptr_and_get_ref(component_ptr, component_type) | |
35 | port = bt2.port._create_from_ptr_and_get_ref(port_ptr, port_type) | |
36 | user_listener(component, port) | |
811644b8 PP |
37 | |
38 | ||
39 | def _graph_ports_connected_listener_from_native(user_listener, | |
5f25509b | 40 | upstream_component_ptr, upstream_component_type, |
811644b8 | 41 | upstream_port_ptr, |
5f25509b | 42 | downstream_component_ptr, downstream_component_type, |
811644b8 | 43 | downstream_port_ptr): |
5f25509b SM |
44 | upstream_component = bt2.component._create_component_from_ptr_and_get_ref( |
45 | upstream_component_ptr, upstream_component_type) | |
46 | upstream_port = bt2.port._create_from_ptr_and_get_ref( | |
47 | upstream_port_ptr, native_bt.PORT_TYPE_OUTPUT) | |
48 | downstream_component = bt2.component._create_component_from_ptr_and_get_ref( | |
49 | downstream_component_ptr, downstream_component_type) | |
50 | downstream_port = bt2.port._create_from_ptr_and_get_ref( | |
51 | downstream_port_ptr, native_bt.PORT_TYPE_INPUT) | |
52 | user_listener(upstream_component, upstream_port, downstream_component, downstream_port) | |
811644b8 PP |
53 | |
54 | ||
78288f58 | 55 | class Graph(object._SharedObject): |
2f16a6a2 PP |
56 | _get_ref = staticmethod(native_bt.graph_get_ref) |
57 | _put_ref = staticmethod(native_bt.graph_put_ref) | |
601c0026 | 58 | |
811644b8 PP |
59 | def __init__(self): |
60 | ptr = native_bt.graph_create() | |
61 | ||
62 | if ptr is None: | |
63 | raise bt2.CreationError('cannot create graph object') | |
64 | ||
65 | super().__init__(ptr) | |
66 | ||
67 | def _handle_status(self, status, gen_error_msg): | |
68 | if status == native_bt.GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION: | |
69 | raise bt2.PortConnectionRefused | |
70 | elif status == native_bt.GRAPH_STATUS_CANCELED: | |
71 | raise bt2.GraphCanceled | |
72 | elif status == native_bt.GRAPH_STATUS_END: | |
73 | raise bt2.Stop | |
74 | elif status == native_bt.GRAPH_STATUS_AGAIN: | |
75 | raise bt2.TryAgain | |
811644b8 PP |
76 | elif status < 0: |
77 | raise bt2.Error(gen_error_msg) | |
78 | ||
894a8df5 | 79 | def add_component(self, component_class, name, params=None): |
5f25509b SM |
80 | if isinstance(component_class, bt2.component._GenericSourceComponentClass): |
81 | cc_ptr = component_class._ptr | |
894a8df5 SM |
82 | add_fn = native_bt.graph_add_source_component |
83 | cc_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE | |
5f25509b SM |
84 | elif isinstance(component_class, bt2.component._GenericFilterComponentClass): |
85 | cc_ptr = component_class._ptr | |
894a8df5 SM |
86 | add_fn = native_bt.graph_add_filter_component |
87 | cc_type = native_bt.COMPONENT_CLASS_TYPE_FILTER | |
5f25509b 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 | |
894a8df5 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 | |
5f25509b 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 | |
811644b8 | 104 | else: |
894a8df5 | 105 | raise TypeError("'{}' is not a component class".format( |
601c0026 | 106 | component_class.__class__.__name__)) |
811644b8 PP |
107 | |
108 | utils._check_str(name) | |
109 | params = bt2.create_value(params) | |
110 | ||
601c0026 | 111 | params_ptr = params._ptr if params is not None else None |
811644b8 | 112 | |
894a8df5 SM |
113 | status, comp_ptr = add_fn(self._ptr, cc_ptr, name, params_ptr) |
114 | self._handle_status(status, 'cannot add component to graph') | |
115 | assert comp_ptr | |
116 | return bt2.component._create_component_from_ptr(comp_ptr, cc_type) | |
811644b8 PP |
117 | |
118 | def connect_ports(self, upstream_port, downstream_port): | |
119 | utils._check_type(upstream_port, bt2.port._OutputPort) | |
120 | utils._check_type(downstream_port, bt2.port._InputPort) | |
121 | status, conn_ptr = native_bt.graph_connect_ports(self._ptr, | |
122 | upstream_port._ptr, | |
123 | downstream_port._ptr) | |
124 | self._handle_status(status, 'cannot connect component ports within graph') | |
125 | assert(conn_ptr) | |
126 | return bt2.connection._Connection._create_from_ptr(conn_ptr) | |
127 | ||
5f25509b SM |
128 | def add_port_added_listener(self, listener): |
129 | if not callable(listener): | |
811644b8 PP |
130 | raise TypeError("'listener' parameter is not callable") |
131 | ||
5f25509b SM |
132 | fn = native_bt.py3_graph_add_port_added_listener |
133 | listener_from_native = functools.partial(_graph_port_added_listener_from_native, | |
134 | listener) | |
811644b8 | 135 | |
5f25509b SM |
136 | listener_ids = fn(self._ptr, listener_from_native) |
137 | if listener_ids is None: | |
138 | utils._raise_bt2_error('cannot add listener to graph object') | |
139 | return bt2._ListenerHandle(listener_ids, self) | |
140 | ||
141 | def add_ports_connected_listener(self, listener): | |
142 | if not callable(listener): | |
143 | raise TypeError("'listener' parameter is not callable") | |
144 | ||
145 | fn = native_bt.py3_graph_add_ports_connected_listener | |
146 | listener_from_native = functools.partial(_graph_ports_connected_listener_from_native, | |
147 | listener) | |
148 | ||
149 | listener_ids = fn(self._ptr, listener_from_native) | |
150 | if listener_ids is None: | |
151 | utils._raise_bt2_error('cannot add listener to graph object') | |
152 | return bt2._ListenerHandle(listener_ids, self) | |
811644b8 PP |
153 | |
154 | def run(self): | |
155 | status = native_bt.graph_run(self._ptr) | |
156 | ||
157 | if status == native_bt.GRAPH_STATUS_END: | |
158 | return | |
159 | ||
160 | self._handle_status(status, 'graph object stopped running because of an unexpected error') | |
161 | ||
162 | def cancel(self): | |
163 | status = native_bt.graph_cancel(self._ptr) | |
164 | self._handle_status(status, 'cannot cancel graph object') | |
165 | ||
166 | @property | |
167 | def is_canceled(self): | |
168 | is_canceled = native_bt.graph_is_canceled(self._ptr) | |
169 | assert(is_canceled >= 0) | |
170 | return is_canceled > 0 | |
171 | ||
2ae9f48c SM |
172 | def create_output_port_message_iterator(self, output_port): |
173 | utils._check_type(output_port, bt2.port._OutputPort) | |
174 | msg_iter_ptr = native_bt.port_output_message_iterator_create(self._ptr, output_port._ptr) | |
175 | ||
176 | if msg_iter_ptr is None: | |
177 | raise bt2.CreationError('cannot create output port message iterator') | |
178 | ||
179 | return bt2.message_iterator._OutputPortMessageIterator(msg_iter_ptr) |