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