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