[VoiceControl] Add new web APIs for voice control 85/156385/1
authorSuyeon Hwang <stom.hwang@samsung.com>
Mon, 19 Jun 2017 02:43:03 +0000 (11:43 +0900)
committerSzymon Jastrzebski <s.jastrzebsk@partner.samsung.com>
Wed, 18 Oct 2017 07:51:11 +0000 (07:51 +0000)
Change-Id: I497d96e45158b398189761952953cfc6253c7698
Signed-off-by: Suyeon Hwang <stom.hwang@samsung.com>
Signed-off-by: Szymon Jastrzebski <s.jastrzebsk@partner.samsung.com>
12 files changed:
packaging/webapi-plugins.spec
src/tizen-wrt.gyp
src/voicecontrol/voicecontrol.gyp [new file with mode: 0755]
src/voicecontrol/voicecontrol_api.js [new file with mode: 0755]
src/voicecontrol/voicecontrol_client.cc [new file with mode: 0755]
src/voicecontrol/voicecontrol_client.h [new file with mode: 0755]
src/voicecontrol/voicecontrol_extension.cc [new file with mode: 0755]
src/voicecontrol/voicecontrol_extension.h [new file with mode: 0755]
src/voicecontrol/voicecontrol_instance.cc [new file with mode: 0755]
src/voicecontrol/voicecontrol_instance.h [new file with mode: 0755]
src/voicecontrol/voicecontrol_util.cc [new file with mode: 0755]
src/voicecontrol/voicecontrol_util.h [new file with mode: 0755]

index 1a62c7e..a42d103 100644 (file)
@@ -69,6 +69,7 @@ Source0:    %{name}-%{version}.tar.gz
 %define tizen_common_feature_callhistory_support             0
 %define tizen_common_feature_nbs_support                     0
 %define tizen_common_feature_tvinputdevice_support           0
+%define tizen_common_feature_voicecontrol_support            0
 
 
 ####################################################################
@@ -157,6 +158,7 @@ Source0:    %{name}-%{version}.tar.gz
 
 %define tizen_mobile_feature_tvinputdevice_support           0
 
+%define tizen_mobile_feature_voicecontrol_support            1
 
 ####################################################################
 #       Wearable Profile :  B2 / TW2                      #
@@ -233,6 +235,8 @@ Source0:    %{name}-%{version}.tar.gz
 %define tizen_wearable_feature_inputdevice_support             1
 %define tizen_wearable_feature_tvinputdevice_support           0
 
+%define tizen_wearable_feature_voicecontrol_support            1
+
 
 ####################################################################
 #       TV Profile                                                 #
@@ -287,6 +291,7 @@ Source0:    %{name}-%{version}.tar.gz
 %define tizen_tv_feature_wi_fi_support                   1
 %define tizen_tv_feature_inputdevice_support             0
 %define tizen_tv_feature_tvinputdevice_support           1
+%define tizen_tv_feature_voicecontrol_support            1
 
 # common, or "unified (undefined)"
 %define unified_build   1
@@ -347,6 +352,7 @@ Source0:    %{name}-%{version}.tar.gz
 %define tizen_feature_callhistory_support             %{expand:%tizen_%{?profile}_feature_callhistory_support}
 %define tizen_feature_nbs_support                     %{expand:%tizen_%{?profile}_feature_nbs_support}
 %define tizen_feature_tvinputdevice_support           %{expand:%tizen_%{?profile}_feature_tvinputdevice_support}
+%define tizen_feature_voicecontrol_support            %{expand:%tizen_%{?profile}_feature_voicecontrol_support}
 %endif
 
 BuildRequires: pkgconfig(security-privilege-manager)
@@ -548,6 +554,10 @@ BuildRequires:  pkgconfig(capi-system-media-key)
 BuildRequires: pkgconfig(widget_service)
 %endif
 
+%if "%{?tizen_feature_voicecontrol_support}" == "1" || "%{?unified_build}" == "1"
+BuildRequires: pkgconfig(voice-control)
+%endif
+
 Requires:      %{name}-compat = %{version}-%{release}
 %if "%{?unified_build}" == "1"
 Recommends:    %{name}-profile_common = %{version}-%{release}
@@ -695,6 +705,7 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_mobile_fe
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_mobile_feature_widget_service_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_mobile_feature_wi_fi_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_mobile_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_mobile_feature_voicecontrol_support}"
 
 ./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
 
