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", event.msgId, event.result);
125 EnrollAsyncWorkType asyncType = ASYNC_WORK_INVALID;
126 switch (event.msgId) {
127 case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_INIT_DONE:
128 asyncType = ASYNC_WORK_INIT;
129 break;
130 case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE:
131 asyncType = ASYNC_WORK_START;
132 break;
133 case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE:
134 asyncType = ASYNC_WORK_COMMIT;
135 break;
136 default:
137 break;
138 }
139 std::lock_guard<std::mutex> lock(mutex_);
140 if (contextMap_.find(asyncType) == contextMap_.end() || contextMap_.at(asyncType).empty()) {
141 INTELL_VOICE_LOG_ERROR("callback is called, But context is empty");
142 return;
143 }
144
145 EnrollAsyncContext *context = contextMap_.at(asyncType).front();
146 contextMap_.at(asyncType).pop();
147 if (context == nullptr) {
148 INTELL_VOICE_LOG_ERROR("context is nullptr");
149 return;
150 }
151
152 context->callbackInfo = {event.msgId, event.result, event.info};
153 if (event.result != 0) {
154 if (event.msgId == INTELL_VOICE_ENGINE_MSG_INIT_DONE) {
155 context->result_ = NAPI_INTELLIGENT_VOICE_INIT_FAILED;
156 } else if (event.msgId == INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE) {
157 context->result_ = NAPI_INTELLIGENT_VOICE_COMMIT_ENROLL_FAILED;
158 }
159 }
160 OnJsCallBack(context);
161 }
162
UvWorkCallBack(uv_work_t * work,int status)163 void EnrollIntellVoiceEngineCallbackNapi::UvWorkCallBack(uv_work_t *work, int status)
164 {
165 INTELL_VOICE_LOG_INFO("enter");
166 auto asyncContext = reinterpret_cast<EnrollAsyncContext *>(work->data);
167 napi_value result = nullptr;
168 if (asyncContext != nullptr) {
169 napi_env env = asyncContext->env_;
170 if (asyncContext->callbackInfo.eventId ==
171 HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE) {
172 asyncContext->callbackInfo.GetCallBackInfoNapiValue(env, result);
173 } else {
174 napi_get_undefined(env, &result);
175 }
176 NapiAsync::CommonCallbackRoutine(env, asyncContext, result);
177 }
178
179 delete work;
180 }
181
OnJsCallBack(EnrollAsyncContext * context)182 void EnrollIntellVoiceEngineCallbackNapi::OnJsCallBack(EnrollAsyncContext *context)
183 {
184 INTELL_VOICE_LOG_INFO("enter, event id:%{public}d", context->callbackInfo.eventId);
185 if (loop_ != nullptr) {
186 uv_work_t *work = new (std::nothrow) uv_work_t;
187 if (work != nullptr) {
188 work->data = reinterpret_cast<void *>(context);
189 int ret = uv_queue_work(
190 loop_, work, [](uv_work_t *work) {}, UvWorkCallBack);
191 if (ret != 0) {
192 INTELL_VOICE_LOG_INFO("Failed to execute libuv work queue");
193 context->contextSp_.reset();
194 delete work;
195 }
196 } else {
197 context->contextSp_.reset();
198 }
199 } else {
200 context->contextSp_.reset();
201 }
202 }
203 } // namespace IntellVoiceNapi
204 } // namespace OHOS