1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "enroll_intell_voice_engine_callback_napi.h"
17 #include "intell_voice_log.h"
18 #include "intell_voice_common_napi.h"
19
20 #define LOG_TAG "EnrollEngineCallbackNapi"
21
22 using namespace std;
23 using namespace OHOS::IntellVoiceEngine;
24 using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0;
25
26 namespace OHOS {
27 namespace IntellVoiceNapi {
GetCallBackInfoNapiValue(const napi_env & env,napi_value & out)28 void EnrollCallbackInfo::GetCallBackInfoNapiValue(const napi_env &env, napi_value &out)
29 {
30 napi_status status = napi_create_object(env, &out);
31 if (status != napi_ok || out == nullptr) {
32 INTELL_VOICE_LOG_ERROR("failed to create js callbackInfo, error: %{public}d", status);
33 return;
34 }
35
36 napi_set_named_property(env, out, "result", SetValue(env, result));
37 napi_set_named_property(env, out, "context", SetValue(env, context));
38 }
39
EnrollIntellVoiceEngineCallbackNapi(const napi_env env)40 EnrollIntellVoiceEngineCallbackNapi::EnrollIntellVoiceEngineCallbackNapi(const napi_env env) : env_(env)
41 {
42 if (env_ != nullptr) {
43 napi_get_uv_event_loop(env_, &loop_);
44 }
45 contextMap_.clear();
46 }
47
~EnrollIntellVoiceEngineCallbackNapi()48 EnrollIntellVoiceEngineCallbackNapi::~EnrollIntellVoiceEngineCallbackNapi()
49 {
50 contextMap_.clear();
51 }
52
QueueAsyncWork(EnrollAsyncContext * context)53 void EnrollIntellVoiceEngineCallbackNapi::QueueAsyncWork(EnrollAsyncContext *context)
54 {
55 std::lock_guard<std::mutex> lock(mutex_);
56 if (contextMap_.find(context->type) == contextMap_.end()) {
57 std::queue<EnrollAsyncContext *> contextQue;
58 contextQue.push(context);
59 contextMap_[context->type] = contextQue;
60 } else {
61 contextMap_.at(context->type).push(context);
62 }
63 }
64
ConvertEventId(EnrollAsyncWorkType type)65 int32_t EnrollIntellVoiceEngineCallbackNapi::ConvertEventId(EnrollAsyncWorkType type)
66 {
67 int32_t eventId = HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_NONE;
68 switch (type) {
69 case ASYNC_WORK_INIT:
70 eventId = HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_INIT_DONE;
71 break;
72 case ASYNC_WORK_START:
73 eventId = HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE;
74 break;
75 case ASYNC_WORK_COMMIT:
76 eventId = HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE;
77 break;
78 default:
79 break;
80 }
81
82 return eventId;
83 }
84
ClearAsyncWork(bool error,const std::string & msg)85 void EnrollIntellVoiceEngineCallbackNapi::ClearAsyncWork(bool error, const std::string &msg)
86 {
87 INTELL_VOICE_LOG_INFO("%{public}s", msg.c_str());
88 std::lock_guard<std::mutex> lock(mutex_);
89 for (auto it = contextMap_.begin(); it != contextMap_.end(); it++) {
90 auto &contextQue = it->second;
91 int32_t eventId = ConvertEventId(it->first);
92 while (!contextQue.empty()) {
93 EnrollAsyncContext *context = contextQue.front();
94 contextQue.pop();
95 if (error) {
96 INTELL_VOICE_LOG_WARN("error occured");
97 }
98 if (context == nullptr) {
99 continue;
100 }
101
102 context->callbackInfo.eventId = eventId;
103 if (eventId == static_cast<int32_t>(INTELL_VOICE_ENGINE_MSG_INIT_DONE)) {
104 context->result_ = NAPI_INTELLIGENT_VOICE_INIT_FAILED;
105 } else if (eventId == static_cast<int32_t>(INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE)) {
106 context->result_ = NAPI_INTELLIGENT_VOICE_SUCCESS;
107 context->callbackInfo.result = UNKNOWN_ERROR;
108 context->callbackInfo.context = "";
109 } else if (eventId == static_cast<int32_t>(INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE)) {
110 context->result_ = NAPI_INTELLIGENT_VOICE_COMMIT_ENROLL_FAILED;
111 } else {
112 INTELL_VOICE_LOG_WARN("invalid type:%{public}d", it->first);
113 continue;
114 }
115
116 OnJsCallBack(context);
117 }
118 }
119 contextMap_.clear();
120 }
121
OnEvent(const IntellVoiceEngineCallBackEvent & event)122 void EnrollIntellVoiceEngineCallbackNapi::OnEvent(const IntellVoiceEngineCallBackEvent &event)
123 {
124 INTELL_VOICE_LOG_INFO("OnEvent: msgId: %{public}d, errCode: %{public}d, context: %{public}s",
125 event.msgId, event.result, event.info.c_str());
126 EnrollAsyncWorkType asyncType = ASYNC_WORK_INVALID;
127 switch (event.msgId) {
128 case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_INIT_DONE:
129 asyncType = ASYNC_WORK_INIT;
130 break;
131 case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE:
132 asyncType = ASYNC_WORK_START;
133 break;
134 case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE:
135 asyncType = ASYNC_WORK_COMMIT;
136 break;
137 default:
138 break;
139 }
140 std::lock_guard<std::mutex> lock(mutex_);
141 if (contextMap_.find(asyncType) == contextMap_.end() || contextMap_.at(asyncType).empty()) {
142 INTELL_VOICE_LOG_ERROR("callback is called, But context is empty");
143 return;
144 }
145
146 EnrollAsyncContext *context = contextMap_.at(asyncType).front();
147 contextMap_.at(asyncType).pop();
148 if (context == nullptr) {
149 INTELL_VOICE_LOG_ERROR("context is nullptr");
150 return;
151 }
152
153 context->callbackInfo = {event.msgId, event.result, event.info};
154 if (event.result != 0) {
155 if (event.msgId == INTELL_VOICE_ENGINE_MSG_INIT_DONE) {
156 context->result_ = NAPI_INTELLIGENT_VOICE_INIT_FAILED;
157 } else if (event.msgId == INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE) {
158 context->result_ = NAPI_INTELLIGENT_VOICE_COMMIT_ENROLL_FAILED;
159 }
160 }
161 OnJsCallBack(context);
162 }
163
UvWorkCallBack(uv_work_t * work,int status)164 void EnrollIntellVoiceEngineCallbackNapi::UvWorkCallBack(uv_work_t *work, int status)
165 {
166 INTELL_VOICE_LOG_INFO("enter");
167 auto asyncContext = reinterpret_cast<EnrollAsyncContext *>(work->data);
168 napi_value result = nullptr;
169 if (asyncContext != nullptr) {
170 napi_env env = asyncContext->env_;
171 if (asyncContext->callbackInfo.eventId ==
172 HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE) {
173 asyncContext->callbackInfo.GetCallBackInfoNapiValue(env, result);
174 } else {
175 napi_get_undefined(env, &result);
176 }
177 NapiAsync::CommonCallbackRoutine(env, asyncContext, result);
178 }
179
180 delete work;
181 }
182
OnJsCallBack(EnrollAsyncContext * context)183 void EnrollIntellVoiceEngineCallbackNapi::OnJsCallBack(EnrollAsyncContext *context)
184 {
185 INTELL_VOICE_LOG_INFO("enter, event id:%{public}d", context->callbackInfo.eventId);
186 if (loop_ != nullptr) {
187 uv_work_t *work = new (std::nothrow) uv_work_t;
188 if (work != nullptr) {
189 work->data = reinterpret_cast<void *>(context);
190 int ret = uv_queue_work(
191 loop_, work, [](uv_work_t *work) {}, UvWorkCallBack);
192 if (ret != 0) {
193 INTELL_VOICE_LOG_INFO("Failed to execute libuv work queue");
194 context->contextSp_.reset();
195 delete work;
196 }
197 } else {
198 context->contextSp_.reset();
199 }
200 } else {
201 context->contextSp_.reset();
202 }
203 }
204 } // namespace IntellVoiceNapi
205 } // namespace OHOS