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 "wakeup_intell_voice_engine_napi.h"
17
18 #include "want.h"
19 #include "iservice_registry.h"
20 #include "system_ability_definition.h"
21
22 #include "intell_voice_common_napi.h"
23 #include "intell_voice_napi_util.h"
24 #include "intell_voice_napi_queue.h"
25
26 #include "intell_voice_log.h"
27 #include "i_intell_voice_engine_callback.h"
28
29 #define LOG_TAG "WakeupIntellVoiceEngineNapi"
30
31 using namespace std;
32 using namespace OHOS::IntellVoice;
33
34 namespace OHOS {
35 namespace IntellVoiceNapi {
36 static __thread napi_ref g_wakeupEngineConstructor = nullptr;
37 WakeupIntelligentVoiceEngineDescriptor WakeupIntellVoiceEngineNapi::g_wakeupEngineDesc_;
38 int32_t WakeupIntellVoiceEngineNapi::constructResult_ = NAPI_INTELLIGENT_VOICE_SUCCESS;
39 static constexpr uint32_t MAX_CHANNEL_CNT = 4;
40
41 static const std::string WAKEUP_ENGINE_NAPI_CLASS_NAME = "WakeupIntelligentVoiceEngine";
42 static const std::string INTELL_VOICE_EVENT_CALLBACK_NAME = "wakeupIntelligentVoiceEvent";
43
WakeupIntellVoiceEngineNapi()44 WakeupIntellVoiceEngineNapi::WakeupIntellVoiceEngineNapi()
45 {
46 INTELL_VOICE_LOG_INFO("enter");
47 }
48
~WakeupIntellVoiceEngineNapi()49 WakeupIntellVoiceEngineNapi::~WakeupIntellVoiceEngineNapi()
50 {
51 INTELL_VOICE_LOG_INFO("enter");
52 if (wrapper_ != nullptr) {
53 napi_delete_reference(env_, wrapper_);
54 }
55 }
56
Export(napi_env env,napi_value exports)57 napi_value WakeupIntellVoiceEngineNapi::Export(napi_env env, napi_value exports)
58 {
59 napi_status status;
60 napi_value constructor;
61 napi_value result = nullptr;
62 const int32_t refCount = 1;
63 napi_get_undefined(env, &result);
64
65 napi_property_descriptor properties[] = {
66 DECLARE_NAPI_FUNCTION("getSupportedRegions", GetSupportedRegions),
67 DECLARE_NAPI_FUNCTION("setSensibility", SetSensibility),
68 DECLARE_NAPI_FUNCTION("setWakeupHapInfo", SetWakeupHapInfo),
69 DECLARE_NAPI_FUNCTION("setParameter", SetParameter),
70 DECLARE_NAPI_FUNCTION("getParameter", GetParameter),
71 DECLARE_NAPI_FUNCTION("release", Release),
72 DECLARE_NAPI_FUNCTION("on", On),
73 DECLARE_NAPI_FUNCTION("off", Off),
74 DECLARE_NAPI_FUNCTION("startCapturer", StartCapturer),
75 DECLARE_NAPI_FUNCTION("read", Read),
76 DECLARE_NAPI_FUNCTION("stopCapturer", StopCapturer),
77 DECLARE_NAPI_FUNCTION("getPcm", GetPcm),
78 };
79
80 napi_property_descriptor static_prop[] = {
81 DECLARE_NAPI_STATIC_FUNCTION(
82 "createWakeupIntelligentVoiceEngine", CreateWakeupIntelligentVoiceEngine)
83 };
84
85 status = napi_define_class(env,
86 WAKEUP_ENGINE_NAPI_CLASS_NAME.c_str(),
87 NAPI_AUTO_LENGTH,
88 Construct,
89 nullptr,
90 sizeof(properties) / sizeof(properties[0]),
91 properties,
92 &constructor);
93 if (status != napi_ok) {
94 return result;
95 }
96
97 status = napi_create_reference(env, constructor, refCount, &g_wakeupEngineConstructor);
98 if (status == napi_ok) {
99 status = napi_set_named_property(env, exports, WAKEUP_ENGINE_NAPI_CLASS_NAME.c_str(), constructor);
100 if (status == napi_ok) {
101 status = napi_define_properties(env, exports,
102 sizeof(static_prop) / sizeof(static_prop[0]), static_prop);
103 if (status == napi_ok) {
104 return exports;
105 }
106 }
107 }
108
109 return result;
110 }
111
Destruct(napi_env env,void * nativeObject,void * finalizeHint)112 void WakeupIntellVoiceEngineNapi::Destruct(napi_env env, void *nativeObject, void *finalizeHint)
113 {
114 if (nativeObject != nullptr) {
115 auto obj = static_cast<WakeupIntellVoiceEngineNapi *>(nativeObject);
116 delete obj;
117 }
118 }
119
Construct(napi_env env,napi_callback_info info)120 napi_value WakeupIntellVoiceEngineNapi::Construct(napi_env env, napi_callback_info info)
121 {
122 INTELL_VOICE_LOG_INFO("enter");
123 napi_status status;
124 size_t argc = ARGC_ONE;
125 napi_value args[ARGC_ONE] = { nullptr };
126
127 napi_value jsThis = nullptr;
128 napi_value undefinedResult = nullptr;
129 napi_get_undefined(env, &undefinedResult);
130
131 constructResult_ = NAPI_INTELLIGENT_VOICE_SUCCESS;
132 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr));
133
134 unique_ptr<WakeupIntellVoiceEngineNapi> engineNapi = make_unique<WakeupIntellVoiceEngineNapi>();
135 if (engineNapi == nullptr) {
136 INTELL_VOICE_LOG_ERROR("Failed to create WakeupIntellVoiceEngineNapi, No memory");
137 constructResult_ = NAPI_INTELLIGENT_VOICE_NO_MEMORY;
138 return undefinedResult;
139 }
140
141 engineNapi->env_ = env;
142 engineNapi->engine_ = std::make_shared<WakeupIntellVoiceEngine>(g_wakeupEngineDesc_);
143 if (engineNapi->engine_ == nullptr) {
144 INTELL_VOICE_LOG_ERROR("create intell voice engine failed");
145 constructResult_ = NAPI_INTELLIGENT_VOICE_NO_MEMORY;
146 return undefinedResult;
147 }
148
149 constructResult_ = IntellVoiceCommonNapi::ConvertResultCode(engineNapi->engine_->result_);
150 if (constructResult_ != NAPI_INTELLIGENT_VOICE_SUCCESS) {
151 return undefinedResult;
152 }
153
154 status = napi_wrap(env, jsThis, static_cast<void *>(engineNapi.get()), WakeupIntellVoiceEngineNapi::Destruct,
155 nullptr, &(engineNapi->wrapper_));
156 if (status == napi_ok) {
157 engineNapi.release();
158 return jsThis;
159 }
160
161 INTELL_VOICE_LOG_ERROR("wrap wakeup intell voice engine failed");
162 return undefinedResult;
163 }
164
CreateWakeupIntelligentVoiceEngine(napi_env env,napi_callback_info info)165 napi_value WakeupIntellVoiceEngineNapi::CreateWakeupIntelligentVoiceEngine(napi_env env, napi_callback_info info)
166 {
167 INTELL_VOICE_LOG_INFO("enter");
168 size_t cbIndex = ARG_INDEX_1;
169 auto context = std::make_shared<AsyncContext>(env);
170 if (context == nullptr) {
171 INTELL_VOICE_LOG_ERROR("create context failed, No memory");
172 return nullptr;
173 }
174
175 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
176 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
177 napi_valuetype valueType = napi_undefined;
178 napi_typeof(env, argv[0], &valueType);
179 CHECK_CONDITION_RETURN_FALSE((valueType != napi_object), "arg type mismatch");
180 napi_value temp = nullptr;
181 napi_status status = napi_get_named_property(env, argv[0], "needReconfirm", &temp);
182 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "get property failed");
183 status = GetValue(env, temp, g_wakeupEngineDesc_.needReconfirm);
184 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "get need reconfirm failed");
185 status = napi_get_named_property(env, argv[0], "wakeupPhrase", &temp);
186 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "get property failed");
187 status = GetValue(env, temp, g_wakeupEngineDesc_.wakeupPhrase);
188 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "get wakeup phrase failed");
189 INTELL_VOICE_LOG_INFO("needReconfirm: %{public}d", g_wakeupEngineDesc_.needReconfirm);
190 INTELL_VOICE_LOG_DEBUG("wakeupPhrase: %{public}s", g_wakeupEngineDesc_.wakeupPhrase.c_str());
191 return true;
192 };
193
194 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
195 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
196
197 AsyncExecute execute = [](napi_env env, void *data) {};
198
199 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
200 napi_value constructor = nullptr;
201 napi_status status = napi_get_reference_value(env, g_wakeupEngineConstructor, &constructor);
202 if (status != napi_ok) {
203 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_NO_MEMORY;
204 napi_get_undefined(env, &result);
205 return;
206 }
207
208 status = napi_new_instance(env, constructor, 0, nullptr, &result);
209 asyncContext->result_ = constructResult_;
210 if (status != napi_ok) {
211 napi_get_undefined(env, &result);
212 }
213 };
214
215 return NapiAsync::AsyncWork(env, context, "CreateWakeupIntelligentVoiceEngine", execute);
216 }
217
GetSupportedRegions(napi_env env,napi_callback_info info)218 napi_value WakeupIntellVoiceEngineNapi::GetSupportedRegions(napi_env env, napi_callback_info info)
219 {
220 INTELL_VOICE_LOG_INFO("enter");
221 size_t cbIndex = ARG_INDEX_0;
222 shared_ptr<AsyncContext> context = make_shared<AsyncContext>(env);
223 if (context == nullptr) {
224 INTELL_VOICE_LOG_ERROR("create AsyncContext failed, No memory");
225 return nullptr;
226 }
227
228 context->result_ = (context->GetCbInfo(env, info, cbIndex, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
229 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
230
231 AsyncExecute execute = [](napi_env env, void *data) {};
232
233 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
234 napi_create_array(env, &result);
235 napi_set_element(env, result, 0, SetValue(env, "CN"));
236 };
237
238 return NapiAsync::AsyncWork(env, context, "GetSupportedRegions", execute);
239 }
240
SetParameter(napi_env env,napi_callback_info info)241 napi_value WakeupIntellVoiceEngineNapi::SetParameter(napi_env env, napi_callback_info info)
242 {
243 INTELL_VOICE_LOG_INFO("enter");
244 size_t cbIndex = ARG_INDEX_2;
245 class SetParameterContext : public AsyncContext {
246 public:
247 explicit SetParameterContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
248 string key;
249 string value;
250 };
251 auto context = make_shared<SetParameterContext>(env);
252 if (context == nullptr) {
253 INTELL_VOICE_LOG_ERROR("create SetParameterContext failed, No memory");
254 return nullptr;
255 }
256
257 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
258 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_TWO), "argc less than 2");
259 CHECK_CONDITION_RETURN_FALSE((GetValue(env, argv[ARG_INDEX_0], context->key) != napi_ok), "Failed to get key");
260 CHECK_CONDITION_RETURN_FALSE((GetValue(env, argv[ARG_INDEX_1], context->value) != napi_ok),
261 "Failed to get value");
262 return true;
263 };
264
265 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
266 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
267
268 AsyncExecute execute;
269 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
270 execute = [](napi_env env, void *data) {
271 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
272 auto asyncContext = static_cast<SetParameterContext *>(data);
273 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
274 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
275 engine->SetParameter(asyncContext->key, asyncContext->value);
276 };
277 } else {
278 execute = [](napi_env env, void *data) {};
279 }
280 return NapiAsync::AsyncWork(env, context, "SetParameter", execute);
281 }
282
GetParameter(napi_env env,napi_callback_info info)283 napi_value WakeupIntellVoiceEngineNapi::GetParameter(napi_env env, napi_callback_info info)
284 {
285 INTELL_VOICE_LOG_INFO("enter");
286 size_t cbIndex = ARG_INDEX_1;
287 class GetParamContext : public AsyncContext {
288 public:
289 explicit GetParamContext(napi_env env) : AsyncContext(env) {};
290 std::string key;
291 std::string value;
292 };
293
294 auto context = make_shared<GetParamContext>(env);
295 if (context == nullptr) {
296 INTELL_VOICE_LOG_ERROR("create AsyncContext failed, No memory");
297 return nullptr;
298 }
299
300 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
301 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
302 napi_status status = GetValue(env, argv[0], context->key);
303 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "Failed to get key");
304 return true;
305 };
306
307 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
308 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
309
310 AsyncExecute execute;
311 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
312 execute = [](napi_env env, void *data) {
313 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
314 auto asyncContext = reinterpret_cast<GetParamContext *>(data);
315 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
316 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
317 asyncContext->value = engine->GetParameter(asyncContext->key);
318 };
319 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
320 auto getParamAsynContext = reinterpret_cast<GetParamContext *>(asyncContext);
321 if (getParamAsynContext != nullptr) {
322 result = SetValue(env, getParamAsynContext->value);
323 }
324 };
325 } else {
326 execute = [](napi_env env, void *data) {};
327 }
328
329 return NapiAsync::AsyncWork(env, context, "GetParameter", execute);
330 }
331
SetSensibility(napi_env env,napi_callback_info info)332 napi_value WakeupIntellVoiceEngineNapi::SetSensibility(napi_env env, napi_callback_info info)
333 {
334 INTELL_VOICE_LOG_INFO("enter");
335 size_t cbIndex = ARG_INDEX_1;
336 class SetSensibilityContext : public AsyncContext {
337 public:
338 explicit SetSensibilityContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
339 int32_t sensibility = 1;
340 };
341 auto context = make_shared<SetSensibilityContext>(env);
342 if (context == nullptr) {
343 INTELL_VOICE_LOG_ERROR("create SetSensibilityContext failed, No memory");
344 return nullptr;
345 }
346
347 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
348 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
349 CHECK_CONDITION_RETURN_FALSE((GetValue(env, argv[0], context->sensibility) != napi_ok),
350 "Failed to get sensibility");
351 return true;
352 };
353
354 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
355 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
356
357 AsyncExecute execute = [](napi_env env, void *data) {
358 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
359 auto asyncContext = static_cast<SetSensibilityContext *>(data);
360 CHECK_CONDITION_RETURN_VOID((asyncContext->result_ != NAPI_INTELLIGENT_VOICE_SUCCESS), "no need to execute");
361 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
362 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
363 engine->SetSensibility(asyncContext->sensibility);
364 };
365
366 return NapiAsync::AsyncWork(env, context, "SetSensibility", execute);
367 }
368
SetWakeupHapInfo(napi_env env,napi_callback_info info)369 napi_value WakeupIntellVoiceEngineNapi::SetWakeupHapInfo(napi_env env, napi_callback_info info)
370 {
371 INTELL_VOICE_LOG_INFO("enter");
372 size_t cbIndex = ARG_INDEX_1;
373 class SetWakeupHapContext : public AsyncContext {
374 public:
375 explicit SetWakeupHapContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
376 WakeupHapInfo hapInfo;
377 };
378 auto context = make_shared<SetWakeupHapContext>(env);
379 if (context == nullptr) {
380 INTELL_VOICE_LOG_ERROR("create SetWakeupHapContext failed, No memory");
381 return nullptr;
382 }
383
384 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
385 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
386 napi_value temp = nullptr;
387 CHECK_CONDITION_RETURN_FALSE((napi_get_named_property(env, argv[0], "bundleName", &temp) != napi_ok),
388 "get property failed");
389 CHECK_CONDITION_RETURN_FALSE((GetValue(env, temp, context->hapInfo.bundleName) != napi_ok),
390 "get bundle name failed");
391 CHECK_CONDITION_RETURN_FALSE((napi_get_named_property(env, argv[0], "abilityName", &temp) != napi_ok),
392 "get property failed");
393 CHECK_CONDITION_RETURN_FALSE((GetValue(env, temp, context->hapInfo.abilityName) != napi_ok),
394 "get ability name failed");
395 return true;
396 };
397
398 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
399 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
400
401 AsyncExecute execute = [](napi_env env, void *data) {
402 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
403 auto asyncContext = static_cast<SetWakeupHapContext *>(data);
404 CHECK_CONDITION_RETURN_VOID((asyncContext->result_ != NAPI_INTELLIGENT_VOICE_SUCCESS), "no need to execute");
405 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
406 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
407 engine->SetWakeupHapInfo(asyncContext->hapInfo);
408 };
409
410 return NapiAsync::AsyncWork(env, context, "SetWakeupHapInfo", execute);
411 }
412
Release(napi_env env,napi_callback_info info)413 napi_value WakeupIntellVoiceEngineNapi::Release(napi_env env, napi_callback_info info)
414 {
415 INTELL_VOICE_LOG_INFO("enter");
416 size_t cbIndex = ARG_INDEX_0;
417 shared_ptr<AsyncContext> context = make_shared<AsyncContext>(env);
418 if (context == nullptr) {
419 INTELL_VOICE_LOG_ERROR("create AsyncContext failed, No memory");
420 return nullptr;
421 }
422
423 context->result_ = (context->GetCbInfo(env, info, cbIndex, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
424 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
425
426 AsyncExecute execute = [](napi_env env, void *data) {
427 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
428 auto asyncContext = static_cast<AsyncContext *>(data);
429 CHECK_CONDITION_RETURN_VOID((asyncContext->result_ != NAPI_INTELLIGENT_VOICE_SUCCESS), "no need to execute");
430 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
431 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
432 engine->Release();
433 reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_ = nullptr;
434 };
435
436 return NapiAsync::AsyncWork(env, context, "Release", execute);
437 }
438
On(napi_env env,napi_callback_info info)439 napi_value WakeupIntellVoiceEngineNapi::On(napi_env env, napi_callback_info info)
440 {
441 INTELL_VOICE_LOG_INFO("enter");
442
443 napi_value undefinedResult = nullptr;
444 napi_get_undefined(env, &undefinedResult);
445
446 size_t argCount = ARGC_TWO;
447 napi_value args[ARGC_TWO] = { nullptr, nullptr };
448 napi_value jsThis = nullptr;
449
450 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
451 if (status != napi_ok || argCount != ARGC_TWO) {
452 INTELL_VOICE_LOG_ERROR("failed to get parameters");
453 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
454 return undefinedResult;
455 }
456
457 napi_valuetype eventType = napi_undefined;
458 if (napi_typeof(env, args[ARG_INDEX_0], &eventType) != napi_ok || eventType != napi_string) {
459 INTELL_VOICE_LOG_ERROR("callback event name type mismatch");
460 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
461 return undefinedResult;
462 }
463
464 string callbackName = "";
465 status = GetValue(env, args[ARG_INDEX_0], callbackName);
466 if (status != napi_ok) {
467 INTELL_VOICE_LOG_ERROR("failed to get callbackName");
468 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
469 return undefinedResult;
470 }
471 INTELL_VOICE_LOG_INFO("callbackName: %{public}s", callbackName.c_str());
472
473 if (callbackName != INTELL_VOICE_EVENT_CALLBACK_NAME) {
474 INTELL_VOICE_LOG_ERROR("no such supported event");
475 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
476 return undefinedResult;
477 }
478
479 napi_valuetype handler = napi_undefined;
480 if (napi_typeof(env, args[ARG_INDEX_1], &handler) != napi_ok || handler != napi_function) {
481 INTELL_VOICE_LOG_ERROR("callback handler type mismatch");
482 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
483 return undefinedResult;
484 }
485
486 return RegisterCallback(env, jsThis, args);
487 }
488
RegisterCallback(napi_env env,napi_value jsThis,napi_value * args)489 napi_value WakeupIntellVoiceEngineNapi::RegisterCallback(napi_env env, napi_value jsThis, napi_value *args)
490 {
491 INTELL_VOICE_LOG_INFO("enter");
492 napi_value result = nullptr;
493 napi_get_undefined(env, &result);
494
495 WakeupIntellVoiceEngineNapi *engineNapi = nullptr;
496 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&engineNapi));
497 if (status != napi_ok || engineNapi == nullptr) {
498 INTELL_VOICE_LOG_ERROR("Failed to get engine napi instance");
499 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_SYSTEM_ERROR);
500 return result;
501 }
502
503 if (engineNapi->engine_ == nullptr) {
504 INTELL_VOICE_LOG_ERROR("engine is null");
505 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_PERMISSION_DENIED);
506 return result;
507 }
508
509 engineNapi->callbackNapi_ = std::make_shared<EngineEventCallbackNapi>(env);
510 if (engineNapi->callbackNapi_ == nullptr) {
511 INTELL_VOICE_LOG_ERROR("allocate callback napi failed");
512 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_NO_MEMORY);
513 return result;
514 }
515 engineNapi->callbackNapi_->SaveCallbackReference(args[ARG_INDEX_1]);
516 engineNapi->engine_->SetCallback(engineNapi->callbackNapi_);
517 INTELL_VOICE_LOG_INFO("Set callback finish");
518 return result;
519 }
520
Off(napi_env env,napi_callback_info info)521 napi_value WakeupIntellVoiceEngineNapi::Off(napi_env env, napi_callback_info info)
522 {
523 INTELL_VOICE_LOG_INFO("enter");
524
525 napi_value undefinedResult = nullptr;
526 napi_get_undefined(env, &undefinedResult);
527
528 const size_t minArgCount = ARGC_ONE;
529 size_t argCount = ARGC_TWO;
530 napi_value args[ARGC_TWO] = { nullptr, nullptr };
531 napi_value jsThis = nullptr;
532
533 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
534 if (status != napi_ok || argCount < minArgCount) {
535 INTELL_VOICE_LOG_ERROR("failed to get parameters");
536 return undefinedResult;
537 }
538
539 napi_valuetype eventType = napi_undefined;
540 if (napi_typeof(env, args[ARG_INDEX_0], &eventType) != napi_ok || eventType != napi_string) {
541 INTELL_VOICE_LOG_ERROR("callback event name type mismatch");
542 return undefinedResult;
543 }
544
545 string callbackName = "";
546 status = GetValue(env, args[ARG_INDEX_0], callbackName);
547 if (status != napi_ok) {
548 INTELL_VOICE_LOG_ERROR("failed to get callbackName");
549 return undefinedResult;
550 }
551 INTELL_VOICE_LOG_INFO("callbackName: %{public}s", callbackName.c_str());
552
553 if (argCount > minArgCount) {
554 napi_valuetype secondArgType = napi_undefined;
555 if (napi_typeof(env, args[ARG_INDEX_1], &secondArgType) != napi_ok || secondArgType != napi_function) {
556 INTELL_VOICE_LOG_ERROR("failed to get callback function instance");
557 return undefinedResult;
558 }
559 } else {
560 args[ARG_INDEX_1] = nullptr;
561 }
562
563 return UnregisterCallback(env, jsThis, callbackName, args[ARG_INDEX_1]);
564 }
565
UnregisterCallback(napi_env env,napi_value jsThis,const std::string & callbackName,napi_value callback)566 napi_value WakeupIntellVoiceEngineNapi::UnregisterCallback(napi_env env, napi_value jsThis,
567 const std::string &callbackName, napi_value callback)
568 {
569 INTELL_VOICE_LOG_INFO("enter");
570 napi_value result = nullptr;
571 napi_get_undefined(env, &result);
572
573 WakeupIntellVoiceEngineNapi *engineNapi = nullptr;
574 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&engineNapi));
575 if (status != napi_ok || engineNapi == nullptr) {
576 INTELL_VOICE_LOG_ERROR("Failed to get engine napi instance");
577 return result;
578 }
579
580 if (callbackName != INTELL_VOICE_EVENT_CALLBACK_NAME) {
581 INTELL_VOICE_LOG_ERROR("No such off callback supported");
582 return result;
583 }
584
585 if (engineNapi->callbackNapi_ == nullptr) {
586 INTELL_VOICE_LOG_ERROR("callback napi is nullptr");
587 return result;
588 }
589
590 if (callback != nullptr) {
591 engineNapi->callbackNapi_->RemoveCallbackReference(callback);
592 if (engineNapi->callbackNapi_->GetCbReferenceSetSize() == 0) {
593 engineNapi->callbackNapi_ = nullptr;
594 }
595 } else {
596 engineNapi->callbackNapi_->RemoveAllCallbackReference();
597 engineNapi->callbackNapi_ = nullptr;
598 }
599 return result;
600 }
601
StartCapturer(napi_env env,napi_callback_info info)602 napi_value WakeupIntellVoiceEngineNapi::StartCapturer(napi_env env, napi_callback_info info)
603 {
604 INTELL_VOICE_LOG_INFO("enter");
605 size_t cbIndex = ARG_INDEX_1;
606 class StartCapturerContext : public AsyncContext {
607 public:
608 explicit StartCapturerContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
609 int32_t channels = 0;
610 };
611 auto context = make_shared<StartCapturerContext>(env);
612 if (context == nullptr) {
613 INTELL_VOICE_LOG_ERROR("create StartCapturerContext failed, No memory");
614 return nullptr;
615 }
616
617 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
618 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
619 CHECK_CONDITION_RETURN_FALSE((GetValue(env, argv[0], context->channels) != napi_ok),
620 "Failed to get channels");
621 if ((context->channels <= 0) || (context->channels >= (0x1 << MAX_CHANNEL_CNT))) {
622 INTELL_VOICE_LOG_ERROR("channels:%{public}d is invalid", context->channels);
623 return false;
624 }
625 return true;
626 };
627
628 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
629 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
630
631 AsyncExecute execute;
632 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
633 execute = [](napi_env env, void *data) {
634 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
635 auto asyncContext = static_cast<StartCapturerContext *>(data);
636 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
637 if (engine == nullptr) {
638 INTELL_VOICE_LOG_ERROR("get engine instance failed");
639 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_START_CAPTURER_FAILED;
640 return;
641 }
642 asyncContext->result_ = IntellVoiceCommonNapi::ConvertResultCode(
643 engine->StartCapturer(asyncContext->channels));
644 };
645 } else {
646 execute = [](napi_env env, void *data) {};
647 }
648
649 return NapiAsync::AsyncWork(env, context, "StartCapturer", execute);
650 }
651
Read(napi_env env,napi_callback_info info)652 napi_value WakeupIntellVoiceEngineNapi::Read(napi_env env, napi_callback_info info)
653 {
654 napi_value undefined = nullptr;
655 napi_get_undefined(env, &undefined);
656
657 class GetAudioContext : public AsyncContext {
658 public:
659 explicit GetAudioContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
660 std::vector<uint8_t> data;
661 };
662
663 shared_ptr<GetAudioContext> context = make_shared<GetAudioContext>(env);
664 CHECK_CONDITION_RETURN_RET(context == nullptr, undefined, "create context fail");
665
666 context->result_ = (context->GetCbInfo(env, info, 0, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
667 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
668
669 AsyncExecute execute;
670 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
671 execute = [](napi_env env, void *data) {
672 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
673 auto asyncContext = static_cast<GetAudioContext *>(data);
674 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
675 if (engine == nullptr) {
676 INTELL_VOICE_LOG_ERROR("get engine instance failed");
677 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_READ_FAILED;
678 return;
679 }
680 if (engine->Read(asyncContext->data) != 0) {
681 INTELL_VOICE_LOG_ERROR("failed to read");
682 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_READ_FAILED;
683 }
684 };
685 } else {
686 execute = [](napi_env env, void *data) {};
687 }
688
689 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
690 CHECK_CONDITION_RETURN_VOID((asyncContext == nullptr), "async context is null");
691 auto context = static_cast<GetAudioContext *>(asyncContext);
692 result = SetValue(env, context->data);
693 vector<uint8_t>().swap(context->data);
694 };
695
696 return NapiAsync::AsyncWork(env, context, "Read", execute);
697 }
698
StopCapturer(napi_env env,napi_callback_info info)699 napi_value WakeupIntellVoiceEngineNapi::StopCapturer(napi_env env, napi_callback_info info)
700 {
701 INTELL_VOICE_LOG_INFO("enter");
702 size_t cbIndex = ARG_INDEX_0;
703 shared_ptr<AsyncContext> context = make_shared<AsyncContext>(env);
704 if (context == nullptr) {
705 INTELL_VOICE_LOG_ERROR("create AsyncContext failed, No memory");
706 return nullptr;
707 }
708
709 context->result_ = (context->GetCbInfo(env, info, cbIndex, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
710 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
711
712 AsyncExecute execute;
713 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
714 execute = [](napi_env env, void *data) {
715 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
716 auto asyncContext = static_cast<AsyncContext *>(data);
717 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
718 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
719 engine->StopCapturer();
720 };
721 } else {
722 execute = [](napi_env env, void *data) {};
723 }
724
725 return NapiAsync::AsyncWork(env, context, "StopCapturer", execute);
726 }
727
GetPcm(napi_env env,napi_callback_info info)728 napi_value WakeupIntellVoiceEngineNapi::GetPcm(napi_env env, napi_callback_info info)
729 {
730 INTELL_VOICE_LOG_INFO("enter");
731 napi_value undefined = nullptr;
732 napi_get_undefined(env, &undefined);
733
734 class GetPcmContext : public AsyncContext {
735 public:
736 explicit GetPcmContext(napi_env env) : AsyncContext(env) {};
737 std::vector<uint8_t> data;
738 };
739
740 auto context = make_shared<GetPcmContext>(env);
741 CHECK_CONDITION_RETURN_RET(context == nullptr, undefined, "create context fail");
742
743 context->result_ = (context->GetCbInfo(env, info, 0, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
744 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
745
746 AsyncExecute execute;
747 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
748 execute = [](napi_env env, void *data) {
749 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
750 auto asyncContext = static_cast<GetPcmContext *>(data);
751 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
752 if (engine == nullptr) {
753 INTELL_VOICE_LOG_ERROR("get engine instance failed");
754 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_NO_MEMORY;
755 return;
756 }
757 if (engine->GetWakeupPcm(asyncContext->data) != 0) {
758 INTELL_VOICE_LOG_ERROR("failed to get wakeup pcm");
759 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_SYSTEM_ERROR;
760 }
761 };
762 } else {
763 execute = [](napi_env env, void *data) {};
764 }
765
766 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
767 CHECK_CONDITION_RETURN_VOID((asyncContext == nullptr), "async context is null");
768 auto context = static_cast<GetPcmContext *>(asyncContext);
769 result = SetValue(env, context->data);
770 vector<uint8_t>().swap(context->data);
771 };
772
773 return NapiAsync::AsyncWork(env, context, "GetPcm", execute);
774 }
775
776 } // namespace IntellVoiceNapi
777 } // namespace OHOS
778