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