• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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