0719a2d9ab651337a1c4a42975ec3d6814bb6164
[platform/core/api/webapi-plugins.git] / src / ml / ml_pipeline.cc
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #include <tizen.h>
17
18 #include "common/logger.h"
19 #include "common/picojson.h"
20 #include "ml_pipeline.h"
21 #include "ml_pipeline_sink.h"
22 #include "ml_utils.h"
23
24 using common::PlatformResult;
25 using common::ErrorCode;
26
27 namespace {
28
29 const std::string kListenerId = "listenerId";
30 const std::string kState = "state";
31
32 std::string StateToString(ml_pipeline_state_e state) {
33   ScopeLogger("state: [%d]", state);
34
35   std::string state_str;
36   switch (state) {
37     case ML_PIPELINE_STATE_UNKNOWN:
38       state_str = "UNKNOWN";
39       break;
40     case ML_PIPELINE_STATE_NULL:
41       state_str = "NULL";
42       break;
43     case ML_PIPELINE_STATE_READY:
44       state_str = "READY";
45       break;
46     case ML_PIPELINE_STATE_PAUSED:
47       state_str = "PAUSED";
48       break;
49     case ML_PIPELINE_STATE_PLAYING:
50       state_str = "PLAYING";
51       break;
52     default:
53       LoggerE("Illegal ml_pipeline_state_e value: [%d]", state);
54       state_str = "UNKNOWN";
55   }
56
57   LoggerD("state_str: [%s]", state_str.c_str());
58   return state_str;
59 }
60
61 }  // namespace
62
63 namespace extension {
64 namespace ml {
65
66 Pipeline::Pipeline(int id, const std::string& state_change_listener_name,
67                    TensorsInfoManager* tensors_info_manager_ptr, common::Instance* instance_ptr)
68     : id_{id},
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());
74 }
75
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());
84
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().
88    */
89   std::unique_ptr<Pipeline> pipeline_ptr{new (std::nothrow) Pipeline{
90       id, state_change_listener_name, tensors_info_manager_ptr, instance_ptr}};
91   if (!pipeline_ptr) {
92     return LogAndCreateResult(ErrorCode::ABORT_ERR, "An unknown occurred.",
93                               ("Could not allocate memory for Pipeline"));
94   }
95
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_);
99   } else {
100     ret = ml_pipeline_construct(definition.c_str(), PipelineStateChangeListener,
101                                 static_cast<void*>(pipeline_ptr.get()), &pipeline_ptr->pipeline_);
102   }
103
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");
107   }
108   LoggerD("ml_pipeline_construct() succeeded");
109
110   *out = std::move(pipeline_ptr);
111   return PlatformResult{};
112 }
113 // Pipeline::createPipeline() end
114
115 Pipeline::~Pipeline() {
116   ScopeLogger("Destroying pipeline: [%d]", id_);
117
118   if (!pipeline_) {
119     LoggerD("pipeline_ has already been destroyed");
120     return;
121   }
122
123   Dispose();
124 }
125
126 void Pipeline::PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data) {
127   ScopeLogger("state: [%s]", StateToString(state).c_str());
128
129   Pipeline* pipeline = static_cast<Pipeline*>(user_data);
130
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)};
135
136   common::Instance::PostMessage(pipeline->instance_ptr_, response);
137 }
138
139 // Pipeline::state begin
140 PlatformResult Pipeline::GetState(std::string* out) {
141   ScopeLogger("id_: [%d]", id_);
142
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");
148   }
149   LoggerD("ml_pipeline_get_state() succeeded");
150
151   *out = StateToString(state);
152   return PlatformResult{};
153 }
154 // Pipeline::state end
155
156 // Pipeline::start() begin
157 PlatformResult Pipeline::Start() {
158   ScopeLogger("id_: [%d]", id_);
159
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");
164   }
165   return PlatformResult{};
166 }
167 // Pipeline::start() end
168
169 // Pipeline::stop() begin
170 PlatformResult Pipeline::Stop() {
171   ScopeLogger("id_: [%d]", id_);
172
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");
177   }
178   return PlatformResult{};
179 }
180 // Pipeline::stop() end
181
182 // Pipeline::dispose() begin
183 PlatformResult Pipeline::Dispose() {
184   ScopeLogger("id_: [%d]", id_);
185
186   /*
187    * TODO in future commits:
188    *
189    * Release all nodes belonging to this pipeline and
190    * cached in this object in containers like
191    * switches_, node_infos_, etc.
192    *
193    * They have to be released HERE (i.e. BEFORE releasing pipeline_).
194    * If they're released after pipeline_, the app may crash.
195    */
196   switches_.clear();
197
198   node_info_.clear();
199
200   valves_.clear();
201
202   sinks_.clear();
203
204   sources_.clear();
205
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");
210   }
211   LoggerD("ml_pipeline_destroy() succeeded");
212
213   pipeline_ = nullptr;
214
215   return PlatformResult{};
216 }
217 // Pipeline::dispose() end
218
219 // Pipeline::getNodeInfo() begin
220 PlatformResult Pipeline::GetNodeInfo(const std::string& name) {
221   ScopeLogger("id_: [%d], name: [%s]", id_, name.c_str());
222
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{};
227   }
228
229   std::unique_ptr<NodeInfo> node_info_ptr;
230   auto ret = NodeInfo::CreateNodeInfo(pipeline_, name, &node_info_ptr);
231
232   if (!ret) {
233     return ret;
234   }
235
236   node_info_.insert({name, std::move(node_info_ptr)});
237
238   return PlatformResult{};
239 }
240 // Pipeline::getNodeInfo() end
241
242 // Pipeline::getSource() begin
243 PlatformResult Pipeline::GetSource(const std::string& name) {
244   ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
245
246   auto source_it = sources_.find(name);
247   if (sources_.end() != source_it) {
248     LoggerD("Source [%s] found", name.c_str());
249     return PlatformResult{};
250   }
251
252   std::unique_ptr<Source> source_ptr;
253   auto ret = Source::CreateSource(name, pipeline_, source_ptr);
254   if (ret) {
255     sources_.insert({name, std::move(source_ptr)});
256   }
257   return ret;
258 }
259 // Pipeline::getSource() end
260
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());
264
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{};
270   }
271   LoggerD("Switch [%s] not found", name.c_str());
272
273   std::unique_ptr<Switch> switch_ptr;
274   auto ret = Switch::CreateSwitch(name, pipeline_, switch_ptr);
275   if (ret) {
276     *type = switch_ptr->GetType();
277     switches_.insert({name, std::move(switch_ptr)});
278   }
279   return ret;
280 }
281 // Pipeline::getSwitch() end
282
283 // Pipeline::getValve() begin
284 PlatformResult Pipeline::GetValve(const std::string& name) {
285   ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
286
287   auto valve_it = valves_.find(name);
288   if (valves_.end() != valve_it) {
289     LoggerD("Valve [%s] found", name.c_str());
290     return PlatformResult{};
291   }
292   LoggerD("Creating [%s] Valve", name.c_str());
293
294   std::unique_ptr<Valve> valve_ptr;
295   auto ret = Valve::CreateValve(name, pipeline_, *this, valve_ptr);
296   if (ret) {
297     valves_.insert({name, std::move(valve_ptr)});
298   }
299   return ret;
300 }
301 // Pipeline::getValve() end
302
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_);
308
309   if (sinks_.count(sink_name)) {
310     LoggerD("Listener for [%s] sink is already registered", sink_name.c_str());
311     return PlatformResult{};
312   }
313
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);
317   if (!ret) {
318     return ret;
319   }
320
321   sinks_.insert({sink_name, std::move(sink_ptr)});
322
323   return PlatformResult{};
324 }
325 // Pipeline::registerSinkCallback() end
326
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_);
330
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"};
335   }
336
337   auto ret = sink_it->second->Unregister();
338   if (ret) {
339     sinks_.erase(sink_it);
340   }
341   return ret;
342 }
343 // Pipeline::unregisterSinkCallback() end
344
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());
349
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"};
354   }
355
356   return nodeinfo_it->second->getProperty(name, type, property);
357 }
358 // NodeInfo::getProperty() end
359
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());
364
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"};
369   }
370
371   return nodeinfo_it->second->setProperty(name, type, property);
372 }
373 // NodeInfo::setProperty() end
374
375 // Source::inputTensorsInfo begin
376 PlatformResult Pipeline::getInputTensorsInfo(const std::string& name, ml_tensors_info_h* result) {
377   ScopeLogger();
378
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"};
383   }
384
385   return source_it->second->getInputTensorsInfo(result);
386 }
387 // Source::inputTensorsInfo end
388
389 // Source::inputData() begin
390 PlatformResult Pipeline::SourceInputData(const std::string& name, TensorsData* tensors_data) {
391   ScopeLogger();
392
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"};
397   }
398
399   return source_it->second->SourceInputData(tensors_data);
400 }
401 // Source::inputData() end
402
403 // Switch::getPadList() begin
404 PlatformResult Pipeline::GetSwitch(const std::string& name, Switch** out) {
405   ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
406
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{};
412   }
413   LoggerE("Switch [%s] not found", name.c_str());
414   return PlatformResult{ErrorCode::ABORT_ERR, "Switch does not exist"};
415 }
416
417 // Switch::getPadList() end
418
419 // Valve::setOpen() begin
420 PlatformResult Pipeline::GetNodeInfo(const std::string& name, NodeInfo** out) {
421   ScopeLogger("id_: [%d], name: [%s]", id_, name.c_str());
422
423   auto ret = GetNodeInfo(name);
424   if (ret) {
425     *out = node_info_[name].get();
426   }
427
428   return ret;
429 }
430
431 PlatformResult Pipeline::GetValve(const std::string& name, Valve** out) {
432   ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
433
434   auto ret = GetValve(name);
435   if (ret) {
436     *out = valves_[name].get();
437   }
438   return ret;
439 }
440 // Valve::setOpen() end
441
442 }  // namespace extension
443 }  // namespace ml