From: Suyeon Hwang Date: Mon, 19 Jun 2017 02:43:03 +0000 (+0900) Subject: [VoiceControl] Add new web APIs for voice control X-Git-Tag: submit/tizen_4.0/20171018.120310~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6aa8dfa49202bd3b2586e482cd347e4cbadc38ae;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [VoiceControl] Add new web APIs for voice control Change-Id: I497d96e45158b398189761952953cfc6253c7698 Signed-off-by: Suyeon Hwang Signed-off-by: Szymon Jastrzebski --- diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 1a62c7ea..a42d1035 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -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 diff --git a/src/tizen-wrt.gyp b/src/tizen-wrt.gyp index 407e5457..410e44a2 100755 --- a/src/tizen-wrt.gyp +++ b/src/tizen-wrt.gyp @@ -322,6 +322,13 @@ ], }, ], + [ + '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 index 00000000..8706d516 --- /dev/null +++ b/src/voicecontrol/voicecontrol.gyp @@ -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 index 00000000..5caa4a45 --- /dev/null +++ b/src/voicecontrol/voicecontrol_api.js @@ -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 index 00000000..bf42449e --- /dev/null +++ b/src/voicecontrol/voicecontrol_client.cc @@ -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 +#include + +#include + +#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& 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::type, int (*)(vc_cmd_h)> ptr(vc_command, &vc_cmd_destroy); + + ret = vc_cmd_set_command(ptr.get(), (*it).get(COMMAND).get().c_str()); + if (VC_ERROR_NONE != ret) { + return MakeErrorObject(ret); + } + + ret = vc_cmd_set_type(ptr.get(), VcConvertCmdType((*it).get(TYPE).get())); + 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 index 00000000..7f067304 --- /dev/null +++ b/src/voicecontrol/voicecontrol_client.h @@ -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 + +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& 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 index 00000000..f3bd17a8 --- /dev/null +++ b/src/voicecontrol/voicecontrol_extension.cc @@ -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 index 00000000..5d989920 --- /dev/null +++ b/src/voicecontrol/voicecontrol_extension.h @@ -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 index 00000000..034b416e --- /dev/null +++ b/src/voicecontrol/voicecontrol_instance.cc @@ -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 +#include + +#include + +#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(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(); + + 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(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::vector list = args.get(LIST).get(); + + 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(); + + 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 index 00000000..633482e2 --- /dev/null +++ b/src/voicecontrol/voicecontrol_instance.h @@ -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 index 00000000..b51bbdc6 --- /dev/null +++ b/src/voicecontrol/voicecontrol_util.cc @@ -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 + +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 index 00000000..3071aa99 --- /dev/null +++ b/src/voicecontrol/voicecontrol_util.h @@ -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