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