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