• 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     MEDIA_DEBUG_LOG("PhotoOutputNapiDestructor enter");
189     PhotoOutputNapi* photoOutput = reinterpret_cast<PhotoOutputNapi*>(nativeObject);
190     if (photoOutput != nullptr) {
191         delete photoOutput;
192     }
193 }
194 
Init(napi_env env,napi_value exports)195 napi_value PhotoOutputNapi::Init(napi_env env, napi_value exports)
196 {
197     napi_status status;
198     napi_value ctorObj;
199     int32_t refCount = 1;
200 
201     napi_property_descriptor photo_output_props[] = {
202         DECLARE_NAPI_FUNCTION("getDefaultCaptureSetting", GetDefaultCaptureSetting),
203         DECLARE_NAPI_FUNCTION("capture", Capture),
204         DECLARE_NAPI_FUNCTION("release", Release),
205         DECLARE_NAPI_FUNCTION("isMirrorSupported", IsMirrorSupported),
206         DECLARE_NAPI_FUNCTION("setMirror", SetMirror),
207         DECLARE_NAPI_FUNCTION("on", On)
208     };
209 
210     status = napi_define_class(env, CAMERA_PHOTO_OUTPUT_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
211                                PhotoOutputNapiConstructor, nullptr,
212                                sizeof(photo_output_props) / sizeof(photo_output_props[PARAM0]),
213                                photo_output_props, &ctorObj);
214     if (status == napi_ok) {
215         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
216         if (status == napi_ok) {
217             status = napi_set_named_property(env, exports, CAMERA_PHOTO_OUTPUT_NAPI_CLASS_NAME, ctorObj);
218             if (status == napi_ok) {
219                 return exports;
220             }
221         }
222     }
223 
224     return nullptr;
225 }
226 
227 // Constructor callback
PhotoOutputNapiConstructor(napi_env env,napi_callback_info info)228 napi_value PhotoOutputNapi::PhotoOutputNapiConstructor(napi_env env, napi_callback_info info)
229 {
230     napi_status status;
231     napi_value result = nullptr;
232     napi_value thisVar = nullptr;
233 
234     napi_get_undefined(env, &result);
235     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
236 
237     if (status == napi_ok && thisVar != nullptr) {
238         std::unique_ptr<PhotoOutputNapi> obj = std::make_unique<PhotoOutputNapi>();
239         obj->env_ = env;
240         obj->photoOutput_ = sPhotoOutput_;
241         std::shared_ptr<PhotoOutputCallback> callback =
242             std::make_shared<PhotoOutputCallback>(PhotoOutputCallback(env));
243         ((sptr<PhotoOutput> &)(obj->photoOutput_))->SetCallback(callback);
244         obj->photoCallback_ = callback;
245 
246         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
247                            PhotoOutputNapi::PhotoOutputNapiDestructor, nullptr, nullptr);
248         if (status == napi_ok) {
249             obj.release();
250             return thisVar;
251         } else {
252             MEDIA_ERR_LOG("Failure wrapping js to native napi");
253         }
254     }
255 
256     return result;
257 }
258 
GetPhotoOutput()259 sptr<PhotoOutput> PhotoOutputNapi::GetPhotoOutput()
260 {
261     return photoOutput_;
262 }
263 
IsPhotoOutput(napi_env env,napi_value obj)264 bool PhotoOutputNapi::IsPhotoOutput(napi_env env, napi_value obj)
265 {
266     bool result = false;
267     napi_status status;
268     napi_value constructor = nullptr;
269 
270     status = napi_get_reference_value(env, sConstructor_, &constructor);
271     if (status == napi_ok) {
272         status = napi_instanceof(env, obj, constructor, &result);
273         if (status != napi_ok) {
274             result = false;
275         }
276     }
277 
278     return result;
279 }
280 
CreatePhotoOutput(napi_env env,Profile & profile,std::string surfaceId)281 napi_value PhotoOutputNapi::CreatePhotoOutput(napi_env env, Profile &profile, std::string surfaceId)
282 {
283     CAMERA_SYNC_TRACE;
284     napi_status status;
285     napi_value result = nullptr;
286     napi_value constructor;
287     MEDIA_INFO_LOG("CreatePhotoOutput start");
288     MEDIA_INFO_LOG("CreatePhotoOutput profile CameraFormat= %{public}d", profile.GetCameraFormat());
289     napi_get_undefined(env, &result);
290     status = napi_get_reference_value(env, sConstructor_, &constructor);
291     if (status == napi_ok) {
292         MEDIA_INFO_LOG("CreatePhotoOutput surfaceId: %{public}s", surfaceId.c_str());
293         sptr<Surface> sface = Media::ImageReceiver::getSurfaceById(surfaceId);
294         if (sface == nullptr) {
295             MEDIA_ERR_LOG("failed to get surface from ImageReceiver");
296             return result;
297         }
298         MEDIA_INFO_LOG("surface width: %{public}d, height: %{public}d", sface->GetDefaultWidth(),
299                        sface->GetDefaultHeight());
300         sface->SetUserData(CameraManager::surfaceFormat, std::to_string(profile.GetCameraFormat()));
301         int retCode = CameraManager::GetInstance()->CreatePhotoOutput(profile, sface, &sPhotoOutput_);
302         if (!CameraNapiUtils::CheckError(env, retCode)) {
303             return nullptr;
304         }
305         if (sPhotoOutput_ == nullptr) {
306             MEDIA_ERR_LOG("failed to create CreatePhotoOutput");
307             return result;
308         }
309         status = napi_new_instance(env, constructor, 0, nullptr, &result);
310         sPhotoOutput_ = nullptr;
311         if (status == napi_ok && result != nullptr) {
312             MEDIA_ERR_LOG("Success to create photo output instance");
313             return result;
314         } else {
315             MEDIA_ERR_LOG("Failed to create photo output instance");
316         }
317     }
318     MEDIA_INFO_LOG("CreatePhotoOutput get undefined");
319     return result;
320 }
321 
CommonCompleteCallback(napi_env env,napi_status status,void * data)322 static void CommonCompleteCallback(napi_env env, napi_status status, void* data)
323 {
324     auto context = static_cast<PhotoOutputAsyncContext*>(data);
325     if (context == nullptr) {
326         MEDIA_ERR_LOG("Async context is null");
327         return;
328     }
329 
330     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
331 
332     if (!context->status) {
333         CameraNapiUtils::CreateNapiErrorObject(env, context->errorCode, context->errorMsg.c_str(), jsContext);
334     } else {
335         jsContext->status = true;
336         napi_get_undefined(env, &jsContext->error);
337         if (context->bRetBool) {
338             napi_get_boolean(env, context->isSupported, &jsContext->data);
339         } else {
340             napi_get_undefined(env, &jsContext->data);
341         }
342     }
343 
344     if (!context->funcName.empty() && context->taskId > 0) {
345         // Finish async trace
346         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
347         jsContext->funcName = context->funcName;
348     }
349 
350     if (context->work != nullptr) {
351         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
352                                              context->work, *jsContext);
353     }
354     delete context;
355 }
356 
QueryAndGetProperty(napi_env env,napi_value arg,const string & propertyName,napi_value & property)357 int32_t QueryAndGetProperty(napi_env env, napi_value arg, const string &propertyName, napi_value &property)
358 {
359     bool present = false;
360     int32_t retval = 0;
361     if ((napi_has_named_property(env, arg, propertyName.c_str(), &present) != napi_ok)
362         || (!present) || (napi_get_named_property(env, arg, propertyName.c_str(), &property) != napi_ok)) {
363             HiLog::Error(LABEL, "Failed to obtain property: %{public}s", propertyName.c_str());
364             retval = -1;
365     }
366 
367     return retval;
368 }
369 
GetLocationProperties(napi_env env,napi_value locationObj,const PhotoOutputAsyncContext & context)370 int32_t GetLocationProperties(napi_env env, napi_value locationObj, const PhotoOutputAsyncContext &context)
371 {
372     PhotoOutputAsyncContext* asyncContext = const_cast<PhotoOutputAsyncContext *>(&context);
373     napi_value latproperty = nullptr;
374     napi_value lonproperty = nullptr;
375     napi_value altproperty = nullptr;
376     double latitude = -1.0;
377     double longitude = -1.0;
378     double altitude = -1.0;
379 
380     if ((QueryAndGetProperty(env, locationObj, "latitude", latproperty) == 0) &&
381         (QueryAndGetProperty(env, locationObj, "longitude", lonproperty) == 0) &&
382         (QueryAndGetProperty(env, locationObj, "altitude", altproperty) == 0)) {
383         if ((napi_get_value_double(env, latproperty, &latitude) != napi_ok) ||
384             (napi_get_value_double(env, lonproperty, &longitude) != napi_ok) ||
385             (napi_get_value_double(env, altproperty, &altitude) != napi_ok)) {
386             return -1;
387         } else {
388             asyncContext->location = std::make_unique<Location>();
389             asyncContext->location->latitude = latitude;
390             asyncContext->location->longitude = longitude;
391             asyncContext->location->altitude = altitude;
392         }
393     } else {
394         return -1;
395     }
396 
397     return 0;
398 }
399 
GetFetchOptionsParam(napi_env env,napi_value arg,const PhotoOutputAsyncContext & context,bool & err)400 static void GetFetchOptionsParam(napi_env env, napi_value arg, const PhotoOutputAsyncContext &context, bool &err)
401 {
402     PhotoOutputAsyncContext* asyncContext = const_cast<PhotoOutputAsyncContext *>(&context);
403     int32_t intValue;
404     std::string strValue;
405     napi_value property = nullptr;
406     PhotoCaptureSetting::QualityLevel quality;
407     PhotoCaptureSetting::RotationConfig rotation;
408 
409     if (QueryAndGetProperty(env, arg, "quality", property) == 0) {
410         if (napi_get_value_int32(env, property, &intValue) != napi_ok
411             || CameraNapiUtils::MapQualityLevelFromJs(intValue, quality) == -1) {
412             err = true;
413             return;
414         } else {
415             asyncContext->quality = quality;
416         }
417     }
418 
419     if (QueryAndGetProperty(env, arg, "rotation", property) == 0) {
420         if (napi_get_value_int32(env, property, &intValue) != napi_ok
421             || CameraNapiUtils::MapImageRotationFromJs(intValue, rotation) == -1) {
422             err = true;
423             return;
424         } else {
425             asyncContext->rotation = rotation;
426         }
427     }
428 
429     if (QueryAndGetProperty(env, arg, "location", property) == 0) {
430         if (GetLocationProperties(env, property, context) == -1) {
431             err = true;
432             return;
433         }
434     }
435 
436     if (QueryAndGetProperty(env, arg, "mirror", property) == 0) {
437         bool isMirror = false;
438         if (napi_get_value_bool(env, property, &isMirror) != napi_ok) {
439             err = true;
440             return;
441         } else {
442             asyncContext->isMirror = isMirror;
443         }
444     }
445 }
446 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],PhotoOutputAsyncContext & asyncContext)447 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
448     PhotoOutputAsyncContext &asyncContext)
449 {
450     const int32_t refCount = 1;
451     napi_value result = nullptr;
452     auto context = &asyncContext;
453     bool err = false;
454 
455     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
456 
457     for (size_t i = PARAM0; i < argc; i++) {
458         napi_valuetype valueType = napi_undefined;
459         napi_typeof(env, argv[i], &valueType);
460         if (i == PARAM0 && valueType == napi_object) {
461             GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
462             if (err) {
463                 HiLog::Error(LABEL, "fetch options retrieval failed");
464                 NAPI_ASSERT(env, false, "type mismatch");
465             }
466             asyncContext.hasPhotoSettings = true;
467         } else if ((i == PARAM0) && (valueType == napi_function)) {
468             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
469             break;
470         } else if ((i == PARAM1) && (valueType == napi_function)) {
471             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
472             break;
473         } else if ((i == PARAM0) && (valueType == napi_boolean)) {
474             napi_get_value_bool(env, argv[i], &context->isSupported);
475             break;
476         } else if ((i == PARAM0) && (valueType == napi_undefined)) {
477             break;
478         } else {
479             NAPI_ASSERT(env, false, "type mismatch");
480         }
481     }
482 
483     // Return true napi_value if params are successfully obtained
484     napi_get_boolean(env, true, &result);
485     return result;
486 }
487 
Capture(napi_env env,napi_callback_info info)488 napi_value PhotoOutputNapi::Capture(napi_env env, napi_callback_info info)
489 {
490     napi_status status;
491     napi_value result = nullptr;
492     size_t argc = ARGS_TWO;
493     napi_value argv[ARGS_TWO] = {0};
494     napi_value thisVar = nullptr;
495     napi_value resource = nullptr;
496 
497     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
498 
499     napi_get_undefined(env, &result);
500     unique_ptr<PhotoOutputAsyncContext> asyncContext = make_unique<PhotoOutputAsyncContext>();
501     if (!CameraNapiUtils::CheckInvalidArgument(env, argc, ARGS_TWO, argv, PHOTO_OUT_CAPTURE)) {
502         asyncContext->isInvalidArgument = true;
503         asyncContext->status = false;
504         asyncContext->errorCode = INVALID_ARGUMENT;
505     }
506     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
507     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
508         if (!asyncContext->isInvalidArgument) {
509             result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
510         }
511         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
512         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
513         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Capture");
514         status = napi_create_async_work(
515             env, nullptr, resource, [](napi_env env, void* data) {
516                 PhotoOutputAsyncContext* context = static_cast<PhotoOutputAsyncContext*>(data);
517                 // Start async trace
518                 context->funcName = "PhotoOutputNapi::Capture";
519                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
520                 if (context->isInvalidArgument) {
521                     return;
522                 }
523                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
524                 if (context->objectInfo == nullptr) {
525                     context->status = false;
526                     return;
527                 }
528 
529                 context->bRetBool = false;
530                 context->status = true;
531                 sptr<PhotoOutput> photoOutput = ((sptr<PhotoOutput> &)(context->objectInfo->photoOutput_));
532                 if ((context->hasPhotoSettings)) {
533                     std::shared_ptr<PhotoCaptureSetting> capSettings = make_shared<PhotoCaptureSetting>();
534 
535                     if (context->quality != -1) {
536                         capSettings->SetQuality(
537                             static_cast<PhotoCaptureSetting::QualityLevel>(context->quality));
538                     }
539 
540                     if (context->rotation != -1) {
541                         capSettings->SetRotation(
542                             static_cast<PhotoCaptureSetting::RotationConfig>(context->rotation));
543                     }
544 
545                     capSettings->SetMirror(context->isMirror);
546 
547                     if (context->location != nullptr) {
548                         capSettings->SetLocation(context->location);
549                     }
550 
551                     context->errorCode = photoOutput->Capture(capSettings);
552                 } else {
553                     context->errorCode = photoOutput->Capture();
554                 }
555                 context->status = context->errorCode == 0;
556             }, CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
557         if (status != napi_ok) {
558             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::Capture");
559             napi_get_undefined(env, &result);
560         } else {
561             napi_queue_async_work(env, asyncContext->work);
562             asyncContext.release();
563         }
564     }
565 
566     return result;
567 }
568 
Release(napi_env env,napi_callback_info info)569 napi_value PhotoOutputNapi::Release(napi_env env, napi_callback_info info)
570 {
571     napi_status status;
572     napi_value result = nullptr;
573     const int32_t refCount = 1;
574     napi_value resource = nullptr;
575     size_t argc = ARGS_ONE;
576     napi_value argv[ARGS_ONE] = {0};
577     napi_value thisVar = nullptr;
578 
579     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
580     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
581 
582     napi_get_undefined(env, &result);
583     std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
584     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
585     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
586         if (argc == ARGS_ONE) {
587             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
588         }
589 
590         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
591         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
592 
593         status = napi_create_async_work(
594             env, nullptr, resource, [](napi_env env, void* data) {
595                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
596                 context->status = false;
597                 // Start async trace
598                 context->funcName = "PhotoOutputNapi::Release";
599                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
600                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
601                 if (context->objectInfo != nullptr && context->objectInfo->photoOutput_ != nullptr) {
602                     context->bRetBool = false;
603                     context->status = true;
604                     ((sptr<PhotoOutput> &)(context->objectInfo->photoOutput_))->Release();
605                 }
606             },
607             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
608         if (status != napi_ok) {
609             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::Release");
610             napi_get_undefined(env, &result);
611         } else {
612             napi_queue_async_work(env, asyncContext->work);
613             asyncContext.release();
614         }
615     }
616 
617     return result;
618 }
619 
GetDefaultCaptureSetting(napi_env env,napi_callback_info info)620 napi_value PhotoOutputNapi::GetDefaultCaptureSetting(napi_env env, napi_callback_info info)
621 {
622     napi_status status;
623     napi_value result = nullptr;
624     const int32_t refCount = 1;
625     napi_value resource = nullptr;
626     size_t argc = ARGS_ONE;
627     napi_value argv[ARGS_ONE] = {0};
628     napi_value thisVar = nullptr;
629 
630     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
631     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
632 
633     napi_get_undefined(env, &result);
634     std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
635     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
636     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
637         if (argc == ARGS_ONE) {
638             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
639         }
640 
641         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
642         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "GetDefaultCaptureSetting");
643 
644         status = napi_create_async_work(
645             env, nullptr, resource, [](napi_env env, void* data) {
646                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
647                 context->status = false;
648                 // Start async trace
649                 context->funcName = "PhotoOutputNapi::GetDefaultCaptureSetting";
650                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
651                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
652                 if (context->objectInfo != nullptr) {
653                     context->bRetBool = false;
654                     context->status = true;
655                 }
656             },
657             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
658         if (status != napi_ok) {
659             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::GetDefaultCaptureSetting");
660             napi_get_undefined(env, &result);
661         } else {
662             napi_queue_async_work(env, asyncContext->work);
663             asyncContext.release();
664         }
665     }
666 
667     return result;
668 }
669 
IsMirrorSupported(napi_env env,napi_callback_info info)670 napi_value PhotoOutputNapi::IsMirrorSupported(napi_env env, napi_callback_info info)
671 {
672     napi_status status;
673     napi_value result = nullptr;
674     size_t argc = ARGS_ZERO;
675     napi_value argv[ARGS_ZERO];
676     napi_value thisVar = nullptr;
677 
678     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
679 
680     napi_get_undefined(env, &result);
681     PhotoOutputNapi* photoOutputNapi = nullptr;
682     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoOutputNapi));
683     if (status == napi_ok && photoOutputNapi != nullptr) {
684         bool isSupported = photoOutputNapi->photoOutput_->IsMirrorSupported();
685         napi_get_boolean(env, isSupported, &result);
686     }
687 
688     return result;
689 }
690 
SetMirror(napi_env env,napi_callback_info info)691 napi_value PhotoOutputNapi::SetMirror(napi_env env, napi_callback_info info)
692 {
693     napi_status status;
694     napi_value result = nullptr;
695     const int32_t refCount = 1;
696     napi_value resource = nullptr;
697     size_t argc = ARGS_TWO;
698     napi_value argv[ARGS_TWO] = {0};
699     napi_value thisVar = nullptr;
700 
701     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
702     NAPI_ASSERT(env, argc <= ARGS_TWO, "requires 2 parameters maximum");
703 
704     napi_get_undefined(env, &result);
705     std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
706     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
707     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
708         if (argc == ARGS_TWO) {
709             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
710         }
711 
712         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
713         asyncContext->isMirror = asyncContext->isSupported;
714         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
715         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "SetMirror");
716         status = napi_create_async_work(
717             env, nullptr, resource, [](napi_env env, void* data) {
718                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
719                 context->status = false;
720                 // Start async trace
721                 context->funcName = "PhotoOutputNapi::SetMirror";
722                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
723                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
724                 if (context->objectInfo != nullptr) {
725                     context->bRetBool = false;
726                     context->status = true;
727                 }
728             },
729             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
730         if (status != napi_ok) {
731             MEDIA_ERR_LOG("Failed to create napi_create_async_work for SetMirror");
732             napi_get_undefined(env, &result);
733         } else {
734             napi_queue_async_work(env, asyncContext->work);
735             asyncContext.release();
736         }
737     }
738 
739     return result;
740 }
741 
On(napi_env env,napi_callback_info info)742 napi_value PhotoOutputNapi::On(napi_env env, napi_callback_info info)
743 {
744     CAMERA_SYNC_TRACE;
745     napi_value undefinedResult = nullptr;
746     size_t argCount = ARGS_TWO;
747     napi_value argv[ARGS_TWO] = {nullptr};
748     napi_value thisVar = nullptr;
749     size_t res = 0;
750     char buffer[SIZE];
751     const int32_t refCount = 1;
752     PhotoOutputNapi* obj = nullptr;
753     napi_status status;
754 
755     napi_get_undefined(env, &undefinedResult);
756 
757     CAMERA_NAPI_GET_JS_ARGS(env, info, argCount, argv, thisVar);
758     NAPI_ASSERT(env, argCount == ARGS_TWO, "requires 2 parameters");
759 
760     if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr) {
761         MEDIA_ERR_LOG("Failed to retrieve details about the callback");
762         return undefinedResult;
763     }
764 
765     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
766     if (status == napi_ok && obj != nullptr) {
767         napi_valuetype valueType = napi_undefined;
768         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string
769             || napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
770             return undefinedResult;
771         }
772 
773         napi_get_value_string_utf8(env, argv[PARAM0], buffer, SIZE, &res);
774         std::string eventType = std::string(buffer);
775 
776         napi_ref callbackRef;
777         napi_create_reference(env, argv[PARAM1], refCount, &callbackRef);
778 
779         if (!eventType.empty()) {
780             obj->photoCallback_->SetCallbackRef(eventType, callbackRef);
781         } else {
782             MEDIA_ERR_LOG("Failed to Register Callback: event type is empty!");
783         }
784     }
785     return undefinedResult;
786 }
787 } // namespace CameraStandard
788 } // namespace OHOS
789