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 CHECK_ERROR_RETURN_RET(valueNapiType != napi_string, "");
223 size_t stringSize = 0;
224 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &stringSize);
225 CHECK_ERROR_RETURN_RET(status != napi_ok || stringSize == 0, "");
226 std::string strValue = std::string(stringSize, '\0');
227 status = napi_get_value_string_utf8(env, value, strValue.data(), stringSize + 1, &stringSize);
228 CHECK_ERROR_RETURN_RET(status != napi_ok || stringSize == 0, "");
229 return strValue;
230 }
231
IsSameNapiValue(napi_env env,napi_value valueSrc,napi_value valueDst)232 bool CameraNapiUtils::IsSameNapiValue(napi_env env, napi_value valueSrc, napi_value valueDst)
233 {
234 CHECK_ERROR_RETURN_RET(valueSrc == nullptr && valueDst == nullptr, true);
235 CHECK_ERROR_RETURN_RET(valueSrc == nullptr || valueDst == nullptr, false);
236 bool isEquals = false;
237 CHECK_ERROR_RETURN_RET_LOG(napi_strict_equals(env, valueSrc, valueDst, &isEquals) != napi_ok, false,
238 "get napi_strict_equals failed");
239 return isEquals;
240 }
241
CallPromiseFun(napi_env env,napi_value promiseValue,void * data,napi_callback thenCallback,napi_callback catchCallback)242 napi_status CameraNapiUtils::CallPromiseFun(
243 napi_env env, napi_value promiseValue, void* data, napi_callback thenCallback, napi_callback catchCallback)
244 {
245 MEDIA_DEBUG_LOG("CallPromiseFun Start");
246 bool isPromise = false;
247 napi_is_promise(env, promiseValue, &isPromise);
248 CHECK_ERROR_RETURN_RET_LOG(!isPromise, napi_invalid_arg, "CallPromiseFun promiseValue is not promise");
249 // Create promiseThen
250 napi_value promiseThen = nullptr;
251 napi_get_named_property(env, promiseValue, "then", &promiseThen);
252 CHECK_ERROR_RETURN_RET_LOG(promiseThen == nullptr, napi_invalid_arg, "CallPromiseFun get promiseThen failed");
253 napi_value thenValue;
254 napi_status ret = napi_create_function(env, "thenCallback", NAPI_AUTO_LENGTH, thenCallback, data, &thenValue);
255 CHECK_ERROR_RETURN_RET_LOG(ret != napi_ok, ret, "CallPromiseFun thenCallback got exception");
256 napi_value catchValue;
257 ret = napi_create_function(env, "catchCallback", NAPI_AUTO_LENGTH, catchCallback, data, &catchValue);
258 CHECK_ERROR_RETURN_RET_LOG(ret != napi_ok, ret, "CallPromiseFun catchCallback got exception");
259 napi_value thenReturnValue;
260 constexpr uint32_t THEN_ARGC = 2;
261 napi_value thenArgv[THEN_ARGC] = { thenValue, catchValue };
262 ret = napi_call_function(env, promiseValue, promiseThen, THEN_ARGC, thenArgv, &thenReturnValue);
263 CHECK_ERROR_RETURN_RET_LOG(ret != napi_ok, ret, "CallPromiseFun PromiseThen got exception");
264 MEDIA_DEBUG_LOG("CallPromiseFun End");
265 return napi_ok;
266 }
267
GetPropertyDescriptor(std::vector<std::vector<napi_property_descriptor>> descriptors)268 std::vector<napi_property_descriptor> CameraNapiUtils::GetPropertyDescriptor(
269 std::vector<std::vector<napi_property_descriptor>> descriptors)
270 {
271 MEDIA_DEBUG_LOG("GetPropertyDescriptor Start %zu", descriptors.size());
272 std::vector<napi_property_descriptor> properties = {};
273 std::for_each(descriptors.begin(), descriptors.end(),
274 [&properties](const std::vector<napi_property_descriptor> descriptor) {
275 properties.insert(properties.end(), descriptor.begin(), descriptor.end());
276 });
277 return properties;
278 };
279
CreateObjectWithPropName(napi_env env,napi_value * result,size_t property_count,const char ** keys)280 napi_status CameraNapiUtils::CreateObjectWithPropName(
281 napi_env env, napi_value* result, size_t property_count, const char** keys)
282 {
283 napi_value values[property_count];
284 for (size_t i = 0; i < property_count; i++) {
285 napi_get_undefined(env, &values[i]);
286 }
287 return napi_create_object_with_named_properties(env, result, property_count, keys, values);
288 }
289
CreateObjectWithPropNameAndValues(napi_env env,napi_value * result,size_t property_count,const char ** keys,const std::vector<std::string> values)290 napi_status CameraNapiUtils::CreateObjectWithPropNameAndValues(
291 napi_env env, napi_value* result, size_t property_count, const char** keys, const std::vector<std::string> values)
292 {
293 napi_value napiValues[property_count];
294 for (size_t i = 0; i < property_count; i++) {
295 napi_create_string_utf8(env, values[i].data(), values[i].size(), &napiValues[i]);
296 }
297 return napi_create_object_with_named_properties(env, result, property_count, keys, napiValues);
298 }
299
GetNapiArgs(napi_env env,napi_callback_info callbackInfo)300 size_t CameraNapiUtils::GetNapiArgs(napi_env env, napi_callback_info callbackInfo)
301 {
302 size_t argsSize = 0;
303 napi_get_cb_info(env, callbackInfo, &argsSize, nullptr, nullptr, nullptr);
304 return argsSize;
305 }
306
CreateFrameRateJSArray(napi_env env,std::vector<int32_t> frameRateRange,napi_value & result)307 void CameraNapiUtils::CreateFrameRateJSArray(napi_env env, std::vector<int32_t> frameRateRange, napi_value &result)
308 {
309 MEDIA_DEBUG_LOG("CreateFrameRateJSArray called");
310 CHECK_ERROR_PRINT_LOG(frameRateRange.empty(), "frameRateRange is empty");
311
312 napi_status status = napi_create_object(env, &result);
313 if (status == napi_ok) {
314 napi_value minRate;
315 status = napi_create_int32(env, frameRateRange[0], &minRate);
316 napi_value maxRate;
317 status = napi_create_int32(env, frameRateRange[1], &maxRate);
318 CHECK_ERROR_PRINT_LOG(status != napi_ok || napi_set_named_property(env, result, "min", minRate) != napi_ok ||
319 napi_set_named_property(env, result, "max", maxRate) != napi_ok,
320 "Failed to create frameRateArray with napi wrapper object.");
321 }
322 }
323
CreateSupportFrameRatesJSArray(napi_env env,std::vector<std::vector<int32_t>> supportedFrameRatesRange)324 napi_value CameraNapiUtils::CreateSupportFrameRatesJSArray(
325 napi_env env, std::vector<std::vector<int32_t>> supportedFrameRatesRange)
326 {
327 MEDIA_DEBUG_LOG("CreateFrameRateJSArray called");
328 napi_value supportedFrameRateArray = nullptr;
329 CHECK_ERROR_PRINT_LOG(supportedFrameRatesRange.empty(), "frameRateRange is empty");
330
331 napi_status status = napi_create_array(env, &supportedFrameRateArray);
332 if (status == napi_ok) {
333 for (size_t i = 0; i < supportedFrameRatesRange.size(); i++) {
334 napi_value supportedFrameRateItem;
335 CreateFrameRateJSArray(env, supportedFrameRatesRange[i], supportedFrameRateItem);
336 CHECK_ERROR_RETURN_RET_LOG(napi_set_element(env, supportedFrameRateArray, i, supportedFrameRateItem) !=
337 napi_ok, nullptr, "Failed to create supportedFrameRateArray with napi wrapper object.");
338 }
339 }
340 return supportedFrameRateArray;
341 }
342
ProcessingPhysicalApertures(napi_env env,std::vector<std::vector<float>> physicalApertures)343 napi_value CameraNapiUtils::ProcessingPhysicalApertures(napi_env env, std::vector<std::vector<float>> physicalApertures)
344 {
345 napi_value result = nullptr;
346 napi_create_array(env, &result);
347 size_t zoomRangeSize = 2;
348 size_t zoomMinIndex = 0;
349 size_t zoomMaxIndex = 1;
350 for (size_t i = 0; i < physicalApertures.size(); i++) {
351 if (physicalApertures[i].size() <= zoomRangeSize) {
352 continue;
353 }
354 napi_value zoomRange;
355 napi_create_array(env, &zoomRange);
356 napi_value physicalApertureRange;
357 napi_create_array(env, &physicalApertureRange);
358 for (size_t y = 0; y < physicalApertures[i].size(); y++) {
359 napi_value value;
360 napi_create_double(env, CameraNapiUtils::FloatToDouble(physicalApertures[i][y]), &value);
361 if (y == zoomMinIndex) {
362 napi_set_element(env, zoomRange, y, value);
363 napi_set_named_property(env, zoomRange, "min", value);
364 continue;
365 }
366 if (y == zoomMaxIndex) {
367 napi_set_element(env, zoomRange, y, value);
368 napi_set_named_property(env, zoomRange, "max", value);
369 continue;
370 }
371 napi_set_element(env, physicalApertureRange, y - zoomRangeSize, value);
372 }
373 napi_value obj;
374 napi_create_object(env, &obj);
375 napi_set_named_property(env, obj, "zoomRange", zoomRange);
376 napi_set_named_property(env, obj, "apertures", physicalApertureRange);
377 napi_set_element(env, result, i, obj);
378 }
379 return result;
380 }
381
CreateJSArray(napi_env env,napi_status & status,std::vector<int32_t> nativeArray)382 napi_value CameraNapiUtils::CreateJSArray(napi_env env, napi_status &status,
383 std::vector<int32_t> nativeArray)
384 {
385 MEDIA_DEBUG_LOG("CreateJSArray is called");
386 napi_value jsArray = nullptr;
387 napi_value item = nullptr;
388
389 CHECK_ERROR_PRINT_LOG(nativeArray.empty(), "nativeArray is empty");
390
391 status = napi_create_array(env, &jsArray);
392 if (status == napi_ok) {
393 for (size_t i = 0; i < nativeArray.size(); i++) {
394 napi_create_int32(env, nativeArray[i], &item);
395 CHECK_ERROR_RETURN_RET_LOG(napi_set_element(env, jsArray, i, item) != napi_ok, nullptr,
396 "Failed to create profile napi wrapper object");
397 }
398 }
399 return jsArray;
400 }
401
ParseMetadataObjectTypes(napi_env env,napi_value arrayParam,std::vector<MetadataObjectType> & metadataObjectTypes)402 napi_value CameraNapiUtils::ParseMetadataObjectTypes(napi_env env, napi_value arrayParam,
403 std::vector<MetadataObjectType> &metadataObjectTypes)
404 {
405 MEDIA_DEBUG_LOG("ParseMetadataObjectTypes is called");
406 napi_value result;
407 uint32_t length = 0;
408 napi_value value;
409 int32_t metadataType = 0;
410 napi_get_array_length(env, arrayParam, &length);
411 napi_valuetype type = napi_undefined;
412 const int32_t invalidType = -1;
413 for (uint32_t i = 0; i < length; i++) {
414 napi_get_element(env, arrayParam, i, &value);
415 napi_typeof(env, value, &type);
416 CHECK_ERROR_RETURN_RET(type != napi_number, nullptr);
417 if (metadataType < static_cast<int32_t>(MetadataObjectType::INVALID) &&
418 metadataType > static_cast<int32_t>(MetadataObjectType::BAR_CODE_DETECTION)) {
419 metadataType = invalidType;
420 }
421 napi_get_value_int32(env, value, &metadataType);
422 metadataObjectTypes.push_back(static_cast<MetadataObjectType>(metadataType));
423 }
424 napi_get_boolean(env, true, &result);
425 return result;
426 }
427 } // namespace CameraStandard
428 } // namespace OHOS
429