1 /*
2  * Copyright (c) 2021-2022 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 "output/metadata_output_napi.h"
17 
18 #include <uv.h>
19 
20 #include "camera_log.h"
21 #include "camera_napi_metadata_utils.h"
22 #include "camera_napi_object_types.h"
23 #include "camera_napi_param_parser.h"
24 #include "camera_napi_template_utils.h"
25 #include "camera_napi_utils.h"
26 #include "camera_napi_worker_queue_keeper.h"
27 #include "camera_security_utils.h"
28 #include "hilog/log.h"
29 #include "napi/native_api.h"
30 #include "napi/native_common.h"
31 
32 namespace OHOS {
33 namespace CameraStandard {
34 thread_local uint32_t MetadataOutputNapi::metadataOutputTaskId = CAMERA_METADATA_OUTPUT_TASKID;
35 namespace {
AsyncCompleteCallback(napi_env env,napi_status status,void * data)36 void AsyncCompleteCallback(napi_env env, napi_status status, void* data)
37 {
38     auto context = static_cast<MetadataOutputAsyncContext*>(data);
39     CHECK_ERROR_RETURN_LOG(context == nullptr, "MetadataOutputNapi AsyncCompleteCallback context is null");
40     MEDIA_INFO_LOG("MetadataOutputNapi AsyncCompleteCallback %{public}s, status = %{public}d",
41         context->funcName.c_str(), context->status);
42     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
43     jsContext->status = context->status;
44     if (!context->status) {
45         CameraNapiUtils::CreateNapiErrorObject(
46             env, context->errorCode, "No Metadata object Types or create array failed!", jsContext);
47     } else {
48         napi_get_undefined(env, &jsContext->data);
49     }
50     if (!context->funcName.empty() && context->taskId > 0) {
51         // Finish async trace
52         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
53         jsContext->funcName = context->funcName;
54     }
55     if (context->work != nullptr) {
56         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, context->work, *jsContext);
57     }
58     context->FreeHeldNapiValue(env);
59     delete context;
60 }
61 } // namespace
62 
63 thread_local napi_ref MetadataOutputNapi::sConstructor_ = nullptr;
64 thread_local sptr<MetadataOutput> MetadataOutputNapi::sMetadataOutput_ = nullptr;
65 
MetadataOutputCallback(napi_env env)66 MetadataOutputCallback::MetadataOutputCallback(napi_env env) : ListenerBase(env) {}
67 
OnMetadataObjectsAvailable(const std::vector<sptr<MetadataObject>> metadataObjList) const68 void MetadataOutputCallback::OnMetadataObjectsAvailable(const std::vector<sptr<MetadataObject>> metadataObjList) const
69 {
70     MEDIA_DEBUG_LOG("OnMetadataObjectsAvailable is called");
71     uv_loop_s* loop = nullptr;
72     napi_get_uv_event_loop(env_, &loop);
73     if (!loop) {
74         MEDIA_ERR_LOG("failed to get event loop");
75         return;
76     }
77     uv_work_t* work = new(std::nothrow) uv_work_t;
78     if (!work) {
79         MEDIA_ERR_LOG("failed to allocate work");
80         return;
81     }
82     std::unique_ptr<MetadataOutputCallbackInfo> callbackInfo =
83         std::make_unique<MetadataOutputCallbackInfo>(metadataObjList, shared_from_this());
84     work->data = reinterpret_cast<void *>(callbackInfo.get());
85     int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
86         MetadataOutputCallbackInfo* callbackInfo = reinterpret_cast<MetadataOutputCallbackInfo *>(work->data);
87         if (callbackInfo) {
88             auto listener = callbackInfo->listener_.lock();
89             if (listener) {
90                 listener->OnMetadataObjectsAvailableCallback(callbackInfo->info_);
91             }
92             delete callbackInfo;
93         }
94         delete work;
95     }, uv_qos_user_initiated);
96     if (ret) {
97         MEDIA_ERR_LOG("failed to execute work");
98         delete work;
99     }  else {
100         callbackInfo.release();
101     }
102 }
103 
CreateMetadataObjJSArray(napi_env env,const std::vector<sptr<MetadataObject>> metadataObjList) const104 napi_value MetadataOutputCallback::CreateMetadataObjJSArray(napi_env env,
105     const std::vector<sptr<MetadataObject>> metadataObjList) const
106 {
107     napi_value metadataObjArray = nullptr;
108     napi_value metadataObj = nullptr;
109     napi_status status;
110 
111     if (metadataObjList.empty()) {
112         MEDIA_ERR_LOG("CreateMetadataObjJSArray: metadataObjList is empty");
113     }
114 
115     status = napi_create_array(env, &metadataObjArray);
116     if (status != napi_ok) {
117         MEDIA_ERR_LOG("CreateMetadataObjJSArray: napi_create_array failed");
118         return metadataObjArray;
119     }
120 
121     size_t j = 0;
122     bool isSystemApp = CameraSecurity::CheckSystemApp();
123     for (size_t i = 0; i < metadataObjList.size(); i++) {
124         metadataObj = CameraNapiObjMetadataObject(*metadataObjList[i]).GenerateNapiValue(env);
125         if (isSystemApp) {
126             AddMetadataObjExtending(env, metadataObjList[i], metadataObj);
127         }
128         if ((metadataObj == nullptr) || napi_set_element(env, metadataObjArray, j++, metadataObj) != napi_ok) {
129             MEDIA_ERR_LOG("CreateMetadataObjJSArray: Failed to create metadata face object napi wrapper object");
130             return nullptr;
131         }
132     }
133     return metadataObjArray;
134 }
135 
AddMetadataObjExtending(napi_env env,sptr<MetadataObject> metadataObj,napi_value & metadataNapiObj) const136 void MetadataOutputCallback::AddMetadataObjExtending(napi_env env, sptr<MetadataObject> metadataObj,
137     napi_value &metadataNapiObj) const
138 {
139     if (metadataObj == nullptr) {
140         MEDIA_DEBUG_LOG("AddMetadataObjExtending got null metadataObj");
141         return;
142     }
143     auto type = metadataObj->GetType();
144     switch (type) {
145         case MetadataObjectType::FACE:
146             CreateHumanFaceMetaData(env, metadataObj, metadataNapiObj);
147             break;
148         case MetadataObjectType::CAT_FACE:
149             CreateCatFaceMetaData(env, metadataObj, metadataNapiObj);
150             break;
151         case MetadataObjectType::DOG_FACE:
152             CreateDogFaceMetaData(env, metadataObj, metadataNapiObj);
153             break;
154         default:
155             return;
156     }
157 }
158 
CreateHumanFaceMetaData(napi_env env,sptr<MetadataObject> metadataObj,napi_value & metadataNapiObj) const159 void MetadataOutputCallback::CreateHumanFaceMetaData(napi_env env, sptr<MetadataObject> metadataObj,
160     napi_value &metadataNapiObj) const
161 {
162     napi_value metadataObjResult = nullptr;
163     napi_value numberNapiObj = nullptr;
164 
165     napi_get_undefined(env, &metadataObjResult);
166     if (metadataObj == nullptr && metadataNapiObj == nullptr) {
167         return;
168     }
169     MetadataFaceObject* faceObjectPtr = static_cast<MetadataFaceObject*>(metadataObj.GetRefPtr());
170     Rect boundingBox = faceObjectPtr->GetLeftEyeBoundingBox();
171     metadataObjResult = CameraNapiBoundingBox(boundingBox).GenerateNapiValue(env);
172     napi_set_named_property(env, metadataNapiObj, "leftEyeBoundingBox", metadataObjResult);
173     boundingBox = faceObjectPtr->GetRightEyeBoundingBox();
174     metadataObjResult = CameraNapiBoundingBox(boundingBox).GenerateNapiValue(env);
175     napi_set_named_property(env, metadataNapiObj, "rightEyeBoundingBox", metadataObjResult);
176 
177     napi_create_int32(env, faceObjectPtr->GetEmotion(), &numberNapiObj);
178     napi_set_named_property(env, metadataNapiObj, "emotion", numberNapiObj);
179     napi_create_int32(env, faceObjectPtr->GetEmotionConfidence(), &numberNapiObj);
180     napi_set_named_property(env, metadataNapiObj, "emotionConfidence", numberNapiObj);
181     napi_create_int32(env, faceObjectPtr->GetPitchAngle(), &numberNapiObj);
182     napi_set_named_property(env, metadataNapiObj, "pitchAngle", numberNapiObj);
183     napi_create_int32(env, faceObjectPtr->GetYawAngle(), &numberNapiObj);
184     napi_set_named_property(env, metadataNapiObj, "yawAngle", numberNapiObj);
185     napi_create_int32(env, faceObjectPtr->GetRollAngle(), &numberNapiObj);
186     napi_set_named_property(env, metadataNapiObj, "rollAngle", numberNapiObj);
187 }
188 
CreateCatFaceMetaData(napi_env env,sptr<MetadataObject> metadataObj,napi_value & metadataNapiObj) const189 void MetadataOutputCallback::CreateCatFaceMetaData(napi_env env, sptr<MetadataObject> metadataObj,
190     napi_value &metadataNapiObj) const
191 {
192     napi_value metadataObjResult = nullptr;
193 
194     napi_get_undefined(env, &metadataObjResult);
195     if (metadataObj == nullptr && metadataNapiObj == nullptr) {
196         return;
197     }
198     MetadataCatFaceObject* faceObjectPtr = static_cast<MetadataCatFaceObject*>(metadataObj.GetRefPtr());
199     Rect boundingBox = faceObjectPtr->GetLeftEyeBoundingBox();
200     metadataObjResult = CameraNapiBoundingBox(boundingBox).GenerateNapiValue(env);
201     napi_set_named_property(env, metadataNapiObj, "leftEyeBoundingBox", metadataObjResult);
202     boundingBox = faceObjectPtr->GetRightEyeBoundingBox();
203     metadataObjResult = CameraNapiBoundingBox(boundingBox).GenerateNapiValue(env);
204     napi_set_named_property(env, metadataNapiObj, "rightEyeBoundingBox", metadataObjResult);
205 }
206 
CreateDogFaceMetaData(napi_env env,sptr<MetadataObject> metadataObj,napi_value & metadataNapiObj) const207 void MetadataOutputCallback::CreateDogFaceMetaData(napi_env env, sptr<MetadataObject> metadataObj,
208     napi_value &metadataNapiObj) const
209 {
210     napi_value metadataObjResult = nullptr;
211 
212     napi_get_undefined(env, &metadataObjResult);
213     if (metadataObj == nullptr && metadataNapiObj == nullptr) {
214         return;
215     }
216     MetadataDogFaceObject* faceObjectPtr = static_cast<MetadataDogFaceObject*>(metadataObj.GetRefPtr());
217     Rect boundingBox = faceObjectPtr->GetLeftEyeBoundingBox();
218     metadataObjResult = CameraNapiBoundingBox(boundingBox).GenerateNapiValue(env);
219     napi_set_named_property(env, metadataNapiObj, "leftEyeBoundingBox", metadataObjResult);
220     boundingBox = faceObjectPtr->GetRightEyeBoundingBox();
221     metadataObjResult = CameraNapiBoundingBox(boundingBox).GenerateNapiValue(env);
222     napi_set_named_property(env, metadataNapiObj, "rightEyeBoundingBox", metadataObjResult);
223 }
224 
OnMetadataObjectsAvailableCallback(const std::vector<sptr<MetadataObject>> metadataObjList) const225 void MetadataOutputCallback::OnMetadataObjectsAvailableCallback(
226     const std::vector<sptr<MetadataObject>> metadataObjList) const
227 {
228     napi_value result[ARGS_TWO];
229     napi_value retVal;
230 
231     napi_get_undefined(env_, &result[PARAM0]);
232     napi_get_undefined(env_, &result[PARAM1]);
233     result[PARAM1] = CreateMetadataObjJSArray(env_, metadataObjList);
234     MEDIA_INFO_LOG("OnMetadataObjectsAvailableCallback metadataObjList size = %{public}zu", metadataObjList.size());
235     if (result[PARAM1] == nullptr) {
236         MEDIA_ERR_LOG("invoke CreateMetadataObjJSArray failed");
237         return;
238     }
239 
240     ExecuteCallbackNapiPara callbackNapiPara { .recv = nullptr, .argc = ARGS_TWO, .argv = result, .result = &retVal };
241     ExecuteCallback("metadataObjectsAvailable", callbackNapiPara);
242 }
243 
MetadataStateCallbackNapi(napi_env env)244 MetadataStateCallbackNapi::MetadataStateCallbackNapi(napi_env env) : ListenerBase(env) {}
245 
OnErrorCallbackAsync(const int32_t errorType) const246 void MetadataStateCallbackNapi::OnErrorCallbackAsync(const int32_t errorType) const
247 {
248     MEDIA_DEBUG_LOG("OnErrorCallbackAsync is called");
249     uv_loop_s* loop = nullptr;
250     napi_get_uv_event_loop(env_, &loop);
251     if (!loop) {
252         MEDIA_ERR_LOG("failed to get event loop");
253         return;
254     }
255     uv_work_t* work = new(std::nothrow) uv_work_t;
256     if (!work) {
257         MEDIA_ERR_LOG("failed to allocate work");
258         return;
259     }
260     std::unique_ptr<MetadataStateCallbackInfo> callbackInfo =
261         std::make_unique<MetadataStateCallbackInfo>(errorType, shared_from_this());
262     work->data = callbackInfo.get();
263     int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
264         MetadataStateCallbackInfo* callbackInfo = reinterpret_cast<MetadataStateCallbackInfo *>(work->data);
265         if (callbackInfo) {
266             auto listener = callbackInfo->listener_.lock();
267             if (listener) {
268                 listener->OnErrorCallback(callbackInfo->errorType_);
269             }
270             delete callbackInfo;
271         }
272         delete work;
273     }, uv_qos_user_initiated);
274     if (ret) {
275         MEDIA_ERR_LOG("failed to execute work");
276         delete work;
277     } else {
278         callbackInfo.release();
279     }
280 }
281 
OnErrorCallback(const int32_t errorType) const282 void MetadataStateCallbackNapi::OnErrorCallback(const int32_t errorType) const
283 {
284     MEDIA_DEBUG_LOG("OnErrorCallback is called");
285     napi_value result;
286     napi_value retVal;
287     napi_value propValue;
288 
289     napi_create_int32(env_, errorType, &propValue);
290     napi_create_object(env_, &result);
291     napi_set_named_property(env_, result, "code", propValue);
292     ExecuteCallbackNapiPara callbackNapiPara { .recv = nullptr, .argc = ARGS_ONE, .argv = &result, .result = &retVal };
293     ExecuteCallback("error", callbackNapiPara);
294 }
295 
OnError(const int32_t errorType) const296 void MetadataStateCallbackNapi::OnError(const int32_t errorType) const
297 {
298     MEDIA_DEBUG_LOG("OnError is called!, errorType: %{public}d", errorType);
299     OnErrorCallbackAsync(errorType);
300 }
301 
MetadataOutputNapi()302 MetadataOutputNapi::MetadataOutputNapi() : env_(nullptr) {}
303 
~MetadataOutputNapi()304 MetadataOutputNapi::~MetadataOutputNapi()
305 {
306     MEDIA_DEBUG_LOG("~MetadataOutputNapi is called");
307 }
308 
MetadataOutputNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)309 void MetadataOutputNapi::MetadataOutputNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
310 {
311     MEDIA_DEBUG_LOG("MetadataOutputNapiDestructor is called");
312     MetadataOutputNapi* metadataOutput = reinterpret_cast<MetadataOutputNapi*>(nativeObject);
313     if (metadataOutput != nullptr) {
314         delete metadataOutput;
315     }
316 }
317 
Init(napi_env env,napi_value exports)318 napi_value MetadataOutputNapi::Init(napi_env env, napi_value exports)
319 {
320     MEDIA_DEBUG_LOG("Init is called");
321     napi_status status;
322     napi_value ctorObj;
323     int32_t refCount = 1;
324 
325     napi_property_descriptor metadata_output_props[] = {
326         DECLARE_NAPI_FUNCTION("addMetadataObjectTypes", AddMetadataObjectTypes),
327         DECLARE_NAPI_FUNCTION("removeMetadataObjectTypes", RemoveMetadataObjectTypes),
328         DECLARE_NAPI_FUNCTION("start", Start),
329         DECLARE_NAPI_FUNCTION("stop", Stop),
330         DECLARE_NAPI_FUNCTION("release", Release),
331         DECLARE_NAPI_FUNCTION("on", On),
332         DECLARE_NAPI_FUNCTION("once", Once),
333         DECLARE_NAPI_FUNCTION("off", Off)
334     };
335 
336     status = napi_define_class(env, CAMERA_METADATA_OUTPUT_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
337                                MetadataOutputNapiConstructor, nullptr,
338                                sizeof(metadata_output_props) / sizeof(metadata_output_props[PARAM0]),
339                                metadata_output_props, &ctorObj);
340     if (status == napi_ok) {
341         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
342         if (status == napi_ok) {
343             status = napi_set_named_property(env, exports, CAMERA_METADATA_OUTPUT_NAPI_CLASS_NAME, ctorObj);
344             if (status == napi_ok) {
345                 return exports;
346             }
347         }
348     }
349     MEDIA_ERR_LOG("Init call Failed!");
350     return nullptr;
351 }
352 
MetadataOutputNapiConstructor(napi_env env,napi_callback_info info)353 napi_value MetadataOutputNapi::MetadataOutputNapiConstructor(napi_env env, napi_callback_info info)
354 {
355     MEDIA_DEBUG_LOG("MetadataOutputNapiConstructor is called");
356     napi_status status;
357     napi_value result = nullptr;
358     napi_value thisVar = nullptr;
359 
360     napi_get_undefined(env, &result);
361     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
362 
363     if (status == napi_ok && thisVar != nullptr) {
364         std::unique_ptr<MetadataOutputNapi> obj = std::make_unique<MetadataOutputNapi>();
365         obj->env_ = env;
366         obj->metadataOutput_ = sMetadataOutput_;
367         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
368                            MetadataOutputNapi::MetadataOutputNapiDestructor, nullptr, nullptr);
369         if (status == napi_ok) {
370             obj.release();
371             return thisVar;
372         } else {
373             MEDIA_ERR_LOG("Failure wrapping js to native napi");
374         }
375     }
376     MEDIA_ERR_LOG("MetadataOutputNapiConstructor call Failed!");
377     return result;
378 }
379 
IsMetadataOutput(napi_env env,napi_value obj)380 bool MetadataOutputNapi::IsMetadataOutput(napi_env env, napi_value obj)
381 {
382     MEDIA_DEBUG_LOG("IsMetadataOutput is called");
383     bool result = false;
384     napi_status status;
385     napi_value constructor = nullptr;
386 
387     status = napi_get_reference_value(env, sConstructor_, &constructor);
388     if (status == napi_ok) {
389         status = napi_instanceof(env, obj, constructor, &result);
390         if (status != napi_ok) {
391             result = false;
392         }
393     }
394     MEDIA_INFO_LOG("IsMetadataOutput(%{public}d)", result);
395     return result;
396 }
397 
GetMetadataOutput()398 sptr<MetadataOutput> MetadataOutputNapi::GetMetadataOutput()
399 {
400     return metadataOutput_;
401 }
402 
CreateMetadataOutput(napi_env env,std::vector<MetadataObjectType> metadataObjectTypes)403 napi_value MetadataOutputNapi::CreateMetadataOutput(napi_env env, std::vector<MetadataObjectType> metadataObjectTypes)
404 {
405     MEDIA_DEBUG_LOG("CreateMetadataOutput is called");
406     CAMERA_SYNC_TRACE;
407     napi_status status;
408     napi_value result = nullptr;
409     napi_value constructor;
410 
411     status = napi_get_reference_value(env, sConstructor_, &constructor);
412     if (status == napi_ok) {
413         int retCode = CameraManager::GetInstance()->CreateMetadataOutput(sMetadataOutput_, metadataObjectTypes);
414         if (!CameraNapiUtils::CheckError(env, retCode)) {
415             return nullptr;
416         }
417         if (sMetadataOutput_ == nullptr) {
418             MEDIA_ERR_LOG("failed to create MetadataOutput");
419             return result;
420         }
421         status = napi_new_instance(env, constructor, 0, nullptr, &result);
422         sMetadataOutput_ = nullptr;
423         if (status == napi_ok && result != nullptr) {
424             return result;
425         } else {
426             MEDIA_ERR_LOG("Failed to create metadata output instance");
427         }
428     }
429     MEDIA_ERR_LOG("CreateMetadataOutput call Failed!");
430     napi_get_undefined(env, &result);
431     return result;
432 }
433 
AddMetadataObjectTypes(napi_env env,napi_callback_info info)434 napi_value MetadataOutputNapi::AddMetadataObjectTypes(napi_env env, napi_callback_info info)
435 {
436     MEDIA_INFO_LOG("AddMetadataObjectTypes is called");
437     napi_status status;
438     napi_value result = nullptr;
439     size_t argc = ARGS_ONE;
440     napi_value argv[ARGS_ONE] = {0};
441     napi_value thisVar = nullptr;
442 
443     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
444     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
445 
446     napi_get_undefined(env, &result);
447     MetadataOutputNapi* metadataOutputNapi = nullptr;
448     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&metadataOutputNapi));
449     if (status != napi_ok || metadataOutputNapi == nullptr) {
450         MEDIA_ERR_LOG("napi_unwrap failure!");
451         return result;
452     }
453     std::vector<MetadataObjectType> metadataObjectType;
454     CameraNapiUtils::ParseMetadataObjectTypes(env, argv[PARAM0], metadataObjectType);
455     int32_t retCode = metadataOutputNapi->metadataOutput_->AddMetadataObjectTypes(metadataObjectType);
456     if (!CameraNapiUtils::CheckError(env, retCode)) {
457         MEDIA_ERR_LOG("AddMetadataObjectTypes failure!");
458     }
459     return result;
460 }
461 
RemoveMetadataObjectTypes(napi_env env,napi_callback_info info)462 napi_value MetadataOutputNapi::RemoveMetadataObjectTypes(napi_env env, napi_callback_info info)
463 {
464     MEDIA_INFO_LOG("RemoveMetadataObjectTypes is called");
465     napi_status status;
466     napi_value result = nullptr;
467     size_t argc = ARGS_ONE;
468     napi_value argv[ARGS_ONE] = {0};
469     napi_value thisVar = nullptr;
470 
471     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
472     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
473 
474     napi_get_undefined(env, &result);
475     MetadataOutputNapi* metadataOutputNapi = nullptr;
476     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&metadataOutputNapi));
477     if (status != napi_ok || metadataOutputNapi == nullptr) {
478         MEDIA_ERR_LOG("napi_unwrap failure!");
479         return result;
480     }
481     std::vector<MetadataObjectType> metadataObjectType;
482     CameraNapiUtils::ParseMetadataObjectTypes(env, argv[PARAM0], metadataObjectType);
483     int32_t retCode = metadataOutputNapi->metadataOutput_->RemoveMetadataObjectTypes(metadataObjectType);
484     if (!CameraNapiUtils::CheckError(env, retCode)) {
485         MEDIA_ERR_LOG("RemoveMetadataObjectTypes failure!");
486     }
487     return result;
488 }
489 
Start(napi_env env,napi_callback_info info)490 napi_value MetadataOutputNapi::Start(napi_env env, napi_callback_info info)
491 {
492     MEDIA_INFO_LOG("Start is called");
493     std::unique_ptr<MetadataOutputAsyncContext> asyncContext = std::make_unique<MetadataOutputAsyncContext>(
494         "MetadataOutputNapi::Start", CameraNapiUtils::IncrementAndGet(metadataOutputTaskId));
495     auto asyncFunction =
496         std::make_shared<CameraNapiAsyncFunction>(env, "Start", asyncContext->callbackRef, asyncContext->deferred);
497     CameraNapiParamParser jsParamParser(env, info, asyncContext->objectInfo, asyncFunction);
498     if (!jsParamParser.AssertStatus(INVALID_ARGUMENT, "invalid argument")) {
499         MEDIA_ERR_LOG("MetadataOutputNapi::Start invalid argument");
500         return nullptr;
501     }
502     asyncContext->HoldNapiValue(env, jsParamParser.GetThisVar());
503     napi_status status = napi_create_async_work(
504         env, nullptr, asyncFunction->GetResourceName(),
505         [](napi_env env, void* data) {
506             MEDIA_INFO_LOG("MetadataOutputNapi::Start running on worker");
507             auto context = static_cast<MetadataOutputAsyncContext*>(data);
508             CHECK_ERROR_RETURN_LOG(context->objectInfo == nullptr, "MetadataOutputNapi::Start async info is nullptr");
509             CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
510             CameraNapiWorkerQueueKeeper::GetInstance()->ConsumeWorkerQueueTask(context->queueTask, [&context]() {
511                 context->errorCode = context->objectInfo->metadataOutput_->Start();
512                 context->status = context->errorCode == CameraErrorCode::SUCCESS;
513                 MEDIA_INFO_LOG("MetadataOutputNapi::Start errorCode:%{public}d", context->errorCode);
514             });
515         },
516         AsyncCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
517     if (status != napi_ok) {
518         MEDIA_ERR_LOG("Failed to create napi_create_async_work for MetadataOutputNapi::Start");
519         asyncFunction->Reset();
520     } else {
521         asyncContext->queueTask =
522             CameraNapiWorkerQueueKeeper::GetInstance()->AcquireWorkerQueueTask("MetadataOutputNapi::Start");
523         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
524         asyncContext.release();
525     }
526     if (asyncFunction->GetAsyncFunctionType() == ASYNC_FUN_TYPE_PROMISE) {
527         return asyncFunction->GetPromise();
528     }
529     return CameraNapiUtils::GetUndefinedValue(env);
530 }
531 
Stop(napi_env env,napi_callback_info info)532 napi_value MetadataOutputNapi::Stop(napi_env env, napi_callback_info info)
533 {
534     MEDIA_INFO_LOG("Stop is called");
535     std::unique_ptr<MetadataOutputAsyncContext> asyncContext = std::make_unique<MetadataOutputAsyncContext>(
536         "MetadataOutputNapi::Stop", CameraNapiUtils::IncrementAndGet(metadataOutputTaskId));
537     auto asyncFunction =
538         std::make_shared<CameraNapiAsyncFunction>(env, "Stop", asyncContext->callbackRef, asyncContext->deferred);
539     CameraNapiParamParser jsParamParser(env, info, asyncContext->objectInfo, asyncFunction);
540     if (!jsParamParser.AssertStatus(INVALID_ARGUMENT, "invalid argument")) {
541         MEDIA_ERR_LOG("MetadataOutputNapi::Stop invalid argument");
542         return nullptr;
543     }
544     asyncContext->HoldNapiValue(env, jsParamParser.GetThisVar());
545     napi_status status = napi_create_async_work(
546         env, nullptr, asyncFunction->GetResourceName(),
547         [](napi_env env, void* data) {
548             MEDIA_INFO_LOG("MetadataOutputNapi::Stop running on worker");
549             auto context = static_cast<MetadataOutputAsyncContext*>(data);
550             CHECK_ERROR_RETURN_LOG(context->objectInfo == nullptr, "MetadataOutputNapi::Stop async info is nullptr");
551             CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
552             CameraNapiWorkerQueueKeeper::GetInstance()->ConsumeWorkerQueueTask(context->queueTask, [&context]() {
553                 context->errorCode = context->objectInfo->metadataOutput_->Stop();
554                 // Always true, ignore error code
555                 context->status = true;
556                 MEDIA_INFO_LOG("MetadataOutputNapi::Stop errorCode:%{public}d", context->errorCode);
557             });
558         },
559         AsyncCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
560     if (status != napi_ok) {
561         MEDIA_ERR_LOG("Failed to create napi_create_async_work for MetadataOutputNapi::Stop");
562         asyncFunction->Reset();
563     } else {
564         asyncContext->queueTask =
565             CameraNapiWorkerQueueKeeper::GetInstance()->AcquireWorkerQueueTask("MetadataOutputNapi::Stop");
566         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
567         asyncContext.release();
568     }
569     if (asyncFunction->GetAsyncFunctionType() == ASYNC_FUN_TYPE_PROMISE) {
570         return asyncFunction->GetPromise();
571     }
572     return CameraNapiUtils::GetUndefinedValue(env);
573 }
574 
Release(napi_env env,napi_callback_info info)575 napi_value MetadataOutputNapi::Release(napi_env env, napi_callback_info info)
576 {
577     MEDIA_INFO_LOG("MetadataOutputNapi::Release is called");
578     std::unique_ptr<MetadataOutputAsyncContext> asyncContext = std::make_unique<MetadataOutputAsyncContext>(
579         "MetadataOutputNapi::Release", CameraNapiUtils::IncrementAndGet(metadataOutputTaskId));
580     auto asyncFunction =
581         std::make_shared<CameraNapiAsyncFunction>(env, "Release", asyncContext->callbackRef, asyncContext->deferred);
582     CameraNapiParamParser jsParamParser(env, info, asyncContext->objectInfo, asyncFunction);
583     if (!jsParamParser.AssertStatus(INVALID_ARGUMENT, "invalid argument")) {
584         MEDIA_ERR_LOG("MetadataOutputNapi::Release invalid argument");
585         return nullptr;
586     }
587     asyncContext->HoldNapiValue(env, jsParamParser.GetThisVar());
588     napi_status status = napi_create_async_work(
589         env, nullptr, asyncFunction->GetResourceName(),
590         [](napi_env env, void* data) {
591             MEDIA_INFO_LOG("MetadataOutputNapi::Release running on worker");
592             auto context = static_cast<MetadataOutputAsyncContext*>(data);
593             CHECK_ERROR_RETURN_LOG(context->objectInfo == nullptr, "MetadataOutputNapi::Release async info is nullptr");
594             CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
595             CameraNapiWorkerQueueKeeper::GetInstance()->ConsumeWorkerQueueTask(context->queueTask, [&context]() {
596                 context->errorCode = context->objectInfo->metadataOutput_->Release();
597                 context->status = context->errorCode == CameraErrorCode::SUCCESS;
598             });
599         },
600         AsyncCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
601     if (status != napi_ok) {
602         MEDIA_ERR_LOG("Failed to create napi_create_async_work for MetadataOutputNapi::Release");
603         asyncFunction->Reset();
604     } else {
605         asyncContext->queueTask =
606             CameraNapiWorkerQueueKeeper::GetInstance()->AcquireWorkerQueueTask("MetadataOutputNapi::Release");
607         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
608         asyncContext.release();
609     }
610     if (asyncFunction->GetAsyncFunctionType() == ASYNC_FUN_TYPE_PROMISE) {
611         return asyncFunction->GetPromise();
612     }
613     return CameraNapiUtils::GetUndefinedValue(env);
614 }
615 
RegisterMetadataObjectsAvailableCallbackListener(const std::string & eventName,napi_env env,napi_value callback,const std::vector<napi_value> & args,bool isOnce)616 void MetadataOutputNapi::RegisterMetadataObjectsAvailableCallbackListener(
617     const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args, bool isOnce)
618 {
619     if (metadataOutputCallback_ == nullptr) {
620         metadataOutputCallback_ = make_shared<MetadataOutputCallback>(env);
621         metadataOutput_->SetCallback(metadataOutputCallback_);
622     }
623     metadataOutputCallback_->SaveCallbackReference(eventName, callback, isOnce);
624 }
625 
UnregisterMetadataObjectsAvailableCallbackListener(const std::string & eventName,napi_env env,napi_value callback,const std::vector<napi_value> & args)626 void MetadataOutputNapi::UnregisterMetadataObjectsAvailableCallbackListener(
627     const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args)
628 {
629     if (metadataOutputCallback_ == nullptr) {
630         MEDIA_ERR_LOG("metadataOutputCallback is null");
631     } else {
632         metadataOutputCallback_->RemoveCallbackRef(eventName, callback);
633     }
634 }
635 
RegisterErrorCallbackListener(const std::string & eventName,napi_env env,napi_value callback,const std::vector<napi_value> & args,bool isOnce)636 void MetadataOutputNapi::RegisterErrorCallbackListener(
637     const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args, bool isOnce)
638 {
639     if (metadataStateCallback_ == nullptr) {
640         metadataStateCallback_ = make_shared<MetadataStateCallbackNapi>(env);
641         metadataOutput_->SetCallback(metadataStateCallback_);
642     }
643     metadataStateCallback_->SaveCallbackReference(eventName, callback, isOnce);
644 }
645 
UnregisterErrorCallbackListener(const std::string & eventName,napi_env env,napi_value callback,const std::vector<napi_value> & args)646 void MetadataOutputNapi::UnregisterErrorCallbackListener(
647     const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args)
648 {
649     if (metadataStateCallback_ == nullptr) {
650         MEDIA_ERR_LOG("metadataStateCallback is null");
651     } else {
652         metadataStateCallback_->RemoveCallbackRef(eventName, callback);
653     }
654 }
655 
GetEmitterFunctions()656 const MetadataOutputNapi::EmitterFunctions& MetadataOutputNapi::GetEmitterFunctions()
657 {
658     const static EmitterFunctions funMap = {
659         { "metadataObjectsAvailable", {
660             &MetadataOutputNapi::RegisterMetadataObjectsAvailableCallbackListener,
661             &MetadataOutputNapi::UnregisterMetadataObjectsAvailableCallbackListener } },
662         { "error", {
663             &MetadataOutputNapi::RegisterErrorCallbackListener,
664             &MetadataOutputNapi::UnregisterErrorCallbackListener } } };
665     return funMap;
666 }
667 
On(napi_env env,napi_callback_info info)668 napi_value MetadataOutputNapi::On(napi_env env, napi_callback_info info)
669 {
670     return ListenerTemplate<MetadataOutputNapi>::On(env, info);
671 }
672 
Once(napi_env env,napi_callback_info info)673 napi_value MetadataOutputNapi::Once(napi_env env, napi_callback_info info)
674 {
675     return ListenerTemplate<MetadataOutputNapi>::Once(env, info);
676 }
677 
Off(napi_env env,napi_callback_info info)678 napi_value MetadataOutputNapi::Off(napi_env env, napi_callback_info info)
679 {
680     return ListenerTemplate<MetadataOutputNapi>::Off(env, info);
681 }
682 } // namespace CameraStandard
683 } // namespace OHOS