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, %{public}p", this);
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 if (engineNapi->engine_->GetEngine() == nullptr) {
150 INTELL_VOICE_LOG_ERROR("create wakeup engine failed");
151 constructResult_ = NAPI_INTELLIGENT_VOICE_PERMISSION_DENIED;
152 return undefinedResult;
153 }
154
155 status = napi_wrap(env, jsThis, static_cast<void *>(engineNapi.get()), WakeupIntellVoiceEngineNapi::Destruct,
156 nullptr, &(engineNapi->wrapper_));
157 if (status == napi_ok) {
158 engineNapi.release();
159 return jsThis;
160 }
161
162 INTELL_VOICE_LOG_ERROR("wrap wakeup intell voice engine failed");
163 return undefinedResult;
164 }
165
CreateWakeupIntelligentVoiceEngine(napi_env env,napi_callback_info info)166 napi_value WakeupIntellVoiceEngineNapi::CreateWakeupIntelligentVoiceEngine(napi_env env, napi_callback_info info)
167 {
168 INTELL_VOICE_LOG_INFO("enter");
169 size_t cbIndex = ARG_INDEX_1;
170 auto context = std::make_shared<AsyncContext>(env);
171 if (context == nullptr) {
172 INTELL_VOICE_LOG_ERROR("create context failed, No memory");
173 return nullptr;
174 }
175
176 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
177 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
178 napi_valuetype valueType = napi_undefined;
179 napi_typeof(env, argv[0], &valueType);
180 CHECK_CONDITION_RETURN_FALSE((valueType != napi_object), "arg type mismatch");
181 napi_value temp = nullptr;
182 napi_status status = napi_get_named_property(env, argv[0], "needReconfirm", &temp);
183 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "get property failed");
184 status = GetValue(env, temp, g_wakeupEngineDesc_.needReconfirm);
185 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "get need reconfirm failed");
186 status = napi_get_named_property(env, argv[0], "wakeupPhrase", &temp);
187 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "get property failed");
188 status = GetValue(env, temp, g_wakeupEngineDesc_.wakeupPhrase);
189 CHECK_CONDITION_RETURN_FALSE((status != napi_ok), "get wakeup phrase failed");
190 INTELL_VOICE_LOG_INFO("needReconfirm: %{public}d", g_wakeupEngineDesc_.needReconfirm);
191 INTELL_VOICE_LOG_INFO("wakeupPhrase: %{public}s", g_wakeupEngineDesc_.wakeupPhrase.c_str());
192 return true;
193 };
194
195 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
196 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
197
198 AsyncExecute execute = [](napi_env env, void *data) {};
199
200 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
201 napi_value constructor = nullptr;
202 napi_status status = napi_get_reference_value(env, g_wakeupEngineConstructor, &constructor);
203 if (status != napi_ok) {
204 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_NO_MEMORY;
205 napi_get_undefined(env, &result);
206 return;
207 }
208
209 status = napi_new_instance(env, constructor, 0, nullptr, &result);
210 asyncContext->result_ = constructResult_;
211 if (status != napi_ok) {
212 napi_get_undefined(env, &result);
213 }
214 };
215
216 return NapiAsync::AsyncWork(env, context, "CreateWakeupIntelligentVoiceEngine", execute);
217 }
218
GetSupportedRegions(napi_env env,napi_callback_info info)219 napi_value WakeupIntellVoiceEngineNapi::GetSupportedRegions(napi_env env, napi_callback_info info)
220 {
221 INTELL_VOICE_LOG_INFO("enter");
222 size_t cbIndex = ARG_INDEX_0;
223 shared_ptr<AsyncContext> context = make_shared<AsyncContext>(env);
224 if (context == nullptr) {
225 INTELL_VOICE_LOG_ERROR("create AsyncContext failed, No memory");
226 return nullptr;
227 }
228
229 context->result_ = (context->GetCbInfo(env, info, cbIndex, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
230 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
231
232 AsyncExecute execute = [](napi_env env, void *data) {};
233
234 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
235 napi_create_array(env, &result);
236 napi_set_element(env, result, 0, SetValue(env, "CN"));
237 };
238
239 return NapiAsync::AsyncWork(env, context, "GetSupportedRegions", execute);
240 }
241
SetParameter(napi_env env,napi_callback_info info)242 napi_value WakeupIntellVoiceEngineNapi::SetParameter(napi_env env, napi_callback_info info)
243 {
244 INTELL_VOICE_LOG_INFO("enter");
245 size_t cbIndex = ARG_INDEX_2;
246 class SetParameterContext : public AsyncContext {
247 public:
248 explicit SetParameterContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
249 string key;
250 string value;
251 };
252 auto context = make_shared<SetParameterContext>(env);
253 if (context == nullptr) {
254 INTELL_VOICE_LOG_ERROR("create SetParameterContext failed, No memory");
255 return nullptr;
256 }
257
258 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
259 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_TWO), "argc less than 2");
260 CHECK_CONDITION_RETURN_FALSE((GetValue(env, argv[ARG_INDEX_0], context->key) != napi_ok), "Failed to get key");
261 CHECK_CONDITION_RETURN_FALSE((GetValue(env, argv[ARG_INDEX_1], context->value) != napi_ok),
262 "Failed to get value");
263 return true;
264 };
265
266 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
267 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
268
269 AsyncExecute execute;
270 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
271 execute = [](napi_env env, void *data) {
272 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
273 auto asyncContext = static_cast<SetParameterContext *>(data);
274 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
275 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
276 engine->SetParameter(asyncContext->key, asyncContext->value);
277 };
278 } else {
279 execute = [](napi_env env, void *data) {};
280 }
281 return NapiAsync::AsyncWork(env, context, "SetParameter", execute);
282 }
283
GetParameter(napi_env env,napi_callback_info info)284 napi_value WakeupIntellVoiceEngineNapi::GetParameter(napi_env env, napi_callback_info info)
285 {
286 INTELL_VOICE_LOG_INFO("enter");
287 size_t cbIndex = ARG_INDEX_1;
288 shared_ptr<AsyncContext> context = make_shared<AsyncContext>(env);
289 if (context == nullptr) {
290 INTELL_VOICE_LOG_ERROR("create AsyncContext failed, No memory");
291 return nullptr;
292 }
293
294 context->result_ = (context->GetCbInfo(env, info, cbIndex, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
295 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
296
297 AsyncExecute execute = [](napi_env env, void *data) {};
298
299 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
300 INTELL_VOICE_LOG_INFO("get parameter enter");
301 result = SetValue(env, "value");
302 };
303
304 return NapiAsync::AsyncWork(env, context, "GetParameter", execute);
305 }
306
SetSensibility(napi_env env,napi_callback_info info)307 napi_value WakeupIntellVoiceEngineNapi::SetSensibility(napi_env env, napi_callback_info info)
308 {
309 INTELL_VOICE_LOG_INFO("enter");
310 size_t cbIndex = ARG_INDEX_1;
311 class SetSensibilityContext : public AsyncContext {
312 public:
313 explicit SetSensibilityContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
314 int32_t sensibility = 1;
315 };
316 auto context = make_shared<SetSensibilityContext>(env);
317 if (context == nullptr) {
318 INTELL_VOICE_LOG_ERROR("create SetSensibilityContext failed, No memory");
319 return nullptr;
320 }
321
322 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
323 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
324 CHECK_CONDITION_RETURN_FALSE((GetValue(env, argv[0], context->sensibility) != napi_ok),
325 "Failed to get sensibility");
326 return true;
327 };
328
329 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
330 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
331
332 AsyncExecute execute = [](napi_env env, void *data) {
333 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
334 auto asyncContext = static_cast<SetSensibilityContext *>(data);
335 CHECK_CONDITION_RETURN_VOID((asyncContext->result_ != NAPI_INTELLIGENT_VOICE_SUCCESS), "no need to execute");
336 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
337 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
338 engine->SetSensibility(asyncContext->sensibility);
339 };
340
341 return NapiAsync::AsyncWork(env, context, "SetSensibility", execute);
342 }
343
SetWakeupHapInfo(napi_env env,napi_callback_info info)344 napi_value WakeupIntellVoiceEngineNapi::SetWakeupHapInfo(napi_env env, napi_callback_info info)
345 {
346 INTELL_VOICE_LOG_INFO("enter");
347 size_t cbIndex = ARG_INDEX_1;
348 class SetWakeupHapContext : public AsyncContext {
349 public:
350 explicit SetWakeupHapContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
351 WakeupHapInfo hapInfo;
352 };
353 auto context = make_shared<SetWakeupHapContext>(env);
354 if (context == nullptr) {
355 INTELL_VOICE_LOG_ERROR("create SetWakeupHapContext failed, No memory");
356 return nullptr;
357 }
358
359 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
360 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
361 napi_value temp = nullptr;
362 CHECK_CONDITION_RETURN_FALSE((napi_get_named_property(env, argv[0], "bundleName", &temp) != napi_ok),
363 "get property failed");
364 CHECK_CONDITION_RETURN_FALSE((GetValue(env, temp, context->hapInfo.bundleName) != napi_ok),
365 "get bundle name failed");
366 CHECK_CONDITION_RETURN_FALSE((napi_get_named_property(env, argv[0], "abilityName", &temp) != napi_ok),
367 "get property failed");
368 CHECK_CONDITION_RETURN_FALSE((GetValue(env, temp, context->hapInfo.abilityName) != napi_ok),
369 "get ability name failed");
370 return true;
371 };
372
373 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
374 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
375
376 AsyncExecute execute = [](napi_env env, void *data) {
377 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
378 auto asyncContext = static_cast<SetWakeupHapContext *>(data);
379 CHECK_CONDITION_RETURN_VOID((asyncContext->result_ != NAPI_INTELLIGENT_VOICE_SUCCESS), "no need to execute");
380 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
381 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
382 engine->SetWakeupHapInfo(asyncContext->hapInfo);
383 };
384
385 return NapiAsync::AsyncWork(env, context, "SetWakeupHapInfo", execute);
386 }
387
Release(napi_env env,napi_callback_info info)388 napi_value WakeupIntellVoiceEngineNapi::Release(napi_env env, napi_callback_info info)
389 {
390 INTELL_VOICE_LOG_INFO("enter");
391 size_t cbIndex = ARG_INDEX_0;
392 shared_ptr<AsyncContext> context = make_shared<AsyncContext>(env);
393 if (context == nullptr) {
394 INTELL_VOICE_LOG_ERROR("create AsyncContext failed, No memory");
395 return nullptr;
396 }
397
398 context->result_ = (context->GetCbInfo(env, info, cbIndex, nullptr) ? 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<AsyncContext *>(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->Release();
408 reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_ = nullptr;
409 };
410
411 return NapiAsync::AsyncWork(env, context, "Release", execute);
412 }
413
On(napi_env env,napi_callback_info info)414 napi_value WakeupIntellVoiceEngineNapi::On(napi_env env, napi_callback_info info)
415 {
416 INTELL_VOICE_LOG_INFO("enter");
417
418 napi_value undefinedResult = nullptr;
419 napi_get_undefined(env, &undefinedResult);
420
421 size_t argCount = ARGC_TWO;
422 napi_value args[ARGC_TWO] = { nullptr, nullptr };
423 napi_value jsThis = nullptr;
424
425 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
426 if (status != napi_ok || argCount != ARGC_TWO) {
427 INTELL_VOICE_LOG_ERROR("failed to get parameters");
428 return undefinedResult;
429 }
430
431 napi_valuetype eventType = napi_undefined;
432 if (napi_typeof(env, args[ARG_INDEX_0], &eventType) != napi_ok || eventType != napi_string) {
433 INTELL_VOICE_LOG_ERROR("callback event name type mismatch");
434 return undefinedResult;
435 }
436
437 string callbackName = "";
438 status = GetValue(env, args[ARG_INDEX_0], callbackName);
439 if (status != napi_ok) {
440 INTELL_VOICE_LOG_ERROR("failed to get callbackName");
441 return undefinedResult;
442 }
443 INTELL_VOICE_LOG_INFO("callbackName: %{public}s", callbackName.c_str());
444
445 if (callbackName != INTELL_VOICE_EVENT_CALLBACK_NAME) {
446 INTELL_VOICE_LOG_ERROR("no such supported event");
447 return undefinedResult;
448 }
449
450 napi_valuetype handler = napi_undefined;
451 if (napi_typeof(env, args[ARG_INDEX_1], &handler) != napi_ok || handler != napi_function) {
452 INTELL_VOICE_LOG_ERROR("callback handler type mismatch");
453 return undefinedResult;
454 }
455
456 return RegisterCallback(env, jsThis, args);
457 }
458
RegisterCallback(napi_env env,napi_value jsThis,napi_value * args)459 napi_value WakeupIntellVoiceEngineNapi::RegisterCallback(napi_env env, napi_value jsThis, napi_value *args)
460 {
461 INTELL_VOICE_LOG_INFO("enter");
462 napi_value result = nullptr;
463 napi_get_undefined(env, &result);
464
465 WakeupIntellVoiceEngineNapi *engineNapi = nullptr;
466 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&engineNapi));
467 if (status != napi_ok || engineNapi == nullptr) {
468 INTELL_VOICE_LOG_ERROR("Failed to get engine napi instance");
469 return result;
470 }
471
472 if (engineNapi->engine_ == nullptr) {
473 INTELL_VOICE_LOG_ERROR("engine is null");
474 IntellVoiceCommonNapi::ThrowError(env, NAPI_INTELLIGENT_VOICE_PERMISSION_DENIED);
475 return result;
476 }
477
478 engineNapi->callbackNapi_ = std::make_shared<EngineEventCallbackNapi>(env);
479 if (engineNapi->callbackNapi_ == nullptr) {
480 INTELL_VOICE_LOG_ERROR("allocate callback napi failed");
481 return result;
482 }
483 engineNapi->callbackNapi_->SaveCallbackReference(args[ARG_INDEX_1]);
484 engineNapi->engine_->SetCallback(engineNapi->callbackNapi_);
485 INTELL_VOICE_LOG_INFO("Set callback finish");
486 return result;
487 }
488
Off(napi_env env,napi_callback_info info)489 napi_value WakeupIntellVoiceEngineNapi::Off(napi_env env, napi_callback_info info)
490 {
491 INTELL_VOICE_LOG_INFO("enter");
492
493 napi_value undefinedResult = nullptr;
494 napi_get_undefined(env, &undefinedResult);
495
496 const size_t minArgCount = ARGC_ONE;
497 size_t argCount = ARGC_TWO;
498 napi_value args[ARGC_TWO] = { nullptr, nullptr };
499 napi_value jsThis = nullptr;
500
501 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
502 if (status != napi_ok || argCount < minArgCount) {
503 INTELL_VOICE_LOG_ERROR("failed to get parameters");
504 return undefinedResult;
505 }
506
507 napi_valuetype eventType = napi_undefined;
508 if (napi_typeof(env, args[ARG_INDEX_0], &eventType) != napi_ok || eventType != napi_string) {
509 INTELL_VOICE_LOG_ERROR("callback event name type mismatch");
510 return undefinedResult;
511 }
512
513 string callbackName = "";
514 status = GetValue(env, args[ARG_INDEX_0], callbackName);
515 if (status != napi_ok) {
516 INTELL_VOICE_LOG_ERROR("failed to get callbackName");
517 return undefinedResult;
518 }
519 INTELL_VOICE_LOG_INFO("callbackName: %{public}s", callbackName.c_str());
520
521 if (argCount > minArgCount) {
522 napi_valuetype secondArgType = napi_undefined;
523 if (napi_typeof(env, args[ARG_INDEX_1], &secondArgType) != napi_ok || secondArgType != napi_function) {
524 INTELL_VOICE_LOG_ERROR("failed to get callback function instance");
525 return undefinedResult;
526 }
527 } else {
528 args[ARG_INDEX_1] = nullptr;
529 }
530
531 return UnregisterCallback(env, jsThis, callbackName, args[ARG_INDEX_1]);
532 }
533
UnregisterCallback(napi_env env,napi_value jsThis,const std::string & callbackName,napi_value callback)534 napi_value WakeupIntellVoiceEngineNapi::UnregisterCallback(napi_env env, napi_value jsThis,
535 const std::string &callbackName, napi_value callback)
536 {
537 INTELL_VOICE_LOG_INFO("enter");
538 napi_value result = nullptr;
539 napi_get_undefined(env, &result);
540
541 WakeupIntellVoiceEngineNapi *engineNapi = nullptr;
542 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&engineNapi));
543 if (status != napi_ok || engineNapi == nullptr) {
544 INTELL_VOICE_LOG_ERROR("Failed to get engine napi instance");
545 return result;
546 }
547
548 if (callbackName != INTELL_VOICE_EVENT_CALLBACK_NAME) {
549 INTELL_VOICE_LOG_ERROR("No such off callback supported");
550 return result;
551 }
552
553 if (engineNapi->callbackNapi_ == nullptr) {
554 INTELL_VOICE_LOG_ERROR("callback napi is nullptr");
555 return result;
556 }
557
558 if (callback != nullptr) {
559 engineNapi->callbackNapi_->RemoveCallbackReference(callback);
560 if (engineNapi->callbackNapi_->GetCbReferenceSetSize() == 0) {
561 engineNapi->callbackNapi_ = nullptr;
562 }
563 } else {
564 engineNapi->callbackNapi_->RemoveAllCallbackReference();
565 engineNapi->callbackNapi_ = nullptr;
566 }
567 return result;
568 }
569
StartCapturer(napi_env env,napi_callback_info info)570 napi_value WakeupIntellVoiceEngineNapi::StartCapturer(napi_env env, napi_callback_info info)
571 {
572 INTELL_VOICE_LOG_INFO("enter");
573 size_t cbIndex = ARG_INDEX_1;
574 class StartCapturerContext : public AsyncContext {
575 public:
576 explicit StartCapturerContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
577 int32_t channels = 0;
578 };
579 auto context = make_shared<StartCapturerContext>(env);
580 if (context == nullptr) {
581 INTELL_VOICE_LOG_ERROR("create StartCapturerContext failed, No memory");
582 return nullptr;
583 }
584
585 CbInfoParser parser = [env, context](size_t argc, napi_value *argv) -> bool {
586 CHECK_CONDITION_RETURN_FALSE((argc < ARGC_ONE), "argc less than 1");
587 CHECK_CONDITION_RETURN_FALSE((GetValue(env, argv[0], context->channels) != napi_ok),
588 "Failed to get channels");
589 if ((context->channels <= 0) || (context->channels >= (0x1 << MAX_CHANNEL_CNT))) {
590 INTELL_VOICE_LOG_ERROR("channels:%{public}d is invalid", context->channels);
591 return false;
592 }
593 return true;
594 };
595
596 context->result_ = (context->GetCbInfo(env, info, cbIndex, parser) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
597 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
598
599 AsyncExecute execute;
600 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
601 execute = [](napi_env env, void *data) {
602 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
603 auto asyncContext = static_cast<StartCapturerContext *>(data);
604 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
605 if (engine == nullptr) {
606 INTELL_VOICE_LOG_ERROR("get engine instance failed");
607 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_START_CAPTURER_FAILED;
608 return;
609 }
610 if (engine->StartCapturer(asyncContext->channels) != 0) {
611 INTELL_VOICE_LOG_ERROR("failed to start capturer");
612 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_START_CAPTURER_FAILED;
613 }
614 };
615 } else {
616 execute = [](napi_env env, void *data) {};
617 }
618
619 return NapiAsync::AsyncWork(env, context, "StartCapturer", execute);
620 }
621
Read(napi_env env,napi_callback_info info)622 napi_value WakeupIntellVoiceEngineNapi::Read(napi_env env, napi_callback_info info)
623 {
624 INTELL_VOICE_LOG_INFO("enter");
625 napi_value undefined = nullptr;
626 napi_get_undefined(env, &undefined);
627
628 class GetAudioContext : public AsyncContext {
629 public:
630 explicit GetAudioContext(napi_env napiEnv) : AsyncContext(napiEnv) {};
631 std::vector<uint8_t> data;
632 };
633
634 shared_ptr<GetAudioContext> context = make_shared<GetAudioContext>(env);
635 CHECK_CONDITION_RETURN_RET(context == nullptr, undefined, "create context fail");
636
637 context->result_ = (context->GetCbInfo(env, info, 0, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
638 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
639
640 AsyncExecute execute;
641 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
642 execute = [](napi_env env, void *data) {
643 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
644 auto asyncContext = static_cast<GetAudioContext *>(data);
645 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
646 if (engine == nullptr) {
647 INTELL_VOICE_LOG_ERROR("get engine instance failed");
648 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_READ_FAILED;
649 return;
650 }
651 if (engine->Read(asyncContext->data) != 0) {
652 INTELL_VOICE_LOG_ERROR("failed to read");
653 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_READ_FAILED;
654 }
655 };
656 } else {
657 execute = [](napi_env env, void *data) {};
658 }
659
660 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
661 CHECK_CONDITION_RETURN_VOID((asyncContext == nullptr), "async context is null");
662 auto context = static_cast<GetAudioContext *>(asyncContext);
663 result = SetValue(env, context->data);
664 vector<uint8_t>().swap(context->data);
665 };
666
667 return NapiAsync::AsyncWork(env, context, "Read", execute);
668 }
669
StopCapturer(napi_env env,napi_callback_info info)670 napi_value WakeupIntellVoiceEngineNapi::StopCapturer(napi_env env, napi_callback_info info)
671 {
672 INTELL_VOICE_LOG_INFO("enter");
673 size_t cbIndex = ARG_INDEX_0;
674 shared_ptr<AsyncContext> context = make_shared<AsyncContext>(env);
675 if (context == nullptr) {
676 INTELL_VOICE_LOG_ERROR("create AsyncContext failed, No memory");
677 return nullptr;
678 }
679
680 context->result_ = (context->GetCbInfo(env, info, cbIndex, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
681 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
682
683 AsyncExecute execute;
684 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
685 execute = [](napi_env env, void *data) {
686 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
687 auto asyncContext = static_cast<AsyncContext *>(data);
688 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
689 CHECK_CONDITION_RETURN_VOID((engine == nullptr), "get engine instance failed");
690 engine->StopCapturer();
691 };
692 } else {
693 execute = [](napi_env env, void *data) {};
694 }
695
696 return NapiAsync::AsyncWork(env, context, "StopCapturer", execute);
697 }
698
GetPcm(napi_env env,napi_callback_info info)699 napi_value WakeupIntellVoiceEngineNapi::GetPcm(napi_env env, napi_callback_info info)
700 {
701 INTELL_VOICE_LOG_INFO("enter");
702 napi_value undefined = nullptr;
703 napi_get_undefined(env, &undefined);
704
705 class GetPcmContext : public AsyncContext {
706 public:
707 explicit GetPcmContext(napi_env env) : AsyncContext(env) {};
708 std::vector<uint8_t> data;
709 };
710
711 auto context = make_shared<GetPcmContext>(env);
712 CHECK_CONDITION_RETURN_RET(context == nullptr, undefined, "create context fail");
713
714 context->result_ = (context->GetCbInfo(env, info, 0, nullptr) ? NAPI_INTELLIGENT_VOICE_SUCCESS :
715 NAPI_INTELLIGENT_VOICE_INVALID_PARAM);
716
717 AsyncExecute execute;
718 if (context->result_ == NAPI_INTELLIGENT_VOICE_SUCCESS) {
719 execute = [](napi_env env, void *data) {
720 CHECK_CONDITION_RETURN_VOID((data == nullptr), "data is nullptr");
721 auto asyncContext = static_cast<GetPcmContext *>(data);
722 auto engine = reinterpret_cast<WakeupIntellVoiceEngineNapi *>(asyncContext->instanceNapi_)->engine_;
723 if (engine == nullptr) {
724 INTELL_VOICE_LOG_ERROR("get engine instance failed");
725 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_NO_MEMORY;
726 return;
727 }
728 if (engine->GetWakeupPcm(asyncContext->data) != 0) {
729 INTELL_VOICE_LOG_ERROR("failed to get wakeup pcm");
730 asyncContext->result_ = NAPI_INTELLIGENT_VOICE_SYSTEM_ERROR;
731 }
732 };
733 } else {
734 execute = [](napi_env env, void *data) {};
735 }
736
737 context->complete_ = [](napi_env env, AsyncContext *asyncContext, napi_value &result) {
738 CHECK_CONDITION_RETURN_VOID((asyncContext == nullptr), "async context is null");
739 auto context = static_cast<GetPcmContext *>(asyncContext);
740 result = SetValue(env, context->data);
741 vector<uint8_t>().swap(context->data);
742 };
743
744 return NapiAsync::AsyncWork(env, context, "GetPcm", execute);
745 }
746
747 } // namespace IntellVoiceNapi
748 } // namespace OHOS
749