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 photoOutput->~PhotoOutputNapi();
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 {
477 NAPI_ASSERT(env, false, "type mismatch");
478 }
479 }
480
481 // Return true napi_value if params are successfully obtained
482 napi_get_boolean(env, true, &result);
483 return result;
484 }
485
Capture(napi_env env,napi_callback_info info)486 napi_value PhotoOutputNapi::Capture(napi_env env, napi_callback_info info)
487 {
488 napi_status status;
489 napi_value result = nullptr;
490 size_t argc = ARGS_TWO;
491 napi_value argv[ARGS_TWO] = {0};
492 napi_value thisVar = nullptr;
493 napi_value resource = nullptr;
494
495 CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
496
497 napi_get_undefined(env, &result);
498 unique_ptr<PhotoOutputAsyncContext> asyncContext = make_unique<PhotoOutputAsyncContext>();
499 if (!CameraNapiUtils::CheckInvalidArgument(env, argc, ARGS_TWO, argv, PHOTO_OUT_CAPTURE)) {
500 asyncContext->isInvalidArgument = true;
501 asyncContext->status = false;
502 asyncContext->errorCode = INVALID_ARGUMENT;
503 }
504 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
505 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
506 if (!asyncContext->isInvalidArgument) {
507 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
508 }
509 CAMERA_NAPI_CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
510 CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
511 CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Capture");
512 status = napi_create_async_work(
513 env, nullptr, resource, [](napi_env env, void* data) {
514 PhotoOutputAsyncContext* context = static_cast<PhotoOutputAsyncContext*>(data);
515 // Start async trace
516 context->funcName = "PhotoOutputNapi::Capture";
517 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
518 if (context->isInvalidArgument) {
519 return;
520 }
521 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
522 if (context->objectInfo == nullptr) {
523 context->status = false;
524 return;
525 }
526
527 context->bRetBool = false;
528 context->status = true;
529 sptr<PhotoOutput> photoOutput = ((sptr<PhotoOutput> &)(context->objectInfo->photoOutput_));
530 if ((context->hasPhotoSettings)) {
531 std::shared_ptr<PhotoCaptureSetting> capSettings = make_shared<PhotoCaptureSetting>();
532
533 if (context->quality != -1) {
534 capSettings->SetQuality(
535 static_cast<PhotoCaptureSetting::QualityLevel>(context->quality));
536 }
537
538 if (context->rotation != -1) {
539 capSettings->SetRotation(
540 static_cast<PhotoCaptureSetting::RotationConfig>(context->rotation));
541 }
542
543 capSettings->SetMirror(context->isMirror);
544
545 if (context->location != nullptr) {
546 capSettings->SetLocation(context->location);
547 }
548
549 context->errorCode = photoOutput->Capture(capSettings);
550 } else {
551 context->errorCode = photoOutput->Capture();
552 }
553 context->status = context->errorCode == 0;
554 }, CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
555 if (status != napi_ok) {
556 MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::Capture");
557 napi_get_undefined(env, &result);
558 } else {
559 napi_queue_async_work(env, asyncContext->work);
560 asyncContext.release();
561 }
562 }
563
564 return result;
565 }
566
Release(napi_env env,napi_callback_info info)567 napi_value PhotoOutputNapi::Release(napi_env env, napi_callback_info info)
568 {
569 napi_status status;
570 napi_value result = nullptr;
571 const int32_t refCount = 1;
572 napi_value resource = nullptr;
573 size_t argc = ARGS_ONE;
574 napi_value argv[ARGS_ONE] = {0};
575 napi_value thisVar = nullptr;
576
577 CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
578 NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
579
580 napi_get_undefined(env, &result);
581 std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
582 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
583 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
584 if (argc == ARGS_ONE) {
585 CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
586 }
587
588 CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
589 CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
590
591 status = napi_create_async_work(
592 env, nullptr, resource, [](napi_env env, void* data) {
593 auto context = static_cast<PhotoOutputAsyncContext*>(data);
594 context->status = false;
595 // Start async trace
596 context->funcName = "PhotoOutputNapi::Release";
597 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
598 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
599 if (context->objectInfo != nullptr) {
600 context->bRetBool = false;
601 context->status = true;
602 ((sptr<PhotoOutput> &)(context->objectInfo->photoOutput_))->Release();
603 }
604 },
605 CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
606 if (status != napi_ok) {
607 MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::Release");
608 napi_get_undefined(env, &result);
609 } else {
610 napi_queue_async_work(env, asyncContext->work);
611 asyncContext.release();
612 }
613 }
614
615 return result;
616 }
617
GetDefaultCaptureSetting(napi_env env,napi_callback_info info)618 napi_value PhotoOutputNapi::GetDefaultCaptureSetting(napi_env env, napi_callback_info info)
619 {
620 napi_status status;
621 napi_value result = nullptr;
622 const int32_t refCount = 1;
623 napi_value resource = nullptr;
624 size_t argc = ARGS_ONE;
625 napi_value argv[ARGS_ONE] = {0};
626 napi_value thisVar = nullptr;
627
628 CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
629 NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
630
631 napi_get_undefined(env, &result);
632 std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
633 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
634 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
635 if (argc == ARGS_ONE) {
636 CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
637 }
638
639 CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
640 CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "GetDefaultCaptureSetting");
641
642 status = napi_create_async_work(
643 env, nullptr, resource, [](napi_env env, void* data) {
644 auto context = static_cast<PhotoOutputAsyncContext*>(data);
645 context->status = false;
646 // Start async trace
647 context->funcName = "PhotoOutputNapi::GetDefaultCaptureSetting";
648 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
649 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
650 if (context->objectInfo != nullptr) {
651 context->bRetBool = false;
652 context->status = true;
653 }
654 },
655 CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
656 if (status != napi_ok) {
657 MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoOutputNapi::GetDefaultCaptureSetting");
658 napi_get_undefined(env, &result);
659 } else {
660 napi_queue_async_work(env, asyncContext->work);
661 asyncContext.release();
662 }
663 }
664
665 return result;
666 }
667
IsMirrorSupported(napi_env env,napi_callback_info info)668 napi_value PhotoOutputNapi::IsMirrorSupported(napi_env env, napi_callback_info info)
669 {
670 napi_status status;
671 napi_value result = nullptr;
672 size_t argc = ARGS_ZERO;
673 napi_value argv[ARGS_ZERO];
674 napi_value thisVar = nullptr;
675
676 CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
677
678 napi_get_undefined(env, &result);
679 PhotoOutputNapi* photoOutputNapi = nullptr;
680 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoOutputNapi));
681 if (status == napi_ok && photoOutputNapi != nullptr) {
682 bool isSupported = photoOutputNapi->photoOutput_->IsMirrorSupported();
683 napi_get_boolean(env, isSupported, &result);
684 }
685
686 return result;
687 }
688
SetMirror(napi_env env,napi_callback_info info)689 napi_value PhotoOutputNapi::SetMirror(napi_env env, napi_callback_info info)
690 {
691 napi_status status;
692 napi_value result = nullptr;
693 const int32_t refCount = 1;
694 napi_value resource = nullptr;
695 size_t argc = ARGS_TWO;
696 napi_value argv[ARGS_TWO] = {0};
697 napi_value thisVar = nullptr;
698
699 CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
700 NAPI_ASSERT(env, argc <= ARGS_TWO, "requires 2 parameters maximum");
701
702 napi_get_undefined(env, &result);
703 std::unique_ptr<PhotoOutputAsyncContext> asyncContext = std::make_unique<PhotoOutputAsyncContext>();
704 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
705 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
706 if (argc == ARGS_TWO) {
707 CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
708 }
709
710 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
711 asyncContext->isMirror = asyncContext->isSupported;
712 CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
713 CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "SetMirror");
714 status = napi_create_async_work(
715 env, nullptr, resource, [](napi_env env, void* data) {
716 auto context = static_cast<PhotoOutputAsyncContext*>(data);
717 context->status = false;
718 // Start async trace
719 context->funcName = "PhotoOutputNapi::SetMirror";
720 context->taskId = CameraNapiUtils::IncreamentAndGet(photoOutputTaskId);
721 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
722 if (context->objectInfo != nullptr) {
723 context->bRetBool = false;
724 context->status = true;
725 }
726 },
727 CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
728 if (status != napi_ok) {
729 MEDIA_ERR_LOG("Failed to create napi_create_async_work for SetMirror");
730 napi_get_undefined(env, &result);
731 } else {
732 napi_queue_async_work(env, asyncContext->work);
733 asyncContext.release();
734 }
735 }
736
737 return result;
738 }
739
On(napi_env env,napi_callback_info info)740 napi_value PhotoOutputNapi::On(napi_env env, napi_callback_info info)
741 {
742 CAMERA_SYNC_TRACE;
743 napi_value undefinedResult = nullptr;
744 size_t argCount = ARGS_TWO;
745 napi_value argv[ARGS_TWO] = {nullptr};
746 napi_value thisVar = nullptr;
747 size_t res = 0;
748 char buffer[SIZE];
749 const int32_t refCount = 1;
750 PhotoOutputNapi* obj = nullptr;
751 napi_status status;
752
753 napi_get_undefined(env, &undefinedResult);
754
755 CAMERA_NAPI_GET_JS_ARGS(env, info, argCount, argv, thisVar);
756 NAPI_ASSERT(env, argCount == ARGS_TWO, "requires 2 parameters");
757
758 if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr) {
759 MEDIA_ERR_LOG("Failed to retrieve details about the callback");
760 return undefinedResult;
761 }
762
763 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
764 if (status == napi_ok && obj != nullptr) {
765 napi_valuetype valueType = napi_undefined;
766 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string
767 || napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
768 return undefinedResult;
769 }
770
771 napi_get_value_string_utf8(env, argv[PARAM0], buffer, SIZE, &res);
772 std::string eventType = std::string(buffer);
773
774 napi_ref callbackRef;
775 napi_create_reference(env, argv[PARAM1], refCount, &callbackRef);
776
777 if (!eventType.empty()) {
778 obj->photoCallback_->SetCallbackRef(eventType, callbackRef);
779 } else {
780 MEDIA_ERR_LOG("Failed to Register Callback: event type is empty!");
781 }
782 }
783 return undefinedResult;
784 }
785 } // namespace CameraStandard
786 } // namespace OHOS
787