• 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 #include "image_napi.h"
19 #include "pixel_map_napi.h"
20 
21 namespace OHOS {
22 namespace CameraStandard {
23 using namespace std;
24 using OHOS::HiviewDFX::HiLog;
25 using OHOS::HiviewDFX::HiLogLabel;
26 namespace {
27     constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PhotoOutputNapi"};
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     MEDIA_DEBUG_LOG("UpdateJSCallbackAsync is called");
38     uv_loop_s* loop = nullptr;
39     napi_get_uv_event_loop(env_, &loop);
40     if (!loop) {
41         MEDIA_ERR_LOG("failed to get event loop");
42         return;
43     }
44     uv_work_t* work = new(std::nothrow) uv_work_t;
45     if (!work) {
46         MEDIA_ERR_LOG("failed to allocate work");
47         return;
48     }
49     std::unique_ptr<PhotoOutputCallbackInfo> callbackInfo =
50         std::make_unique<PhotoOutputCallbackInfo>(propName, info, this);
51     work->data = callbackInfo.get();
52     int ret = uv_queue_work(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
53         PhotoOutputCallbackInfo* callbackInfo = reinterpret_cast<PhotoOutputCallbackInfo *>(work->data);
54         if (callbackInfo) {
55             callbackInfo->listener_->UpdateJSCallback(callbackInfo->eventName_, callbackInfo->info_);
56             delete callbackInfo;
57         }
58         delete work;
59     });
60     if (ret) {
61         MEDIA_ERR_LOG("failed to execute work");
62         delete work;
63     } else {
64         callbackInfo.release();
65     }
66 }
67 
OnCaptureStarted(const int32_t captureID) const68 void PhotoOutputCallback::OnCaptureStarted(const int32_t captureID) const
69 {
70     CAMERA_SYNC_TRACE;
71     MEDIA_DEBUG_LOG("OnCaptureStarted is called!, captureID: %{public}d", captureID);
72     CallbackInfo info;
73     info.captureID = captureID;
74     UpdateJSCallbackAsync("OnCaptureStarted", info);
75 }
76 
OnCaptureEnded(const int32_t captureID,const int32_t frameCount) const77 void PhotoOutputCallback::OnCaptureEnded(const int32_t captureID, const int32_t frameCount) const
78 {
79     CAMERA_SYNC_TRACE;
80     MEDIA_DEBUG_LOG("OnCaptureEnded is called!, captureID: %{public}d, frameCount: %{public}d",
81         captureID, frameCount);
82     CallbackInfo info;
83     info.captureID = captureID;
84     info.frameCount = frameCount;
85     UpdateJSCallbackAsync("OnCaptureEnded", info);
86 }
87 
OnFrameShutter(const int32_t captureId,const uint64_t timestamp) const88 void PhotoOutputCallback::OnFrameShutter(const int32_t captureId, const uint64_t timestamp) const
89 {
90     CAMERA_SYNC_TRACE;
91     MEDIA_DEBUG_LOG("OnFrameShutter is called, captureID: %{public}d, timestamp: %{public}" PRIu64,
92         captureId, timestamp);
93     CallbackInfo info;
94     info.captureID = captureId;
95     info.timestamp = timestamp;
96     UpdateJSCallbackAsync("OnFrameShutter", info);
97 }
98 
OnCaptureError(const int32_t captureId,const int32_t errorCode) const99 void PhotoOutputCallback::OnCaptureError(const int32_t captureId, const int32_t errorCode) const
100 {
101     MEDIA_DEBUG_LOG("OnCaptureError is called!, captureID: %{public}d, errorCode: %{public}d",
102         captureId, errorCode);
103     CallbackInfo info;
104     info.captureID = captureId;
105     info.errorCode = errorCode;
106     UpdateJSCallbackAsync("OnCaptureError", info);
107 }
108 
SetCallbackRef(const std::string & eventType,const napi_ref & callbackRef)109 void PhotoOutputCallback::SetCallbackRef(const std::string &eventType, const napi_ref &callbackRef)
110 {
111     MEDIA_DEBUG_LOG("SetCallbackRef is called");
112     if (eventType.compare("captureStart") == 0) {
113         captureStartCallbackRef_ = callbackRef;
114     } else if (eventType.compare("captureEnd") == 0) {
115         captureEndCallbackRef_ = callbackRef;
116     } else if (eventType.compare("frameShutter") == 0) {
117         frameShutterCallbackRef_ = callbackRef;
118     } else if (eventType.compare("error") == 0) {
119         errorCallbackRef_ = callbackRef;
120     } else {
121         MEDIA_ERR_LOG("Incorrect photo callback event type received from JS");
122     }
123 }
124 
UpdateJSCallback(std::string propName,const CallbackInfo & info) const125 void PhotoOutputCallback::UpdateJSCallback(std::string propName, const CallbackInfo &info) const
126 {
127     MEDIA_DEBUG_LOG("UpdateJSCallback is called");
128     napi_value result[ARGS_TWO];
129     napi_value callback = nullptr;
130     napi_value retVal;
131     napi_value propValue;
132     napi_get_undefined(env_, &result[PARAM0]);
133     napi_get_undefined(env_, &result[PARAM1]);
134 
135     if (propName.compare("OnCaptureStarted") == 0) {
136         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(captureStartCallbackRef_,
137             "OnCaptureStart callback is not registered by JS");
138         napi_create_int32(env_, info.captureID, &result[PARAM1]);
139         napi_get_reference_value(env_, captureStartCallbackRef_, &callback);
140     } else if (propName.compare("OnCaptureEnded") == 0) {
141         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(captureEndCallbackRef_,
142             "OnCaptureEnd callback is not registered by JS");
143         napi_create_object(env_, &result[PARAM1]);
144         napi_create_int32(env_, info.captureID, &propValue);
145         napi_set_named_property(env_, result[PARAM1], "captureId", propValue);
146         napi_create_int32(env_, info.frameCount, &propValue);
147         napi_set_named_property(env_, result[PARAM1], "frameCount", propValue);
148         napi_get_reference_value(env_, captureEndCallbackRef_, &callback);
149     } else if (propName.compare("OnFrameShutter") == 0) {
150         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(frameShutterCallbackRef_,
151             "OnFrameShutter callback is not registered by JS");
152         napi_create_object(env_, &result[PARAM1]);
153         napi_create_int32(env_, info.captureID, &propValue);
154         napi_set_named_property(env_, result[PARAM1], "captureId", propValue);
155         napi_create_int64(env_, info.timestamp, &propValue);
156         napi_set_named_property(env_, result[PARAM1], "timestamp", propValue);
157         napi_get_reference_value(env_, frameShutterCallbackRef_, &callback);
158     } else {
159         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(errorCallbackRef_,
160             "OnError callback is not registered by JS");
161         napi_value errJsResult[ARGS_ONE];
162         int32_t jsErrorCodeUnknown = -1;
163         napi_create_object(env_, &errJsResult[PARAM0]);
164         napi_create_int32(env_, jsErrorCodeUnknown, &propValue);
165         napi_set_named_property(env_, errJsResult[PARAM0], "code", propValue);
166         napi_get_reference_value(env_, errorCallbackRef_, &callback);
167         if (errorCallbackRef_ != nullptr) {
168             napi_delete_reference(env_, errorCallbackRef_);
169         }
170         napi_call_function(env_, nullptr, callback, ARGS_ONE, errJsResult, &retVal);
171         return;
172     }
173 
174     napi_call_function(env_, nullptr, callback, ARGS_TWO, result, &retVal);
175 }
176 
ThumbnailListener(napi_env env,const napi_ref & callbackRef,const sptr<PhotoOutput> photoOutput)177 ThumbnailListener::ThumbnailListener(napi_env env, const napi_ref &callbackRef, const sptr<PhotoOutput> photoOutput)
178     : env_(env), thumbnailCallbackRef_(callbackRef), photoOutput_(photoOutput) {}
179 
OnBufferAvailable()180 void ThumbnailListener::OnBufferAvailable()
181 {
182     CAMERA_SYNC_TRACE;
183     MEDIA_INFO_LOG("ThumbnailListener:OnBufferAvailable() called");
184     if (!photoOutput_) {
185         MEDIA_ERR_LOG("photoOutput napi sPhotoOutput_ is null");
186         return;
187     }
188     UpdateJSCallbackAsync(photoOutput_);
189 }
190 
UpdateJSCallback(sptr<PhotoOutput> photoOutput) const191 void ThumbnailListener::UpdateJSCallback(sptr<PhotoOutput> photoOutput) const
192 {
193     CAMERA_NAPI_CHECK_NULL_PTR_RETURN_VOID(thumbnailCallbackRef_,
194                                            "OnThunbnail callback is not registered by JS");
195 
196     napi_value valueParam = nullptr;
197     napi_value result[ARGS_TWO] = {0};
198     napi_get_undefined(env_, &result[0]);
199     napi_get_undefined(env_, &result[1]);
200     napi_value callback = nullptr;
201     napi_value retVal;
202     MEDIA_ERR_LOG("enter ImageNapi::Create start");
203     int32_t fence = -1;
204     int64_t timestamp;
205     OHOS::Rect damage;
206     sptr<SurfaceBuffer> thumbnailBuffer = nullptr;
207     SurfaceError surfaceRet = photoOutput_->thumbnailSurface_->AcquireBuffer(thumbnailBuffer, fence, timestamp, damage);
208     if (surfaceRet != SURFACE_ERROR_OK) {
209         MEDIA_ERR_LOG("ThumbnailListener Failed to acquire surface buffer");
210         return;
211     }
212     MEDIA_INFO_LOG("ThumbnailListener start decode surface buffer");
213     int32_t thumbnailWidth;
214     int32_t thumbnailHeight;
215     thumbnailBuffer->GetExtraData()->ExtraGet(OHOS::CameraStandard::dataWidth, thumbnailWidth);
216     thumbnailBuffer->GetExtraData()->ExtraGet(OHOS::CameraStandard::dataHeight, thumbnailHeight);
217     Media::InitializationOptions opts;
218     opts.pixelFormat = Media::PixelFormat::RGBA_8888;
219     opts.size = {
220             .width = thumbnailWidth,
221             .height = thumbnailHeight
222     };
223     MEDIA_INFO_LOG("thumbnailWidth:%{public}d, thumbnailheight: %{public}d, bufSize: %{public}d",
224         thumbnailWidth, thumbnailHeight, thumbnailBuffer->GetSize());
225     auto pixelMap = Media::PixelMap::Create(opts);
226     pixelMap->SetPixelsAddr(thumbnailBuffer->GetVirAddr(), nullptr, thumbnailBuffer->GetSize(),
227                             Media::AllocatorType::HEAP_ALLOC, nullptr);
228     valueParam = Media::PixelMapNapi::CreatePixelMap(env_, std::move(pixelMap));
229     if (valueParam == nullptr) {
230         MEDIA_ERR_LOG("ImageNapi Create failed");
231         napi_get_undefined(env_, &valueParam);
232     }
233     MEDIA_INFO_LOG("enter ImageNapi::Create end");
234     napi_get_reference_value(env_, thumbnailCallbackRef_, &callback);
235     result[1] = valueParam;
236     napi_call_function(env_, nullptr, callback, ARGS_TWO, result, &retVal);
237     photoOutput_->thumbnailSurface_->ReleaseBuffer(thumbnailBuffer, -1);
238 }
239 
UpdateJSCallbackAsync(sptr<PhotoOutput> photoOutput) const240 void ThumbnailListener::UpdateJSCallbackAsync(sptr<PhotoOutput> photoOutput) const
241 {
242     uv_loop_s* loop = nullptr;
243     napi_get_uv_event_loop(env_, &loop);
244     if (!loop) {
245         MEDIA_ERR_LOG("ThumbnailListener:UpdateJSCallbackAsync() failed to get event loop");
246         return;
247     }
248     uv_work_t* work = new(std::nothrow) uv_work_t;
249     if (!work) {
250         MEDIA_ERR_LOG("ThumbnailListener:UpdateJSCallbackAsync() failed to allocate work");
251         return;
252     }
253     std::unique_ptr<ThumbnailListenerInfo> callbackInfo =
254             std::make_unique<ThumbnailListenerInfo>(photoOutput, this);
255     work->data = callbackInfo.get();
256     int ret = uv_queue_work(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
257         ThumbnailListenerInfo* callbackInfo = reinterpret_cast<ThumbnailListenerInfo *>(work->data);
258         if (callbackInfo) {
259             callbackInfo->listener_->UpdateJSCallback(callbackInfo->photoOutput_);
260             MEDIA_ERR_LOG("ThumbnailListener:UpdateJSCallbackAsync() complete");
261             callbackInfo->photoOutput_ =  nullptr;
262             callbackInfo->listener_ = nullptr;
263             delete callbackInfo;
264         }
265         delete work;
266     });
267     if (ret) {
268         MEDIA_ERR_LOG("ThumbnailListener:UpdateJSCallbackAsync() failed to execute work");
269         delete work;
270     } else {
271         callbackInfo.release();
272     }
273 }
274 
PhotoOutputNapi()275 PhotoOutputNapi::PhotoOutputNapi() : env_(nullptr), wrapper_(nullptr)
276 {
277 }
278 
~PhotoOutputNapi()279 PhotoOutputNapi::~PhotoOutputNapi()
280 {
281     MEDIA_DEBUG_LOG("~PhotoOutputNapi is called");
282     if (wrapper_ != nullptr) {
283         napi_delete_reference(env_, wrapper_);
284     }
285     if (photoOutput_) {
286         photoOutput_ = nullptr;
287     }
288     if (photoCallback_) {
289         photoCallback_ = nullptr;
290     }
291 }
292 
PhotoOutputNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)293 void PhotoOutputNapi::PhotoOutputNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
294 {
295     MEDIA_DEBUG_LOG("PhotoOutputNapiDestructor is called");
296     PhotoOutputNapi* photoOutput = reinterpret_cast<PhotoOutputNapi*>(nativeObject);
297     if (photoOutput != nullptr) {
298         delete photoOutput;
299     }
300 }
301 
Init(napi_env env,napi_value exports)302 napi_value PhotoOutputNapi::Init(napi_env env, napi_value exports)
303 {
304     MEDIA_DEBUG_LOG("Init is called");
305     napi_status status;
306     napi_value ctorObj;
307     int32_t refCount = 1;
308 
309     napi_property_descriptor photo_output_props[] = {
310         DECLARE_NAPI_FUNCTION("getDefaultCaptureSetting", GetDefaultCaptureSetting),
311         DECLARE_NAPI_FUNCTION("capture", Capture),
312         DECLARE_NAPI_FUNCTION("release", Release),
313         DECLARE_NAPI_FUNCTION("isMirrorSupported", IsMirrorSupported),
314         DECLARE_NAPI_FUNCTION("setMirror", SetMirror),
315         DECLARE_NAPI_FUNCTION("enableQuickThumbnail", EnableQuickThumbnail),
316         DECLARE_NAPI_FUNCTION("isQuickThumbnailSupported", IsQuickThumbnailSupported),
317         DECLARE_NAPI_FUNCTION("on", On)
318     };
319 
320     status = napi_define_class(env, CAMERA_PHOTO_OUTPUT_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
321                                PhotoOutputNapiConstructor, nullptr,
322                                sizeof(photo_output_props) / sizeof(photo_output_props[PARAM0]),
323                                photo_output_props, &ctorObj);
324     if (status == napi_ok) {
325         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
326         if (status == napi_ok) {
327             status = napi_set_named_property(env, exports, CAMERA_PHOTO_OUTPUT_NAPI_CLASS_NAME, ctorObj);
328             if (status == napi_ok) {
329                 return exports;
330             }
331         }
332     }
333     MEDIA_ERR_LOG("Init call Failed!");
334     return nullptr;
335 }
336 
337 // Constructor callback
PhotoOutputNapiConstructor(napi_env env,napi_callback_info info)338 napi_value PhotoOutputNapi::PhotoOutputNapiConstructor(napi_env env, napi_callback_info info)
339 {
340     MEDIA_DEBUG_LOG("PhotoOutputNapiConstructor is called");
341     napi_status status;
342     napi_value result = nullptr;
343     napi_value thisVar = nullptr;
344 
345     napi_get_undefined(env, &result);
346     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
347 
348     if (status == napi_ok && thisVar != nullptr) {
349         std::unique_ptr<PhotoOutputNapi> obj = std::make_unique<PhotoOutputNapi>();
350         obj->env_ = env;
351         obj->photoOutput_ = sPhotoOutput_;
352         std::shared_ptr<PhotoOutputCallback> callback =
353             std::make_shared<PhotoOutputCallback>(PhotoOutputCallback(env));
354         ((sptr<PhotoOutput> &)(obj->photoOutput_))->SetCallback(callback);
355         obj->photoCallback_ = callback;
356 
357         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
358                            PhotoOutputNapi::PhotoOutputNapiDestructor, nullptr, nullptr);
359         if (status == napi_ok) {
360             obj.release();
361             return thisVar;
362         } else {
363             MEDIA_ERR_LOG("Failure wrapping js to native napi");
364         }
365     }
366     MEDIA_ERR_LOG("PhotoOutputNapiConstructor call Failed!");
367     return result;
368 }
369 
GetPhotoOutput()370 sptr<PhotoOutput> PhotoOutputNapi::GetPhotoOutput()
371 {
372     return photoOutput_;
373 }
374 
IsPhotoOutput(napi_env env,napi_value obj)375 bool PhotoOutputNapi::IsPhotoOutput(napi_env env, napi_value obj)
376 {
377     MEDIA_DEBUG_LOG("IsPhotoOutput is called");
378     bool result = false;
379     napi_status status;
380     napi_value constructor = nullptr;
381 
382     status = napi_get_reference_value(env, sConstructor_, &constructor);
383     if (status == napi_ok) {
384         status = napi_instanceof(env, obj, constructor, &result);
385         if (status != napi_ok) {
386             result = false;
387         }
388     }
389     return result;
390 }
391 
CreatePhotoOutput(napi_env env,Profile & profile,std::string surfaceId)392 napi_value PhotoOutputNapi::CreatePhotoOutput(napi_env env, Profile &profile, std::string surfaceId)
393 {
394     MEDIA_DEBUG_LOG("CreatePhotoOutput is called, profile CameraFormat= %{public}d", profile.GetCameraFormat());
395     CAMERA_SYNC_TRACE;
396     napi_status status;
397     napi_value result = nullptr;
398     napi_value constructor;
399     napi_get_undefined(env, &result);
400     status = napi_get_reference_value(env, sConstructor_, &constructor);
401     if (status == napi_ok) {
402         MEDIA_INFO_LOG("CreatePhotoOutput surfaceId: %{public}s", surfaceId.c_str());
403         sptr<Surface> sface = Media::ImageReceiver::getSurfaceById(surfaceId);
404         if (sface == nullptr) {
405             MEDIA_ERR_LOG("failed to get surface from ImageReceiver");
406             return result;
407         }
408         MEDIA_INFO_LOG("surface width: %{public}d, height: %{public}d", sface->GetDefaultWidth(),
409                        sface->GetDefaultHeight());
410         sface->SetUserData(CameraManager::surfaceFormat, std::to_string(profile.GetCameraFormat()));
411         sptr<IBufferProducer> surfaceProducer = sface->GetProducer();
412         int retCode = CameraManager::GetInstance()->CreatePhotoOutput(profile, surfaceProducer, &sPhotoOutput_);
413         if (!CameraNapiUtils::CheckError(env, retCode)) {
414             return nullptr;
415         }
416         if (sPhotoOutput_ == nullptr) {
417             MEDIA_ERR_LOG("failed to create CreatePhotoOutput");
418             return result;
419         }
420         status = napi_new_instance(env, constructor, 0, nullptr, &result);
421         sPhotoOutput_ = nullptr;
422         if (status == napi_ok && result != nullptr) {
423             MEDIA_DEBUG_LOG("Success to create photo output instance");
424             return result;
425         } else {
426             MEDIA_ERR_LOG("Failed to create photo output instance");
427         }
428     }
429     MEDIA_ERR_LOG("CreatePhotoOutput call Failed!");
430     return result;
431 }
432 
CommonCompleteCallback(napi_env env,napi_status status,void * data)433 static void CommonCompleteCallback(napi_env env, napi_status status, void* data)
434 {
435     MEDIA_DEBUG_LOG("CommonCompleteCallback is called");
436     auto context = static_cast<PhotoOutputAsyncContext*>(data);
437     if (context == nullptr) {
438         MEDIA_ERR_LOG("Async context is null");
439         return;
440     }
441 
442     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
443 
444     if (!context->status) {
445         CameraNapiUtils::CreateNapiErrorObject(env, context->errorCode, context->errorMsg.c_str(), jsContext);
446     } else {
447         jsContext->status = true;
448         napi_get_undefined(env, &jsContext->error);
449         if (context->bRetBool) {
450             napi_get_boolean(env, context->isSupported, &jsContext->data);
451         } else {
452             napi_get_undefined(env, &jsContext->data);
453         }
454     }
455 
456     if (!context->funcName.empty() && context->taskId > 0) {
457         // Finish async trace
458         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
459         jsContext->funcName = context->funcName;
460     }
461 
462     if (context->work != nullptr) {
463         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
464                                              context->work, *jsContext);
465     }
466     delete context;
467 }
468 
QueryAndGetProperty(napi_env env,napi_value arg,const string & propertyName,napi_value & property)469 int32_t QueryAndGetProperty(napi_env env, napi_value arg, const string &propertyName, napi_value &property)
470 {
471     MEDIA_DEBUG_LOG("QueryAndGetProperty is called");
472     bool present = false;
473     int32_t retval = 0;
474     if ((napi_has_named_property(env, arg, propertyName.c_str(), &present) != napi_ok)
475         || (!present) || (napi_get_named_property(env, arg, propertyName.c_str(), &property) != napi_ok)) {
476             MEDIA_ERR_LOG("Failed to obtain property: %{public}s", propertyName.c_str());
477             retval = -1;
478     }
479 
480     return retval;
481 }
482 
GetLocationProperties(napi_env env,napi_value locationObj,const PhotoOutputAsyncContext & context)483 int32_t GetLocationProperties(napi_env env, napi_value locationObj, const PhotoOutputAsyncContext &context)
484 {
485     MEDIA_DEBUG_LOG("GetLocationProperties is called");
486     PhotoOutputAsyncContext* asyncContext = const_cast<PhotoOutputAsyncContext *>(&context);
487     napi_value latproperty = nullptr;
488     napi_value lonproperty = nullptr;
489     napi_value altproperty = nullptr;
490     double latitude = -1.0;
491     double longitude = -1.0;
492     double altitude = -1.0;
493 
494     if ((QueryAndGetProperty(env, locationObj, "latitude", latproperty) == 0) &&
495         (QueryAndGetProperty(env, locationObj, "longitude", lonproperty) == 0) &&
496         (QueryAndGetProperty(env, locationObj, "altitude", altproperty) == 0)) {
497         if ((napi_get_value_double(env, latproperty, &latitude) != napi_ok) ||
498             (napi_get_value_double(env, lonproperty, &longitude) != napi_ok) ||
499             (napi_get_value_double(env, altproperty, &altitude) != napi_ok)) {
500             return -1;
501         } else {
502             asyncContext->location = std::make_unique<Location>();
503             asyncContext->location->latitude = latitude;
504             asyncContext->location->longitude = longitude;
505             asyncContext->location->altitude = altitude;
506         }
507     } else {
508         return -1;
509     }
510 
511     return 0;
512 }
513 
GetFetchOptionsParam(napi_env env,napi_value arg,const PhotoOutputAsyncContext & context,bool & err)514 static void GetFetchOptionsParam(napi_env env, napi_value arg, const PhotoOutputAsyncContext &context, bool &err)
515 {
516     MEDIA_DEBUG_LOG("GetFetchOptionsParam is called");
517     PhotoOutputAsyncContext* asyncContext = const_cast<PhotoOutputAsyncContext *>(&context);
518     int32_t intValue;
519     std::string strValue;
520     napi_value property = nullptr;
521     PhotoCaptureSetting::QualityLevel quality;
522     PhotoCaptureSetting::RotationConfig rotation;
523 
524     if (QueryAndGetProperty(env, arg, "quality", property) == 0) {
525         if (napi_get_value_int32(env, property, &intValue) != napi_ok
526             || CameraNapiUtils::MapQualityLevelFromJs(intValue, quality) == -1) {
527             err = true;
528             return;
529         } else {
530             asyncContext->quality = quality;
531         }
532     }
533 
534     if (QueryAndGetProperty(env, arg, "rotation", property) == 0) {
535         if (napi_get_value_int32(env, property, &intValue) != napi_ok
536             || CameraNapiUtils::MapImageRotationFromJs(intValue, rotation) == -1) {
537             err = true;
538             return;
539         } else {
540             asyncContext->rotation = rotation;
541         }
542     }
543 
544     if (QueryAndGetProperty(env, arg, "location", property) == 0) {
545         if (GetLocationProperties(env, property, context) == -1) {
546             err = true;
547             return;
548         }
549     }
550 
551     if (QueryAndGetProperty(env, arg, "mirror", property) == 0) {
552         bool isMirror = false;
553         if (napi_get_value_bool(env, property, &isMirror) != napi_ok) {
554             err = true;
555             return;
556         } else {
557             asyncContext->isMirror = isMirror;
558         }
559     }
560 }
561 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],PhotoOutputAsyncContext & asyncContext)562 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
563     PhotoOutputAsyncContext &asyncContext)
564 {
565     MEDIA_DEBUG_LOG("ConvertJSArgsToNative is called");
566     const int32_t refCount = 1;
567     napi_value result = nullptr;
568     auto context = &asyncContext;
569     bool err = false;
570 
571     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
572 
573     for (size_t i = PARAM0; i < argc; i++) {
574         napi_valuetype valueType = napi_undefined;
575         napi_typeof(env, argv[i], &valueType);
576         if (i == PARAM0 && valueType == napi_object) {
577             GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
578             if (err) {
579                 MEDIA_ERR_LOG("fetch options retrieval failed");
580                 NAPI_ASSERT(env, false, "type mismatch");
581             }
582             asyncContext.hasPhotoSettings = true;
583         } else if ((i == PARAM0) && (valueType == napi_function)) {
584             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
585             break;
586         } else if ((i == PARAM1) && (valueType == napi_function)) {
587             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
588             break;
589         } else if ((i == PARAM0) && (valueType == napi_boolean)) {
590             napi_get_value_bool(env, argv[i], &context->isSupported);
591             break;
592         } else if ((i == PARAM0) && (valueType == napi_undefined)) {
593             break;
594         } else {
595             NAPI_ASSERT(env, false, "type mismatch");
596         }
597     }
598 
599     // Return true napi_value if params are successfully obtained
600     napi_get_boolean(env, true, &result);
601     return result;
602 }
603 
Capture(napi_env env,napi_callback_info info)604 napi_value PhotoOutputNapi::Capture(napi_env env, napi_callback_info info)
605 {
606     MEDIA_INFO_LOG("Capture is called");
607     napi_status status;
608     napi_value result = nullptr;
609     size_t argc = ARGS_TWO;
610     napi_value argv[ARGS_TWO] = {0};
611     napi_value thisVar = nullptr;
612     napi_value resource = nullptr;
613 
614     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
615 
616     napi_get_undefined(env, &result);
617     unique_ptr<PhotoOutputAsyncContext> asyncContext = make_unique<PhotoOutputAsyncContext>();
618     if (!CameraNapiUtils::CheckInvalidArgument(env, argc, ARGS_TWO, argv, PHOTO_OUT_CAPTURE)) {
619         asyncContext->isInvalidArgument = true;
620         asyncContext->status = false;
621         asyncContext->errorCode = INVALID_ARGUMENT;
622     }
623     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
624     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
625         if (!asyncContext->isInvalidArgument) {
626             result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
627         }
628         CAMERA_NAPI_CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
629         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
630         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Capture");
631         status = napi_create_async_work(
632             env, nullptr, resource, [](napi_env env, void* data) {
633                 PhotoOutputAsyncContext* context = static_cast<PhotoOutputAsyncContext*>(data);
634                 // Start async trace
635                 context->funcName = "PhotoOutputNapi::Capture";
636                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
637                 if (context->isInvalidArgument) {
638                     return;
639                 }
640                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
641                 if (context->objectInfo == nullptr) {
642                     context->status = false;
643                     return;
644                 }
645 
646                 context->bRetBool = false;
647                 context->status = true;
648                 sptr<PhotoOutput> photoOutput = ((sptr<PhotoOutput> &)(context->objectInfo->photoOutput_));
649                 if ((context->hasPhotoSettings)) {
650                     std::shared_ptr<PhotoCaptureSetting> capSettings = make_shared<PhotoCaptureSetting>();
651 
652                     if (context->quality != -1) {
653                         capSettings->SetQuality(
654                             static_cast<PhotoCaptureSetting::QualityLevel>(context->quality));
655                     }
656 
657                     if (context->rotation != -1) {
658                         capSettings->SetRotation(
659                             static_cast<PhotoCaptureSetting::RotationConfig>(context->rotation));
660                     }
661 
662                     capSettings->SetMirror(context->isMirror);
663 
664                     if (context->location != nullptr) {
665                         capSettings->SetLocation(context->location);
666                     }
667 
668                     context->errorCode = photoOutput->Capture(capSettings);
669                 } else {
670                     context->errorCode = photoOutput->Capture();
671                 }
672                 context->status = context->errorCode == 0;
673             }, CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
674         if (status != napi_ok) {
675             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::Capture");
676             napi_get_undefined(env, &result);
677         } else {
678             napi_queue_async_work(env, asyncContext->work);
679             asyncContext.release();
680         }
681     } else {
682         MEDIA_ERR_LOG("Capture call Failed!");
683     }
684     return result;
685 }
686 
Release(napi_env env,napi_callback_info info)687 napi_value PhotoOutputNapi::Release(napi_env env, napi_callback_info info)
688 {
689     MEDIA_INFO_LOG("Release is called");
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_ONE;
695     napi_value argv[ARGS_ONE] = {0};
696     napi_value thisVar = nullptr;
697 
698     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
699     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter 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_ONE) {
706             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
707         }
708 
709         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
710         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
711 
712         status = napi_create_async_work(
713             env, nullptr, resource, [](napi_env env, void* data) {
714                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
715                 context->status = false;
716                 // Start async trace
717                 context->funcName = "PhotoOutputNapi::Release";
718                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
719                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
720                 if (context->objectInfo != nullptr && context->objectInfo->photoOutput_ != nullptr) {
721                     context->bRetBool = false;
722                     context->status = true;
723                     ((sptr<PhotoOutput> &)(context->objectInfo->photoOutput_))->Release();
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 PhotoOutputNapi::Release");
729             napi_get_undefined(env, &result);
730         } else {
731             napi_queue_async_work(env, asyncContext->work);
732             asyncContext.release();
733         }
734     } else {
735         MEDIA_ERR_LOG("Release call Failed!");
736     }
737     return result;
738 }
739 
GetDefaultCaptureSetting(napi_env env,napi_callback_info info)740 napi_value PhotoOutputNapi::GetDefaultCaptureSetting(napi_env env, napi_callback_info info)
741 {
742     MEDIA_DEBUG_LOG("GetDefaultCaptureSetting is called");
743     napi_status status;
744     napi_value result = nullptr;
745     const int32_t refCount = 1;
746     napi_value resource = nullptr;
747     size_t argc = ARGS_ONE;
748     napi_value argv[ARGS_ONE] = {0};
749     napi_value thisVar = nullptr;
750 
751     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
752     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
753 
754     napi_get_undefined(env, &result);
755     std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
756     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
757     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
758         if (argc == ARGS_ONE) {
759             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
760         }
761 
762         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
763         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "GetDefaultCaptureSetting");
764 
765         status = napi_create_async_work(
766             env, nullptr, resource, [](napi_env env, void* data) {
767                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
768                 context->status = false;
769                 // Start async trace
770                 context->funcName = "PhotoOutputNapi::GetDefaultCaptureSetting";
771                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
772                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
773                 if (context->objectInfo != nullptr) {
774                     context->bRetBool = false;
775                     context->status = true;
776                 }
777             },
778             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
779         if (status != napi_ok) {
780             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::GetDefaultCaptureSetting");
781             napi_get_undefined(env, &result);
782         } else {
783             napi_queue_async_work(env, asyncContext->work);
784             asyncContext.release();
785         }
786     } else {
787         MEDIA_ERR_LOG("GetDefaultCaptureSetting call Failed!");
788     }
789     return result;
790 }
791 
IsMirrorSupported(napi_env env,napi_callback_info info)792 napi_value PhotoOutputNapi::IsMirrorSupported(napi_env env, napi_callback_info info)
793 {
794     MEDIA_INFO_LOG("IsMirrorSupported is called");
795     napi_status status;
796     napi_value result = nullptr;
797     size_t argc = ARGS_ZERO;
798     napi_value argv[ARGS_ZERO];
799     napi_value thisVar = nullptr;
800 
801     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
802 
803     napi_get_undefined(env, &result);
804     PhotoOutputNapi* photoOutputNapi = nullptr;
805     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoOutputNapi));
806     if (status == napi_ok && photoOutputNapi != nullptr) {
807         bool isSupported = photoOutputNapi->photoOutput_->IsMirrorSupported();
808         napi_get_boolean(env, isSupported, &result);
809     } else {
810         MEDIA_ERR_LOG("IsMirrorSupported call Failed!");
811     }
812     return result;
813 }
814 
IsQuickThumbnailSupported(napi_env env,napi_callback_info info)815 napi_value PhotoOutputNapi::IsQuickThumbnailSupported(napi_env env, napi_callback_info info)
816 {
817     if (!CameraNapiUtils::CheckSystemApp(env)) {
818         MEDIA_ERR_LOG("SystemApi IsQuickThumbnailSupported is called!");
819         return nullptr;
820     }
821     napi_status status;
822     napi_value result = nullptr;
823     size_t argc = ARGS_ZERO;
824     napi_value argv[ARGS_ZERO];
825     napi_value thisVar = nullptr;
826 
827     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
828 
829     napi_get_undefined(env, &result);
830     PhotoOutputNapi* photoOutputNapi = nullptr;
831     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoOutputNapi));
832     if (status == napi_ok && photoOutputNapi != nullptr) {
833         int32_t retCode = photoOutputNapi->photoOutput_->IsQuickThumbnailSupported();
834         bool isSupported = (retCode == 0);
835         if (retCode > 0 && !CameraNapiUtils::CheckError(env, retCode)) {
836             return result;
837         }
838         napi_get_boolean(env, isSupported, &result);
839     }
840     return result;
841 }
842 
SetMirror(napi_env env,napi_callback_info info)843 napi_value PhotoOutputNapi::SetMirror(napi_env env, napi_callback_info info)
844 {
845     MEDIA_DEBUG_LOG("SetMirror is called");
846     napi_status status;
847     napi_value result = nullptr;
848     const int32_t refCount = 1;
849     napi_value resource = nullptr;
850     size_t argc = ARGS_TWO;
851     napi_value argv[ARGS_TWO] = {0};
852     napi_value thisVar = nullptr;
853 
854     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
855     NAPI_ASSERT(env, argc <= ARGS_TWO, "requires 2 parameters maximum");
856 
857     napi_get_undefined(env, &result);
858     std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
859     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
860     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
861         if (argc == ARGS_TWO) {
862             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
863         }
864 
865         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
866         asyncContext->isMirror = asyncContext->isSupported;
867         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
868         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "SetMirror");
869         status = napi_create_async_work(
870             env, nullptr, resource, [](napi_env env, void* data) {
871                 auto context = static_cast<PhotoOutputAsyncContext*>(data);
872                 context->status = false;
873                 // Start async trace
874                 context->funcName = "PhotoOutputNapi::SetMirror";
875                 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
876                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
877                 if (context->objectInfo != nullptr) {
878                     context->bRetBool = false;
879                     context->status = true;
880                 }
881             },
882             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
883         if (status != napi_ok) {
884             MEDIA_ERR_LOG("Failed to create napi_create_async_work for SetMirror");
885             napi_get_undefined(env, &result);
886         } else {
887             napi_queue_async_work(env, asyncContext->work);
888             asyncContext.release();
889         }
890     } else {
891         MEDIA_ERR_LOG("SetMirror call Failed!");
892     }
893 
894     return result;
895 }
896 
EnableQuickThumbnail(napi_env env,napi_callback_info info)897 napi_value PhotoOutputNapi::EnableQuickThumbnail(napi_env env, napi_callback_info info)
898 {
899     if (!CameraNapiUtils::CheckSystemApp(env)) {
900         MEDIA_ERR_LOG("SystemApi EnableQuickThumbnail is called!");
901         return nullptr;
902     }
903     napi_status status;
904     napi_value result = nullptr;
905     size_t argc = ARGS_ONE;
906     napi_value argv[ARGS_ONE] = {0};
907     napi_value thisVar = nullptr;
908     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
909     NAPI_ASSERT(env, argc == ARGS_ONE, "requires one parameter");
910     napi_valuetype valueType = napi_undefined;
911     napi_typeof(env, argv[0], &valueType);
912     if (valueType != napi_boolean && !CameraNapiUtils::CheckError(env, INVALID_ARGUMENT)) {
913         return result;
914     }
915     napi_get_undefined(env, &result);
916     PhotoOutputNapi* photoOutputNapi = nullptr;
917     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoOutputNapi));
918     bool thumbnailSwitch;
919     if (status == napi_ok && photoOutputNapi != nullptr) {
920         napi_get_value_bool(env, argv[PARAM0], &thumbnailSwitch);
921         photoOutputNapi->isQuickThumbnailEnabled_ = thumbnailSwitch;
922         int32_t retCode = photoOutputNapi->photoOutput_->SetThumbnail(thumbnailSwitch);
923         if (retCode != 0 && !CameraNapiUtils::CheckError(env, retCode)) {
924             return result;
925         }
926     }
927     return result;
928 }
929 
On(napi_env env,napi_callback_info info)930 napi_value PhotoOutputNapi::On(napi_env env, napi_callback_info info)
931 {
932     MEDIA_INFO_LOG("On is called");
933     CAMERA_SYNC_TRACE;
934     napi_value undefinedResult = nullptr;
935     size_t argCount = ARGS_TWO;
936     napi_value argv[ARGS_TWO] = {nullptr};
937     napi_value thisVar = nullptr;
938     size_t res = 0;
939     char buffer[SIZE];
940     const int32_t refCount = 1;
941     PhotoOutputNapi* obj = nullptr;
942     napi_status status;
943 
944     napi_get_undefined(env, &undefinedResult);
945 
946     CAMERA_NAPI_GET_JS_ARGS(env, info, argCount, argv, thisVar);
947     NAPI_ASSERT(env, argCount == ARGS_TWO, "requires 2 parameters");
948 
949     if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr) {
950         MEDIA_ERR_LOG("Failed to retrieve details about the callback");
951         return undefinedResult;
952     }
953 
954     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
955     if (status == napi_ok && obj != nullptr) {
956         napi_valuetype valueType = napi_undefined;
957         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string
958             || napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
959             return undefinedResult;
960         }
961 
962         napi_get_value_string_utf8(env, argv[PARAM0], buffer, SIZE, &res);
963         std::string eventType = std::string(buffer);
964 
965         napi_ref callbackRef;
966         napi_create_reference(env, argv[PARAM1], refCount, &callbackRef);
967 
968         if (eventType == OHOS::CameraStandard::thumbnailRegisterName) {
969             // create thumbnail listener when eventType is thumbnail
970             if (!CameraNapiUtils::CheckSystemApp(env)) {
971                 MEDIA_ERR_LOG("SystemApi quickThumbnail on is called!");
972                 return nullptr;
973             }
974             if (!obj->isQuickThumbnailEnabled_) {
975                 MEDIA_ERR_LOG("quickThumbnail is not enabled!");
976                 napi_throw_error(env, std::to_string(SESSION_NOT_RUNNING).c_str(), "");
977                 return undefinedResult;
978             }
979             sptr<ThumbnailListener> listener = new ThumbnailListener(env, callbackRef, obj->photoOutput_);
980             ((sptr<PhotoOutput> &)(obj->photoOutput_))->SetThumbnailListener((sptr<IBufferConsumerListener>&)listener);
981         } else if (!eventType.empty()) {
982             obj->photoCallback_->SetCallbackRef(eventType, callbackRef);
983         } else {
984             MEDIA_ERR_LOG("Failed to Register Callback: event type is empty!");
985         }
986     } else {
987         MEDIA_ERR_LOG("On call Failed!");
988     }
989     return undefinedResult;
990 }
991 } // namespace CameraStandard
992 } // namespace OHOS
993