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