[ML][pipeline] Implement Pipeline::getSwitch() 75/251075/11
authorPawel Wasowski <p.wasowski2@samsung.com>
Tue, 12 Jan 2021 15:38:43 +0000 (16:38 +0100)
committerPawel Wasowski <p.wasowski2@samsung.com>
Mon, 18 Jan 2021 17:59:36 +0000 (18:59 +0100)
ACR: TWDAPI-274

[Verification] Code tested in Chrome DevTools with below snippets works
fine

var pipeline_def = "videotestsrc is-live=true"
                   + " ! videoconvert"
                   + " ! tensor_converter"
                   + " ! output-selector name=outs outs.src_0"
                   + " ! tensor_sink name=sink0 async=false outs.src_1"
                   + " ! tensor_sink name=sink1 async=false"

var pipeline = tizen.ml.pipeline.createPipeline(pipeline_def, function(state) {console.log(state);})

pipeline.getSwitch('outs')
// Switch {name: "outs", type: "OUTPUT_SELECTOR", _pipeline_id: 3}

pipeline.getSwitch('non existent switch')
//  VM31:1 Uncaught WebAPIException {code: 0, name: "InvalidValuesError"

Change-Id: Ia7d6838b5e49072c35f0b796151c436d4a3b60e1
Signed-off-by: Pawel Wasowski <p.wasowski2@samsung.com>
src/ml/js/ml_pipeline.js
src/ml/ml.gyp
src/ml/ml_instance.cc
src/ml/ml_instance.h
src/ml/ml_pipeline.cc
src/ml/ml_pipeline.h
src/ml/ml_pipeline_manager.cc
src/ml/ml_pipeline_manager.h
src/ml/ml_pipeline_switch.cc [new file with mode: 0644]
src/ml/ml_pipeline_switch.h [new file with mode: 0644]

index df2913a..2cfb8be 100755 (executable)
@@ -212,7 +212,52 @@ Pipeline.prototype.getNodeInfo = function() {
 //Pipeline::getSource() end
 
 //Pipeline::getSwitch() begin
+function Switch(name, type, pipeline_id) {
+    Object.defineProperties(this, {
+        name: {
+            enumerable: true,
+            value: name
+        },
+        type: {
+            enumerable: true,
+            value: type
+        },
+        _pipeline_id: {
+            value: pipeline_id
+        }
+    });
+}
 
+var ValidPipelineGetSwitchExceptions = [
+    'InvalidStateError',
+    'InvalidValuesError',
+    'NotFoundError',
+    'NotSupportedError',
+    'AbortError'
+];
+Pipeline.prototype.getSwitch = function() {
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'name',
+            type: validator_.Types.STRING
+        }
+    ]);
+
+    var nativeArgs = {
+        name: args.name,
+        id: this._id
+    };
+    var result = native_.callSync('MLPipelineGetSwitch', nativeArgs);
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObjectAndValidate(
+            result,
+            ValidPipelineGetSwitchExceptions,
+            AbortError
+        );
+    }
+
+    return new Switch(nativeArgs.name, result.type, this._id);
+};
 //Pipeline::getSwitch() end
 
 //Pipeline::getValve() begin
index c0ab826..1c60e04 100644 (file)
@@ -21,6 +21,8 @@
         'ml_pipeline_manager.h',
         'ml_pipeline_nodeinfo.cc',
         'ml_pipeline_nodeinfo.h',
+        'ml_pipeline_switch.cc',
+        'ml_pipeline_switch.h',
         'ml_utils.cc',
         'ml_utils.h',
       ],
