• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/video_output_napi.h"
17 #include <uv.h>
18 #include "hilog/log.h"
19 
20 namespace OHOS {
21 namespace CameraStandard {
22 using OHOS::HiviewDFX::HiLog;
23 using OHOS::HiviewDFX::HiLogLabel;
24 
25 namespace {
26     constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "VideoOutputNapi"};
27 }
28 
29 thread_local napi_ref VideoOutputNapi::sConstructor_ = nullptr;
30 thread_local sptr<VideoOutput> VideoOutputNapi::sVideoOutput_ = nullptr;
31 thread_local uint32_t VideoOutputNapi::videoOutputTaskId = CAMERA_VIDEO_OUTPUT_TASKID;
32 
VideoCallbackListener(napi_env env)33 VideoCallbackListener::VideoCallbackListener(napi_env env) : env_(env) {}
34 
UpdateJSCallbackAsync(std::string propName,const int32_t value) const35 void VideoCallbackListener::UpdateJSCallbackAsync(std::string propName, const int32_t value) const
36 {
37     uv_loop_s* loop = nullptr;
38     napi_get_uv_event_loop(env_, &loop);
39     if (!loop) {
40         MEDIA_ERR_LOG("VideoCallbackListener:UpdateJSCallbackAsync() failed to get event loop");
41         return;
42     }
43     uv_work_t* work = new(std::nothrow) uv_work_t;
44     if (!work) {
45         MEDIA_ERR_LOG("VideoCallbackListener:UpdateJSCallbackAsync() failed to allocate work");
46         return;
47     }
48     std::unique_ptr<VideoOutputCallbackInfo> callbackInfo =
49         std::make_unique<VideoOutputCallbackInfo>(propName, value, this);
50     work->data = callbackInfo.get();
51     int ret = uv_queue_work(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
52         VideoOutputCallbackInfo* callbackInfo = reinterpret_cast<VideoOutputCallbackInfo *>(work->data);
53         if (callbackInfo) {
54             callbackInfo->listener_->UpdateJSCallback(callbackInfo->eventName_, callbackInfo->value_);
55             delete callbackInfo;
56         }
57         delete work;
58     });
59     if (ret) {
60         MEDIA_ERR_LOG("VideoCallbackListener:UpdateJSCallbackAsync() failed to execute work");
61         delete work;
62     }  else {
63         callbackInfo.release();
64     }
65 }
66 
OnFrameStarted() const67 void VideoCallbackListener::OnFrameStarted() const
68 {
69     CAMERA_SYNC_TRACE;
70     MEDIA_INFO_LOG("VideoCallbackListener::OnFrameStarted");
71     UpdateJSCallbackAsync("OnFrameStarted", -1);
72 }
73 
OnFrameEnded(const int32_t frameCount) const74 void VideoCallbackListener::OnFrameEnded(const int32_t frameCount) const
75 {
76     CAMERA_SYNC_TRACE;
77     MEDIA_INFO_LOG("VideoCallbackListener::OnFrameEnded frameCount: %{public}d", frameCount);
78     UpdateJSCallbackAsync("OnFrameEnded", frameCount);
79 }
80 
OnError(const int32_t errorCode) const81 void VideoCallbackListener::OnError(const int32_t errorCode) const
82 {
83     MEDIA_INFO_LOG("VideoCallbackListener::OnError errorCode: %{public}d", errorCode);
84     UpdateJSCallbackAsync("OnError", errorCode);
85 }
86 
SetCallbackRef(const std::string & eventType,const napi_ref & callbackRef)87 void VideoCallbackListener::SetCallbackRef(const std::string &eventType, const napi_ref &callbackRef)
88 {
89     if (eventType.compare("frameStart") == 0) {
90         frameStartCallbackRef_ = callbackRef;
91     } else if (eventType.compare("frameEnd") == 0) {
92         frameEndCallbackRef_ = callbackRef;
93     } else if (eventType.compare("error") == 0) {
94         errorCallbackRef_ = callbackRef;
95     } else {
96         MEDIA_ERR_LOG("Incorrect video callback event type received from JS");
97     }
98 }
99 
UpdateJSCallback(std::string propName,const int32_t value) const100 void VideoCallbackListener::UpdateJSCallback(std::string propName, const int32_t value) const
101 {
102     napi_value result[ARGS_ONE];
103     napi_value callback = nullptr;
104     napi_value retVal;
105     napi_value propValue;
106     int32_t jsErrorCodeUnknown = -1;
107 
108     if (propName.compare("OnFrameStarted") == 0) {
109         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(frameStartCallbackRef_,
110             "OnFrameStart callback is not registered by JS");
111         napi_get_undefined(env_, &result[PARAM0]);
112         napi_get_reference_value(env_, frameStartCallbackRef_, &callback);
113     } else if (propName.compare("OnFrameEnded") == 0) {
114         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(frameEndCallbackRef_,
115             "OnFrameEnd callback is not registered by JS");
116         napi_get_undefined(env_, &result[PARAM0]);
117         napi_get_reference_value(env_, frameEndCallbackRef_, &callback);
118     } else {
119         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(errorCallbackRef_,
120             "OnError callback is not registered by JS");
121         napi_create_object(env_, &result[PARAM0]);
122         napi_create_int32(env_, jsErrorCodeUnknown, &propValue);
123         napi_set_named_property(env_, result[PARAM0], "code", propValue);
124         napi_get_reference_value(env_, errorCallbackRef_, &callback); // should errorcode be valued as -1
125         if (errorCallbackRef_ != nullptr) {
126             napi_delete_reference(env_, errorCallbackRef_);
127         }
128     }
129 
130     napi_call_function(env_, nullptr, callback, ARGS_ONE, result, &retVal);
131 }
132 
VideoOutputNapi()133 VideoOutputNapi::VideoOutputNapi() : env_(nullptr), wrapper_(nullptr)
134 {
135 }
136 
~VideoOutputNapi()137 VideoOutputNapi::~VideoOutputNapi()
138 {
139     if (wrapper_ != nullptr) {
140         napi_delete_reference(env_, wrapper_);
141     }
142     if (videoOutput_) {
143         videoOutput_ = nullptr;
144     }
145     if (videoCallback_) {
146         videoCallback_ = nullptr;
147     }
148 }
149 
VideoOutputNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)150 void VideoOutputNapi::VideoOutputNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
151 {
152     VideoOutputNapi* videoOutput = reinterpret_cast<VideoOutputNapi*>(nativeObject);
153     if (videoOutput != nullptr) {
154         videoOutput->~VideoOutputNapi();
155     }
156 }
157 
Init(napi_env env,napi_value exports)158 napi_value VideoOutputNapi::Init(napi_env env, napi_value exports)
159 {
160     napi_status status;
161     napi_value ctorObj;
162     int32_t refCount = 1;
163 
164     napi_property_descriptor video_output_props[] = {
165         DECLARE_NAPI_FUNCTION("start", Start),
166         DECLARE_NAPI_FUNCTION("stop", Stop),
167         DECLARE_NAPI_FUNCTION("getFrameRateRange", GetFrameRateRange),
168         DECLARE_NAPI_FUNCTION("setFrameRateRange", SetFrameRateRange),
169         DECLARE_NAPI_FUNCTION("release", Release),
170         DECLARE_NAPI_FUNCTION("on", On)
171     };
172 
173     status = napi_define_class(env, CAMERA_VIDEO_OUTPUT_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
174                                VideoOutputNapiConstructor, nullptr,
175                                sizeof(video_output_props) / sizeof(video_output_props[PARAM0]),
176                                video_output_props, &ctorObj);
177     if (status == napi_ok) {
178         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
179         if (status == napi_ok) {
180             status = napi_set_named_property(env, exports, CAMERA_VIDEO_OUTPUT_NAPI_CLASS_NAME, ctorObj);
181             if (status == napi_ok) {
182                 return exports;
183             }
184         }
185     }
186 
187     return nullptr;
188 }
189 
190 // Constructor callback
VideoOutputNapiConstructor(napi_env env,napi_callback_info info)191 napi_value VideoOutputNapi::VideoOutputNapiConstructor(napi_env env, napi_callback_info info)
192 {
193     napi_status status;
194     napi_value result = nullptr;
195     napi_value thisVar = nullptr;
196 
197     napi_get_undefined(env, &result);
198     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
199 
200     if (status == napi_ok && thisVar != nullptr) {
201         std::unique_ptr<VideoOutputNapi> obj = std::make_unique<VideoOutputNapi>();
202         if (obj != nullptr) {
203             obj->env_ = env;
204             obj->videoOutput_ = sVideoOutput_;
205 
206             std::shared_ptr<VideoCallbackListener> callback =
207                             std::make_shared<VideoCallbackListener>(VideoCallbackListener(env));
208             ((sptr<VideoOutput> &)(obj->videoOutput_))->SetCallback(callback);
209             obj->videoCallback_ = callback;
210 
211             status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
212                                VideoOutputNapi::VideoOutputNapiDestructor, nullptr, &(obj->wrapper_));
213             if (status == napi_ok) {
214                 obj.release();
215                 return thisVar;
216             } else {
217                 MEDIA_ERR_LOG("Failure wrapping js to native napi");
218             }
219         }
220     }
221 
222     return result;
223 }
224 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],VideoOutputAsyncContext & asyncContext)225 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
226     VideoOutputAsyncContext &asyncContext)
227 {
228     std::string str = "";
229     std::vector<std::string> strArr;
230     std::string order = "";
231     const int32_t refCount = 1;
232     napi_value result;
233     auto context = &asyncContext;
234 
235     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
236 
237     for (size_t i = PARAM0; i < argc; i++) {
238         napi_valuetype valueType = napi_undefined;
239         napi_typeof(env, argv[i], &valueType);
240 
241         if (i == PARAM0 && valueType == napi_number) {
242             napi_get_value_int32(env, argv[i], &context->minFrameRate);
243         } else if (i == PARAM1 && valueType == napi_number) {
244             napi_get_value_int32(env, argv[i], &context->maxFrameRate);
245         } else if (i == PARAM2 && valueType == napi_function) {
246             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
247         } else {
248             NAPI_ASSERT(env, false, "type mismatch");
249         }
250     }
251     // Return true napi_value if params are successfully obtained
252     napi_get_boolean(env, true, &result);
253     return result;
254 }
255 
CommonCompleteCallback(napi_env env,napi_status status,void * data)256 static void CommonCompleteCallback(napi_env env, napi_status status, void* data)
257 {
258     auto context = static_cast<VideoOutputAsyncContext*>(data);
259 
260     if (context == nullptr) {
261         MEDIA_ERR_LOG("Async context is null");
262         return;
263     }
264 
265     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
266 
267     if (!context->status) {
268         CameraNapiUtils::CreateNapiErrorObject(env, context->errorCode, context->errorMsg.c_str(), jsContext);
269     } else {
270         jsContext->status = true;
271         napi_get_undefined(env, &jsContext->error);
272         if (context->bRetBool) {
273             napi_get_boolean(env, context->status, &jsContext->data);
274         } else {
275             napi_get_undefined(env, &jsContext->data);
276         }
277     }
278 
279     if (!context->funcName.empty() && context->taskId > 0) {
280         // Finish async trace
281         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
282         jsContext->funcName = context->funcName;
283     }
284 
285     if (context->work != nullptr) {
286         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
287                                              context->work, *jsContext);
288     }
289     delete context;
290 }
291 
GetVideoOutput()292 sptr<VideoOutput> VideoOutputNapi::GetVideoOutput()
293 {
294     return videoOutput_;
295 }
296 
IsVideoOutput(napi_env env,napi_value obj)297 bool VideoOutputNapi::IsVideoOutput(napi_env env, napi_value obj)
298 {
299     bool result = false;
300     napi_status status;
301     napi_value constructor = nullptr;
302 
303     status = napi_get_reference_value(env, sConstructor_, &constructor);
304     if (status == napi_ok) {
305         status = napi_instanceof(env, obj, constructor, &result);
306         if (status != napi_ok) {
307             result = false;
308         }
309     }
310 
311     return result;
312 }
313 
CreateVideoOutput(napi_env env,VideoProfile & profile,std::string surfaceId)314 napi_value VideoOutputNapi::CreateVideoOutput(napi_env env, VideoProfile &profile, std::string surfaceId)
315 {
316     CAMERA_SYNC_TRACE;
317     napi_status status;
318     napi_value result = nullptr;
319     napi_value constructor;
320 
321     status = napi_get_reference_value(env, sConstructor_, &constructor);
322     if (status == napi_ok) {
323         uint64_t iSurfaceId;
324         std::istringstream iss(surfaceId);
325         iss >> iSurfaceId;
326         sptr<Surface> surface = SurfaceUtils::GetInstance()->GetSurface(iSurfaceId);
327         if (surface == nullptr) {
328             MEDIA_ERR_LOG("failed to get surface from SurfaceUtils");
329             return result;
330         }
331         surface->SetUserData(CameraManager::surfaceFormat, std::to_string(profile.GetCameraFormat()));
332         int retCode = CameraManager::GetInstance()->CreateVideoOutput(profile, surface, &sVideoOutput_);
333         if (!CameraNapiUtils::CheckError(env, retCode)) {
334             return nullptr;
335         }
336         if (sVideoOutput_ == nullptr) {
337             MEDIA_ERR_LOG("failed to create VideoOutput");
338             return result;
339         }
340         status = napi_new_instance(env, constructor, 0, nullptr, &result);
341         sVideoOutput_ = nullptr;
342         if (status == napi_ok && result != nullptr) {
343             return result;
344         } else {
345             MEDIA_ERR_LOG("Failed to create video output instance");
346         }
347     }
348 
349     napi_get_undefined(env, &result);
350     return result;
351 }
352 
Start(napi_env env,napi_callback_info info)353 napi_value VideoOutputNapi::Start(napi_env env, napi_callback_info info)
354 {
355     napi_status status;
356     napi_value result = nullptr;
357     const int32_t refCount = 1;
358     napi_value resource = nullptr;
359     size_t argc = ARGS_ONE;
360     napi_value argv[ARGS_ONE] = {0};
361     napi_value thisVar = nullptr;
362 
363     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
364     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
365 
366     napi_get_undefined(env, &result);
367     std::unique_ptr<VideoOutputAsyncContext> asyncContext = std::make_unique<VideoOutputAsyncContext>();
368     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
369     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
370         if (argc == ARGS_ONE) {
371             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
372         }
373         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
374         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Start");
375         status = napi_create_async_work(env, nullptr, resource,
376             [](napi_env env, void* data) {
377                 auto context = static_cast<VideoOutputAsyncContext*>(data);
378                 context->status = false;
379                 // Start async trace
380                 context->funcName = "VideoOutputNapi::Start";
381                 context->taskId = CameraNapiUtils::IncreamentAndGet(videoOutputTaskId);
382                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
383                 if (context->objectInfo != nullptr) {
384                     context->bRetBool = false;
385                     context->errorCode = ((sptr<VideoOutput> &)(context->objectInfo->videoOutput_))->Start();
386                     context->status = context->errorCode == 0;
387                 }
388             },
389             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
390         if (status != napi_ok) {
391             MEDIA_ERR_LOG("Failed to create napi_create_async_work for VideoOutputNapi::Start");
392             napi_get_undefined(env, &result);
393         } else {
394             napi_queue_async_work(env, asyncContext->work);
395             asyncContext.release();
396         }
397     }
398 
399     return result;
400 }
401 
Stop(napi_env env,napi_callback_info info)402 napi_value VideoOutputNapi::Stop(napi_env env, napi_callback_info info)
403 {
404     napi_status status;
405     napi_value result = nullptr;
406     const int32_t refCount = 1;
407     napi_value resource = nullptr;
408     size_t argc = ARGS_ONE;
409     napi_value argv[ARGS_ONE] = {0};
410     napi_value thisVar = nullptr;
411 
412     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
413     NAPI_ASSERT(env, argc <= 1, "requires 1 parameter maximum");
414 
415     napi_get_undefined(env, &result);
416     std::unique_ptr<VideoOutputAsyncContext> asyncContext = std::make_unique<VideoOutputAsyncContext>();
417     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
418     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
419         if (argc == ARGS_ONE) {
420             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
421         }
422         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
423         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Stop");
424         status = napi_create_async_work(env, nullptr, resource,
425             [](napi_env env, void* data) {
426                 auto context = static_cast<VideoOutputAsyncContext*>(data);
427                 context->status = false;
428                 // Start async trace
429                 context->funcName = "VideoOutputNapi::Stop";
430                 context->taskId = CameraNapiUtils::IncreamentAndGet(videoOutputTaskId);
431                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
432                 if (context->objectInfo != nullptr) {
433                     context->bRetBool = false;
434                     context->errorCode = ((sptr<VideoOutput> &)(context->objectInfo->videoOutput_))->Stop();
435                     context->status = context->errorCode == 0;
436                 }
437             },
438             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
439         if (status != napi_ok) {
440             MEDIA_ERR_LOG("Failed to create napi_create_async_work for VideoOutputNapi::Stop");
441             napi_get_undefined(env, &result);
442         } else {
443             napi_queue_async_work(env, asyncContext->work);
444             asyncContext.release();
445         }
446     }
447 
448     return result;
449 }
450 
GetFrameRateRangeAsyncCallbackComplete(napi_env env,napi_status status,void * data)451 void GetFrameRateRangeAsyncCallbackComplete(napi_env env, napi_status status, void* data)
452 {
453     auto context = static_cast<VideoOutputAsyncContext*>(data);
454     napi_value frameRateRange = nullptr;
455 
456     CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
457 
458     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
459     jsContext->status = true;
460     napi_get_undefined(env, &jsContext->error);
461     if ((!context->vecFrameRateRangeList.empty()) && (napi_create_array(env, &frameRateRange) == napi_ok)) {
462         int32_t j = 0;
463         for (size_t i = 0; i < context->vecFrameRateRangeList.size(); i++) {
464             int32_t  frameRate = context->vecFrameRateRangeList[i];
465             napi_value value;
466             if (napi_create_int32(env, frameRate, &value) == napi_ok) {
467                 napi_set_element(env, frameRateRange, j, value);
468                 j++;
469             }
470         }
471         jsContext->data = frameRateRange;
472     } else {
473         MEDIA_ERR_LOG("vecFrameRateRangeList is empty or failed to create array!");
474         CameraNapiUtils::CreateNapiErrorObject(env, context->errorCode,
475             "vecFrameRateRangeList is empty or failed to create array!", jsContext);
476     }
477 
478     if (!context->funcName.empty() && context->taskId > 0) {
479         // Finish async trace
480         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
481         jsContext->funcName = context->funcName;
482     }
483 
484     if (context->work != nullptr) {
485         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
486                                              context->work, *jsContext);
487     }
488     delete context;
489 }
490 
GetFrameRateRange(napi_env env,napi_callback_info info)491 napi_value VideoOutputNapi::GetFrameRateRange(napi_env env, napi_callback_info info)
492 {
493     CAMERA_SYNC_TRACE;
494     napi_status status;
495     napi_value result = nullptr;
496     const int32_t refCount = 1;
497     napi_value resource = nullptr;
498     size_t argc = ARGS_ONE;
499     napi_value argv[ARGS_ONE] = {0};
500     napi_value thisVar = nullptr;
501 
502     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
503     NAPI_ASSERT(env, (argc <= ARGS_ONE), "requires 1 parameter maximum");
504 
505     napi_get_undefined(env, &result);
506     auto asyncContext = std::make_unique<VideoOutputAsyncContext>();
507     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
508     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
509         if (argc == ARGS_ONE) {
510             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
511         }
512         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
513         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "GetFrameRateRange");
514         status = napi_create_async_work(
515             env, nullptr, resource, [](napi_env env, void* data) {
516                 auto context = static_cast<VideoOutputAsyncContext*>(data);
517                 context->status = false;
518                 if (context->objectInfo != nullptr) {
519                     if (!context->vecFrameRateRangeList.empty()) {
520                         context->status = true;
521                     } else {
522                         context->status = false;
523                         MEDIA_ERR_LOG("GetFrameRateRange vecFrameRateRangeList is empty!");
524                     }
525                 }
526             },
527             GetFrameRateRangeAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
528         if (status != napi_ok) {
529             MEDIA_ERR_LOG("Failed to create napi_create_async_work for GetFrameRateRange");
530             napi_get_undefined(env, &result);
531         } else {
532             napi_queue_async_work(env, asyncContext->work);
533             asyncContext.release();
534         }
535     }
536 
537     return result;
538 }
539 
isFrameRateRangeAvailable(napi_env env,void * data)540 bool isFrameRateRangeAvailable(napi_env env, void* data)
541 {
542     bool invalidFrameRate = true;
543     const int32_t FRAME_RATE_RANGE_STEP = 2;
544     auto context = static_cast<VideoOutputAsyncContext*>(data);
545     if (context == nullptr) {
546         MEDIA_ERR_LOG("Async context is null");
547         return invalidFrameRate;
548     }
549 
550     if (!context->vecFrameRateRangeList.empty()) {
551         for (size_t i = 0; i < (context->vecFrameRateRangeList.size() - 1); i += FRAME_RATE_RANGE_STEP) {
552             int32_t minVal = context->vecFrameRateRangeList[i];
553             int32_t maxVal = context->vecFrameRateRangeList[i + 1];
554             if ((context->minFrameRate == minVal) && (context->maxFrameRate == maxVal)) {
555                 invalidFrameRate = false;
556                 break;
557             }
558         }
559     } else {
560         MEDIA_ERR_LOG("isFrameRateRangeAvailable: vecFrameRateRangeList is empty!");
561     }
562     return invalidFrameRate;
563 }
564 
SetFrameRateRange(napi_env env,napi_callback_info info)565 napi_value VideoOutputNapi::SetFrameRateRange(napi_env env, napi_callback_info info)
566 {
567     CAMERA_SYNC_TRACE;
568     napi_status status;
569     napi_value result = nullptr;
570     napi_value resource = nullptr;
571     size_t argc = ARGS_THREE;
572     napi_value argv[ARGS_THREE] = {0};
573     napi_value thisVar = nullptr;
574 
575     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
576     NAPI_ASSERT(env, (argc == ARGS_TWO || argc == ARGS_THREE), "requires 3 parameters maximum");
577 
578     napi_get_undefined(env, &result);
579     auto asyncContext = std::make_unique<VideoOutputAsyncContext>();
580     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
581     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
582         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
583         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
584         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
585         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "SetFrameRateRange");
586         status = napi_create_async_work(
587             env, nullptr, resource,
588             [](napi_env env, void* data) {
589                 auto context = static_cast<VideoOutputAsyncContext*>(data);
590                 context->status = false;
591                 // Start async trace
592                 context->funcName = "VideoOutputNapi::SetFrameRateRange";
593                 context->taskId = CameraNapiUtils::IncreamentAndGet(videoOutputTaskId);
594                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
595                 if (context->objectInfo != nullptr) {
596                     context->bRetBool = false;
597                     bool isValidRange = isFrameRateRangeAvailable(env, data);
598                     if (!isValidRange) {
599                         context->status = true;
600                     } else {
601                         MEDIA_ERR_LOG("Failed to get range values for SetFrameRateRange");
602                         context->errorMsg = "Failed to get range values for SetFrameRateRange";
603                     }
604                 }
605             },
606             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
607         if (status != napi_ok) {
608             MEDIA_ERR_LOG("Failed to create napi_create_async_work for SetFrameRateRange");
609             napi_get_undefined(env, &result);
610         } else {
611             napi_queue_async_work(env, asyncContext->work);
612             asyncContext.release();
613         }
614     }
615 
616     return result;
617 }
618 
Release(napi_env env,napi_callback_info info)619 napi_value VideoOutputNapi::Release(napi_env env, napi_callback_info info)
620 {
621     napi_status status;
622     napi_value result = nullptr;
623     const int32_t refCount = 1;
624     napi_value resource = nullptr;
625     size_t argc = ARGS_ONE;
626     napi_value argv[ARGS_ONE] = {0};
627     napi_value thisVar = nullptr;
628 
629     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
630     NAPI_ASSERT(env, argc <= 1, "requires 1 parameter maximum");
631 
632     napi_get_undefined(env, &result);
633     std::unique_ptr<VideoOutputAsyncContext> asyncContext = std::make_unique<VideoOutputAsyncContext>();
634     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
635     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
636         if (argc == ARGS_ONE) {
637             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
638         }
639 
640         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
641         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
642 
643         status = napi_create_async_work(
644             env, nullptr, resource, [](napi_env env, void* data) {
645                 auto context = static_cast<VideoOutputAsyncContext*>(data);
646                 context->status = false;
647                 // Start async trace
648                 context->funcName = "VideoOutputNapi::Release";
649                 context->taskId = CameraNapiUtils::IncreamentAndGet(videoOutputTaskId);
650                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
651                 if (context->objectInfo != nullptr) {
652                     context->bRetBool = false;
653                     context->status = true;
654                     ((sptr<VideoOutput> &)(context->objectInfo->videoOutput_))->Release();
655                 }
656             },
657             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
658         if (status != napi_ok) {
659             MEDIA_ERR_LOG("Failed to create napi_create_async_work for VideoOutputNapi::Release");
660             napi_get_undefined(env, &result);
661         } else {
662             napi_queue_async_work(env, asyncContext->work);
663             asyncContext.release();
664         }
665     }
666 
667     return result;
668 }
669 
On(napi_env env,napi_callback_info info)670 napi_value VideoOutputNapi::On(napi_env env, napi_callback_info info)
671 {
672     CAMERA_SYNC_TRACE;
673     napi_value undefinedResult = nullptr;
674     size_t argCount = ARGS_TWO;
675     napi_value argv[ARGS_TWO] = {nullptr};
676     napi_value thisVar = nullptr;
677     size_t res = 0;
678     char buffer[SIZE];
679     const int32_t refCount = 1;
680     VideoOutputNapi* obj = nullptr;
681     napi_status status;
682 
683     napi_get_undefined(env, &undefinedResult);
684 
685     CAMERA_NAPI_GET_JS_ARGS(env, info, argCount, argv, thisVar);
686     NAPI_ASSERT(env, argCount == ARGS_TWO, "requires 2 parameters");
687 
688     if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr) {
689         MEDIA_ERR_LOG("Failed to retrieve details about the callback");
690         return undefinedResult;
691     }
692 
693     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
694     if (status == napi_ok && obj != nullptr) {
695         napi_valuetype valueType = napi_undefined;
696         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string
697             || napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
698             return undefinedResult;
699         }
700 
701         napi_get_value_string_utf8(env, argv[PARAM0], buffer, SIZE, &res);
702         std::string eventType = std::string(buffer);
703 
704         napi_ref callbackRef;
705         napi_create_reference(env, argv[PARAM1], refCount, &callbackRef);
706 
707         if (!eventType.empty()) {
708             obj->videoCallback_->SetCallbackRef(eventType, callbackRef);
709         } else {
710             MEDIA_ERR_LOG("Failed to Register Callback: event type is empty!");
711         }
712     }
713 
714     return undefinedResult;
715 }
716 } // namespace CameraStandard
717 } // namespace OHOS
718