1 /*
2  * Copyright (c) 2024-2024 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 "camera_napi_security_utils.h"
17 #include "camera_napi_param_parser.h"
18 #include "uv.h"
19 #include "mode/slow_motion_session_napi.h"
20 
21 namespace OHOS {
22 namespace CameraStandard {
23 using namespace std;
24 
25 thread_local napi_ref SlowMotionSessionNapi::sConstructor_ = nullptr;
26 
OnSlowMotionStateCbAsync(const SlowMotionState state) const27 void SlowMotionStateListener::OnSlowMotionStateCbAsync(const SlowMotionState state) const
28 {
29     MEDIA_DEBUG_LOG("OnSlowMotionStateCbAsync is called");
30     uv_loop_s* loop = nullptr;
31     napi_get_uv_event_loop(env_, &loop);
32     if (!loop) {
33         MEDIA_ERR_LOG("failed to get event loop");
34         return;
35     }
36     uv_work_t* work = new(std::nothrow) uv_work_t;
37     if (!work) {
38         MEDIA_ERR_LOG("failed to allocate work");
39         return;
40     }
41     std::unique_ptr<SlowMotionStateListenerInfo> callbackInfo =
42         std::make_unique<SlowMotionStateListenerInfo>(state, this);
43     work->data = callbackInfo.get();
44     int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t* work) {}, [] (uv_work_t* work, int status) {
45         SlowMotionStateListenerInfo* callbackInfo = reinterpret_cast<SlowMotionStateListenerInfo *>(work->data);
46         if (callbackInfo) {
47             callbackInfo->listener_->OnSlowMotionStateCb(callbackInfo->state_);
48             delete callbackInfo;
49         }
50         delete work;
51     }, uv_qos_user_initiated);
52     if (ret) {
53         MEDIA_ERR_LOG("failed to execute work");
54         delete work;
55     } else {
56         callbackInfo.release();
57     }
58 }
59 
OnSlowMotionStateCb(const SlowMotionState state) const60 void SlowMotionStateListener::OnSlowMotionStateCb(const SlowMotionState state) const
61 {
62     MEDIA_DEBUG_LOG("OnSlowMotionStateCb is called, state: %{public}d", state);
63     napi_value result[ARGS_TWO] = {nullptr, nullptr};
64     napi_value retVal;
65     napi_get_undefined(env_, &result[PARAM0]);
66     napi_create_int32(env_, state, &result[PARAM1]);
67     ExecuteCallbackNapiPara callbackNapiPara { .recv = nullptr, .argc = ARGS_TWO, .argv = result, .result = &retVal };
68     ExecuteCallback("slowMotionStatus", callbackNapiPara);
69 }
70 
OnSlowMotionState(SlowMotionState state)71 void SlowMotionStateListener::OnSlowMotionState(SlowMotionState state)
72 {
73     OnSlowMotionStateCbAsync(state);
74 }
75 
SlowMotionSessionNapi()76 SlowMotionSessionNapi::SlowMotionSessionNapi() : env_(nullptr)
77 {
78 }
79 
~SlowMotionSessionNapi()80 SlowMotionSessionNapi::~SlowMotionSessionNapi()
81 {
82     MEDIA_DEBUG_LOG("~SlowMotionSessionNapi is called");
83 }
84 
SlowMotionSessionNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)85 void SlowMotionSessionNapi::SlowMotionSessionNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
86 {
87     MEDIA_DEBUG_LOG("SlowMotionSessionNapiDestructor is called");
88     SlowMotionSessionNapi* cameraObj = reinterpret_cast<SlowMotionSessionNapi*>(nativeObject);
89     if (cameraObj != nullptr) {
90         delete cameraObj;
91     }
92 }
93 
Init(napi_env env,napi_value exports)94 napi_value SlowMotionSessionNapi::Init(napi_env env, napi_value exports)
95 {
96     MEDIA_DEBUG_LOG("Init is called");
97     napi_status status;
98     napi_value ctorObj;
99     std::vector<napi_property_descriptor> slow_motion_props = {
100         DECLARE_NAPI_FUNCTION("isSlowMotionDetectionSupported", IsSlowMotionDetectionSupported),
101         DECLARE_NAPI_FUNCTION("setSlowMotionDetectionArea", SetSlowMotionDetectionArea)
102     };
103     std::vector<std::vector<napi_property_descriptor>> descriptors = {camera_process_props, flash_props,
104         auto_exposure_props, focus_props, zoom_props, filter_props, slow_motion_props};
105     std::vector<napi_property_descriptor> slow_motion_session_props =
106         CameraNapiUtils::GetPropertyDescriptor(descriptors);
107     status = napi_define_class(env, SLOW_MOTION_SESSION_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
108                                SlowMotionSessionNapiConstructor, nullptr,
109                                slow_motion_session_props.size(),
110                                slow_motion_session_props.data(), &ctorObj);
111     if (status == napi_ok) {
112         int32_t refCount = 1;
113         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
114         if (status == napi_ok) {
115             status = napi_set_named_property(env, exports, SLOW_MOTION_SESSION_NAPI_CLASS_NAME, ctorObj);
116             if (status == napi_ok) {
117                 return exports;
118             }
119         } else {
120             MEDIA_ERR_LOG("napi_create_reference Failed!");
121         }
122     }
123     MEDIA_ERR_LOG("Init call Failed!");
124     return nullptr;
125 }
126 
CreateCameraSession(napi_env env)127 napi_value SlowMotionSessionNapi::CreateCameraSession(napi_env env)
128 {
129     MEDIA_DEBUG_LOG("CreateCameraSession is called");
130     CAMERA_SYNC_TRACE;
131     napi_status status;
132     napi_value result = nullptr;
133     napi_value constructor;
134     status = napi_get_reference_value(env, sConstructor_, &constructor);
135     if (status == napi_ok) {
136         sCameraSession_ = CameraManager::GetInstance()->CreateCaptureSession(SceneMode::SLOW_MOTION);
137         if (sCameraSession_ == nullptr) {
138             MEDIA_ERR_LOG("Failed to create SlowMotion session instance");
139             napi_get_undefined(env, &result);
140             return result;
141         }
142         status = napi_new_instance(env, constructor, 0, nullptr, &result);
143         sCameraSession_ = nullptr;
144         if (status == napi_ok && result != nullptr) {
145             MEDIA_DEBUG_LOG("success to create slow motion session napi instance");
146             return result;
147         } else {
148             MEDIA_ERR_LOG("Failed to create slow motion session napi instance");
149         }
150     }
151     MEDIA_ERR_LOG("Failed to create slow motion session napi instance last");
152     napi_get_undefined(env, &result);
153     return result;
154 }
155 
SlowMotionSessionNapiConstructor(napi_env env,napi_callback_info info)156 napi_value SlowMotionSessionNapi::SlowMotionSessionNapiConstructor(napi_env env, napi_callback_info info)
157 {
158     MEDIA_DEBUG_LOG("SlowMotionSessionNapiConstructor is called");
159     napi_status status;
160     napi_value result = nullptr;
161     napi_value thisVar = nullptr;
162 
163     napi_get_undefined(env, &result);
164     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
165 
166     if (status == napi_ok && thisVar != nullptr) {
167         std::unique_ptr<SlowMotionSessionNapi> obj = std::make_unique<SlowMotionSessionNapi>();
168         obj->env_ = env;
169         if (sCameraSession_ == nullptr) {
170             MEDIA_ERR_LOG("sCameraSession is null");
171             return result;
172         }
173         obj->slowMotionSession_ = static_cast<SlowMotionSession*>(sCameraSession_.GetRefPtr());
174         obj->cameraSession_ = obj->slowMotionSession_;
175         if (obj->slowMotionSession_ == nullptr) {
176             MEDIA_ERR_LOG("slowMotionSession is null");
177             return result;
178         }
179         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
180             SlowMotionSessionNapi::SlowMotionSessionNapiDestructor, nullptr, nullptr);
181         if (status == napi_ok) {
182             obj.release();
183             return thisVar;
184         } else {
185             MEDIA_ERR_LOG("SlowMotionSessionNapi Failure wrapping js to native napi");
186         }
187     }
188     MEDIA_ERR_LOG("SlowMotionSessionNapi call Failed!");
189     return result;
190 }
191 
IsSlowMotionDetectionSupported(napi_env env,napi_callback_info info)192 napi_value SlowMotionSessionNapi::IsSlowMotionDetectionSupported(napi_env env, napi_callback_info info)
193 {
194     MEDIA_INFO_LOG("IsSlowMotionDetectionSupported is called");
195     napi_value result = CameraNapiUtils::GetUndefinedValue(env);
196     if (!CameraNapiSecurity::CheckSystemApp(env)) {
197         MEDIA_ERR_LOG("SystemApi IsSlowMotionDetectionSupported is called!");
198         return result;
199     }
200     SlowMotionSessionNapi* slowMotionSessionNapi = nullptr;
201     CameraNapiParamParser jsParamParser(env, info, slowMotionSessionNapi);
202     if (!jsParamParser.AssertStatus(INVALID_ARGUMENT, "parse parameter occur error")) {
203         MEDIA_ERR_LOG("IsSlowMotionDetectionSupported parse parameter occur error");
204         return result;
205     }
206     if (slowMotionSessionNapi != nullptr && slowMotionSessionNapi->slowMotionSession_ != nullptr) {
207         bool isSupported = slowMotionSessionNapi->slowMotionSession_->IsSlowMotionDetectionSupported();
208         napi_get_boolean(env, isSupported, &result);
209     } else {
210         MEDIA_ERR_LOG("IsSlowMotionDetectionSupported call Failed!");
211     }
212     return result;
213 }
214 
GetDoubleProperty(napi_env env,napi_value param,const std::string & propertyName,double & propertyValue)215 napi_value SlowMotionSessionNapi::GetDoubleProperty(napi_env env, napi_value param, const std::string& propertyName,
216     double& propertyValue)
217 {
218     napi_status status;
219     napi_value property;
220     status = napi_get_named_property(env, param, propertyName.c_str(), &property);
221     if (status != napi_ok) {
222         return nullptr;
223     }
224     status = napi_get_value_double(env, property, &propertyValue);
225     if (status != napi_ok) {
226         return nullptr;
227     }
228     return property;
229 }
230 
SetSlowMotionDetectionArea(napi_env env,napi_callback_info info)231 napi_value SlowMotionSessionNapi::SetSlowMotionDetectionArea(napi_env env, napi_callback_info info)
232 {
233     MEDIA_INFO_LOG("SetSlowMotionDetectionArea is called");
234     napi_value result = CameraNapiUtils::GetUndefinedValue(env);
235     if (!CameraNapiSecurity::CheckSystemApp(env)) {
236         MEDIA_ERR_LOG("SystemApi SetSlowMotionDetectionArea is called!");
237         return result;
238     }
239     SlowMotionSessionNapi* slowMotionSessionNapi = nullptr;
240     napi_status status;
241     size_t argc = ARGS_ONE;
242     napi_value argv[ARGS_ONE] = {0};
243     napi_value thisVar = nullptr;
244     double topLeftX;
245     double topLeftY;
246     double width;
247     double height;
248 
249     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
250 
251     if ((GetDoubleProperty(env, argv[PARAM0], "topLeftX", topLeftX) == nullptr) ||
252         (GetDoubleProperty(env, argv[PARAM0], "topLeftY", topLeftY) == nullptr) ||
253         (GetDoubleProperty(env, argv[PARAM0], "width", width) == nullptr) ||
254         (GetDoubleProperty(env, argv[PARAM0], "height", height) == nullptr)) {
255         return result;
256     }
257 
258     Rect rect = (Rect) {topLeftX, topLeftY, width, height};
259     napi_get_undefined(env, &result);
260     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&slowMotionSessionNapi));
261     if (status == napi_ok && slowMotionSessionNapi != nullptr && slowMotionSessionNapi->slowMotionSession_ != nullptr) {
262         slowMotionSessionNapi->slowMotionSession_->SetSlowMotionDetectionArea(rect);
263     } else {
264         MEDIA_ERR_LOG("SetSlowMotionDetectionArea call Failed!");
265     }
266     return result;
267 }
268 
RegisterSlowMotionStateCb(const std::string & eventName,napi_env env,napi_value callback,const std::vector<napi_value> & args,bool isOnce)269 void SlowMotionSessionNapi::RegisterSlowMotionStateCb(
270     const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args, bool isOnce)
271 {
272     MEDIA_INFO_LOG("RegisterSlowMotionStateCb is called");
273     if (slowMotionStateListener_ == nullptr) {
274         shared_ptr<SlowMotionStateListener> slowMotionStateListenerTemp =
275             static_pointer_cast<SlowMotionStateListener>(slowMotionSession_->GetApplicationCallback());
276         if (slowMotionStateListenerTemp == nullptr) {
277             slowMotionStateListenerTemp = make_shared<SlowMotionStateListener>(env);
278             slowMotionSession_->SetCallback(slowMotionStateListenerTemp);
279         }
280         slowMotionStateListener_ = slowMotionStateListenerTemp;
281     }
282     slowMotionStateListener_->SaveCallbackReference(eventName, callback, isOnce);
283     MEDIA_INFO_LOG("RegisterSlowMotionStateCb success");
284 }
285 
UnregisterSlowMotionStateCb(const std::string & eventName,napi_env env,napi_value callback,const std::vector<napi_value> & args)286 void SlowMotionSessionNapi::UnregisterSlowMotionStateCb(
287     const std::string& eventName, napi_env env, napi_value callback, const std::vector<napi_value>& args)
288 {
289     MEDIA_INFO_LOG("UnregisterSlowMotionStateCb is called");
290     if (slowMotionStateListener_ == nullptr) {
291         MEDIA_ERR_LOG("slowMotionStateListener_ is null");
292     } else {
293         slowMotionStateListener_->RemoveCallbackRef(eventName, callback);
294     }
295 }
296 } // namespace CameraStandard
297 } // namespace OHOS