• 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/photo_output_napi.h"
17 #include <uv.h>
18 
19 namespace OHOS {
20 namespace CameraStandard {
21 using namespace std;
22 using OHOS::HiviewDFX::HiLog;
23 using OHOS::HiviewDFX::HiLogLabel;
24 
25 namespace {
26     constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PhotoOutputNapi"};
27 }
28 
29 thread_local napi_ref PhotoOutputNapi::sConstructor_ = nullptr;
30 thread_local sptr<PhotoOutput> PhotoOutputNapi::sPhotoOutput_ = nullptr;
31 thread_local uint32_t PhotoOutputNapi::photoOutputTaskId = CAMERA_PHOTO_OUTPUT_TASKID;
32 
PhotoOutputCallback(napi_env env)33 PhotoOutputCallback::PhotoOutputCallback(napi_env env) : env_(env) {}
34 
UpdateJSCallbackAsync(std::string propName,const CallbackInfo & info) const35 void PhotoOutputCallback::UpdateJSCallbackAsync(std::string propName, const CallbackInfo &info) const
36 {
37     uv_loop_s* loop = nullptr;
38     napi_get_uv_event_loop(env_, &loop);
39     if (!loop) {
40         MEDIA_ERR_LOG("PhotoOutputCallback: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("PhotoOutputCallback:UpdateJSCallbackAsync() failed to allocate work");
46         return;
47     }
48     std::unique_ptr<PhotoOutputCallbackInfo> callbackInfo =
49         std::make_unique<PhotoOutputCallbackInfo>(propName, info, 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         PhotoOutputCallbackInfo* callbackInfo = reinterpret_cast<PhotoOutputCallbackInfo *>(work->data);
53         if (callbackInfo) {
54             callbackInfo->listener_->UpdateJSCallback(callbackInfo->eventName_, callbackInfo->info_);
55             delete callbackInfo;
56         }
57         delete work;
58     });
59     if (ret) {
60         MEDIA_ERR_LOG("PhotoOutputCallback:UpdateJSCallbackAsync() failed to execute work");
61         delete work;
62     } else {
63         callbackInfo.release();
64     }
65 }
66 
OnCaptureStarted(const int32_t captureID) const67 void PhotoOutputCallback::OnCaptureStarted(const int32_t captureID) const
68 {
69     CAMERA_SYNC_TRACE;
70     MEDIA_INFO_LOG("PhotoOutputCallback:OnCaptureStarted() is called!, captureID: %{public}d", captureID);
71     CallbackInfo info;
72     info.captureID = captureID;
73     UpdateJSCallbackAsync("OnCaptureStarted", info);
74 }
75 
OnCaptureEnded(const int32_t captureID,const int32_t frameCount) const76 void PhotoOutputCallback::OnCaptureEnded(const int32_t captureID, const int32_t frameCount) const
77 {
78     CAMERA_SYNC_TRACE;
79     MEDIA_INFO_LOG("PhotoOutputCallback:OnCaptureEnded() is called!, captureID: %{public}d, frameCount: %{public}d",
80                    captureID, frameCount);
81     CallbackInfo info;
82     info.captureID = captureID;
83     info.frameCount = frameCount;
84     UpdateJSCallbackAsync("OnCaptureEnded", info);
85 }
86 
OnFrameShutter(const int32_t captureId,const uint64_t timestamp) const87 void PhotoOutputCallback::OnFrameShutter(const int32_t captureId, const uint64_t timestamp) const
88 {
89     CAMERA_SYNC_TRACE;
90     MEDIA_INFO_LOG("PhotoOutputCallback:OnFrameShutter() called, captureID: %{public}d, timestamp: %{public}" PRIu64,
91         captureId, timestamp);
92     CallbackInfo info;
93     info.captureID = captureId;
94     info.timestamp = timestamp;
95     UpdateJSCallbackAsync("OnFrameShutter", info);
96 }
97 
OnCaptureError(const int32_t captureId,const int32_t errorCode) const98 void PhotoOutputCallback::OnCaptureError(const int32_t captureId, const int32_t errorCode) const
99 {
100     MEDIA_INFO_LOG("PhotoOutputCallback:OnCaptureError() is called!, captureID: %{public}d, errorCode: %{public}d",
101         captureId, errorCode);
102     CallbackInfo info;
103     info.captureID = captureId;
104     info.errorCode = errorCode;
105     UpdateJSCallbackAsync("OnCaptureError", info);
106 }
107 
SetCallbackRef(const std::string & eventType,const napi_ref & callbackRef)108 void PhotoOutputCallback::SetCallbackRef(const std::string &eventType, const napi_ref &callbackRef)
109 {
110     if (eventType.compare("captureStart") == 0) {
111         captureStartCallbackRef_ = callbackRef;
112     } else if (eventType.compare("captureEnd") == 0) {
113         captureEndCallbackRef_ = callbackRef;
114     } else if (eventType.compare("frameShutter") == 0) {
115         frameShutterCallbackRef_ = callbackRef;
116     } else if (eventType.compare("error") == 0) {
117         errorCallbackRef_ = callbackRef;
118     } else {
119         MEDIA_ERR_LOG("Incorrect photo callback event type received from JS");
120     }
121 }
122 
UpdateJSCallback(std::string propName,const CallbackInfo & info) const123 void PhotoOutputCallback::UpdateJSCallback(std::string propName, const CallbackInfo &info) const
124 {
125     napi_value result[ARGS_ONE];
126     napi_value callback = nullptr;
127     napi_value retVal;
128     napi_value propValue;
129     int32_t jsErrorCodeUnknown = -1;
130 
131     if (propName.compare("OnCaptureStarted") == 0) {
132         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(captureStartCallbackRef_,
133             "OnCaptureStart callback is not registered by JS");
134         napi_create_int32(env_, info.captureID, &result[PARAM0]);
135         napi_get_reference_value(env_, captureStartCallbackRef_, &callback);
136     } else if (propName.compare("OnCaptureEnded") == 0) {
137         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(captureEndCallbackRef_,
138             "OnCaptureEnd callback is not registered by JS");
139         napi_create_object(env_, &result[PARAM0]);
140         napi_create_int32(env_, info.captureID, &propValue);
141         napi_set_named_property(env_, result[PARAM0], "captureId", propValue);
142         napi_create_int32(env_, info.frameCount, &propValue);
143         napi_set_named_property(env_, result[PARAM0], "frameCount", propValue);
144         napi_get_reference_value(env_, captureEndCallbackRef_, &callback);
145     } else if (propName.compare("OnFrameShutter") == 0) {
146         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(frameShutterCallbackRef_,
147             "OnFrameShutter callback is not registered by JS");
148         napi_create_object(env_, &result[PARAM0]);
149         napi_create_int32(env_, info.captureID, &propValue);
150         napi_set_named_property(env_, result[PARAM0], "captureId", propValue);
151         napi_create_int64(env_, info.timestamp, &propValue);
152         napi_set_named_property(env_, result[PARAM0], "timestamp", propValue);
153         napi_get_reference_value(env_, frameShutterCallbackRef_, &callback);
154     } else {
155         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(errorCallbackRef_,
156             "OnError callback is not registered by JS");
157         napi_create_object(env_, &result[PARAM0]);
158         napi_create_int32(env_, jsErrorCodeUnknown, &propValue);
159         napi_set_named_property(env_, result[PARAM0], "code", propValue);
160         napi_get_reference_value(env_, errorCallbackRef_, &callback);
161         if (errorCallbackRef_ != nullptr) {
162             napi_delete_reference(env_, errorCallbackRef_);
163         }
164     }
165 
166     napi_call_function(env_, nullptr, callback, ARGS_ONE, result, &retVal);
167 }
168 
PhotoOutputNapi()169 PhotoOutputNapi::PhotoOutputNapi() : env_(nullptr), wrapper_(nullptr)
170 {
171 }
172 
~PhotoOutputNapi()173 PhotoOutputNapi::~PhotoOutputNapi()
174 {
175     if (wrapper_ != nullptr) {
176         napi_delete_reference(env_, wrapper_);
177     }
178     if (photoOutput_) {
179         photoOutput_ = nullptr;
180     }
181     if (photoCallback_) {
182         photoCallback_ = nullptr;
183     }
184 }
185 
PhotoOutputNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)186 void PhotoOutputNapi::PhotoOutputNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
187 {
188     PhotoOutputNapi* photoOutput = reinterpret_cast<PhotoOutputNapi*>(nativeObject);
189     if (photoOutput != nullptr) {
190         photoOutput->~PhotoOutputNapi();
191     }
192 }
193 
Init(napi_env env,napi_value exports)194 napi_value PhotoOutputNapi::Init(napi_env env, napi_value exports)
195 {
196     napi_status status;
197     napi_value ctorObj;
198     int32_t refCount = 1;
199 
200     napi_property_descriptor photo_output_props[] = {
201         DECLARE_NAPI_FUNCTION("getDefaultCaptureSetting", GetDefaultCaptureSetting),
202         DECLARE_NAPI_FUNCTION("capture", Capture),
203         DECLARE_NAPI_FUNCTION("release", Release),
204         DECLARE_NAPI_FUNCTION("isMirrorSupported", IsMirrorSupported),
205         DECLARE_NAPI_FUNCTION("setMirror", SetMirror),
206         DECLARE_NAPI_FUNCTION("on", On)
207     };
208 
209     status = napi_define_class(env, CAMERA_PHOTO_OUTPUT_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
210                                PhotoOutputNapiConstructor, nullptr,
211                                sizeof(photo_output_props) / sizeof(photo_output_props[PARAM0]),
212                                photo_output_props, &ctorObj);
213     if (status == napi_ok) {
214         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
215         if (status == napi_ok) {
216             status = napi_set_named_property(env, exports, CAMERA_PHOTO_OUTPUT_NAPI_CLASS_NAME, ctorObj);
217             if (status == napi_ok) {
218                 return exports;
219             }
220         }
221     }
222 
223     return nullptr;
224 }
225 
226 // Constructor callback
PhotoOutputNapiConstructor(napi_env env,napi_callback_info info)227 napi_value PhotoOutputNapi::PhotoOutputNapiConstructor(napi_env env, napi_callback_info info)
228 {
229     napi_status status;
230     napi_value result = nullptr;
231     napi_value thisVar = nullptr;
232 
233     napi_get_undefined(env, &result);
234     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
235 
236     if (status == napi_ok && thisVar != nullptr) {
237         std::unique_ptr<PhotoOutputNapi> obj = std::make_unique<PhotoOutputNapi>();
238         obj->env_ = env;
239         obj->photoOutput_ = sPhotoOutput_;
240         std::shared_ptr<PhotoOutputCallback> callback =
241             std::make_shared<PhotoOutputCallback>(PhotoOutputCallback(env));
242         ((sptr<PhotoOutput> &)(obj->photoOutput_))->SetCallback(callback);
243         obj->photoCallback_ = callback;
244 
245         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
246                            PhotoOutputNapi::PhotoOutputNapiDestructor, nullptr, &(obj->wrapper_));
247         if (status == napi_ok) {
248             obj.release();
249             return thisVar;
250         } else {
251             MEDIA_ERR_LOG("Failure wrapping js to native napi");
252         }
253     }
254 
255     return result;
256 }
257 
GetPhotoOutput()258 sptr<PhotoOutput> PhotoOutputNapi::GetPhotoOutput()
259 {
260     return photoOutput_;
261 }
262 
IsPhotoOutput(napi_env env,napi_value obj)263 bool PhotoOutputNapi::IsPhotoOutput(napi_env env, napi_value obj)
264 {
265     bool result = false;
266     napi_status status;
267     napi_value constructor = nullptr;
268 
269     status = napi_get_reference_value(env, sConstructor_, &constructor);
270     if (status == napi_ok) {
271         status = napi_instanceof(env, obj, constructor, &result);
272         if (status != napi_ok) {
273             result = false;
274         }
275     }
276 
277     return result;
278 }
279 
CreatePhotoOutput(napi_env env,Profile & profile,std::string surfaceId)280 napi_value PhotoOutputNapi::CreatePhotoOutput(napi_env env, Profile &profile, std::string surfaceId)
281 {
282     CAMERA_SYNC_TRACE;
283     napi_status status;
284     napi_value result = nullptr;
285     napi_value constructor;
286     MEDIA_INFO_LOG("CreatePhotoOutput start");
287     MEDIA_INFO_LOG("CreatePhotoOutput profile CameraFormat= %{public}d", profile.GetCameraFormat());
288     napi_get_undefined(env, &result);
289     status = napi_get_reference_value(env, sConstructor_, &constructor);
290     if (status == napi_ok) {
291         MEDIA_INFO_LOG("CreatePhotoOutput surfaceId: %{public}s", surfaceId.c_str());
292         sptr<Surface> sface = Media::ImageReceiver::getSurfaceById(surfaceId);
293         if (sface == nullptr) {
294             MEDIA_ERR_LOG("failed to get surface from ImageReceiver");
295             return result;
296         }
297         MEDIA_INFO_LOG("surface width: %{public}d, height: %{public}d", sface->GetDefaultWidth(),
298                        sface->GetDefaultHeight());
299         sface->SetUserData(CameraManager::surfaceFormat, std::to_string(profile.GetCameraFormat()));
300         int retCode = CameraManager::GetInstance()->CreatePhotoOutput(profile, sface, &sPhotoOutput_);
301         if (!CameraNapiUtils::CheckError(env, retCode)) {
302             return nullptr;
303         }
304         if (sPhotoOutput_ == nullptr) {
305             MEDIA_ERR_LOG("failed to create CreatePhotoOutput");
306             return result;
307         }
308         status = napi_new_instance(env, constructor, 0, nullptr, &result);
309         sPhotoOutput_ = nullptr;
310         if (status == napi_ok && result != nullptr) {
311             MEDIA_ERR_LOG("Success to create photo output instance");
312             return result;
313         } else {
314             MEDIA_ERR_LOG("Failed to create photo output instance");
315         }
316     }
317     MEDIA_INFO_LOG("CreatePhotoOutput get undefined");
318     return result;
319 }
320 
CommonCompleteCallback(napi_env env,napi_status status,void * data)321 static void CommonCompleteCallback(napi_env env, napi_status status, void* data)
322 {
323     auto context = static_cast<PhotoOutputAsyncContext*>(data);
324     if (context == nullptr) {
325         MEDIA_ERR_LOG("Async context is null");
326         return;
327     }
328 
329     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
330 
331     if (!context->status) {
332         CameraNapiUtils::CreateNapiErrorObject(env, context->errorCode, context->errorMsg.c_str(), jsContext);
333     } else {
334         jsContext->status = true;
335         napi_get_undefined(env, &jsContext->error);
336         if (context->bRetBool) {
337             napi_get_boolean(env, context->isSupported, &jsContext->data);
338         } else {
339             napi_get_undefined(env, &jsContext->data);
340         }
341     }
342 
343     if (!context->funcName.empty() && context->taskId > 0) {
344         // Finish async trace
345         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
346         jsContext->funcName = context->funcName;
347     }
348 
349     if (context->work != nullptr) {
350         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
351                                              context->work, *jsContext);
352     }
353     delete context;
354 }
355 
QueryAndGetProperty(napi_env env,napi_value arg,const string & propertyName,napi_value & property)356 int32_t QueryAndGetProperty(napi_env env, napi_value arg, const string &propertyName, napi_value &property)
357 {
358     bool present = false;
359     int32_t retval = 0;
360     if ((napi_has_named_property(env, arg, propertyName.c_str(), &present) != napi_ok)
361         || (!present) || (napi_get_named_property(env, arg, propertyName.c_str(), &property) != napi_ok)) {
362             HiLog::Error(LABEL, "Failed to obtain property: %{public}s", propertyName.c_str());
363             retval = -1;
364     }
365 
366     return retval;
367 }
368 
GetLocationProperties(napi_env env,napi_value locationObj,const PhotoOutputAsyncContext & context)369 int32_t GetLocationProperties(napi_env env, napi_value locationObj, const PhotoOutputAsyncContext &context)
370 {
371     PhotoOutputAsyncContext* asyncContext = const_cast<PhotoOutputAsyncContext *>(&context);
372     napi_value latproperty = nullptr;
373     napi_value lonproperty = nullptr;
374     napi_value altproperty = nullptr;
375     double latitude = -1.0;
376     double longitude = -1.0;
377     double altitude = -1.0;
378 
379     if ((QueryAndGetProperty(env, locationObj, "latitude", latproperty) == 0) &&
380         (QueryAndGetProperty(env, locationObj, "longitude", lonproperty) == 0) &&
381         (QueryAndGetProperty(env, locationObj, "altitude", altproperty) == 0)) {
382         if ((napi_get_value_double(env, latproperty, &latitude) != napi_ok) ||
383             (napi_get_value_double(env, lonproperty, &longitude) != napi_ok) ||
384             (napi_get_value_double(env, altproperty, &altitude) != napi_ok)) {
385             return -1;
386         } else {
387             asyncContext->location = std::make_unique<Location>();
388             asyncContext->location->latitude = latitude;
389             asyncContext->location->longitude = longitude;
390             asyncContext->location->altitude = altitude;
391         }
392     } else {
393         return -1;
394     }
395 
396     return 0;
397 }
398 
GetFetchOptionsParam(napi_env env,napi_value arg,const PhotoOutputAsyncContext & context,bool & err)399 static void GetFetchOptionsParam(napi_env env, napi_value arg, const PhotoOutputAsyncContext &context, bool &err)
400 {
401     PhotoOutputAsyncContext* asyncContext = const_cast<PhotoOutputAsyncContext *>(&context);
402     int32_t intValue;
403     std::string strValue;
404     napi_value property = nullptr;
405     PhotoCaptureSetting::QualityLevel quality;
406     PhotoCaptureSetting::RotationConfig rotation;
407 
408     if (QueryAndGetProperty(env, arg, "quality", property) == 0) {
409         if (napi_get_value_int32(env, property, &intValue) != napi_ok
410             || CameraNapiUtils::MapQualityLevelFromJs(intValue, quality) == -1) {
411             err = true;
412             return;
413         } else {
414             asyncContext->quality = quality;
415         }
416     }
417 
418     if (QueryAndGetProperty(env, arg, "rotation", property) == 0) {
419         if (napi_get_value_int32(env, property, &intValue) != napi_ok
420             || CameraNapiUtils::MapImageRotationFromJs(intValue, rotation) == -1) {
421             err = true;
422             return;
423         } else {
424             asyncContext->rotation = rotation;
425         }
426     }
427 
428     if (QueryAndGetProperty(env, arg, "location", property) == 0) {
429         if (GetLocationProperties(env, property, context) == -1) {
430             err = true;
431             return;
432         }
433     }
434 
435     if (QueryAndGetProperty(env, arg, "mirror", property) == 0) {
436         bool isMirror = false;
437         if (napi_get_value_bool(env, property, &isMirror) != napi_ok) {
438             err = true;
439             return;
440         } else {
441             asyncContext->isMirror = isMirror;
442         }
443     }
444 }
445 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],PhotoOutputAsyncContext & asyncContext)446 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
447     PhotoOutputAsyncContext &asyncContext)
448 {
449     const int32_t refCount = 1;
450     napi_value result = nullptr;
451     auto context = &asyncContext;
452     bool err = false;
453 
454     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
455 
456     for (size_t i = PARAM0; i < argc; i++) {
457         napi_valuetype valueType = napi_undefined;
458         napi_typeof(env, argv[i], &valueType);
459         if (i == PARAM0 && valueType == napi_object) {
460             GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
461             if (err) {
462                 HiLog::Error(LABEL, "fetch options retrieval failed");
463                 NAPI_ASSERT(env, false, "type mismatch");
464             }
465             asyncContext.hasPhotoSettings = true;
466         } else if ((i == PARAM0) && (valueType == napi_function)) {
467             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
468             break;
469         } else if ((i == PARAM1) && (valueType == napi_function)) {
470             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
471             break;
472         } else if ((i == PARAM0) && (valueType == napi_boolean)) {
473             napi_get_value_bool(env, argv[i], &context->isSupported);
474             break;
475         } else {
476             NAPI_ASSERT(env, false, "type mismatch");
477         }
478     }
479 
480     // Return true napi_value if params are successfully obtained
481     napi_get_boolean(env, true, &result);
482     return result;
483 }
484 
Capture(napi_env env,napi_callback_info info)485 napi_value PhotoOutputNapi::Capture(napi_env env, napi_callback_info info)
486 {
487     napi_status status;
488     napi_value result = nullptr;
489     size_t argc = ARGS_TWO;
490     napi_value argv[ARGS_TWO] = {0};
491     napi_value thisVar = nullptr;
492     napi_value resource = nullptr;
493 
494     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
495 
496     napi_get_undefined(env, &result);
497     unique_ptr<PhotoOutputAsyncContext> asyncContext = make_unique<PhotoOutputAsyncContext>();
498     if (!CameraNapiUtils::CheckInvalidArgument(env, argc, ARGS_TWO, argv, PHOTO_OUT_CAPTURE)) {
499         asyncContext->isInvalidArgument = true;
500         asyncContext->status = false;
501         asyncContext->errorCode = INVALID_ARGUMENT;
502     }
503     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
504     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
505         if (!asyncContext->isInvalidArgument) {
506             result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
507         }
508         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
509         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
510         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Capture");
511         status = napi_create_async_work(
512             env, nullptr, resource, [](napi_env env, void* data) {
513                 PhotoOutputAsyncContext* context = static_cast<PhotoOutputAsyncContext*>(data);
514                 // Start async trace
515                 context->funcName = "PhotoOutputNapi::Capture";
516                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
517                 if (context->isInvalidArgument) {
518                     return;
519                 }
520                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
521                 if (context->objectInfo == nullptr) {
522                     context->status = false;
523                     return;
524                 }
525 
526                 context->bRetBool = false;
527                 context->status = true;
528                 sptr<PhotoOutput> photoOutput = ((sptr<PhotoOutput> &)(context->objectInfo->photoOutput_));
529                 if ((context->hasPhotoSettings)) {
530                     std::shared_ptr<PhotoCaptureSetting> capSettings = make_shared<PhotoCaptureSetting>();
531 
532                     if (context->quality != -1) {
533                         capSettings->SetQuality(
534                             static_cast<PhotoCaptureSetting::QualityLevel>(context->quality));
535                     }
536 
537                     if (context->rotation != -1) {
538                         capSettings->SetRotation(
539                             static_cast<PhotoCaptureSetting::RotationConfig>(context->rotation));
540                     }
541 
542                     capSettings->SetMirror(context->isMirror);
543 
544                     if (context->location != nullptr) {
545                         capSettings->SetLocation(context->location);
546                     }
547 
548                     context->errorCode = photoOutput->Capture(capSettings);
549                 } else {
550                     context->errorCode = photoOutput->Capture();
551                 }
552                 context->status = context->errorCode == 0;
553             }, CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
554         if (status != napi_ok) {
555             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::Capture");
556             napi_get_undefined(env, &result);
557         } else {
558             napi_queue_async_work(env, asyncContext->work);
559             asyncContext.release();
560         }
561     }
562 
563     return result;
564 }
565 
Release(napi_env env,napi_callback_info info)566 napi_value PhotoOutputNapi::Release(napi_env env, napi_callback_info info)
567 {
568     napi_status status;
569     napi_value result = nullptr;
570     const int32_t refCount = 1;
571     napi_value resource = nullptr;
572     size_t argc = ARGS_ONE;
573     napi_value argv[ARGS_ONE] = {0};
574     napi_value thisVar = nullptr;
575 
576     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
577     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
578 
579     napi_get_undefined(env, &result);
580     std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
581     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
582     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
583         if (argc == ARGS_ONE) {
584             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
585         }
586 
587         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
588         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
589 
590         status = napi_create_async_work(
591             env, nullptr, resource, [](napi_env env, void* data) {
592                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
593                 context->status = false;
594                 // Start async trace
595                 context->funcName = "PhotoOutputNapi::Release";
596                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
597                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
598                 if (context->objectInfo != nullptr) {
599                     context->bRetBool = false;
600                     context->status = true;
601                     ((sptr<PhotoOutput> &)(context->objectInfo->photoOutput_))->Release();
602                 }
603             },
604             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
605         if (status != napi_ok) {
606             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::Release");
607             napi_get_undefined(env, &result);
608         } else {
609             napi_queue_async_work(env, asyncContext->work);
610             asyncContext.release();
611         }
612     }
613 
614     return result;
615 }
616 
GetDefaultCaptureSetting(napi_env env,napi_callback_info info)617 napi_value PhotoOutputNapi::GetDefaultCaptureSetting(napi_env env, napi_callback_info info)
618 {
619     napi_status status;
620     napi_value result = nullptr;
621     const int32_t refCount = 1;
622     napi_value resource = nullptr;
623     size_t argc = ARGS_ONE;
624     napi_value argv[ARGS_ONE] = {0};
625     napi_value thisVar = nullptr;
626 
627     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
628     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
629 
630     napi_get_undefined(env, &result);
631     std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
632     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
633     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
634         if (argc == ARGS_ONE) {
635             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
636         }
637 
638         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
639         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "GetDefaultCaptureSetting");
640 
641         status = napi_create_async_work(
642             env, nullptr, resource, [](napi_env env, void* data) {
643                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
644                 context->status = false;
645                 // Start async trace
646                 context->funcName = "PhotoOutputNapi::GetDefaultCaptureSetting";
647                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
648                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
649                 if (context->objectInfo != nullptr) {
650                     context->bRetBool = false;
651                     context->status = true;
652                 }
653             },
654             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
655         if (status != napi_ok) {
656             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::GetDefaultCaptureSetting");
657             napi_get_undefined(env, &result);
658         } else {
659             napi_queue_async_work(env, asyncContext->work);
660             asyncContext.release();
661         }
662     }
663 
664     return result;
665 }
666 
IsMirrorSupported(napi_env env,napi_callback_info info)667 napi_value PhotoOutputNapi::IsMirrorSupported(napi_env env, napi_callback_info info)
668 {
669     napi_status status;
670     napi_value result = nullptr;
671     size_t argc = ARGS_ZERO;
672     napi_value argv[ARGS_ZERO];
673     napi_value thisVar = nullptr;
674 
675     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
676 
677     napi_get_undefined(env, &result);
678     PhotoOutputNapi* photoOutputNapi = nullptr;
679     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoOutputNapi));
680     if (status == napi_ok && photoOutputNapi != nullptr) {
681         bool isSupported = photoOutputNapi->photoOutput_->IsMirrorSupported();
682         napi_get_boolean(env, isSupported, &result);
683     }
684 
685     return result;
686 }
687 
SetMirror(napi_env env,napi_callback_info info)688 napi_value PhotoOutputNapi::SetMirror(napi_env env, napi_callback_info info)
689 {
690     napi_status status;
691     napi_value result = nullptr;
692     const int32_t refCount = 1;
693     napi_value resource = nullptr;
694     size_t argc = ARGS_TWO;
695     napi_value argv[ARGS_TWO] = {0};
696     napi_value thisVar = nullptr;
697 
698     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
699     NAPI_ASSERT(env, argc <= ARGS_TWO, "requires 2 parameters maximum");
700 
701     napi_get_undefined(env, &result);
702     std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
703     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
704     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
705         if (argc == ARGS_TWO) {
706             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
707         }
708 
709         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
710         asyncContext->isMirror = asyncContext->isSupported;
711         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
712         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "SetMirror");
713         status = napi_create_async_work(
714             env, nullptr, resource, [](napi_env env, void* data) {
715                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
716                 context->status = false;
717                 // Start async trace
718                 context->funcName = "PhotoOutputNapi::SetMirror";
719                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
720                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
721                 if (context->objectInfo != nullptr) {
722                     context->bRetBool = false;
723                     context->status = true;
724                 }
725             },
726             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
727         if (status != napi_ok) {
728             MEDIA_ERR_LOG("Failed to create napi_create_async_work for SetMirror");
729             napi_get_undefined(env, &result);
730         } else {
731             napi_queue_async_work(env, asyncContext->work);
732             asyncContext.release();
733         }
734     }
735 
736     return result;
737 }
738 
On(napi_env env,napi_callback_info info)739 napi_value PhotoOutputNapi::On(napi_env env, napi_callback_info info)
740 {
741     CAMERA_SYNC_TRACE;
742     napi_value undefinedResult = nullptr;
743     size_t argCount = ARGS_TWO;
744     napi_value argv[ARGS_TWO] = {nullptr};
745     napi_value thisVar = nullptr;
746     size_t res = 0;
747     char buffer[SIZE];
748     const int32_t refCount = 1;
749     PhotoOutputNapi* obj = nullptr;
750     napi_status status;
751 
752     napi_get_undefined(env, &undefinedResult);
753 
754     CAMERA_NAPI_GET_JS_ARGS(env, info, argCount, argv, thisVar);
755     NAPI_ASSERT(env, argCount == ARGS_TWO, "requires 2 parameters");
756 
757     if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr) {
758         MEDIA_ERR_LOG("Failed to retrieve details about the callback");
759         return undefinedResult;
760     }
761 
762     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
763     if (status == napi_ok && obj != nullptr) {
764         napi_valuetype valueType = napi_undefined;
765         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string
766             || napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
767             return undefinedResult;
768         }
769 
770         napi_get_value_string_utf8(env, argv[PARAM0], buffer, SIZE, &res);
771         std::string eventType = std::string(buffer);
772 
773         napi_ref callbackRef;
774         napi_create_reference(env, argv[PARAM1], refCount, &callbackRef);
775 
776         if (!eventType.empty()) {
777             obj->photoCallback_->SetCallbackRef(eventType, callbackRef);
778         } else {
779             MEDIA_ERR_LOG("Failed to Register Callback: event type is empty!");
780         }
781     }
782     return undefinedResult;
783 }
784 } // namespace CameraStandard
785 } // namespace OHOS
786