• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "input/camera_input_napi.h"
17 #include <uv.h>
18 #include "input/camera_info_napi.h"
19 
20 namespace OHOS {
21 namespace CameraStandard {
22 using namespace std;
23 using OHOS::HiviewDFX::HiLog;
24 using OHOS::HiviewDFX::HiLogLabel;
25 
26 namespace {
27     constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CameraNapi"};
28 }
29 
30 thread_local napi_ref CameraInputNapi::sConstructor_ = nullptr;
31 thread_local sptr<CameraInput> CameraInputNapi::sCameraInput_ = nullptr;
32 thread_local uint32_t CameraInputNapi::cameraInputTaskId = CAMERA_INPUT_TASKID;
33 
OnErrorCallbackAsync(const int32_t errorType,const int32_t errorMsg) const34 void ErrorCallbackListener::OnErrorCallbackAsync(const int32_t errorType, const int32_t errorMsg) const
35 {
36     uv_loop_s* loop = nullptr;
37     napi_get_uv_event_loop(env_, &loop);
38     if (!loop) {
39         MEDIA_ERR_LOG("ErrorCallbackListener:OnErrorCallbackAsync() failed to get event loop");
40         return;
41     }
42     uv_work_t* work = new(std::nothrow) uv_work_t;
43     if (!work) {
44         MEDIA_ERR_LOG("ErrorCallbackListener:OnErrorCallbackAsync() failed to allocate work");
45         return;
46     }
47     std::unique_ptr<ErrorCallbackInfo> callbackInfo = std::make_unique<ErrorCallbackInfo>(errorType, errorMsg, this);
48     work->data = callbackInfo.get();
49     int ret = uv_queue_work(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
50         ErrorCallbackInfo* callbackInfo = reinterpret_cast<ErrorCallbackInfo *>(work->data);
51         if (callbackInfo) {
52             callbackInfo->listener_->OnErrorCallback(callbackInfo->errorType_, callbackInfo->errorMsg_);
53             delete callbackInfo;
54         }
55         delete work;
56     });
57     if (ret) {
58         MEDIA_ERR_LOG("ErrorCallbackListener:OnErrorCallbackAsync() failed to execute work");
59         delete work;
60     } else {
61         callbackInfo.release();
62     }
63 }
64 
OnErrorCallback(const int32_t errorType,const int32_t errorMsg) const65 void ErrorCallbackListener::OnErrorCallback(const int32_t errorType, const int32_t errorMsg) const
66 {
67     napi_value result;
68     napi_value callback = nullptr;
69     napi_value retVal;
70     napi_value propValue;
71     napi_create_int32(env_, errorType, &propValue);
72     napi_create_object(env_, &result);
73     napi_set_named_property(env_, result, "code", propValue);
74     napi_get_reference_value(env_, callbackRef_, &callback);
75     napi_call_function(env_, nullptr, callback, ARGS_ONE, &result, &retVal);
76 }
77 
OnError(const int32_t errorType,const int32_t errorMsg) const78 void ErrorCallbackListener::OnError(const int32_t errorType, const int32_t errorMsg) const
79 {
80     MEDIA_INFO_LOG("ErrorCallbackListener:OnError() is called!, errorType: %{public}d", errorType);
81     OnErrorCallbackAsync(errorType, errorMsg);
82 }
83 
CameraInputNapi()84 CameraInputNapi::CameraInputNapi() : env_(nullptr), wrapper_(nullptr)
85 {
86 }
87 
~CameraInputNapi()88 CameraInputNapi::~CameraInputNapi()
89 {
90     if (wrapper_ != nullptr) {
91         napi_delete_reference(env_, wrapper_);
92     }
93     if (cameraInput_) {
94         cameraInput_ = nullptr;
95     }
96 }
97 
CameraInputNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)98 void CameraInputNapi::CameraInputNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
99 {
100     CameraInputNapi* cameraObj = reinterpret_cast<CameraInputNapi*>(nativeObject);
101     if (cameraObj != nullptr) {
102         cameraObj->~CameraInputNapi();
103     }
104 }
105 
Init(napi_env env,napi_value exports)106 napi_value CameraInputNapi::Init(napi_env env, napi_value exports)
107 {
108     napi_status status;
109     napi_value ctorObj;
110     int32_t refCount = 1;
111 
112     // todo: Open and Close in native have not implemented
113     napi_property_descriptor camera_input_props[] = {
114         DECLARE_NAPI_FUNCTION("open", Open),
115         DECLARE_NAPI_FUNCTION("close", Close),
116         DECLARE_NAPI_FUNCTION("release", Release),
117         DECLARE_NAPI_FUNCTION("on", On)
118     };
119 
120     status = napi_define_class(env, CAMERA_INPUT_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
121                                CameraInputNapiConstructor, nullptr,
122                                sizeof(camera_input_props) / sizeof(camera_input_props[PARAM0]),
123                                camera_input_props, &ctorObj);
124     if (status == napi_ok) {
125         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
126         if (status == napi_ok) {
127             status = napi_set_named_property(env, exports, CAMERA_INPUT_NAPI_CLASS_NAME, ctorObj);
128             if (status == napi_ok) {
129                 return exports;
130             }
131         }
132     }
133 
134     return nullptr;
135 }
136 
137 // Constructor callback
CameraInputNapiConstructor(napi_env env,napi_callback_info info)138 napi_value CameraInputNapi::CameraInputNapiConstructor(napi_env env, napi_callback_info info)
139 {
140     napi_status status;
141     napi_value result = nullptr;
142     napi_value thisVar = nullptr;
143 
144     napi_get_undefined(env, &result);
145     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
146 
147     if (status == napi_ok && thisVar != nullptr) {
148         std::unique_ptr<CameraInputNapi> obj = std::make_unique<CameraInputNapi>();
149         obj->env_ = env;
150         obj->cameraInput_ = sCameraInput_;
151         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
152                            CameraInputNapi::CameraInputNapiDestructor, nullptr, &(obj->wrapper_));
153         if (status == napi_ok) {
154             obj.release();
155             return thisVar;
156         } else {
157             MEDIA_ERR_LOG("Failure wrapping js to native napi");
158         }
159     }
160 
161     return result;
162 }
163 
CreateCameraInput(napi_env env,sptr<CameraInput> cameraInput)164 napi_value CameraInputNapi::CreateCameraInput(napi_env env, sptr<CameraInput> cameraInput)
165 {
166     CAMERA_SYNC_TRACE;
167     napi_status status;
168     napi_value result = nullptr;
169     napi_value constructor;
170     if (cameraInput == nullptr) {
171         return result;
172     }
173     status = napi_get_reference_value(env, sConstructor_, &constructor);
174     if (status == napi_ok) {
175         sCameraInput_ = cameraInput;
176         status = napi_new_instance(env, constructor, 0, nullptr, &result);
177         if (status == napi_ok && result != nullptr) {
178             return result;
179         } else {
180             MEDIA_ERR_LOG("Failed to create Camera input instance");
181         }
182     }
183 
184     napi_get_undefined(env, &result);
185     return result;
186 }
187 
GetCameraInput()188 sptr<CameraInput> CameraInputNapi::GetCameraInput()
189 {
190     return cameraInput_;
191 }
192 
CommonCompleteCallback(napi_env env,napi_status status,void * data)193 void CommonCompleteCallback(napi_env env, napi_status status, void* data)
194 {
195     auto context = static_cast<CameraInputAsyncContext*>(data);
196 
197     if (context == nullptr) {
198         MEDIA_ERR_LOG("Async context is null");
199         return;
200     }
201 
202     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
203 
204     MEDIA_INFO_LOG("%{public}s, modeForAsync = %{public}d, status = %{public}d",
205         context->funcName.c_str(), context->modeForAsync, context->status);
206     switch (context->modeForAsync) {
207         case OPEN_ASYNC_CALLBACK:
208             context->errorCode = context->objectInfo->GetCameraInput()->Open();
209             context->status = context->errorCode == 0;
210             jsContext->status = context->status;
211             MEDIA_INFO_LOG("%{public}s, GetCameraInput()->Open() status = %{public}d",
212                 context->funcName.c_str(), context->status);
213             break;
214         case CLOSE_ASYNC_CALLBACK:
215             context->errorCode = context->objectInfo->GetCameraInput()->Close();
216             context->status = context->errorCode == 0;
217             jsContext->status = context->status;
218             MEDIA_INFO_LOG("%{public}s, GetCameraInput()->Close() status = %{public}d",
219                 context->funcName.c_str(), context->status);
220             break;
221         case RELEASE_ASYNC_CALLBACK:
222             context->objectInfo->GetCameraInput()->Release();
223             jsContext->status = context->status;
224             MEDIA_INFO_LOG("%{public}s, GetCameraInput()->Release() status = %{public}d",
225                 context->funcName.c_str(), context->status);
226             break;
227         default:
228             break;
229     }
230 
231     if (!context->status) {
232         CameraNapiUtils::CreateNapiErrorObject(env, context->errorCode, context->errorMsg.c_str(), jsContext);
233     } else {
234         napi_get_undefined(env, &jsContext->data);
235     }
236 
237     if (!context->funcName.empty() && context->taskId > 0) {
238         // Finish async trace
239         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
240         jsContext->funcName = context->funcName.c_str();
241     }
242 
243     if (context->work != nullptr) {
244         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
245                                              context->work, *jsContext);
246     }
247     delete context;
248 }
249 
Open(napi_env env,napi_callback_info info)250 napi_value CameraInputNapi::Open(napi_env env, napi_callback_info info)
251 {
252     napi_status status;
253     napi_value result = nullptr;
254     const int32_t refCount = 1;
255     napi_value resource = nullptr;
256     size_t argc = ARGS_ONE;
257     napi_value argv[ARGS_ONE] = {0};
258     napi_value thisVar = nullptr;
259 
260     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
261     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
262     napi_get_boolean(env, true, &result);
263     CAMERA_NAPI_CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
264     std::unique_ptr<CameraInputAsyncContext> asyncContext = std::make_unique<CameraInputAsyncContext>();
265     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
266     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
267         if (argc == ARGS_ONE) {
268             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
269         }
270 
271         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
272         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Open");
273 
274         status = napi_create_async_work(
275             env, nullptr, resource, [](napi_env env, void* data) {
276                 auto context = static_cast<CameraInputAsyncContext*>(data);
277                 context->status = false;
278                 // Start async trace
279                 context->funcName = "CameraInputNapi::Open";
280                 context->taskId = CameraNapiUtils::IncreamentAndGet(cameraInputTaskId);
281                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
282                 if (context->objectInfo != nullptr) {
283                     context->status = true;
284                     context->modeForAsync = OPEN_ASYNC_CALLBACK;
285                 }
286             },
287             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
288         if (status != napi_ok) {
289             MEDIA_ERR_LOG("Failed to create napi_create_async_work for CameraInputNapi::Open");
290             if (asyncContext->callbackRef != nullptr) {
291                 napi_delete_reference(env, asyncContext->callbackRef);
292             }
293             napi_get_undefined(env, &result);
294         } else {
295             napi_queue_async_work(env, asyncContext->work);
296             asyncContext.release();
297         }
298     }
299 
300     return result;
301 }
302 
Close(napi_env env,napi_callback_info info)303 napi_value CameraInputNapi::Close(napi_env env, napi_callback_info info)
304 {
305     napi_status status;
306     napi_value result = nullptr;
307     const int32_t refCount = 1;
308     napi_value resource = nullptr;
309     size_t argc = ARGS_ONE;
310     napi_value argv[ARGS_ONE] = {0};
311     napi_value thisVar = nullptr;
312 
313     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
314     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
315     napi_get_boolean(env, true, &result);
316     CAMERA_NAPI_CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
317     std::unique_ptr<CameraInputAsyncContext> asyncContext = std::make_unique<CameraInputAsyncContext>();
318     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
319     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
320         if (argc == ARGS_ONE) {
321             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
322         }
323 
324         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
325         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Close");
326 
327         status = napi_create_async_work(
328             env, nullptr, resource, [](napi_env env, void* data) {
329                 auto context = static_cast<CameraInputAsyncContext*>(data);
330                 context->status = false;
331                 // Start async trace
332                 context->funcName = "CameraInputNapi::Close";
333                 context->taskId = CameraNapiUtils::IncreamentAndGet(cameraInputTaskId);
334                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
335                 if (context->objectInfo != nullptr) {
336                     context->status = true;
337                     context->modeForAsync = CLOSE_ASYNC_CALLBACK;
338                 }
339             },
340             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
341         if (status != napi_ok) {
342             MEDIA_ERR_LOG("Failed to create napi_create_async_work for CameraInputNapi::Close");
343             if (asyncContext->callbackRef != nullptr) {
344                 napi_delete_reference(env, asyncContext->callbackRef);
345             }
346             napi_get_undefined(env, &result);
347         } else {
348             napi_queue_async_work(env, asyncContext->work);
349             asyncContext.release();
350         }
351     }
352 
353     return result;
354 }
355 
Release(napi_env env,napi_callback_info info)356 napi_value CameraInputNapi::Release(napi_env env, napi_callback_info info)
357 {
358     napi_status status;
359     napi_value result = nullptr;
360     const int32_t refCount = 1;
361     napi_value resource = nullptr;
362     size_t argc = ARGS_ONE;
363     napi_value argv[ARGS_ONE] = {0};
364     napi_value thisVar = nullptr;
365 
366     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
367     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
368     napi_get_boolean(env, true, &result);
369     CAMERA_NAPI_CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
370     std::unique_ptr<CameraInputAsyncContext> asyncContext = std::make_unique<CameraInputAsyncContext>();
371     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
372     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
373         if (argc == ARGS_ONE) {
374             CAMERA_NAPI_GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
375         }
376 
377         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
378         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
379 
380         status = napi_create_async_work(
381             env, nullptr, resource, [](napi_env env, void* data) {
382                 auto context = static_cast<CameraInputAsyncContext*>(data);
383                 context->status = false;
384                 // Start async trace
385                 context->funcName = "CameraInputNapi::Release";
386                 context->taskId = CameraNapiUtils::IncreamentAndGet(cameraInputTaskId);
387                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
388                 if (context->objectInfo != nullptr) {
389                     context->status = true;
390                     context->modeForAsync = RELEASE_ASYNC_CALLBACK;
391                 }
392             },
393             CommonCompleteCallback, static_cast<void*>(asyncContext.get()), &asyncContext->work);
394         if (status != napi_ok) {
395             MEDIA_ERR_LOG("Failed to create napi_create_async_work for CameraInputNapi::Release");
396             if (asyncContext->callbackRef != nullptr) {
397                 napi_delete_reference(env, asyncContext->callbackRef);
398             }
399             napi_get_undefined(env, &result);
400         } else {
401             napi_queue_async_work(env, asyncContext->work);
402             asyncContext.release();
403         }
404     }
405 
406     return result;
407 }
408 
RegisterCallback(napi_env env,const string & eventType,napi_ref callbackRef)409 void CameraInputNapi::RegisterCallback(napi_env env, const string &eventType, napi_ref callbackRef)
410 {
411     if (eventType.empty()) {
412         MEDIA_ERR_LOG("Failed to Register Callback callback name is empty!");
413         return;
414     }
415 
416     if (eventType.compare("error") == 0) {
417         // Set callback for error
418         shared_ptr<ErrorCallbackListener> errorCallback = make_shared<ErrorCallbackListener>(env, callbackRef);
419         cameraInput_->SetErrorCallback(errorCallback);
420     } else {
421         MEDIA_ERR_LOG("Incorrect callback event type provided for camera input!");
422     }
423 }
424 
On(napi_env env,napi_callback_info info)425 napi_value CameraInputNapi::On(napi_env env, napi_callback_info info)
426 {
427     CAMERA_SYNC_TRACE;
428     napi_value undefinedResult = nullptr;
429     size_t argCount = ARGS_THREE;
430     napi_value argv[ARGS_THREE] = {nullptr};
431     napi_value thisVar = nullptr;
432     size_t res = 0;
433     char buffer[SIZE];
434     const int32_t refCount = 1;
435     CameraInputNapi* obj = nullptr;
436     CameraDeviceNapi* cameraDeviceNapi = nullptr;
437     napi_status status;
438 
439     napi_get_undefined(env, &undefinedResult);
440 
441     CAMERA_NAPI_GET_JS_ARGS(env, info, argCount, argv, thisVar);
442 
443     NAPI_ASSERT(env, argCount == ARGS_THREE, "requires 3 parameters");
444 
445     if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr || argv[PARAM2] == nullptr) {
446         MEDIA_ERR_LOG("Failed to retrieve details about the callback");
447         return undefinedResult;
448     }
449 
450     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
451     if (status == napi_ok && obj != nullptr) {
452         napi_valuetype valueType = napi_undefined;
453         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string
454             || napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_object
455             || napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
456             return undefinedResult;
457         }
458 
459         napi_get_value_string_utf8(env, argv[PARAM0], buffer, SIZE, &res);
460         std::string eventType = std::string(buffer);
461 
462         status = napi_unwrap(env, argv[PARAM1], reinterpret_cast<void **>(&cameraDeviceNapi));
463         if (status != napi_ok || cameraDeviceNapi == nullptr) {
464             MEDIA_ERR_LOG("Could not able to read cameraDevice argument!");
465             return undefinedResult;
466         }
467 
468         napi_ref callbackRef;
469         napi_create_reference(env, argv[PARAM2], refCount, &callbackRef);
470 
471         obj->RegisterCallback(env, eventType, callbackRef);
472     }
473 
474     return undefinedResult;
475 }
476 } // namespace CameraStandard
477 } // namespace OHOS
478