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