1 /*
2 * Copyright (C) 2025 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 "screen_capture_monitor_napi.h"
17 #include "media_dfx.h"
18 #include "media_log.h"
19 #include <refbase.h>
20 #include "media_errors.h"
21 #include "recorder_napi_utils.h"
22
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_RECORDER, "ScreenCaptureMonitorNapi"};
25 }
26
27 namespace OHOS {
28 namespace Media {
29 thread_local napi_ref ScreenCaptureMonitorNapi::constructor_ = nullptr;
30 const std::string CLASS_NAME = "ScreenCaptureMonitor";
31
SignError(ScreenCaptureMonitorAsyncContext * asyncCtx,int32_t code,const std::string & param1,const std::string & param2,const std::string & add="")32 static void SignError(ScreenCaptureMonitorAsyncContext *asyncCtx, int32_t code,
33 const std::string ¶m1, const std::string ¶m2, const std::string &add = "")
34 {
35 std::string message = MSExtErrorAPI9ToString(static_cast<MediaServiceExtErrCodeAPI9>(code), param1, param2) + add;
36 asyncCtx->SignError(code, message);
37 }
38
ScreenCaptureMonitorNapi()39 ScreenCaptureMonitorNapi::ScreenCaptureMonitorNapi()
40 {
41 MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances create", FAKE_POINTER(this));
42 }
43
~ScreenCaptureMonitorNapi()44 ScreenCaptureMonitorNapi::~ScreenCaptureMonitorNapi()
45 {
46 MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances destroy", FAKE_POINTER(this));
47 }
48
Init(napi_env env,napi_value exports)49 napi_value ScreenCaptureMonitorNapi::Init(napi_env env, napi_value exports)
50 {
51 MEDIA_LOGI("JS Init Start");
52 napi_property_descriptor staticProperty[] = {
53 DECLARE_NAPI_STATIC_FUNCTION("getScreenCaptureMonitor", JsGetScreenCaptureMonitor),
54 };
55
56 napi_property_descriptor properties[] = {
57 DECLARE_NAPI_FUNCTION("on", JsSetEventCallback),
58 DECLARE_NAPI_FUNCTION("off", JsCancelEventCallback),
59
60 DECLARE_NAPI_GETTER("isSystemScreenRecorderWorking", JsIsSystemScreenRecorderWorking),
61 };
62
63 napi_value constructor = nullptr;
64 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
65 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
66 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define ScreenCaptureMonitor class");
67
68 status = napi_create_reference(env, constructor, 1, &constructor_);
69 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
70
71 status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
72 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
73
74 status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
75 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
76
77 MEDIA_LOGI("Js Init End");
78 return exports;
79 }
80
Constructor(napi_env env,napi_callback_info info)81 napi_value ScreenCaptureMonitorNapi::Constructor(napi_env env, napi_callback_info info)
82 {
83 MediaTrace trace("ScreenCaptureMonitorNapi::Constructor");
84 MEDIA_LOGI("Js Constructor Start");
85 napi_value result = nullptr;
86 napi_get_undefined(env, &result);
87
88 size_t argCount = 0;
89 napi_value jsThis = nullptr;
90 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
91 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
92
93 ScreenCaptureMonitorNapi *jsMonitor = new(std::nothrow) ScreenCaptureMonitorNapi();
94 CHECK_AND_RETURN_RET_LOG(jsMonitor != nullptr, result, "failed to new ScreenCaptureMonitorNapi");
95
96 jsMonitor->env_ = env;
97
98 sptr<ScreenCaptureMonitorCallback> monitorCb(new ScreenCaptureMonitorCallback(env));
99 jsMonitor->monitorCb_ = monitorCb;
100 CHECK_AND_RETURN_RET_LOG(jsMonitor->monitorCb_ != nullptr, result, "failed to CreateRecorderCb");
101 ScreenCaptureMonitor::GetInstance()->RegisterScreenCaptureMonitorListener(jsMonitor->monitorCb_);
102 status = napi_wrap(env, jsThis, reinterpret_cast<void *>(jsMonitor),
103 ScreenCaptureMonitorNapi::Destructor, nullptr, nullptr);
104 if (status != napi_ok) {
105 delete jsMonitor;
106 MEDIA_LOGE("Failed to wrap native instance");
107 return result;
108 }
109
110 MEDIA_LOGI("Js Constructor End");
111
112 return jsThis;
113 }
114
Destructor(napi_env env,void * nativeObject,void * finalize)115 void ScreenCaptureMonitorNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
116 {
117 MediaTrace trace("ScreenCaptureMonitorNapi::Destructor");
118 MEDIA_LOGI("Js Destructor Start");
119 (void)finalize;
120 if (nativeObject != nullptr) {
121 ScreenCaptureMonitorNapi *napi = reinterpret_cast<ScreenCaptureMonitorNapi *>(nativeObject);
122 napi->monitorCb_ = nullptr;
123 delete napi;
124 }
125 MEDIA_LOGI("Js Destructor End");
126 }
127
JsGetScreenCaptureMonitor(napi_env env,napi_callback_info info)128 napi_value ScreenCaptureMonitorNapi::JsGetScreenCaptureMonitor(napi_env env, napi_callback_info info)
129 {
130 MediaTrace trace("ScreenCaptureMonitorNapi::JsGetScreenCaptureMonitor");
131 MEDIA_LOGI("Js GetScreenCaptureMonitor Start");
132 napi_value result = nullptr;
133 napi_get_undefined(env, &result);
134
135 // get args
136 napi_value jsThis = nullptr;
137 napi_value args[1] = { nullptr };
138 size_t argCount = 1;
139 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
140 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
141
142 std::unique_ptr<ScreenCaptureMonitorAsyncContext> asyncCtx =
143 std::make_unique<ScreenCaptureMonitorAsyncContext>(env);
144 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
145
146 if (!SystemPermission()) {
147 SignError(asyncCtx.get(), MSERR_EXT_API9_PERMISSION_DENIED, "GetScreenCaptureMonitor", "system");
148 }
149
150 asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
151 asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
152 asyncCtx->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
153 asyncCtx->ctorFlag = true;
154
155 auto ret = MediaAsyncContext::SendCompleteEvent(env, asyncCtx.get(), napi_eprio_immediate);
156 if (ret != napi_status::napi_ok) {
157 MEDIA_LOGE("failed to SendEvent, ret = %{public}d", ret);
158 }
159 asyncCtx.release();
160
161 MEDIA_LOGI("Js JsGetScreenCaptureMonitor End");
162
163 return result;
164 }
165
JsSetEventCallback(napi_env env,napi_callback_info info)166 napi_value ScreenCaptureMonitorNapi::JsSetEventCallback(napi_env env, napi_callback_info info)
167 {
168 MediaTrace trace("ScreenCaptureMonitorNapi::JsSetEventCallback");
169 MEDIA_LOGI("JsSetEventCallback Start");
170 napi_value result = nullptr;
171 napi_get_undefined(env, &result);
172
173 std::unique_ptr<ScreenCaptureMonitorAsyncContext> asyncCtx =
174 std::make_unique<ScreenCaptureMonitorAsyncContext>(env);
175 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
176
177 if (!SystemPermission()) {
178 SignError(asyncCtx.get(), MSERR_EXT_API9_PERMISSION_DENIED, "On", "system");
179 }
180
181 size_t argCount = 2;
182 constexpr size_t requireArgc = 1;
183 napi_value args[2] = { nullptr, nullptr };
184 ScreenCaptureMonitorNapi *monitorNapi = ScreenCaptureMonitorNapi::GetJsInstanceAndArgs(env, info, argCount, args);
185 CHECK_AND_RETURN_RET_LOG(monitorNapi != nullptr, result, "Failed to retrieve instance");
186
187 napi_valuetype valueType0 = napi_undefined;
188 napi_valuetype valueType1 = napi_undefined;
189
190 if (argCount < requireArgc) {
191 return result;
192 }
193
194 if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string) {
195 return result;
196 }
197
198 if (napi_typeof(env, args[1], &valueType1) != napi_ok || valueType1 != napi_function) {
199 return result;
200 }
201
202 std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
203 if (callbackName != EVENT_SYSTEM_SCREEN_RECORD) {
204 return result;
205 }
206
207 napi_ref ref = nullptr;
208 napi_status status = napi_create_reference(env, args[1], 1, &ref);
209 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
210
211 std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
212 monitorNapi->SetCallbackReference(callbackName, autoRef);
213
214 MEDIA_LOGI("JsSetEventCallback End");
215 return result;
216 }
217
JsCancelEventCallback(napi_env env,napi_callback_info info)218 napi_value ScreenCaptureMonitorNapi::JsCancelEventCallback(napi_env env, napi_callback_info info)
219 {
220 MediaTrace trace("ScreenCaptureMonitorNapi::JsCancelEventCallback");
221 MEDIA_LOGI("JsCancelEventCallback Start");
222 napi_value result = nullptr;
223 napi_get_undefined(env, &result);
224 constexpr size_t requireArgc = 1;
225 size_t argCount = 1;
226
227 std::unique_ptr<ScreenCaptureMonitorAsyncContext> asyncCtx =
228 std::make_unique<ScreenCaptureMonitorAsyncContext>(env);
229 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
230
231 if (!SystemPermission()) {
232 SignError(asyncCtx.get(), MSERR_EXT_API9_PERMISSION_DENIED, "Off", "system");
233 }
234
235 napi_value args[1] = { nullptr };
236 ScreenCaptureMonitorNapi *monitorNapi = ScreenCaptureMonitorNapi::GetJsInstanceAndArgs(env, info, argCount, args);
237 CHECK_AND_RETURN_RET_LOG(monitorNapi != nullptr, result, "Failed to retrieve instance");
238
239 napi_valuetype valueType0 = napi_undefined;
240
241 if (argCount < requireArgc) {
242 return result;
243 }
244
245 if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string) {
246 return result;
247 }
248
249 std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
250 if (callbackName != EVENT_SYSTEM_SCREEN_RECORD) {
251 return result;
252 }
253
254 monitorNapi->CancelCallbackReference(callbackName);
255
256 MEDIA_LOGI("JsCancelEventCallback End");
257 return result;
258 }
259
JsIsSystemScreenRecorderWorking(napi_env env,napi_callback_info info)260 napi_value ScreenCaptureMonitorNapi::JsIsSystemScreenRecorderWorking(napi_env env, napi_callback_info info)
261 {
262 MediaTrace trace("ScreenCaptureMonitorNapi::JsIsSystemScreenRecorderWorking");
263 MEDIA_LOGI("Js IsSystemScreenRecorderWorking Start");
264 napi_value result = nullptr;
265 napi_get_undefined(env, &result);
266
267 std::unique_ptr<ScreenCaptureMonitorAsyncContext> asyncCtx =
268 std::make_unique<ScreenCaptureMonitorAsyncContext>(env);
269 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
270
271 if (!SystemPermission()) {
272 SignError(asyncCtx.get(), MSERR_EXT_API9_PERMISSION_DENIED, "IsSystemScreenRecorderWorking", "system");
273 }
274
275 size_t argCount = 0;
276 bool isSystemScreenRecorderWorking = false;
277 napi_status status = napi_get_boolean(env, isSystemScreenRecorderWorking, &result);
278
279 ScreenCaptureMonitorNapi *monitorNapi = ScreenCaptureMonitorNapi::GetJsInstanceAndArgs(
280 env, info, argCount, nullptr);
281 CHECK_AND_RETURN_RET_LOG(monitorNapi != nullptr, result, "Failed to GetJsInstanceAndArgs");
282
283 isSystemScreenRecorderWorking = ScreenCaptureMonitor::GetInstance()->IsSystemScreenRecorderWorking();
284 status = napi_get_boolean(env, isSystemScreenRecorderWorking, &result);
285 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_boolean failed");
286
287 return result;
288 }
289
GetJsInstanceAndArgs(napi_env env,napi_callback_info info,size_t & argCount,napi_value * args)290 ScreenCaptureMonitorNapi *ScreenCaptureMonitorNapi::GetJsInstanceAndArgs(
291 napi_env env, napi_callback_info info, size_t &argCount, napi_value *args)
292 {
293 napi_value jsThis = nullptr;
294 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
295 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
296 MEDIA_LOGD("argCount:%{public}zu", argCount);
297
298 ScreenCaptureMonitorNapi *monitorNapi = nullptr;
299 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&monitorNapi));
300 CHECK_AND_RETURN_RET_LOG(status == napi_ok && monitorNapi != nullptr, nullptr, "failed to retrieve instance");
301
302 return monitorNapi;
303 }
304
SetCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)305 void ScreenCaptureMonitorNapi::SetCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
306 {
307 eventCbMap_[callbackName] = ref;
308 CHECK_AND_RETURN_LOG(monitorCb_ != nullptr, "monitorCb_ is nullptr!");
309 auto napiCb = static_cast<ScreenCaptureMonitorCallback*>(monitorCb_.GetRefPtr());
310 napiCb->SaveCallbackReference(callbackName, ref);
311 }
312
CancelCallbackReference(const std::string & callbackName)313 void ScreenCaptureMonitorNapi::CancelCallbackReference(const std::string &callbackName)
314 {
315 CHECK_AND_RETURN_LOG(monitorCb_ != nullptr, "monitorCb_ is nullptr!");
316 auto napiCb = static_cast<ScreenCaptureMonitorCallback*>(monitorCb_.GetRefPtr());
317 napiCb->CancelCallbackReference(callbackName);
318 eventCbMap_[callbackName] = nullptr;
319 }
320 } // Media
321 } // OHOS