@@ -780,6 +791,7 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_mobile_fe
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_mobile_feature_widget_service_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_mobile_feature_wi_fi_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_mobile_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_mobile_feature_voicecontrol_support}"
 
 ./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
 
@@ -844,6 +856,7 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_wearable_
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_wearable_feature_widget_service_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_wearable_feature_wi_fi_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_wearable_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_wearable_feature_voicecontrol_support}"
 
 ./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
 
@@ -924,6 +937,7 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_wearable_
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_wearable_feature_widget_service_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_wearable_feature_wi_fi_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_wearable_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_wearable_feature_voicecontrol_support}"
 
 ./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
 
@@ -988,6 +1002,7 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_tv_featur
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_tv_feature_widget_service_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_tv_feature_wi_fi_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_tv_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_tv_feature_voicecontrol_support}"
 
 ./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
 
@@ -1057,6 +1072,7 @@ GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_web_setting_support=%{?tizen_common_fe
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_widget_service_support=%{?tizen_common_feature_widget_service_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_wi_fi_support=%{?tizen_common_feature_wi_fi_support}"
 GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_tvinputdevice_support=%{?tizen_common_feature_tvinputdevice_support}"
+GYP_OPTIONS="$GYP_OPTIONS -Dtizen_feature_voicecontrol_support=%{?tizen_common_feature_voicecontrol_support}"
 
 ./tools/gyp/gyp $GYP_OPTIONS src/tizen-wrt.gyp
 
index 407e545..410e44a 100755 (executable)
             ],
           },
         ],
+        [
+          'tizen_feature_voicecontrol_support==1', {
+            'dependencies': [
+              'voicecontrol/voicecontrol.gyp:*',
+            ],
+          },
+        ],
       ], # end conditions
     },
   ], # end targets
