2 * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "common/logger.h"
19 #include "common/picojson.h"
20 #include "ml_pipeline.h"
21 #include "ml_pipeline_sink.h"
24 using common::PlatformResult;
25 using common::ErrorCode;
29 const std::string kListenerId = "listenerId";
30 const std::string kState = "state";
32 std::string StateToString(ml_pipeline_state_e state) {
33 ScopeLogger("state: [%d]", state);
35 std::string state_str;
37 case ML_PIPELINE_STATE_UNKNOWN:
38 state_str = "UNKNOWN";
40 case ML_PIPELINE_STATE_NULL:
43 case ML_PIPELINE_STATE_READY:
46 case ML_PIPELINE_STATE_PAUSED:
49 case ML_PIPELINE_STATE_PLAYING:
50 state_str = "PLAYING";
53 LoggerE("Illegal ml_pipeline_state_e value: [%d]", state);
54 state_str = "UNKNOWN";
57 LoggerD("state_str: [%s]", state_str.c_str());
66 Pipeline::Pipeline(int id, const std::string& state_change_listener_name,
67 TensorsInfoManager* tensors_info_manager_ptr, common::Instance* instance_ptr)
69 pipeline_{nullptr}, // this will be set to a proper pointer in CreatePipeline()
70 state_change_listener_name_{state_change_listener_name},
71 tensors_info_manager_ptr_{tensors_info_manager_ptr},
72 instance_ptr_{instance_ptr} {
73 ScopeLogger("id: [%d], state_change_listener_name: [%s]", id, state_change_listener_name.c_str());
76 // Pipeline::createPipeline() begin
77 PlatformResult Pipeline::CreatePipeline(int id, const std::string& definition,
78 const std::string& state_change_listener_name,
79 common::Instance* instance_ptr,
80 TensorsInfoManager* tensors_info_manager_ptr,
81 std::unique_ptr<Pipeline>* out) {
82 ScopeLogger("id: [%d], definition: [%s], state_change_listener_name: [%s]", id,
83 definition.c_str(), state_change_listener_name.c_str());
85 /* We need to create the Pipeline object before setting its pipeline_ member,
86 * because Pipeline is the user data for the listener registered by
87 * ml_pipeline_construct().
89 std::unique_ptr<Pipeline> pipeline_ptr{new (std::nothrow) Pipeline{
90 id, state_change_listener_name, tensors_info_manager_ptr, instance_ptr}};
92 return LogAndCreateResult(ErrorCode::ABORT_ERR, "An unknown occurred.",
93 ("Could not allocate memory for Pipeline"));
96 int ret = ML_ERROR_UNKNOWN;
97 if (state_change_listener_name == "") {
98 ret = ml_pipeline_construct(definition.c_str(), nullptr, nullptr, &pipeline_ptr->pipeline_);
100 ret = ml_pipeline_construct(definition.c_str(), PipelineStateChangeListener,
101 static_cast<void*>(pipeline_ptr.get()), &pipeline_ptr->pipeline_);
104 if (ML_ERROR_NONE != ret) {
105 LoggerE("ml_pipeline_construct() failed: [%d] (%s)", ret, get_error_message(ret));
106 return util::ToPlatformResult(ret, "Could not create a pipeline");
108 LoggerD("ml_pipeline_construct() succeeded");
110 *out = std::move(pipeline_ptr);
111 return PlatformResult{};
113 // Pipeline::createPipeline() end
115 Pipeline::~Pipeline() {
116 ScopeLogger("Destroying pipeline: [%d]", id_);
119 LoggerD("pipeline_ has already been destroyed");
126 void Pipeline::PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data) {
127 ScopeLogger("state: [%s]", StateToString(state).c_str());
129 Pipeline* pipeline = static_cast<Pipeline*>(user_data);
131 picojson::value response{picojson::object{}};
132 response.get<picojson::object>()[kListenerId] =
133 picojson::value{pipeline->state_change_listener_name_};
134 response.get<picojson::object>()[kState] = picojson::value{StateToString(state)};
136 common::Instance::PostMessage(pipeline->instance_ptr_, response);
139 // Pipeline::state begin
140 PlatformResult Pipeline::GetState(std::string* out) {
141 ScopeLogger("id_: [%d]", id_);
143 ml_pipeline_state_e state = ML_PIPELINE_STATE_UNKNOWN;
144 auto ret = ml_pipeline_get_state(pipeline_, &state);
145 if (ML_ERROR_NONE != ret) {
146 LoggerE("ml_pipeline_get_state() failed: [%d] (%s)", ret, get_error_message(ret));
147 return util::ToPlatformResult(ret, "Could not get pipeline state");
149 LoggerD("ml_pipeline_get_state() succeeded");
151 *out = StateToString(state);
152 return PlatformResult{};
154 // Pipeline::state end
156 // Pipeline::start() begin
157 PlatformResult Pipeline::Start() {
158 ScopeLogger("id_: [%d]", id_);
160 auto ret = ml_pipeline_start(pipeline_);
161 if (ML_ERROR_NONE != ret) {
162 LoggerE("ml_pipeline_start() failed: [%d] (%s)", ret, get_error_message(ret));
163 return util::ToPlatformResult(ret, "Could not start pipeline");
165 return PlatformResult{};
167 // Pipeline::start() end
169 // Pipeline::stop() begin
170 PlatformResult Pipeline::Stop() {
171 ScopeLogger("id_: [%d]", id_);
173 auto ret = ml_pipeline_stop(pipeline_);
174 if (ML_ERROR_NONE != ret) {
175 LoggerE("ml_pipeline_stop() failed: [%d] (%s)", ret, get_error_message(ret));
176 return util::ToPlatformResult(ret, "Could not stop pipeline");
178 return PlatformResult{};
180 // Pipeline::stop() end
182 // Pipeline::dispose() begin
183 PlatformResult Pipeline::Dispose() {
184 ScopeLogger("id_: [%d]", id_);
187 * TODO in future commits:
189 * Release all nodes belonging to this pipeline and
190 * cached in this object in containers like
191 * switches_, node_infos_, etc.
193 * They have to be released HERE (i.e. BEFORE releasing pipeline_).
194 * If they're released after pipeline_, the app may crash.
206 auto ret = ml_pipeline_destroy(pipeline_);
207 if (ML_ERROR_NONE != ret) {
208 LoggerE("ml_pipeline_destroy() failed: [%d] (%s)", ret, get_error_message(ret));
209 return util::ToPlatformResult(ret, "Could not dispose the pipeline");
211 LoggerD("ml_pipeline_destroy() succeeded");
215 return PlatformResult{};
217 // Pipeline::dispose() end
219 // Pipeline::getNodeInfo() begin
220 PlatformResult Pipeline::GetNodeInfo(const std::string& name) {
221 ScopeLogger("id_: [%d], name: [%s]", id_, name.c_str());
223 auto nodeinfo_it = node_info_.find(name);
224 if (node_info_.end() != nodeinfo_it) {
225 LoggerD("NodeInfo [%s] found", name.c_str());
226 return PlatformResult{};
229 std::unique_ptr<NodeInfo> node_info_ptr;
230 auto ret = NodeInfo::CreateNodeInfo(pipeline_, name, &node_info_ptr);
236 node_info_.insert({name, std::move(node_info_ptr)});
238 return PlatformResult{};
240 // Pipeline::getNodeInfo() end
242 // Pipeline::getSource() begin
243 PlatformResult Pipeline::GetSource(const std::string& name) {
244 ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
246 auto source_it = sources_.find(name);
247 if (sources_.end() != source_it) {
248 LoggerD("Source [%s] found", name.c_str());
249 return PlatformResult{};
252 std::unique_ptr<Source> source_ptr;
253 auto ret = Source::CreateSource(name, pipeline_, source_ptr);
255 sources_.insert({name, std::move(source_ptr)});
259 // Pipeline::getSource() end
261 // Pipeline::getSwitch() begin
262 PlatformResult Pipeline::GetSwitch(const std::string& name, std::string* type) {
263 ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
265 auto switch_it = switches_.find(name);
266 if (switches_.end() != switch_it) {
267 LoggerD("Switch [%s] found", name.c_str());
268 *type = switch_it->second->GetType();
269 return PlatformResult{};
271 LoggerD("Switch [%s] not found", name.c_str());
273 std::unique_ptr<Switch> switch_ptr;
274 auto ret = Switch::CreateSwitch(name, pipeline_, switch_ptr);
276 *type = switch_ptr->GetType();
277 switches_.insert({name, std::move(switch_ptr)});
281 // Pipeline::getSwitch() end
283 // Pipeline::getValve() begin
284 PlatformResult Pipeline::GetValve(const std::string& name) {
285 ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
287 auto valve_it = valves_.find(name);
288 if (valves_.end() != valve_it) {
289 LoggerD("Valve [%s] found", name.c_str());
290 return PlatformResult{};
292 LoggerD("Creating [%s] Valve", name.c_str());
294 std::unique_ptr<Valve> valve_ptr;
295 auto ret = Valve::CreateValve(name, pipeline_, *this, valve_ptr);
297 valves_.insert({name, std::move(valve_ptr)});
301 // Pipeline::getValve() end
303 // Pipeline::registerSinkCallback() begin
304 PlatformResult Pipeline::RegisterSinkListener(const std::string& sink_name,
305 const std::string& listener_name) {
306 ScopeLogger("sink_name: [%s], listener_name: [%s], id_: [%d]", sink_name.c_str(),
307 listener_name.c_str(), id_);
309 if (sinks_.count(sink_name)) {
310 LoggerD("Listener for [%s] sink is already registered", sink_name.c_str());
311 return PlatformResult{};
314 std::unique_ptr<Sink> sink_ptr;
315 auto ret = Sink::CreateAndRegisterSink(sink_name, listener_name, pipeline_, instance_ptr_,
316 tensors_info_manager_ptr_, &sink_ptr);
321 sinks_.insert({sink_name, std::move(sink_ptr)});
323 return PlatformResult{};
325 // Pipeline::registerSinkCallback() end
327 // Pipeline::unregisterSinkCallback() begin
328 PlatformResult Pipeline::UnregisterSinkListener(const std::string& sink_name) {
329 ScopeLogger("sink_name: [%s], id_: [%d]", sink_name.c_str(), id_);
331 auto sink_it = sinks_.find(sink_name);
332 if (sinks_.end() == sink_it) {
333 LoggerD("sink [%s] not found", sink_name.c_str());
334 return PlatformResult{ErrorCode::INVALID_VALUES_ERR, "The sink has not been registered"};
337 auto ret = sink_it->second->Unregister();
339 sinks_.erase(sink_it);
343 // Pipeline::unregisterSinkCallback() end
345 // NodeInfo::getProperty() begin
346 PlatformResult Pipeline::getProperty(const std::string& node_name, const std::string& name,
347 const std::string& type, picojson::object* property) {
348 ScopeLogger("id_: [%d], name: [%s], type: [%s]", id_, name.c_str(), type.c_str());
350 auto nodeinfo_it = node_info_.find(node_name);
351 if (node_info_.end() == nodeinfo_it) {
352 LoggerD("NodeInfo [%s] not found", node_name.c_str());
353 return PlatformResult{ErrorCode::NOT_FOUND_ERR, "NodeInfo not found"};
356 return nodeinfo_it->second->getProperty(name, type, property);
358 // NodeInfo::getProperty() end
360 // NodeInfo::setProperty() begin
361 PlatformResult Pipeline::setProperty(const std::string& node_name, const std::string& name,
362 const std::string& type, const picojson::value& property) {
363 ScopeLogger("id_: [%d], name: [%s], type: [%s]", id_, name.c_str(), type.c_str());
365 auto nodeinfo_it = node_info_.find(node_name);
366 if (node_info_.end() == nodeinfo_it) {
367 LoggerD("NodeInfo [%s] not found", node_name.c_str());
368 return PlatformResult{ErrorCode::NOT_FOUND_ERR, "NodeInfo not found"};
371 return nodeinfo_it->second->setProperty(name, type, property);
373 // NodeInfo::setProperty() end
375 // Source::inputTensorsInfo begin
376 PlatformResult Pipeline::getInputTensorsInfo(const std::string& name, ml_tensors_info_h* result) {
379 auto source_it = sources_.find(name);
380 if (sources_.end() == source_it) {
381 LoggerD("Source [%s] not found", name.c_str());
382 return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Source not found"};
385 return source_it->second->getInputTensorsInfo(result);
387 // Source::inputTensorsInfo end
389 // Source::inputData() begin
390 PlatformResult Pipeline::SourceInputData(const std::string& name, TensorsData* tensors_data) {
393 auto source_it = sources_.find(name);
394 if (sources_.end() == source_it) {
395 LoggerD("Source [%s] not found", name.c_str());
396 return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Source not found"};
399 return source_it->second->SourceInputData(tensors_data);
401 // Source::inputData() end
403 // Switch::getPadList() begin
404 PlatformResult Pipeline::GetSwitch(const std::string& name, Switch** out) {
405 ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
407 auto switch_it = switches_.find(name);
408 if (switches_.end() != switch_it) {
409 LoggerD("Switch [%s] found", name.c_str());
410 *out = switch_it->second.get();
411 return PlatformResult{};
413 LoggerE("Switch [%s] not found", name.c_str());
414 return PlatformResult{ErrorCode::ABORT_ERR, "Switch does not exist"};
417 // Switch::getPadList() end
419 // Valve::setOpen() begin
420 PlatformResult Pipeline::GetNodeInfo(const std::string& name, NodeInfo** out) {
421 ScopeLogger("id_: [%d], name: [%s]", id_, name.c_str());
423 auto ret = GetNodeInfo(name);
425 *out = node_info_[name].get();
431 PlatformResult Pipeline::GetValve(const std::string& name, Valve** out) {
432 ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
434 auto ret = GetValve(name);
436 *out = valves_[name].get();
440 // Valve::setOpen() end
442 } // namespace extension