• 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     MEDIA_DEBUG_LOG("CameraInputNapiDestructor enter");
101     CameraInputNapi* cameraObj = reinterpret_cast<CameraInputNapi*>(nativeObject);
102     if (cameraObj != nullptr) {
103         cameraObj->~CameraInputNapi();
104     }
105 }
106 
Init(napi_env env,napi_value exports)107 napi_value CameraInputNapi::Init(napi_env env, napi_value exports)
108 {
109     napi_status status;
110     napi_value ctorObj;
111     int32_t refCount = 1;
112 
113     // todo: Open and Close in native have not implemented
114     napi_property_descriptor camera_input_props[] = {
115         DECLARE_NAPI_FUNCTION("open", Open),
116         DECLARE_NAPI_FUNCTION("close", Close),
117         DECLARE_NAPI_FUNCTION("release", Release),
118         DECLARE_NAPI_FUNCTION("on", On)
119     };
120 
121     status = napi_define_class(env, CAMERA_INPUT_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
122                                CameraInputNapiConstructor, nullptr,
123                                sizeof(camera_input_props) / sizeof(camera_input_props[PARAM0]),
124                                camera_input_props, &ctorObj);
125     if (status == napi_ok) {
126         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
127         if (status == napi_ok) {
128             status = napi_set_named_property(env, exports, CAMERA_INPUT_NAPI_CLASS_NAME, ctorObj);
129             if (status == napi_ok) {
130                 return exports;
131             }
132         }
133     }
134 
135     return nullptr;
136 }
137 
138 // Constructor callback
CameraInputNapiConstructor(napi_env env,napi_callback_info info)139 napi_value CameraInputNapi::CameraInputNapiConstructor(napi_env env, napi_callback_info info)
140 {
141     napi_status status;
142     napi_value result = nullptr;
143     napi_value thisVar = nullptr;
144 
145     napi_get_undefined(env, &result);
146     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
147 
148     if (status == napi_ok && thisVar != nullptr) {
149         std::unique_ptr<CameraInputNapi> obj = std::make_unique<CameraInputNapi>();
150         obj->env_ = env;
151         obj->cameraInput_ = sCameraInput_;
152         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
153                            CameraInputNapi::CameraInputNapiDestructor, nullptr, nullptr);
154         if (status == napi_ok) {
155             obj.release();
156             return thisVar;
157         } else {
158             MEDIA_ERR_LOG("Failure wrapping js to native napi");
159         }
160     }
161 
162     return result;
163 }
164 
CreateCameraInput(napi_env env,sptr<CameraInput> cameraInput)165 napi_value CameraInputNapi::CreateCameraInput(napi_env env, sptr<CameraInput> cameraInput)
166 {
167     CAMERA_SYNC_TRACE;
168     napi_status status;
169     napi_value result = nullptr;
170     napi_value constructor;
171     if (cameraInput == nullptr) {
172         return result;
173     }
174     status = napi_get_reference_value(env, sConstructor_, &constructor);
175     if (status == napi_ok) {
176         sCameraInput_ = cameraInput;
177         status = napi_new_instance(env, constructor, 0, nullptr, &result);
178         if (status == napi_ok && result != nullptr) {
179             return result;
180         } else {
181             MEDIA_ERR_LOG("Failed to create Camera input instance");
182         }
183     }
184 
185     napi_get_undefined(env, &result);
186     return result;
187 }
188 
GetCameraInput()189 sptr<CameraInput> CameraInputNapi::GetCameraInput()
190 {
191     return cameraInput_;
192 }
193 
CommonCompleteCallback(napi_env env,napi_status status,void * data)194 void CommonCompleteCallback(napi_env env, napi_status status, void* data)
195 {
196     auto context = static_cast<CameraInputAsyncContext*>(data);
197 
198     if (context == nullptr) {
199         MEDIA_ERR_LOG("Async context is null");
200         return;
201     }
202 
203     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
204 
205     MEDIA_INFO_LOG("%{public}s, modeForAsync = %{public}d, status = %{public}d",
206         context->funcName.c_str(), context->modeForAsync, context->status);
207     switch (context->modeForAsync) {
208         case OPEN_ASYNC_CALLBACK:
209             if (context->objectInfo && context->objectInfo->GetCameraInput()) {
210                 context->errorCode = context->objectInfo->GetCameraInput()->Open();
211                 context->status = context->errorCode == 0;
212                 jsContext->status = context->status;
213             }
214             break;
215         case CLOSE_ASYNC_CALLBACK:
216             if (context->objectInfo && context->objectInfo->GetCameraInput()) {
217                 context->errorCode = context->objectInfo->GetCameraInput()->Close();
218                 context->status = context->errorCode == 0;
219                 jsContext->status = context->status;
220             }
221             break;
222         case RELEASE_ASYNC_CALLBACK:
223             if (context->objectInfo && context->objectInfo->GetCameraInput()) {
224                 context->objectInfo->GetCameraInput()->Release();
225                 jsContext->status = context->status;
226             }
227             break;
228         default:
229             break;
230     }
231 
232     if (!context->status) {
233         CameraNapiUtils::CreateNapiErrorObject(env, context->errorCode, context->errorMsg.c_str(), jsContext);
234     } else {
235         napi_get_undefined(env, &jsContext->data);
236     }
237 
238     if (!context->funcName.empty() && context->taskId > 0) {
239         // Finish async trace
240         CAMERA_FINISH_ASYNC_TRACE(context->funcName, context->taskId);
241         jsContext->funcName = context->funcName.c_str();
242     }
243 
244     if (context->work != nullptr) {
245         CameraNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, 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