diff --git a/src/voicecontrol/voicecontrol.gyp b/src/voicecontrol/voicecontrol.gyp
new file mode 100755 (executable)
index 0000000..8706d51
--- /dev/null
@@ -0,0 +1,34 @@
+{
+  'includes':[
+    '../common/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'tizen_voicecontrol',
+      'type': 'loadable_module',
+      'dependencies': [
+        '../common/common.gyp:tizen_common',
+      ],
+      'sources': [
+        'voicecontrol_api.js',
+        'voicecontrol_client.cc',
+        'voicecontrol_client.h',
+        'voicecontrol_extension.cc',
+        'voicecontrol_extension.h',
+        'voicecontrol_instance.cc',
+        'voicecontrol_instance.h',
+        'voicecontrol_util.cc',
+        'voicecontrol_util.cc'
+      ],
+      'conditions': [
+        ['tizen == 1', {
+          'variables': {
+            'packages': [
+              'voice-control'
+            ]
+          },
+        }],
+      ],
+    },
+  ],
+}
diff --git a/src/voicecontrol/voicecontrol_api.js b/src/voicecontrol/voicecontrol_api.js
new file mode 100755 (executable)
index 0000000..5caa4a4
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+
+var utils_ = xwalk.utils;
+var type_ = utils_.type;
+var converter_ = utils_.converter;
+var validator_ = utils_.validator;
+var types_ = validator_.Types;
+var native_ = new xwalk.utils.NativeManager(extension);
+
+function ListenerManager(native, listenerName, handle) {
+  this.listeners = {};
+  this.nextId = 1;
+  this.nativeSet = false;
+  this.native = native;
+  this.listenerName = listenerName;
+  this.handle = handle || function (msg, listener, watchId) {};
+}
+
+ListenerManager.prototype.addListener = function (callback, nativeCall, data) {
+  var id = this.nextId;
+  if (!this.nativeSet) {
+    this.native.addListener(this.listenerName, function (msg) {
+      for (var watchId in this.listeners) {
+        if (this.listeners.hasOwnProperty(watchId)) {
+          this.handle(msg, this.listeners[watchId], watchId);
+        }
+      }
+    }.bind(this));
+    var result = this.native.callSync(nativeCall, data || {});
+    if (this.native.isFailure(result)) {
+      throw this.native.getErrorObject(result);
+    }
+    this.nativeSet = true;
+  }
+
+  this.listeners[id] = callback;
+  ++this.nextId;
+
+  return id;
+};
+
+ListenerManager.prototype.removeListener = function (watchId, nativeCall) {
+  if (this.listeners.hasOwnProperty(watchId)) {
+    delete this.listeners[watchId];
+  }
+
+  if (this.nativeSet && type_.isEmptyObject(this.listeners)) {
+    this.native.callSync(nativeCall);
+    this.native.removeListener(this.listenerName);
+    this.nativeSet = false;
+  }
+};
+
+var VcResultListener = new ListenerManager(native_, 'onresult', function(result, listener) {
+  listener(result.event, result.list, result.results);
+});
+
+var VcLangListener = new ListenerManager(native_, 'onlanguagechanged', function(result, listener) {
+  listener(result.previous, result.current);
+});
+
+var VoiceControlResultEvent = {
+  SUCCESS: 'SUCCESS',
+  FAILURE: 'FAILURE'
+};
+
+var VoiceControlCommandType = {
+  FOREGROUND: 'FOREGROUND'
+};
+
+function VoiceControlClientManager() {
+}
+
+VoiceControlClientManager.prototype.getVoiceControlClient = function () {
+  var result = native_.callSync('VoiceControlClientManager_getVoiceControlClient', {});
+
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+
+  return new VoiceControlClient();
+};
+
+function VoiceControlClient() {
+}
+
+VoiceControlClient.prototype.getCurrentLanguage = function () {
+  var result = native_.callSync('VoiceControlClient_getCurrentLanguage', {});
+
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+
+  return native_.getResultObject(result);
+};
+
+VoiceControlClient.prototype.setCommandList = function (list, type) {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'list', type: types_.ARRAY, values: VoiceControlCommand},
+    {name: 'type', type: types_.ENUM, values: type_.getValues(VoiceControlCommandType), optional: true, nullable: true}
+  ]);
+
+  if (type_.isNullOrUndefined(args.type)) {
+    args.type = VoiceControlCommandType.FOREGROUND;
+  }
+
+  var data = {
+    list: args.list,
+    type: args.type
+  };
+
+  var result = native_.callSync('VoiceControlClient_setCommandList', data);
+
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+};
+
+VoiceControlClient.prototype.unsetCommandList = function (type) {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'type', type: types_.ENUM, values: type_.getValues(VoiceControlCommandType), optional: true, nullable: true}
+  ]);
+
+  if (type_.isNullOrUndefined(args.type)) {
+    args.type = VoiceControlCommandType.FOREGROUND;
+  }
+
+  var result = native_.callSync('VoiceControlClient_unsetCommandList', {type: args.type});
+
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+};
+
+VoiceControlClient.prototype.addResultListener = function (listener) {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'listener', type: types_.FUNCTION}
+  ]);
+
+  return VcResultListener.addListener(args.listener, 'VoiceControlClient_addResultListener');
+};
+
+VoiceControlClient.prototype.removeResultListener = function (id) {
+  if (!type_.isNumber(id)) {
+    throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR, 'Cannot convert id to int.');
+  }
+
+  var args = validator_.validateArgs(arguments, [
+    {name: 'id', type: types_.LONG}
+  ]);
+
+  VcResultListener.removeListener(args.id, 'VoiceControlClient_removeResultListener');
+};
+
+VoiceControlClient.prototype.addLanguageChangeListener = function (listener) {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'listener', type: types_.FUNCTION}
+  ]);
+
+  return VcLangListener.addListener(args.listener, 'VoiceControlClient_addLanguageChangeListener');
+};
+
+VoiceControlClient.prototype.removeLanguageChangeListener = function (id) {
+  if (!type_.isNumber(id)) {
+    throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR, 'Cannot convert id to int.');
+  }
+
+  var args = validator_.validateArgs(arguments, [
+    {name: 'id', type: types_.LONG}
+  ]);
+
+  VcLangListener.removeListener(args.id, 'VoiceControlClient_removeLanguageChangeListener');
+};
+
+VoiceControlClient.prototype.release = function () {
+  var result = native_.callSync('VoiceControlClient_release', {});
+
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+};
+
+// Constructor of VoiceControlCommand
+function VoiceControlCommand(command, type) {
+  validator_.isConstructorCall(this, VoiceControlCommand);
+
+  var _command = command;
+  var _type = type;
+
+  if (type_.isNullOrUndefined(_type)) {
+    _type = VoiceControlCommandType.FOREGROUND;
+  }
+
+  Object.defineProperties(this,
+    {
+      command: {
+        enumerable: true,
+        get: function () {
+          return _command;
+        },
+        set: function (value) {
+          _command = value;
+        }
+      },
+      type: {
+        enumerable: true,
+        get: function () {
+          return _type;
+        },
+        set: function (value) {
+          if (type_.arrayContains(type_.getValues(VoiceControlCommandType), value)) {
+            _type = value;
+          }
+        }
+      }
+    });
+}
+
+exports = new VoiceControlClientManager();
+tizen.VoiceControlCommand = VoiceControlCommand;
diff --git a/src/voicecontrol/voicecontrol_client.cc b/src/voicecontrol/voicecontrol_client.cc
new file mode 100755 (executable)
index 0000000..bf42449
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017 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 "voicecontrol/voicecontrol_util.h"
+#include "voicecontrol/voicecontrol_client.h"
+#include <voice_control.h>
+#include <voice_control_internal.h>
+
+#include <functional>
+
+#include "common/picojson.h"
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "common/scope_exit.h"
+#include "common/tools.h"
+
+namespace extension {
+namespace voicecontrol {
+
+VoiceControlClient* VoiceControlClient::GetInstance() {
+  ScopeLogger();
+  static VoiceControlClient instance;
+
+  return &instance;
+}
+
+VoiceControlClient::VoiceControlClient() : is_result_cb_set(false), is_lang_cb_set(false) {
+}
+
+VoiceControlClient::~VoiceControlClient() {
+}
+
+int VcConvertCmdType(const std::string &type) {
+  // TODO add switch here when also other types of command will be also supported.
+  // For now, only foreground is supported, we are returning it as default value.
+  return VC_COMMAND_TYPE_FOREGROUND;
+}
+
+common::PlatformResult VoiceControlClient::GetCurrentLanguage(std::string *language) {
+  ScopeLogger();
+
+  char *lang = nullptr;
+  int ret = VC_ERROR_NONE;
+
+  ret = vc_get_current_language(&lang);
+  if (VC_ERROR_NONE != ret) {
+    LoggerE("Fail to get current language");
+    return MakeErrorObject(ret);
+  }
+
+  *language = std::string(lang);
+  free(lang);
+
+  return MakeErrorObject(ret);
+}
+
+common::PlatformResult VoiceControlClient::SetCommandList(const std::vector<picojson::value>& list, const std::string& type) {
+  ScopeLogger();
+
+  int ret = VC_ERROR_NONE;
+  int type_enum = VcConvertCmdType(type);
+
+  vc_cmd_list_h vc_cmd_list = nullptr;
+  SCOPE_EXIT {
+    vc_cmd_list_destroy(vc_cmd_list, true);
+  };
+
+  ret = vc_cmd_list_create(&vc_cmd_list);
+  if (VC_ERROR_NONE != ret) {
+    return MakeErrorObject(ret);
+  }
+
+  for (auto it = list.begin(); it != list.end(); it++) {
+    vc_cmd_h vc_command = nullptr;
+    ret = vc_cmd_create(&vc_command);
+    if (VC_ERROR_NONE != ret) {
+      return MakeErrorObject(ret);
+    }
+
+    std::unique_ptr<std::remove_pointer<vc_cmd_h>::type, int (*)(vc_cmd_h)> ptr(vc_command, &vc_cmd_destroy);
+
+    ret = vc_cmd_set_command(ptr.get(), (*it).get(COMMAND).get<std::string>().c_str());
+    if (VC_ERROR_NONE != ret) {
+      return MakeErrorObject(ret);
+    }
+
+    ret = vc_cmd_set_type(ptr.get(), VcConvertCmdType((*it).get(TYPE).get<std::string>()));
+    if (VC_ERROR_NONE != ret) {
+      return MakeErrorObject(ret);
+    }
+
+    ret = vc_cmd_list_add(vc_cmd_list, ptr.get());
+    if (VC_ERROR_NONE != ret) {
+      return MakeErrorObject(ret);
+    }
+    ptr.release();
+  }
+
+  ret = vc_set_command_list(vc_cmd_list, type_enum);
+  return MakeErrorObject(ret);
+}
+
+common::PlatformResult VoiceControlClient::UnsetCommandList(const std::string& type) {
+  ScopeLogger();
+
+  int ret = VC_ERROR_NONE;
+  int type_enum = VcConvertCmdType(type);
+
+  ret = vc_unset_command_list(type_enum);
+  return MakeErrorObject(ret);
+}
+
+common::PlatformResult VoiceControlClient::AddResultListener() {
+  ScopeLogger();
+
+  is_result_cb_set = true;
+  return MakeErrorObject(VC_ERROR_NONE);
+}
+
+common::PlatformResult VoiceControlClient::RemoveResultListener() {
+  ScopeLogger();
+
+  is_result_cb_set = false;
+  return MakeErrorObject(VC_ERROR_NONE);
+}
+
+common::PlatformResult VoiceControlClient::AddLanguageChangeListener() {
+  ScopeLogger();
+
+  is_lang_cb_set = true;
+  return MakeErrorObject(VC_ERROR_NONE);
+}
+
+common::PlatformResult VoiceControlClient::RemoveLanguageChangeListener() {
+  ScopeLogger();
+
+  is_lang_cb_set = false;
+  return MakeErrorObject(VC_ERROR_NONE);
+}
+
+
+const bool VoiceControlClient::IsResultListenerSet() {
+  ScopeLogger();
+
+  return is_result_cb_set;
+}
+
+const bool VoiceControlClient::IsLanguageChangedListenerSet() {
+  ScopeLogger();
+
+  return is_lang_cb_set;
+}
+
+#undef CHECK_EXIST
+
+} // namespace voicecontrol
+} // namespace extension
diff --git a/src/voicecontrol/voicecontrol_client.h b/src/voicecontrol/voicecontrol_client.h
new file mode 100755 (executable)
index 0000000..7f06730
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017 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 VOICECONTROL_VOICECONTROL_CLIENT_H_
+#define VOICECONTROL_VOICECONTROL_CLIENT_H_
+
+#include "common/extension.h"
+#include <voice_control.h>
+
+namespace extension {
+namespace voicecontrol {
+
+class VoiceControlClient {
+ public:
+  static VoiceControlClient* GetInstance();
+
+ public:
+  VoiceControlClient();
+  ~VoiceControlClient();
+
+  common::PlatformResult GetCurrentLanguage(std::string *language);
+  common::PlatformResult SetCommandList(const std::vector<picojson::value>& list, const std::string& type);
+  common::PlatformResult UnsetCommandList(const std::string& type);
+  common::PlatformResult AddResultListener();
+  common::PlatformResult RemoveResultListener();
+  common::PlatformResult AddLanguageChangeListener();
+  common::PlatformResult RemoveLanguageChangeListener();
+
+  const bool IsResultListenerSet();
+  const bool IsLanguageChangedListenerSet();
+
+ private:
+  bool is_result_cb_set;
+  bool is_lang_cb_set;
+};
+
+} // namespace voicecontrol
+} // namespace extension
+
+#endif // VOICECONTROL_VOICECONTROL_CLIENT_H_
\ No newline at end of file
diff --git a/src/voicecontrol/voicecontrol_extension.cc b/src/voicecontrol/voicecontrol_extension.cc
new file mode 100755 (executable)
index 0000000..f3bd17a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017 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 "voicecontrol/voicecontrol_extension.h"
+
+#include "voicecontrol/voicecontrol_instance.h"
+
+// This will be generated from voicecontrol_api.js
+extern const char kSource_voicecontrol_api[];
+
+common::Extension* CreateExtension() {
+  return new VoicecontrolExtension;
+}
+
+VoicecontrolExtension::VoicecontrolExtension() {
+  SetExtensionName("tizen.voicecontrol");
+  SetJavaScriptAPI(kSource_voicecontrol_api);
+
+  const char* entry_points[] = {
+      "tizen.VoiceControlCommand",
+      NULL
+    };
+  SetExtraJSEntryPoints(entry_points);
+}
+
+VoicecontrolExtension::~VoicecontrolExtension() {}
+
+common::Instance* VoicecontrolExtension::CreateInstance() {
+  return new extension::voicecontrol::VoiceControlInstance;
+}
\ No newline at end of file
diff --git a/src/voicecontrol/voicecontrol_extension.h b/src/voicecontrol/voicecontrol_extension.h
new file mode 100755 (executable)
index 0000000..5d98992
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 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 VOICECONTROL_VOICECONTROL_EXTENSION_H_
+#define VOICECONTROL_VOICECONTROL_EXTENSION_H_
+
+#include "common/extension.h"
+
+class VoicecontrolExtension : public common::Extension {
+ public:
+  VoicecontrolExtension();
+  virtual ~VoicecontrolExtension();
+
+ private:
+  virtual common::Instance* CreateInstance();
+};
+
+#endif // VOICECONTROL_VOICECONTROL_EXTENSION_H_
diff --git a/src/voicecontrol/voicecontrol_instance.cc b/src/voicecontrol/voicecontrol_instance.cc
new file mode 100755 (executable)
index 0000000..034b416
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2017 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 "voicecontrol/voicecontrol_instance.h"
+#include "voicecontrol/voicecontrol_client.h"
+#include "voicecontrol/voicecontrol_util.h"
+#include <voice_control.h>
+#include <voice_control_internal.h>
+
+#include <functional>
+
+#include "common/picojson.h"
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "common/scope_exit.h"
+#include "common/tools.h"
+
+namespace extension {
+namespace voicecontrol {
+
+namespace {
+// The privileges that are required in Voicecontrol API
+const std::string kPrivilegeVoiceControl = "http://tizen.org/privilege/recorder";
+
+void ReplyAsync(VoiceControlInstance* instance, const std::string& listenerId, bool isSuccess, picojson::object& param) {
+  ScopeLogger();
+  param["listenerId"] = picojson::value(listenerId);
+  param["status"] = picojson::value(isSuccess ? "success" : "error");
+
+  /* All callback functions are called by voice control framework */
+  /* Send result from callback to javascript */
+  picojson::value result = picojson::value(param);
+
+  instance->PostMessage(instance, result.serialize().c_str());
+}
+
+
+
+/* Define callback functions for voice control */
+void VcResultCb(vc_result_event_e event, vc_cmd_list_h cmd_list, const char* result, void *user_data) {
+  ScopeLogger();
+  VoiceControlInstance *instance = static_cast<VoiceControlInstance *>(user_data);
+
+  if (nullptr != instance && VoiceControlClient::GetInstance()->IsResultListenerSet()) {
+    LoggerD("VcResultCb");
+    picojson::object param = picojson::object();
+    param["event"] = picojson::value(std::string(((event == VC_RESULT_EVENT_RESULT_SUCCESS) ? "SUCCESS" : "FAILURE")));
+
+    int len = 0;
+    int ret = VC_ERROR_NONE;
+
+    ret = vc_cmd_list_get_count(cmd_list, &len);
+    if (VC_ERROR_NONE != ret) {
+      LoggerE("Fail to get the count of the result list");
+      return;
+    }
+
+    picojson::array& value_vector = param.insert(std::make_pair("list",
+      picojson::value(picojson::array(len)))).first->second.get<picojson::array>();
+
+    ret = vc_cmd_list_first(cmd_list);
+    for (auto i = 0; VC_ERROR_NONE == ret && i < len; i++) {
+      LoggerD("Current (%d), Count (%d)", i, len);
+      vc_cmd_h vc_command = nullptr;
+      char* command = nullptr;
+      SCOPE_EXIT {
+        free(command);
+      };
+
+      ret = vc_cmd_list_get_current(cmd_list, &vc_command);
+      if (VC_ERROR_NONE != ret) {
+        break;
+      }
+      ret = vc_cmd_get_command(vc_command, &command);
+      if (VC_ERROR_NONE != ret) {
+        break;
+      }
+
+      if (nullptr != command) {
+        LoggerD("Command (%s)", command);
+        value_vector[i] = picojson::value(command);
+      }
+
+      ret = vc_cmd_list_next(cmd_list);
+    }
+
+    param["results"] = picojson::value(std::string(result));
+
+    ReplyAsync(instance, ON_RESULT, true, param);
+  }
+}
+
+void VcLanguageChangedCb(const char* previous, const char* current, void* user_data) {
+  ScopeLogger();
+  VoiceControlInstance *instance = static_cast<VoiceControlInstance *>(user_data);
+  if (nullptr != instance && VoiceControlClient::GetInstance()->IsLanguageChangedListenerSet()) {
+    LoggerD("VcLanguageChangedCb");
+    picojson::object param = picojson::object();
+    param["previous"] = picojson::value(std::string(previous));
+    param["current"] = picojson::value(std::string(current));
+
+    ReplyAsync(instance, ON_LANG, true, param);
+  }
+}
+} // namespace
+
+using namespace common;
+using namespace extension::voicecontrol;
+
+VoiceControlInstance::VoiceControlInstance() {
+  using namespace std::placeholders;
+  #define REGISTER_SYNC(c,x) \
+    RegisterSyncHandler(c, std::bind(&VoiceControlInstance::x, this, _1, _2));
+  REGISTER_SYNC("VoiceControlClient_getCurrentLanguage", GetCurrentLanguage);
+  REGISTER_SYNC("VoiceControlClient_setCommandList", SetCommandList);
+  REGISTER_SYNC("VoiceControlClient_unsetCommandList", UnsetCommandList);
+  REGISTER_SYNC("VoiceControlClient_addResultListener", AddResultListener);
+  REGISTER_SYNC("VoiceControlClient_removeResultListener", RemoveResultListener);
+  REGISTER_SYNC("VoiceControlClient_addLanguageChangeListener", AddLanguageChangeListener);
+  REGISTER_SYNC("VoiceControlClient_removeLanguageChangeListener", RemoveLanguageChangeListener);
+  REGISTER_SYNC("VoiceControlClient_release", Release);
+  REGISTER_SYNC("VoiceControlClientManager_getVoiceControlClient", GetVoiceControlClient);
+  #undef REGISTER_SYNC
+}
+
+VoiceControlInstance::~VoiceControlInstance() {
+  int ret = VC_ERROR_NONE;
+  ret = vc_deinitialize();
+  if (VC_ERROR_NONE != ret && VC_ERROR_INVALID_STATE != ret) {
+    LoggerE("Fail to deinitialize voice control, ret(%d)", ret);
+  }
+}
+
+#define CHECK_EXIST(args, name, out) \
+  if (!args.contains(name)) {\
+    ReportError(TypeMismatchException(name + " is required argument"), out);\
+    return;\
+  }
+
+void VoiceControlInstance::GetVoiceControlClient(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeVoiceControl, &out);
+
+  int ret = VC_ERROR_NONE;
+  vc_state_e state = VC_STATE_NONE;
+  ret = vc_initialize();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_get_state(&state);
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  if (VC_STATE_READY == state) {
+    LoggerD("VoiceControlClient already initialized");
+    ReportSuccess(out);
+    return;
+  }
+
+  ret = vc_set_result_cb(VcResultCb, this);
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_set_current_language_changed_cb(VcLanguageChangedCb, this);
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_prepare_sync();
+    if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+
+void VoiceControlInstance::Release(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  int ret = VC_ERROR_NONE;
+
+  ret = vc_unprepare();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_unset_result_cb();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_unset_current_language_changed_cb();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ret = vc_deinitialize();
+  if (VC_ERROR_NONE != ret) {
+    LogAndReportError(MakeErrorObject(ret), &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+void VoiceControlInstance::GetCurrentLanguage(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  std::string language;
+  common::PlatformResult result = VoiceControlClient::GetInstance()->GetCurrentLanguage(&language);
+
+  if (result.IsSuccess()) {
+    ReportSuccess(picojson::value(language), out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::SetCommandList(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeVoiceControl, &out);
+
+  CHECK_EXIST(args, TYPE, out)
+  CHECK_EXIST(args, LIST, out)
+
+  std::string type = args.get(TYPE).get<std::string>();
+  std::vector<picojson::value> list = args.get(LIST).get<picojson::array>();
+
+  common::PlatformResult result = VoiceControlClient::GetInstance()->SetCommandList(list, type);
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::UnsetCommandList(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_PRIVILEGE_ACCESS(kPrivilegeVoiceControl, &out);
+
+  CHECK_EXIST(args, TYPE, out)
+
+  std::string type = args.get(TYPE).get<std::string>();
+
+  common::PlatformResult result = VoiceControlClient::GetInstance()->UnsetCommandList(type);
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::AddResultListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  common::PlatformResult result = VoiceControlClient::GetInstance()->AddResultListener();
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::RemoveResultListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  common::PlatformResult result = VoiceControlClient::GetInstance()->RemoveResultListener();
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::AddLanguageChangeListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  common::PlatformResult result = VoiceControlClient::GetInstance()->AddLanguageChangeListener();
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void VoiceControlInstance::RemoveLanguageChangeListener(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  common::PlatformResult result = VoiceControlClient::GetInstance()->RemoveLanguageChangeListener();
+
+  if (result.IsSuccess()) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+#undef CHECK_EXIST
+
+} // namespace voicecontrol
+} // namespace extension
diff --git a/src/voicecontrol/voicecontrol_instance.h b/src/voicecontrol/voicecontrol_instance.h
new file mode 100755 (executable)
index 0000000..633482e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 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 VOICECONTROL_VOICECONTROL_INSTANCE_H_
+#define VOICECONTROL_VOICECONTROL_INSTANCE_H_
+
+#include "common/extension.h"
+
+namespace extension {
+namespace voicecontrol {
+
+class VoiceControlInstance : public common::ParsedInstance {
+ public:
+  VoiceControlInstance();
+  virtual ~VoiceControlInstance();
+
+ private:
+  void GetVoiceControlClient(const picojson::value& args, picojson::object& out);
+  void Release(const picojson::value& args, picojson::object& out);
+
+  void GetCurrentLanguage(const picojson::value& args, picojson::object& out);
+  void SetCommandList(const picojson::value& args, picojson::object& out);
+  void UnsetCommandList(const picojson::value& args, picojson::object& out);
+  void AddResultListener(const picojson::value& args, picojson::object& out);
+  void RemoveResultListener(const picojson::value& args, picojson::object& out);
+  void AddLanguageChangeListener(const picojson::value& args, picojson::object& out);
+  void RemoveLanguageChangeListener(const picojson::value& args, picojson::object& out);
+};
+
+} // namespace voicecontrol
+} // namespace extension
+
+#endif // VOICECONTROL_VOICECONTROL_INSTANCE_H_
\ No newline at end of file
diff --git a/src/voicecontrol/voicecontrol_util.cc b/src/voicecontrol/voicecontrol_util.cc
new file mode 100755 (executable)
index 0000000..b51bbdc
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 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 "voicecontrol/voicecontrol_util.h"
+#include <voice_control.h>
+
+namespace extension {
+namespace voicecontrol {
+
+const std::string& MakeErrorMessage(const int ret) {
+  switch (ret) {
+    case VC_ERROR_NONE:
+      return NO_ERROR;
+    case VC_ERROR_INVALID_PARAMETER:
+      return INVALID_PARAMETER;
+    case VC_ERROR_OUT_OF_MEMORY:
+      return OUT_OF_MEMORY;
+    case VC_ERROR_OPERATION_FAILED:
+    case VC_ERROR_INVALID_STATE:
+      return OPERATION_FAILED;
+    case VC_ERROR_PERMISSION_DENIED:
+      return PERMISSION_DENIED;
+    case VC_ERROR_NOT_SUPPORTED:
+      return NOT_SUPPORTED;
+    default:
+      return OPERATION_FAILED;
+  }
+}
+
+common::PlatformResult MakeErrorObject(const int ret) {
+  std::string message = MakeErrorMessage(ret);
+  switch (ret) {
+    case VC_ERROR_NONE:
+      return common::PlatformResult(common::ErrorCode::NO_ERROR);
+    case VC_ERROR_INVALID_PARAMETER:
+      return common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR, message);
+    case VC_ERROR_PERMISSION_DENIED:
+      return common::PlatformResult(common::ErrorCode::SECURITY_ERR, message);
+    case VC_ERROR_NOT_SUPPORTED:
+      return common::PlatformResult(common::ErrorCode::NOT_SUPPORTED_ERR, message);
+    default:
+      return common::PlatformResult(common::ErrorCode::ABORT_ERR, message);
+  }
+}
+
+} // namespace voicecontrol
+} // namespace extension
diff --git a/src/voicecontrol/voicecontrol_util.h b/src/voicecontrol/voicecontrol_util.h
new file mode 100755 (executable)
index 0000000..3071aa9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 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 VOICECONTROL_VOICECONTROL_UTIL_H_
+#define VOICECONTROL_VOICECONTROL_UTIL_H_
+
+#include "common/extension.h"
+
+namespace extension {
+namespace voicecontrol {
+
+namespace {
+  /* Error message text */
+  const std::string NO_ERROR = "No error";
+  const std::string INVALID_PARAMETER = "Invalid parameter!";
+  const std::string OUT_OF_MEMORY = "Out of memory!";
+  const std::string OPERATION_FAILED = "Operation failed!";
+  const std::string PERMISSION_DENIED = "Permission denied!";
+  const std::string NOT_SUPPORTED = "Not supported!";
+
+  /* Parameter name */
+  const std::string CALLBACK_ID = "callbackId";
+  const std::string TYPE = "type";
+  const std::string LIST = "list";
+  const std::string COMMAND = "command";
+
+  /* Voice control command type */
+  const std::string FOREGROUND = "FOREGROUND";
+
+  /* Listener types on javascript */
+  const std::string ON_RESULT = "onresult";
+  const std::string ON_LANG = "onlanguagechanged";
+}
+
+  const std::string& MakeErrorMessage(const int ret);
+  common::PlatformResult MakeErrorObject(const int ret);
+
+} // namespace voicecontrol
+} // namespace extension
+
+#endif // VOICECONTROL_VOICECONTROL_UTIL_H_
\ No newline at end of file