index e9445ad..853dab4 100644 (file)
@@ -59,6 +59,7 @@ MlInstance::MlInstance() : pipeline_manager_{this} {
   REGISTER_METHOD(MLPipelineStart);
   REGISTER_METHOD(MLPipelineStop);
   REGISTER_METHOD(MLPipelineGetNodeInfo);
+  REGISTER_METHOD(MLPipelineGetSwitch);
 // Pipeline API end
 
 #undef REGISTER_METHOD
@@ -266,7 +267,34 @@ void MlInstance::MLPipelineGetNodeInfo(const picojson::value& args, picojson::ob
 // Pipeline::getSource() end
 
 // Pipeline::getSwitch() begin
+void MlInstance::MLPipelineGetSwitch(const picojson::value& args, picojson::object& out) {
+  ScopeLogger("args: %s", args.serialize().c_str());
 
+  if (!args.get(kId).is<double>()) {
+    LoggerD("id is not a number");
+    ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Invalid pipeline"}, &out);
+    return;
+  }
+
+  if (!args.get(kName).is<std::string>()) {
+    LoggerD("name is not a string");
+    ReportError(PlatformResult{ErrorCode::ABORT_ERR, "Invalid name"}, &out);
+    return;
+  }
+
+  auto name = args.get(kName).get<std::string>();
+  auto pipeline_id = args.get(kId).get<double>();
+  std::string type;
+
+  auto ret = pipeline_manager_.GetSwitch(name, pipeline_id, &type);
+  if (!ret) {
+    LogAndReportError(ret, &out);
+    return;
+  }
+
+  out["type"] = picojson::value{type};
+  ReportSuccess(out);
+}
 // Pipeline::getSwitch() end
 
 // Pipeline::getValve() begin
index 47d9567..acb013c 100644 (file)
@@ -73,7 +73,7 @@ class MlInstance : public common::ParsedInstance {
   // Pipeline::getSource() end
 
   // Pipeline::getSwitch() begin
-
+  void MLPipelineGetSwitch(const picojson::value& args, picojson::object& out);
   // Pipeline::getSwitch() end
 
   // Pipeline::getValve() begin
index c843df3..de5edb1 100644 (file)
@@ -190,6 +190,7 @@ PlatformResult Pipeline::Dispose() {
    * They have to be released HERE (i.e. BEFORE releasing pipeline_).
    * If they're released after pipeline_, the app may crash.
    */
+  switches_.clear();
 
   node_info_.clear();
 
@@ -234,7 +235,25 @@ PlatformResult Pipeline::GetNodeInfo(std::string& name) {
 // Pipeline::getSource() end
 
 // Pipeline::getSwitch() begin
+PlatformResult Pipeline::GetSwitch(const std::string& name, std::string* type) {
+  ScopeLogger("id: [%d], name: [%s]", id_, name.c_str());
 
+  auto switch_it = switches_.find(name);
+  if (switches_.end() != switch_it) {
+    LoggerD("Switch [%s] found", name.c_str());
+    *type = switch_it->second->GetType();
+    return PlatformResult{};
+  }
+  LoggerD("Switch [%s] not found", name.c_str());
+
+  std::unique_ptr<Switch> switch_ptr;
+  auto ret = Switch::CreateSwitch(name, pipeline_, &switch_ptr);
+  if (ret) {
+    *type = switch_ptr->GetType();
+    switches_.insert({name, std::move(switch_ptr)});
+  }
+  return ret;
+}
 // Pipeline::getSwitch() end
 
 // Pipeline::getValve() begin
index 80c859b..9d3df8c 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <map>
 #include <string>
+#include <unordered_map>
 
 #include <nnstreamer/nnstreamer.h>
 
 #include "common/picojson.h"
 #include "common/platform_result.h"
 #include "ml_pipeline_nodeinfo.h"
+#include "ml_pipeline_switch.h"
 
 using common::PlatformResult;
-using extension::ml::pipeline::NodeInfo;
+using namespace extension::ml::pipeline;
 
 namespace extension {
 namespace ml {
@@ -46,7 +48,6 @@ class Pipeline {
                                        common::Instance* instance_ptr,
                                        std::unique_ptr<Pipeline>* out);
   // PipelineManager::createPipeline() end
-
   Pipeline() = delete;
   Pipeline(const Pipeline&) = delete;
   Pipeline& operator=(const Pipeline&) = delete;
@@ -78,7 +79,7 @@ class Pipeline {
   // Pipeline::getSource() end
 
   // Pipeline::getSwitch() begin
-
+  PlatformResult GetSwitch(const std::string& name, std::string* type);
   // Pipeline::getSwitch() end
 
   // Pipeline::getValve() begin
@@ -127,16 +128,24 @@ class Pipeline {
  private:
   Pipeline(int id, const std::string& state_change_listener_name, common::Instance* instance_ptr);
 
+  const int id_;
+  ml_pipeline_h pipeline_;
+  const std::string state_change_listener_name_;
+  common::Instance* instance_ptr_;
+
   /* ######### VERY IMPORTANT #########
    * All nnstreamer handles to nodes belonging to this Pipeline
    * object have to be released in Dispose(), before calling
    * ml_pipeline_destroy(pipeline_) (otherwise, the app may crash).
    */
-  const int id_;
-  ml_pipeline_h pipeline_;
-  const std::string state_change_listener_name_;
-  common::Instance* instance_ptr_;
 
+  /*
+   * As switch controls the flow of the data in the pipeline
+   * and users could potentially want to access it
+   * often, we use unordered_map instead of a map for quick
+   * retrieval.
+   */
+  std::unordered_map<std::string, std::unique_ptr<Switch>> switches_;
   std::map<std::string, std::unique_ptr<NodeInfo>> node_info_;
 
   static void PipelineStateChangeListener(ml_pipeline_state_e state, void* user_data);
index cadb4d4..20bae15 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "ml_pipeline_manager.h"
 #include "common/tools.h"
+#include "ml_pipeline_switch.h"
 
 using common::PlatformResult;
 using common::ErrorCode;
@@ -147,7 +148,18 @@ PlatformResult PipelineManager::GetNodeInfo(int id, std::string& name) {
 // Pipeline::getSource() end
 
 // Pipeline::getSwitch() begin
+PlatformResult PipelineManager::GetSwitch(const std::string& name, int pipeline_id,
+                                          std::string* type) {
+  ScopeLogger("name: [%s], pipeline_id: [%d]", name.c_str(), pipeline_id);
 
+  auto pipeline_it = pipelines_.find(pipeline_id);
+  if (pipelines_.end() == pipeline_it) {
+    LoggerD("Pipeline not found: [%d]", pipeline_id);
+    return PlatformResult{ErrorCode::NOT_FOUND_ERR, "Pipeline not found"};
+  }
+
+  return pipeline_it->second->GetSwitch(name, type);
+}
 // Pipeline::getSwitch() end
 
 // Pipeline::getValve() begin
index 63ee5aa..f031fc8 100644 (file)
@@ -68,7 +68,7 @@ class PipelineManager {
   // Pipeline::getSource() end
 
   // Pipeline::getSwitch() begin
-
+  PlatformResult GetSwitch(const std::string& name, int pipeline_id, std::string* type);
   // Pipeline::getSwitch() end
 
   // Pipeline::getValve() begin
diff --git a/src/ml/ml_pipeline_switch.cc b/src/ml/ml_pipeline_switch.cc
new file mode 100644 (file)
index 0000000..43a8220
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "ml_pipeline_switch.h"
+#include "ml_utils.h"
+
+using common::PlatformResult;
+using common::ErrorCode;
+
+namespace {
+
+std::string TypeToString(ml_pipeline_switch_e type) {
+  ScopeLogger("type: [%d]", type);
+
+  std::string type_str =
+      (ML_PIPELINE_SWITCH_INPUT_SELECTOR == type) ? "INPUT_SELECTOR" : "OUTPUT_SELECTOR";
+  LoggerD("type_str: [%s]", type_str.c_str());
+  return type_str;
+}
+
+}  // namespace
+
+namespace extension {
+namespace ml {
+namespace pipeline {
+
+PlatformResult Switch::CreateSwitch(const std::string& name, ml_pipeline_h pipeline,
+                                    std::unique_ptr<Switch>* out) {
+  ScopeLogger("name: [%s], pipeline: [%p]", name.c_str(), pipeline);
+
+  ml_pipeline_switch_e type = ML_PIPELINE_SWITCH_INPUT_SELECTOR;
+  ml_pipeline_switch_h switch_handle = nullptr;
+  auto ret = ml_pipeline_switch_get_handle(pipeline, name.c_str(), &type, &switch_handle);
+  if (ML_ERROR_NONE != ret) {
+    LoggerE("ml_pipeline_switch_get_handle() failed: [%d] (%s)", ret, get_error_message(ret));
+    return util::ToPlatformResult(ret, "Could not get switch");
+  }
+  LoggerD("ml_pipeline_switch_get_handle() succeeded");
+
+  out->reset(new (std::nothrow) Switch{name, TypeToString(type), switch_handle});
+  if (!out) {
+    ret = ml_pipeline_switch_release_handle(switch_handle);
+    if (ML_ERROR_NONE != ret) {
+      LoggerE("ml_pipeline_switch_release_handle() failed: [%d] (%s)", ret, get_error_message(ret));
+    } else {
+      LoggerD("ml_pipeline_switch_release_handle() succeeded");
+    }
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Could not get the switch",
+                              ("Could not allocate memory"));
+  }
+
+  return PlatformResult{};
+}
+
+Switch::Switch(const std::string& name, const std::string& type, ml_pipeline_switch_h switch_handle)
+    : name_{name}, type_{type}, switch_{switch_handle} {
+  ScopeLogger("name: [%s], type: [%s], handle: [%p]", name.c_str(), type.c_str(), switch_handle);
+}
+
+Switch::~Switch() {
+  ScopeLogger("name: [%s], type: [%s], handle: [%p]", name_.c_str(), type_.c_str(), switch_);
+
+  auto ret = ml_pipeline_switch_release_handle(switch_);
+  if (ML_ERROR_NONE != ret) {
+    LoggerE("ml_pipeline_switch_release_handle() failed: [%d] (%s)", ret, get_error_message(ret));
+  } else {
+    LoggerD("ml_pipeline_switch_release_handle() succeeded");
+  }
+}
+
+std::string Switch::GetType() const {
+  ScopeLogger("type: [%s]", type_.c_str());
+  return type_;
+}
+
+}  // namespace pipeline
+}  // namespace ml
+}  // namespace extension
\ No newline at end of file
diff --git a/src/ml/ml_pipeline_switch.h b/src/ml/ml_pipeline_switch.h
new file mode 100644 (file)
index 0000000..3175387
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef ML_ML_PIPELINE_SWITCH_H_
+#define ML_ML_PIPELINE_SWITCH_H_
+
+#include <memory>
+#include <string>
+
+#include <nnstreamer/nnstreamer.h>
+
+#include "common/platform_result.h"
+
+using common::PlatformResult;
+
+namespace extension {
+namespace ml {
+namespace pipeline {
+
+class Switch {
+ public:
+  static PlatformResult CreateSwitch(const std::string& name, ml_pipeline_h pipeline,
+                                     std::unique_ptr<Switch>* out);
+
+  std::string GetType() const;
+
+  ~Switch();
+
+  Switch(const Switch&) = delete;
+  Switch& operator=(const Switch&) = delete;
+
+ private:
+  Switch(const std::string& name, const std::string& type, ml_pipeline_switch_h switch_handle);
+  const std::string name_;
+  const std::string type_;
+  const ml_pipeline_switch_h switch_;
+};
+
+}  // namespace pipeline
+}  // namespace ml
+}  // namespace extension
+
+#endif  // ML_ML_PIPELINE_SWITCH_H_
\ No newline at end of file