1 /*
2 * Copyright (c) 2021-2023 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 "camera_napi_utils.h"
17
18 #include "camera_error_code.h"
19 #include "camera_log.h"
20 #include "napi/native_api.h"
21
22 namespace OHOS {
23 namespace CameraStandard {
24 bool CameraNapiUtils::mEnableSecure = false;
CreateNapiErrorObject(napi_env env,int32_t errorCode,const char * errString,std::unique_ptr<JSAsyncContextOutput> & jsContext)25 void CameraNapiUtils::CreateNapiErrorObject(napi_env env, int32_t errorCode, const char* errString,
26 std::unique_ptr<JSAsyncContextOutput> &jsContext)
27 {
28 napi_get_undefined(env, &jsContext->data);
29 napi_value napiErrorCode = nullptr;
30 napi_value napiErrorMsg = nullptr;
31
32 std::string errorCodeStr = std::to_string(errorCode);
33 napi_create_string_utf8(env, errorCodeStr.c_str(), NAPI_AUTO_LENGTH, &napiErrorCode);
34 napi_create_string_utf8(env, errString, NAPI_AUTO_LENGTH, &napiErrorMsg);
35
36 napi_create_object(env, &jsContext->error);
37 napi_set_named_property(env, jsContext->error, "code", napiErrorCode);
38 napi_set_named_property(env, jsContext->error, "message", napiErrorMsg);
39
40 jsContext->status = false;
41 }
42
InvokeJSAsyncMethod(napi_env env,napi_deferred deferred,napi_ref callbackRef,napi_async_work work,const JSAsyncContextOutput & asyncContext)43 void CameraNapiUtils::InvokeJSAsyncMethod(napi_env env, napi_deferred deferred,
44 napi_ref callbackRef, napi_async_work work, const JSAsyncContextOutput &asyncContext)
45 {
46 napi_value retVal;
47 napi_value callback = nullptr;
48 std::string funcName = asyncContext.funcName;
49 MEDIA_INFO_LOG("%{public}s, context->InvokeJSAsyncMethod start", funcName.c_str());
50 /* Deferred is used when JS Callback method expects a promise value */
51 if (deferred) {
52 if (asyncContext.status) {
53 napi_resolve_deferred(env, deferred, asyncContext.data);
54 MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod napi_resolve_deferred", funcName.c_str());
55 } else {
56 napi_reject_deferred(env, deferred, asyncContext.error);
57 MEDIA_ERR_LOG("%{public}s, InvokeJSAsyncMethod napi_reject_deferred", funcName.c_str());
58 }
59 MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod end deferred", funcName.c_str());
60 } else {
61 MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod callback", funcName.c_str());
62 napi_value result[ARGS_TWO];
63 result[PARAM0] = asyncContext.error;
64 result[PARAM1] = asyncContext.data;
65 napi_get_reference_value(env, callbackRef, &callback);
66 MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod napi_call_function start", funcName.c_str());
67 napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
68 MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod napi_call_function end", funcName.c_str());
69 napi_delete_reference(env, callbackRef);
70 }
71 napi_delete_async_work(env, work);
72 MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod inner end", funcName.c_str());
73 }
74
IncrementAndGet(uint32_t & num)75 int32_t CameraNapiUtils::IncrementAndGet(uint32_t& num)
76 {
77 int32_t temp = num & 0x00ffffff;
78 if (temp >= 0xffff) {
79 num = num & 0xff000000;
80 }
81 num++;
82 return num;
83 }
84
GetEnableSecureCamera()85 bool CameraNapiUtils::GetEnableSecureCamera()
86 {
87 return mEnableSecure;
88 }
89
IsEnableSecureCamera(bool isEnable)90 void CameraNapiUtils::IsEnableSecureCamera(bool isEnable)
91 {
92 mEnableSecure = isEnable;
93 }
94
CheckInvalidArgument(napi_env env,size_t argc,int32_t length,napi_value * argv,CameraSteps step)95 bool CameraNapiUtils::CheckInvalidArgument(napi_env env, size_t argc, int32_t length,
96 napi_value *argv, CameraSteps step)
97 {
98 bool isPass = true;
99 napi_valuetype valueTypeArray[length];
100 for (int32_t i = 0; i < length; i++) {
101 napi_typeof(env, argv[i], &valueTypeArray[i]);
102 }
103 switch (step) {
104 case CREATE_CAMERA_INPUT_INSTANCE:
105 if (argc == ARGS_ONE) {
106 isPass = valueTypeArray[0] == napi_object;
107 } else if (argc == ARGS_TWO) {
108 isPass = (valueTypeArray[0] == napi_number) && (valueTypeArray[1] == napi_number);
109 } else {
110 isPass = false;
111 }
112 break;
113
114 case CREATE_PREVIEW_OUTPUT_INSTANCE:
115 isPass = (argc == ARGS_TWO) &&
116 (valueTypeArray[0] == napi_object) && (valueTypeArray[1] == napi_string);
117 break;
118
119 case CREATE_PHOTO_OUTPUT_INSTANCE:
120 isPass = (argc >= ARGS_ONE) && (valueTypeArray[0] == napi_object);
121 break;
122
123 case CREATE_VIDEO_OUTPUT_INSTANCE:
124 isPass = (argc == ARGS_TWO) &&
125 (valueTypeArray[0] == napi_object) && (valueTypeArray[1] == napi_string);
126 break;
127
128 case CREATE_METADATA_OUTPUT_INSTANCE:
129 isPass = argc == ARGS_ONE;
130 if (argc == ARGS_ONE) {
131 napi_is_array(env, argv[0], &isPass);
132 } else {
133 isPass = false;
134 }
135 break;
136
137 case ADD_INPUT:
138 isPass = (argc == ARGS_ONE) && (valueTypeArray[0] == napi_object);
139 break;
140
141 case REMOVE_INPUT:
142 isPass = (argc == ARGS_ONE) && (valueTypeArray[0] == napi_object);
143 break;
144
145 case ADD_OUTPUT:
146 isPass = (argc == ARGS_ONE) && (valueTypeArray[0] == napi_object);
147 break;
148
149 case REMOVE_OUTPUT:
150 isPass = (argc == ARGS_ONE) && (valueTypeArray[0] == napi_object);
151 break;
152
153 case PHOTO_OUT_CAPTURE:
154 if (argc == ARGS_ZERO) {
155 isPass = true;
156 } else if (argc == ARGS_ONE) {
157 isPass = (valueTypeArray[0] == napi_object) || (valueTypeArray[0] == napi_function) ||
158 (valueTypeArray[0] == napi_undefined);
159 } else if (argc == ARGS_TWO) {
160 isPass = (valueTypeArray[0] == napi_object) && (valueTypeArray[1] == napi_function);
161 } else {
162 isPass = false;
163 }
164 break;
165
166 case PHOTO_OUT_BURST_CAPTURE:
167 if (argc == ARGS_ONE) {
168 isPass = valueTypeArray[0] == napi_object;
169 } else {
170 isPass = false;
171 }
172 break;
173
174 case ADD_DEFERRED_SURFACE:
175 if (argc == ARGS_ONE) {
176 isPass = valueTypeArray[0] == napi_string;
177 } else if (argc == ARGS_TWO) {
178 isPass = (valueTypeArray[0] == napi_string) && (valueTypeArray[1] == napi_function);
179 } else {
180 isPass = false;
181 }
182 break;
183
184 case CREATE_DEFERRED_PREVIEW_OUTPUT:
185 if (argc == ARGS_ONE) {
186 isPass = valueTypeArray[0] == napi_object;
187 } else {
188 isPass = false;
189 }
190 break;
191
192 default:
193 break;
194 }
195 if (!isPass) {
196 std::string errorCode = std::to_string(CameraErrorCode::INVALID_ARGUMENT);
197 napi_throw_type_error(env, errorCode.c_str(), "");
198 }
199 return isPass;
200 }
201
CheckError(napi_env env,int32_t retCode)202 bool CameraNapiUtils::CheckError(napi_env env, int32_t retCode)
203 {
204 if ((retCode != 0)) {
205 std::string errorCode = std::to_string(retCode);
206 napi_throw_error(env, errorCode.c_str(), "");
207 return false;
208 }
209 return true;
210 }
211
FloatToDouble(float val)212 double CameraNapiUtils::FloatToDouble(float val)
213 {
214 const double precision = 1000000.0;
215 return std::round(val * precision) / precision;
216 }
217
GetStringArgument(napi_env env,napi_value value)218 std::string CameraNapiUtils::GetStringArgument(napi_env env, napi_value value)
219 {
220 napi_valuetype valueNapiType = napi_undefined;
221 napi_typeof(env, value, &valueNapiType);
222 if (valueNapiType != napi_string) {
223 return "";
224 }
225 size_t stringSize = 0;
226 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &stringSize);
227 if (status != napi_ok || stringSize == 0) {
228 return "";
229 }
230 std::string strValue = std::string(stringSize, '\0');
231 status = napi_get_value_string_utf8(env, value, strValue.data(), stringSize + 1, &stringSize);
232 if (status != napi_ok || stringSize == 0) {
233 return "";
234 }
235 return strValue;
236 }
237
IsSameNapiValue(napi_env env,napi_value valueSrc,napi_value valueDst)238 bool CameraNapiUtils::IsSameNapiValue(napi_env env, napi_value valueSrc, napi_value valueDst)
239 {
240 if (valueSrc == nullptr && valueDst == nullptr) {
241 return true;
242 }
243 if (valueSrc == nullptr || valueDst == nullptr) {
244 return false;
245 }
246 bool isEquals = false;
247 if (napi_strict_equals(env, valueSrc, valueDst, &isEquals) != napi_ok) {
248 MEDIA_ERR_LOG("get napi_strict_equals failed");
249 return false;
250 }
251 return isEquals;
252 }
253
CallPromiseFun(napi_env env,napi_value promiseValue,void * data,napi_callback thenCallback,napi_callback catchCallback)254 napi_status CameraNapiUtils::CallPromiseFun(
255 napi_env env, napi_value promiseValue, void* data, napi_callback thenCallback, napi_callback catchCallback)
256 {
257 MEDIA_DEBUG_LOG("CallPromiseFun Start");
258 bool isPromise = false;
259 napi_is_promise(env, promiseValue, &isPromise);
260 if (!isPromise) {
261 MEDIA_ERR_LOG("CallPromiseFun promiseValue is not promise");
262 return napi_invalid_arg;
263 }
264 // Create promiseThen
265 napi_value promiseThen = nullptr;
266 napi_get_named_property(env, promiseValue, "then", &promiseThen);
267 if (promiseThen == nullptr) {
268 MEDIA_ERR_LOG("CallPromiseFun get promiseThen failed");
269 return napi_invalid_arg;
270 }
271 napi_value thenValue;
272 napi_status ret = napi_create_function(env, "thenCallback", NAPI_AUTO_LENGTH, thenCallback, data, &thenValue);
273 if (ret != napi_ok) {
274 MEDIA_ERR_LOG("CallPromiseFun thenCallback got exception");
275 return ret;
276 }
277 napi_value catchValue;
278 ret = napi_create_function(env, "catchCallback", NAPI_AUTO_LENGTH, catchCallback, data, &catchValue);
279 if (ret != napi_ok) {
280 MEDIA_ERR_LOG("CallPromiseFun catchCallback got exception");
281 return ret;
282 }
283 napi_value thenReturnValue;
284 constexpr uint32_t THEN_ARGC = 2;
285 napi_value thenArgv[THEN_ARGC] = { thenValue, catchValue };
286 ret = napi_call_function(env, promiseValue, promiseThen, THEN_ARGC, thenArgv, &thenReturnValue);
287 if (ret != napi_ok) {
288 MEDIA_ERR_LOG("CallPromiseFun PromiseThen got exception");
289 return ret;
290 }
291 MEDIA_DEBUG_LOG("CallPromiseFun End");
292 return napi_ok;
293 }
294
GetPropertyDescriptor(std::vector<std::vector<napi_property_descriptor>> descriptors)295 std::vector<napi_property_descriptor> CameraNapiUtils::GetPropertyDescriptor(
296 std::vector<std::vector<napi_property_descriptor>> descriptors)
297 {
298 MEDIA_DEBUG_LOG("GetPropertyDescriptor Start %zu", descriptors.size());
299 std::vector<napi_property_descriptor> properties = {};
300 std::for_each(descriptors.begin(), descriptors.end(),
301 [&properties](const std::vector<napi_property_descriptor> descriptor) {
302 properties.insert(properties.end(), descriptor.begin(), descriptor.end());
303 });
304 return properties;
305 };
306
CreateObjectWithPropName(napi_env env,napi_value * result,size_t property_count,const char ** keys)307 napi_status CameraNapiUtils::CreateObjectWithPropName(
308 napi_env env, napi_value* result, size_t property_count, const char** keys)
309 {
310 napi_value values[property_count];
311 for (size_t i = 0; i < property_count; i++) {
312 napi_get_undefined(env, &values[i]);
313 }
314 return napi_create_object_with_named_properties(env, result, property_count, keys, values);
315 }
316
CreateObjectWithPropNameAndValues(napi_env env,napi_value * result,size_t property_count,const char ** keys,const std::vector<std::string> values)317 napi_status CameraNapiUtils::CreateObjectWithPropNameAndValues(
318 napi_env env, napi_value* result, size_t property_count, const char** keys, const std::vector<std::string> values)
319 {
320 napi_value napiValues[property_count];
321 for (size_t i = 0; i < property_count; i++) {
322 napi_create_string_utf8(env, values[i].data(), values[i].size(), &napiValues[i]);
323 }
324 return napi_create_object_with_named_properties(env, result, property_count, keys, napiValues);
325 }
326
GetNapiArgs(napi_env env,napi_callback_info callbackInfo)327 size_t CameraNapiUtils::GetNapiArgs(napi_env env, napi_callback_info callbackInfo)
328 {
329 size_t argsSize = 0;
330 napi_get_cb_info(env, callbackInfo, &argsSize, nullptr, nullptr, nullptr);
331 return argsSize;
332 }
333
CreateFrameRateJSArray(napi_env env,std::vector<int32_t> frameRateRange,napi_value & result)334 void CameraNapiUtils::CreateFrameRateJSArray(napi_env env, std::vector<int32_t> frameRateRange, napi_value &result)
335 {
336 MEDIA_DEBUG_LOG("CreateFrameRateJSArray called");
337 if (frameRateRange.empty()) {
338 MEDIA_ERR_LOG("frameRateRange is empty");
339 }
340
341 napi_status status = napi_create_object(env, &result);
342 if (status == napi_ok) {
343 napi_value minRate;
344 status = napi_create_int32(env, frameRateRange[0], &minRate);
345 napi_value maxRate;
346 status = napi_create_int32(env, frameRateRange[1], &maxRate);
347 if (status != napi_ok || napi_set_named_property(env, result, "min", minRate) != napi_ok ||
348 napi_set_named_property(env, result, "max", maxRate) != napi_ok) {
349 MEDIA_ERR_LOG("Failed to create frameRateArray with napi wrapper object.");
350 }
351 }
352 }
353
CreateSupportFrameRatesJSArray(napi_env env,std::vector<std::vector<int32_t>> supportedFrameRatesRange)354 napi_value CameraNapiUtils::CreateSupportFrameRatesJSArray(
355 napi_env env, std::vector<std::vector<int32_t>> supportedFrameRatesRange)
356 {
357 MEDIA_DEBUG_LOG("CreateFrameRateJSArray called");
358 napi_value supportedFrameRateArray = nullptr;
359 if (supportedFrameRatesRange.empty()) {
360 MEDIA_ERR_LOG("frameRateRange is empty");
361 }
362
363 napi_status status = napi_create_array(env, &supportedFrameRateArray);
364 if (status == napi_ok) {
365 for (size_t i = 0; i < supportedFrameRatesRange.size(); i++) {
366 napi_value supportedFrameRateItem;
367 CreateFrameRateJSArray(env, supportedFrameRatesRange[i], supportedFrameRateItem);
368 if (napi_set_element(env, supportedFrameRateArray, i, supportedFrameRateItem) != napi_ok) {
369 MEDIA_ERR_LOG("Failed to create supportedFrameRateArray with napi wrapper object.");
370 return nullptr;
371 }
372 }
373 }
374 return supportedFrameRateArray;
375 }
376
ProcessingPhysicalApertures(napi_env env,std::vector<std::vector<float>> physicalApertures)377 napi_value CameraNapiUtils::ProcessingPhysicalApertures(napi_env env, std::vector<std::vector<float>> physicalApertures)
378 {
379 napi_value result = nullptr;
380 napi_create_array(env, &result);
381 size_t zoomRangeSize = 2;
382 size_t zoomMinIndex = 0;
383 size_t zoomMaxIndex = 1;
384 for (size_t i = 0; i < physicalApertures.size(); i++) {
385 if (physicalApertures[i].size() <= zoomRangeSize) {
386 continue;
387 }
388 napi_value zoomRange;
389 napi_create_array(env, &zoomRange);
390 napi_value physicalApertureRange;
391 napi_create_array(env, &physicalApertureRange);
392 for (size_t y = 0; y < physicalApertures[i].size(); y++) {
393 napi_value value;
394 napi_create_double(env, CameraNapiUtils::FloatToDouble(physicalApertures[i][y]), &value);
395 if (y == zoomMinIndex) {
396 napi_set_element(env, zoomRange, y, value);
397 napi_set_named_property(env, zoomRange, "min", value);
398 continue;
399 }
400 if (y == zoomMaxIndex) {
401 napi_set_element(env, zoomRange, y, value);
402 napi_set_named_property(env, zoomRange, "max", value);
403 continue;
404 }
405 napi_set_element(env, physicalApertureRange, y - zoomRangeSize, value);
406 }
407 napi_value obj;
408 napi_create_object(env, &obj);
409 napi_set_named_property(env, obj, "zoomRange", zoomRange);
410 napi_set_named_property(env, obj, "apertures", physicalApertureRange);
411 napi_set_element(env, result, i, obj);
412 }
413 return result;
414 }
415
CreateJSArray(napi_env env,napi_status status,std::vector<int32_t> nativeArray)416 napi_value CameraNapiUtils::CreateJSArray(napi_env env, napi_status status,
417 std::vector<int32_t> nativeArray)
418 {
419 MEDIA_DEBUG_LOG("CreateJSArray is called");
420 napi_value jsArray = nullptr;
421 napi_value item = nullptr;
422
423 if (nativeArray.empty()) {
424 MEDIA_ERR_LOG("nativeArray is empty");
425 }
426
427 status = napi_create_array(env, &jsArray);
428 if (status == napi_ok) {
429 for (size_t i = 0; i < nativeArray.size(); i++) {
430 napi_create_int32(env, nativeArray[i], &item);
431 if (napi_set_element(env, jsArray, i, item) != napi_ok) {
432 MEDIA_ERR_LOG("Failed to create profile napi wrapper object");
433 return nullptr;
434 }
435 }
436 }
437 return jsArray;
438 }
439
ParseMetadataObjectTypes(napi_env env,napi_value arrayParam,std::vector<MetadataObjectType> & metadataObjectTypes)440 napi_value CameraNapiUtils::ParseMetadataObjectTypes(napi_env env, napi_value arrayParam,
441 std::vector<MetadataObjectType> &metadataObjectTypes)
442 {
443 MEDIA_DEBUG_LOG("ParseMetadataObjectTypes is called");
444 napi_value result;
445 uint32_t length = 0;
446 napi_value value;
447 int32_t metadataType = 0;
448 napi_get_array_length(env, arrayParam, &length);
449 napi_valuetype type = napi_undefined;
450 const int32_t invalidType = -1;
451 for (uint32_t i = 0; i < length; i++) {
452 napi_get_element(env, arrayParam, i, &value);
453 napi_typeof(env, value, &type);
454 if (type != napi_number) {
455 return nullptr;
456 }
457 if (metadataType < static_cast<int32_t>(MetadataObjectType::INVALID) ||
458 metadataType > static_cast<int32_t>(MetadataObjectType::BAR_CODE_DETECTION)) {
459 metadataType = invalidType;
460 }
461 napi_get_value_int32(env, value, &metadataType);
462 metadataObjectTypes.push_back(static_cast<MetadataObjectType>(metadataType));
463 }
464 napi_get_boolean(env, true, &result);
465 return result;
466 }
467 } // namespace CameraStandard
468 } // namespace OHOS
469