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