1 /*
2 * Copyright (C) 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 "avscreen_capture_napi.h"
17 #include "avscreen_capture_callback.h"
18 #include "common_napi.h"
19 #include "media_dfx.h"
20 #include "media_log.h"
21 #ifndef CROSS_PLATFORM
22 #include "display_manager.h"
23 #include "media_errors.h"
24 #include "recorder_napi_utils.h"
25 #endif
26 namespace {
27 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_SCREENCAPTURE, "AVScreenCaptureNapi"};
28 }
29
30 namespace OHOS {
31 namespace Media {
32 thread_local napi_ref AVScreenCaptureNapi::constructor_ = nullptr;
33 const std::string CLASS_NAME = "AVScreenCapture";
34 std::map<std::string, AVScreenCaptureNapi::AvScreenCaptureTaskqFunc> AVScreenCaptureNapi::taskQFuncs_ = {
35 {AVScreenCapturegOpt::START_RECORDING, &AVScreenCaptureNapi::StartRecording},
36 {AVScreenCapturegOpt::STOP_RECORDING, &AVScreenCaptureNapi::StopRecording},
37 {AVScreenCapturegOpt::RELEASE, &AVScreenCaptureNapi::Release},
38 };
39
AVScreenCaptureNapi()40 AVScreenCaptureNapi::AVScreenCaptureNapi()
41 {
42 MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances create", FAKE_POINTER(this));
43 }
44
~AVScreenCaptureNapi()45 AVScreenCaptureNapi::~AVScreenCaptureNapi()
46 {
47 MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances destroy", FAKE_POINTER(this));
48 }
49
Init(napi_env env,napi_value exports)50 napi_value AVScreenCaptureNapi::Init(napi_env env, napi_value exports)
51 {
52 napi_property_descriptor staticProperty[] = {
53 DECLARE_NAPI_STATIC_FUNCTION("createAVScreenCaptureRecorder", JsCreateAVScreenRecorder),
54 DECLARE_NAPI_STATIC_FUNCTION("reportAVScreenCaptureUserChoice", JsReportAVScreenCaptureUserChoice),
55 DECLARE_NAPI_STATIC_FUNCTION("getAVScreenCaptureConfigurableParameters",
56 JsGetAVScreenCaptureConfigurableParameters)
57 };
58
59 napi_property_descriptor properties[] = {
60 DECLARE_NAPI_FUNCTION("init", JsInit),
61 DECLARE_NAPI_FUNCTION("startRecording", JsStartRecording),
62 DECLARE_NAPI_FUNCTION("stopRecording", JsStopRecording),
63 DECLARE_NAPI_FUNCTION("skipPrivacyMode", JsSkipPrivacyMode),
64 DECLARE_NAPI_FUNCTION("setMicEnabled", JsSetMicrophoneEnabled),
65 DECLARE_NAPI_FUNCTION("release", JsRelease),
66 DECLARE_NAPI_FUNCTION("on", JsSetEventCallback),
67 DECLARE_NAPI_FUNCTION("off", JsCancelEventCallback),
68 };
69
70 napi_value constructor = nullptr;
71 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
72 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
73 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AVScreenCapture class");
74
75 status = napi_create_reference(env, constructor, 1, &constructor_);
76 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
77
78 status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
79 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
80
81 status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
82 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
83
84 MEDIA_LOGD("AVScreenCaptureNapi Init success");
85 return exports;
86 }
87
Constructor(napi_env env,napi_callback_info info)88 napi_value AVScreenCaptureNapi::Constructor(napi_env env, napi_callback_info info)
89 {
90 MediaTrace trace("AVScreenCaptureNapi::Constructor");
91 napi_value result = nullptr;
92 napi_get_undefined(env, &result);
93
94 size_t argCount = 0;
95 napi_value jsThis = nullptr;
96 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
97 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
98
99 AVScreenCaptureNapi *jsScreenCapture = new(std::nothrow) AVScreenCaptureNapi();
100 CHECK_AND_RETURN_RET_LOG(jsScreenCapture != nullptr, result, "failed to new AVScreenCaptureNapi");
101 jsScreenCapture->env_ = env;
102 jsScreenCapture->screenCapture_ = ScreenCaptureFactory::CreateScreenCapture();
103 if (jsScreenCapture->screenCapture_ == nullptr) {
104 delete jsScreenCapture;
105 MEDIA_LOGE("failed to CreateScreenCapture");
106 return result;
107 }
108
109 jsScreenCapture->taskQue_ = std::make_unique<TaskQueue>("OS_AVScreenCaptureNapi");
110 (void)jsScreenCapture->taskQue_->Start();
111
112 jsScreenCapture->screenCaptureCb_ = std::make_shared<AVScreenCaptureCallback>(env);
113 if (jsScreenCapture->screenCaptureCb_ == nullptr) {
114 delete jsScreenCapture;
115 MEDIA_LOGE("failed to CreateScreenCaptureCb");
116 return result;
117 }
118
119 (void)jsScreenCapture->screenCapture_->SetScreenCaptureCallback(jsScreenCapture->screenCaptureCb_);
120
121 status = napi_wrap(env, jsThis, reinterpret_cast<void *>(jsScreenCapture),
122 AVScreenCaptureNapi::Destructor, nullptr, nullptr);
123 if (status != napi_ok) {
124 delete jsScreenCapture;
125 MEDIA_LOGE("Failed to wrap native instance");
126 return result;
127 }
128
129 MEDIA_LOGI("Constructor success");
130 return jsThis;
131 }
132
Destructor(napi_env env,void * nativeObject,void * finalize)133 void AVScreenCaptureNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
134 {
135 MediaTrace trace("AVScreenCaptureNapi::Destructor");
136 (void)finalize;
137 if (nativeObject != nullptr) {
138 AVScreenCaptureNapi *napi = reinterpret_cast<AVScreenCaptureNapi *>(nativeObject);
139 if (napi->taskQue_ != nullptr) {
140 (void)napi->taskQue_->Stop();
141 }
142
143 napi->screenCaptureCb_ = nullptr;
144
145 if (napi->screenCapture_) {
146 napi->screenCapture_->Release();
147 napi->screenCapture_ = nullptr;
148 }
149
150 delete napi;
151 }
152 MEDIA_LOGI("Destructor success");
153 }
154
JsCreateAVScreenRecorder(napi_env env,napi_callback_info info)155 napi_value AVScreenCaptureNapi::JsCreateAVScreenRecorder(napi_env env, napi_callback_info info)
156 {
157 MediaTrace trace("AVScreenCapture::JsCreateAVScreenRecorder");
158 napi_value result = nullptr;
159 napi_get_undefined(env, &result);
160
161 // get args
162 napi_value jsThis = nullptr;
163 napi_value args[1] = { nullptr };
164 size_t argCount = 1;
165 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
166 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
167
168 std::unique_ptr<AVScreenCaptureAsyncContext> asyncCtx = std::make_unique<AVScreenCaptureAsyncContext>(env);
169 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
170
171 asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
172 asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
173 asyncCtx->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
174 asyncCtx->ctorFlag = true;
175 auto ret = MediaAsyncContext::SendCompleteEvent(env, asyncCtx.get(), napi_eprio_immediate);
176 if (ret != napi_status::napi_ok) {
177 MEDIA_LOGE("failed to SendEvent, ret = %{public}d", ret);
178 } else {
179 asyncCtx.release();
180 }
181
182 MEDIA_LOGI("JsCreateAVScreenRecorder success");
183 return result;
184 }
185
GetReturnInfo(int32_t errCode,const std::string & operate,const std::string & param,const std::string & add="")186 RetInfo GetReturnInfo(int32_t errCode, const std::string &operate, const std::string ¶m,
187 const std::string &add = "")
188 {
189 MEDIA_LOGE("failed to %{public}s, param %{public}s, errCode = %{public}d",
190 operate.c_str(), param.c_str(), errCode);
191 MediaServiceExtErrCodeAPI9 err = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(errCode));
192
193 std::string message;
194 if (err == MSERR_EXT_API9_INVALID_PARAMETER) {
195 message = MSExtErrorAPI9ToString(err, param, "") + add;
196 } else {
197 message = MSExtErrorAPI9ToString(err, operate, "") + add;
198 }
199
200 MEDIA_LOGE("errCode: %{public}d, errMsg: %{public}s", err, message.c_str());
201 return RetInfo(err, message);
202 }
203
JsReportAVScreenCaptureUserChoice(napi_env env,napi_callback_info info)204 napi_value AVScreenCaptureNapi::JsReportAVScreenCaptureUserChoice(napi_env env, napi_callback_info info)
205 {
206 MediaTrace trace("AVScreenCapture::JsReportAVScreenCaptureUserChoice");
207 const std::string &opt = AVScreenCapturegOpt::REPORT_USER_CHOICE;
208 MEDIA_LOGI("Js %{public}s Start", opt.c_str());
209
210 const int32_t maxParam = 2; // config + callbackRef
211 size_t argCount = maxParam;
212 napi_value args[maxParam] = { nullptr };
213
214 napi_value result = nullptr;
215 napi_get_undefined(env, &result);
216
217 auto asyncCtx = std::make_unique<AVScreenCaptureAsyncContext>(env);
218 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
219
220 napi_value jsThis = nullptr;
221 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
222 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
223 MEDIA_LOGI("argCountL %{public}zu", argCount);
224
225 if (argCount < maxParam) {
226 asyncCtx->AVScreenCaptureSignError(MSERR_MANDATORY_PARAMETER_UNSPECIFIED, "ReportUserChoice", "");
227 return result;
228 }
229
230 napi_valuetype valueType = napi_undefined;
231 if (napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
232 asyncCtx->AVScreenCaptureSignError(MSERR_INCORRECT_PARAMETER_TYPE, "ReportUserChoice", "sessionId",
233 "sessionId is not number");
234 return result;
235 }
236 int32_t sessionId;
237 status = napi_get_value_int32(env, args[0], &sessionId);
238 if (status != napi_ok) {
239 asyncCtx->AVScreenCaptureSignError(MSERR_INCORRECT_PARAMETER_TYPE, "ReportUserChoice", "sessionId",
240 "UserChoice get sessionId failed");
241 return result;
242 }
243
244 valueType = napi_undefined;
245 if (napi_typeof(env, args[1], &valueType) != napi_ok || valueType != napi_string) {
246 asyncCtx->AVScreenCaptureSignError(MSERR_INCORRECT_PARAMETER_TYPE, "ReportUserChoice", "choice",
247 "choice is not string");
248 return result;
249 }
250 std::string choice = CommonNapi::GetStringArgument(env, args[1]);
251 MEDIA_LOGI("JsReportAVScreenCaptureUserChoice sessionId: %{public}d, choice: %{public}s",
252 sessionId, choice.c_str());
253
254 asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
255 asyncCtx->controller_ = ScreenCaptureControllerFactory::CreateScreenCaptureController();
256 asyncCtx->controller_->ReportAVScreenCaptureUserChoice(sessionId, choice);
257
258 napi_value resource = nullptr;
259 napi_create_string_utf8(env, opt.c_str(), NAPI_AUTO_LENGTH, &resource);
260 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, AsyncJsReportAVScreenCaptureUserChoice,
261 MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
262 NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncCtx->work, napi_qos_user_initiated));
263 asyncCtx.release();
264
265 MEDIA_LOGI("Js %{public}s End", opt.c_str());
266 return result;
267 }
268
JsGetAVScreenCaptureConfigurableParameters(napi_env env,napi_callback_info info)269 napi_value AVScreenCaptureNapi::JsGetAVScreenCaptureConfigurableParameters(napi_env env, napi_callback_info info)
270 {
271 MediaTrace trace("AVScreenCapture::JsGetAVScreenCaptureConfigurableParameters");
272 const std::string &opt = AVScreenCapturegOpt::GET_CONFIG_PARAMS;
273 MEDIA_LOGI("Js %{public}s Start", opt.c_str());
274
275 const int32_t maxParam = 1;
276 size_t argCount = maxParam;
277 napi_value args[maxParam] = { nullptr };
278 napi_value result = nullptr;
279 auto asyncCtx = std::make_unique<AVScreenCaptureAsyncContext>(env);
280 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
281 napi_value jsThis = nullptr;
282 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
283 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
284 MEDIA_LOGI("argCount %{public}zu", argCount);
285 if (argCount < maxParam) {
286 ThrowCustomError(env, MSERR_EXT_API9_PERMISSION_DENIED, "parameter missing");
287 }
288 napi_valuetype valueType = napi_undefined;
289 if (napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
290 ThrowCustomError(env, MSERR_EXT_API9_PERMISSION_DENIED, "invalid parameter type");
291 }
292 int32_t sessionId;
293 status = napi_get_value_int32(env, args[0], &sessionId);
294 if (status != napi_ok) {
295 ThrowCustomError(env, MSERR_EXT_API9_PERMISSION_DENIED, "invalid parameter type");
296 }
297 if (!SystemPermission()) {
298 ThrowCustomError(env, MSERR_EXT_API9_PERMISSION_DENIED, "permission denied");
299 }
300 std::string resultStr = "";
301 asyncCtx->controller_ = ScreenCaptureControllerFactory::CreateScreenCaptureController();
302 if (asyncCtx->controller_ == nullptr) {
303 ThrowCustomError(env, MSERR_EXT_API9_PERMISSION_DENIED, "failed to create controller");
304 }
305 int32_t res = asyncCtx->controller_->GetAVScreenCaptureConfigurableParameters(sessionId, resultStr);
306 if (res != MSERR_OK) {
307 ThrowCustomError(env, MSERR_EXT_API20_SESSION_NOT_EXIST, "session does not exist.");
308 }
309 napi_create_string_utf8(env, resultStr.c_str(), NAPI_AUTO_LENGTH, &result);
310 napi_value resource = nullptr;
311 napi_create_string_utf8(env, opt.c_str(), NAPI_AUTO_LENGTH, &resource);
312 asyncCtx.release();
313 MEDIA_LOGI("Js %{public}s End", opt.c_str());
314 return result;
315 }
316
ThrowCustomError(napi_env env,int32_t errorCode,const char * errorMessage)317 napi_value AVScreenCaptureNapi::ThrowCustomError(napi_env env, int32_t errorCode, const char* errorMessage)
318 {
319 napi_value message = nullptr;
320 napi_value error = nullptr;
321 napi_value codeValue = nullptr;
322 napi_value propName = nullptr;
323
324 napi_create_string_utf8(env, errorMessage, NAPI_AUTO_LENGTH, &message);
325 napi_create_error(env, nullptr, message, &error);
326 napi_create_int32(env, errorCode, &codeValue);
327 napi_create_string_utf8(env, "code", NAPI_AUTO_LENGTH, &propName);
328 napi_set_property(env, error, propName, codeValue);
329 napi_throw(env, error);
330 return nullptr;
331 }
332
AsyncJsReportAVScreenCaptureUserChoice(napi_env env,void * data)333 void AVScreenCaptureNapi::AsyncJsReportAVScreenCaptureUserChoice(napi_env env, void* data)
334 {
335 AVScreenCaptureAsyncContext* asyncCtx = reinterpret_cast<AVScreenCaptureAsyncContext *>(data);
336 CHECK_AND_RETURN_LOG(asyncCtx != nullptr, "asyncCtx is nullptr!");
337
338 if (asyncCtx->task_) {
339 auto result = asyncCtx->task_->GetResult();
340 if (result.Value().first != MSERR_EXT_API9_OK) {
341 asyncCtx->SignError(result.Value().first, result.Value().second);
342 }
343 }
344 MEDIA_LOGI("The js thread of ReportAVScreenCaptureUserChoice finishes execution and returns");
345 }
346
JsInit(napi_env env,napi_callback_info info)347 napi_value AVScreenCaptureNapi::JsInit(napi_env env, napi_callback_info info)
348 {
349 MediaTrace trace("AVScreenCapture::JsInit");
350 const std::string &opt = AVScreenCapturegOpt::INIT;
351 MEDIA_LOGI("Js %{public}s Start", opt.c_str());
352
353 const int32_t maxParam = 2; // config + callbackRef
354 size_t argCount = maxParam;
355 napi_value args[maxParam] = { nullptr };
356
357 napi_value result = nullptr;
358 napi_get_undefined(env, &result);
359
360 auto asyncCtx = std::make_unique<AVScreenCaptureAsyncContext>(env);
361 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
362 asyncCtx->napi = AVScreenCaptureNapi::GetJsInstanceAndArgs(env, info, argCount, args);
363 CHECK_AND_RETURN_RET_LOG(asyncCtx->napi != nullptr, result, "failed to GetJsInstanceAndArgs");
364 CHECK_AND_RETURN_RET_LOG(asyncCtx->napi->taskQue_ != nullptr, result, "taskQue is nullptr!");
365
366 asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[1]);
367 asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
368
369 if (asyncCtx->napi->GetConfig(asyncCtx, env, args[0]) == MSERR_OK) {
370 asyncCtx->task_ = AVScreenCaptureNapi::GetInitTask(asyncCtx);
371 (void)asyncCtx->napi->taskQue_->EnqueueTask(asyncCtx->task_);
372 }
373
374 napi_value resource = nullptr;
375 napi_create_string_utf8(env, opt.c_str(), NAPI_AUTO_LENGTH, &resource);
376 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
377 AVScreenCaptureAsyncContext* asyncCtx = reinterpret_cast<AVScreenCaptureAsyncContext *>(data);
378 CHECK_AND_RETURN_LOG(asyncCtx != nullptr, "asyncCtx is nullptr!");
379
380 if (asyncCtx->task_) {
381 auto result = asyncCtx->task_->GetResult();
382 if (result.Value().first != MSERR_EXT_API9_OK) {
383 asyncCtx->SignError(result.Value().first, result.Value().second);
384 }
385 }
386 MEDIA_LOGI("The js thread of init finishes execution and returns");
387 }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
388 NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncCtx->work, napi_qos_user_initiated));
389 asyncCtx.release();
390
391 MEDIA_LOGI("Js %{public}s End", opt.c_str());
392 return result;
393 }
394
JsStartRecording(napi_env env,napi_callback_info info)395 napi_value AVScreenCaptureNapi::JsStartRecording(napi_env env, napi_callback_info info)
396 {
397 MediaTrace trace("AVScreenCapture::JsStartRecording");
398 return ExecuteByPromise(env, info, AVScreenCapturegOpt::START_RECORDING);
399 }
400
JsStopRecording(napi_env env,napi_callback_info info)401 napi_value AVScreenCaptureNapi::JsStopRecording(napi_env env, napi_callback_info info)
402 {
403 MediaTrace trace("AVScreenCapture::JsStopRecording");
404 return ExecuteByPromise(env, info, AVScreenCapturegOpt::STOP_RECORDING);
405 }
406
GetWindowIDsVectorParams(std::vector<uint64_t> & windowIDsVec,napi_env env,napi_value * args)407 napi_status AVScreenCaptureNapi::GetWindowIDsVectorParams(std::vector<uint64_t> &windowIDsVec, napi_env env,
408 napi_value* args)
409 {
410 uint32_t array_length;
411 napi_status status = napi_get_array_length(env, args[0], &array_length);
412 if (status != napi_ok) {
413 return status;
414 }
415 for (uint32_t i = 0; i < array_length; i++) {
416 napi_value temp;
417 status = napi_get_element(env, args[0], i, &temp);
418 int32_t tempValue = -1;
419 if (status == napi_ok) {
420 napi_get_value_int32(env, temp, &tempValue);
421 }
422 if (tempValue >= 0) {
423 windowIDsVec.push_back(static_cast<uint64_t>(tempValue));
424 } else {
425 MEDIA_LOGI("JsSkipPrivacyMode skip %{public}d", tempValue);
426 }
427 }
428 return napi_ok;
429 }
430
JsSkipPrivacyMode(napi_env env,napi_callback_info info)431 napi_value AVScreenCaptureNapi::JsSkipPrivacyMode(napi_env env, napi_callback_info info)
432 {
433 MediaTrace trace("AVScreenCapture::JsSkipPrivacyMode");
434 const std::string &opt = AVScreenCapturegOpt::SKIP_PRIVACY_MODE;
435 MEDIA_LOGI("Js %{public}s Start", opt.c_str());
436 size_t argCount = 1; // arg[0] vector
437 napi_value args[1] = { nullptr };
438 napi_value result = nullptr;
439 napi_get_undefined(env, &result);
440 auto asyncCtx = std::make_unique<AVScreenCaptureAsyncContext>(env);
441 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
442 asyncCtx->napi = AVScreenCaptureNapi::GetJsInstanceAndArgs(env, info, argCount, args);
443 CHECK_AND_RETURN_RET_LOG(asyncCtx->napi != nullptr, result, "failed to GetJsInstanceAndArgs");
444 CHECK_AND_RETURN_RET_LOG(asyncCtx->napi->taskQue_ != nullptr, result, "taskQue is nullptr!");
445 std::vector<uint64_t> windowIDsVec;
446 napi_get_cb_info(env, info, &argCount, args, nullptr, nullptr);
447 napi_status status = GetWindowIDsVectorParams(windowIDsVec, env, args);
448 CHECK_AND_RETURN_RET_LOG(status == napi_ok, (asyncCtx->AVScreenCaptureSignError(MSERR_EXT_API9_INVALID_PARAMETER,
449 "SkipPrivacyMode", "SkipPrivacyMode get value failed"), result), "failed to GetWindowIDsVectorParams");
450 asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
451 asyncCtx->task_ = AVScreenCaptureNapi::GetSkipPrivacyModeTask(asyncCtx, windowIDsVec);
452 (void)asyncCtx->napi->taskQue_->EnqueueTask(asyncCtx->task_);
453 napi_value resource = nullptr;
454 napi_create_string_utf8(env, opt.c_str(), NAPI_AUTO_LENGTH, &resource);
455 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
456 AVScreenCaptureAsyncContext* asyncCtx = reinterpret_cast<AVScreenCaptureAsyncContext *>(data);
457 CHECK_AND_RETURN_LOG(asyncCtx != nullptr, "asyncCtx is nullptr!");
458 if (asyncCtx->task_) {
459 auto result = asyncCtx->task_->GetResult();
460 if (result.Value().first != MSERR_EXT_API9_OK) {
461 asyncCtx->SignError(result.Value().first, result.Value().second);
462 }
463 }
464 MEDIA_LOGI("The js thread of init finishes execution and returns");
465 }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
466 NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncCtx->work, napi_qos_user_initiated));
467 asyncCtx.release();
468 MEDIA_LOGI("Js %{public}s End", opt.c_str());
469 return result;
470 }
471
JsSetMicrophoneEnabled(napi_env env,napi_callback_info info)472 napi_value AVScreenCaptureNapi::JsSetMicrophoneEnabled(napi_env env, napi_callback_info info)
473 {
474 MediaTrace trace("AVScreenCapture::JsSetMicrophoneEnabled");
475 const std::string &opt = AVScreenCapturegOpt::SET_MIC_ENABLE;
476 MEDIA_LOGI("Js %{public}s Start", opt.c_str());
477
478 const int32_t maxParam = 1; // config + callbackRef
479 size_t argCount = maxParam;
480 napi_value args[maxParam] = { nullptr };
481
482 napi_value result = nullptr;
483 napi_get_undefined(env, &result);
484
485 auto asyncCtx = std::make_unique<AVScreenCaptureAsyncContext>(env);
486 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
487 asyncCtx->napi = AVScreenCaptureNapi::GetJsInstanceAndArgs(env, info, argCount, args);
488 CHECK_AND_RETURN_RET_LOG(asyncCtx->napi != nullptr, result, "failed to GetJsInstanceAndArgs");
489 CHECK_AND_RETURN_RET_LOG(asyncCtx->napi->taskQue_ != nullptr, result, "taskQue is nullptr!");
490
491 napi_valuetype valueType = napi_undefined;
492 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_boolean) {
493 asyncCtx->AVScreenCaptureSignError(MSERR_EXT_API9_INVALID_PARAMETER, "SetMivcrophoneEnable",
494 "setMicrophone input is not boolean");
495 return result;
496 }
497 bool enable;
498 napi_status status = napi_get_value_bool(env, args[0], &enable);
499 if (status != napi_ok) {
500 asyncCtx->AVScreenCaptureSignError(MSERR_EXT_API9_INVALID_PARAMETER, "SetMivcrophoneEnable",
501 "setMicrophone get value failed");
502 return result;
503 }
504
505 asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
506 asyncCtx->task_ = AVScreenCaptureNapi::GetSetMicrophoneEnableTask(asyncCtx, enable);
507 (void)asyncCtx->napi->taskQue_->EnqueueTask(asyncCtx->task_);
508
509 napi_value resource = nullptr;
510 napi_create_string_utf8(env, opt.c_str(), NAPI_AUTO_LENGTH, &resource);
511 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
512 AVScreenCaptureAsyncContext* asyncCtx = reinterpret_cast<AVScreenCaptureAsyncContext *>(data);
513 CHECK_AND_RETURN_LOG(asyncCtx != nullptr, "asyncCtx is nullptr!");
514
515 if (asyncCtx->task_) {
516 auto result = asyncCtx->task_->GetResult();
517 if (result.Value().first != MSERR_EXT_API9_OK) {
518 asyncCtx->SignError(result.Value().first, result.Value().second);
519 }
520 }
521 MEDIA_LOGI("The js thread of init finishes execution and returns");
522 }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
523 NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncCtx->work, napi_qos_user_initiated));
524 asyncCtx.release();
525
526 MEDIA_LOGI("Js %{public}s End", opt.c_str());
527 return result;
528 }
529
JsRelease(napi_env env,napi_callback_info info)530 napi_value AVScreenCaptureNapi::JsRelease(napi_env env, napi_callback_info info)
531 {
532 MediaTrace trace("AVScreenCapture::JsRelease");
533 return ExecuteByPromise(env, info, AVScreenCapturegOpt::RELEASE);
534 }
535
JsSetEventCallback(napi_env env,napi_callback_info info)536 napi_value AVScreenCaptureNapi::JsSetEventCallback(napi_env env, napi_callback_info info)
537 {
538 MediaTrace trace("AVScreenCapture::JsSetEventCallback");
539 MEDIA_LOGI("JsSetEventCallback Start");
540 napi_value result = nullptr;
541 napi_get_undefined(env, &result);
542
543 size_t argCount = 2;
544 napi_value args[2] = { nullptr, nullptr };
545 AVScreenCaptureNapi *avScreenCaptureNapi = AVScreenCaptureNapi::GetJsInstanceAndArgs(env, info, argCount, args);
546 CHECK_AND_RETURN_RET_LOG(avScreenCaptureNapi != nullptr, result, "Failed to retrieve instance");
547
548 napi_valuetype valueType0 = napi_undefined;
549 napi_valuetype valueType1 = napi_undefined;
550 if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string ||
551 napi_typeof(env, args[1], &valueType1) != napi_ok || valueType1 != napi_function) {
552 avScreenCaptureNapi->ErrorCallback(MSERR_INVALID_VAL, "SetEventCallback");
553 return result;
554 }
555
556 std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
557 if (callbackName != AVScreenCaptureEvent::EVENT_ERROR &&
558 callbackName != AVScreenCaptureEvent::EVENT_STATE_CHANGE) {
559 avScreenCaptureNapi->ErrorCallback(MSERR_INVALID_VAL, "SetEventCallback");
560 return result;
561 }
562
563 napi_ref ref = nullptr;
564 napi_status status = napi_create_reference(env, args[1], 1, &ref);
565 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
566
567 std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
568 avScreenCaptureNapi->SetCallbackReference(callbackName, autoRef);
569
570 MEDIA_LOGI("JsSetEventCallback set callback %{public}s End", callbackName.c_str());
571 return result;
572 }
573
JsCancelEventCallback(napi_env env,napi_callback_info info)574 napi_value AVScreenCaptureNapi::JsCancelEventCallback(napi_env env, napi_callback_info info)
575 {
576 MediaTrace trace("AVScreenCapture::JsCancelEventCallback");
577 MEDIA_LOGI("JsCancelEventCallback Start");
578 napi_value result = nullptr;
579 napi_get_undefined(env, &result);
580
581 size_t argCount = 1;
582 napi_value args[1] = { nullptr };
583 AVScreenCaptureNapi *avScreenCaptureNapi = AVScreenCaptureNapi::GetJsInstanceAndArgs(env, info, argCount, args);
584 CHECK_AND_RETURN_RET_LOG(avScreenCaptureNapi != nullptr, result, "Failed to retrieve instance");
585
586 napi_valuetype valueType0 = napi_undefined;
587 if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string) {
588 avScreenCaptureNapi->ErrorCallback(MSERR_INVALID_VAL, "CancelEventCallback");
589 return result;
590 }
591
592 std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
593 if (callbackName != AVScreenCaptureEvent::EVENT_ERROR &&
594 callbackName != AVScreenCaptureEvent::EVENT_STATE_CHANGE) {
595 avScreenCaptureNapi->ErrorCallback(MSERR_INVALID_VAL, "CancelEventCallback");
596 return result;
597 }
598
599 avScreenCaptureNapi->CancelCallbackReference(callbackName);
600
601 MEDIA_LOGI("JsCancelEventCallback cancel callback %{public}s End", callbackName.c_str());
602 return result;
603 }
604
GetInitTask(const std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx)605 std::shared_ptr<TaskHandler<RetInfo>> AVScreenCaptureNapi::GetInitTask(
606 const std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx)
607 {
608 return std::make_shared<TaskHandler<RetInfo>>([napi = asyncCtx->napi, config = asyncCtx->config_]() {
609 const std::string &option = AVScreenCapturegOpt::INIT;
610 MEDIA_LOGI("%{public}s Start", option.c_str());
611
612 CHECK_AND_RETURN_RET(napi != nullptr && napi->screenCapture_ != nullptr,
613 GetReturnInfo(MSERR_INVALID_OPERATION, option, ""));
614
615 int32_t ret = napi->screenCapture_->Init(config);
616 CHECK_AND_RETURN_RET(ret == MSERR_OK, ((void)napi->screenCapture_->Release(), GetReturnInfo(ret, "Init", "")));
617
618 MEDIA_LOGI("%{public}s End", option.c_str());
619 return RetInfo(MSERR_EXT_API9_OK, "");
620 });
621 }
622
GetSkipPrivacyModeTask(const std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,const std::vector<uint64_t> windowIDsVec)623 std::shared_ptr<TaskHandler<RetInfo>> AVScreenCaptureNapi::GetSkipPrivacyModeTask(
624 const std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx, const std::vector<uint64_t> windowIDsVec)
625 {
626 return std::make_shared<TaskHandler<RetInfo>>([napi = asyncCtx->napi, windowIDsVec]() {
627 const std::string &option = AVScreenCapturegOpt::SKIP_PRIVACY_MODE;
628 MEDIA_LOGI("%{public}s Start", option.c_str());
629 CHECK_AND_RETURN_RET(napi != nullptr && napi->screenCapture_ != nullptr,
630 GetReturnInfo(MSERR_INVALID_OPERATION, option, ""));
631 int32_t ret = napi->screenCapture_->SkipPrivacyMode(const_cast<std::vector<uint64_t> &>(windowIDsVec));
632 CHECK_AND_RETURN_RET(ret == MSERR_OK, GetReturnInfo(MSERR_UNKNOWN, option, ""));
633 MEDIA_LOGI("%{public}s End", option.c_str());
634 return RetInfo(MSERR_EXT_API9_OK, "");
635 });
636 }
637
GetSetMicrophoneEnableTask(const std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,const bool enable)638 std::shared_ptr<TaskHandler<RetInfo>> AVScreenCaptureNapi::GetSetMicrophoneEnableTask(
639 const std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx, const bool enable)
640 {
641 return std::make_shared<TaskHandler<RetInfo>>([napi = asyncCtx->napi, enable]() {
642 const std::string &option = AVScreenCapturegOpt::SET_MIC_ENABLE;
643 MEDIA_LOGI("%{public}s Start", option.c_str());
644
645 CHECK_AND_RETURN_RET(napi != nullptr && napi->screenCapture_ != nullptr,
646 GetReturnInfo(MSERR_INVALID_OPERATION, option, ""));
647
648 int32_t ret = napi->screenCapture_->SetMicrophoneEnabled(enable);
649 CHECK_AND_RETURN_RET(ret == MSERR_OK, GetReturnInfo(MSERR_UNKNOWN, option, ""));
650
651 MEDIA_LOGI("%{public}s End", option.c_str());
652 return RetInfo(MSERR_EXT_API9_OK, "");
653 });
654 }
655
GetJsInstanceAndArgs(napi_env env,napi_callback_info info,size_t & argCount,napi_value * args)656 AVScreenCaptureNapi *AVScreenCaptureNapi::GetJsInstanceAndArgs(
657 napi_env env, napi_callback_info info, size_t &argCount, napi_value *args)
658 {
659 napi_value jsThis = nullptr;
660 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
661 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
662 MEDIA_LOGI("argCount:%{public}zu", argCount);
663
664 AVScreenCaptureNapi *screenCaptureNapi = nullptr;
665 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&screenCaptureNapi));
666 CHECK_AND_RETURN_RET_LOG(status == napi_ok && screenCaptureNapi != nullptr, nullptr,
667 "failed to retrieve instance");
668
669 return screenCaptureNapi;
670 }
671
StartRecording()672 RetInfo AVScreenCaptureNapi::StartRecording()
673 {
674 int32_t ret = screenCapture_->SetPrivacyAuthorityEnabled();
675 CHECK_AND_RETURN_RET(ret == MSERR_OK, GetReturnInfo(ret, "SetPrivacyAuthorityEnabled", ""));
676 ret = screenCapture_->StartScreenRecording();
677 CHECK_AND_RETURN_RET(ret == MSERR_OK, GetReturnInfo(ret, "StartRecording", ""));
678 return RetInfo(MSERR_EXT_API9_OK, "");
679 }
680
StopRecording()681 RetInfo AVScreenCaptureNapi::StopRecording()
682 {
683 int32_t ret = screenCapture_->StopScreenRecording();
684 CHECK_AND_RETURN_RET(ret == MSERR_OK, GetReturnInfo(ret, "StopRecording", ""));
685 return RetInfo(MSERR_EXT_API9_OK, "");
686 }
687
Release()688 RetInfo AVScreenCaptureNapi::Release()
689 {
690 int32_t ret = screenCapture_->Release();
691 CHECK_AND_RETURN_RET(ret == MSERR_OK, GetReturnInfo(ret, "Release", ""));
692 return RetInfo(MSERR_EXT_API9_OK, "");
693 }
694
GetConfig(std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,napi_env env,napi_value args)695 int32_t AVScreenCaptureNapi::GetConfig(std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx,
696 napi_env env, napi_value args)
697 {
698 napi_valuetype valueType = napi_undefined;
699 if (args == nullptr || napi_typeof(env, args, &valueType) != napi_ok || valueType != napi_object) {
700 asyncCtx->AVScreenCaptureSignError(MSERR_INCORRECT_PARAMETER_TYPE, "GetConfig", "AVScreenCaptureRecordConfig",
701 "config type should be AVScreenCaptureRecordConfig.");
702 return MSERR_INCORRECT_PARAMETER_TYPE;
703 }
704
705 asyncCtx->config_.captureMode = CaptureMode::CAPTURE_HOME_SCREEN;
706 asyncCtx->config_.dataType = DataType::CAPTURE_FILE;
707
708 int32_t ret = GetAudioInfo(asyncCtx, env, args);
709 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "failed to GetAudioInfo");
710 ret = GetVideoInfo(asyncCtx, env, args);
711 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "failed to GetVideoInfo");
712 ret = GetRecorderInfo(asyncCtx, env, args);
713 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "failed to GetRecorderInfo");
714 ret = GetStrategy(asyncCtx, env, args);
715 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "failed to GetStrategy");
716 return MSERR_OK;
717 }
718
GetAudioInfo(std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,napi_env env,napi_value args)719 int32_t AVScreenCaptureNapi::GetAudioInfo(std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx,
720 napi_env env, napi_value args)
721 {
722 int32_t audioSampleRate = AVSCREENCAPTURE_DEFAULT_AUDIO_SAMPLE_RATE;
723 int32_t audioChannels = AVSCREENCAPTURE_DEFAULT_AUDIO_CHANNELS;
724 int32_t audioBitrate = AVSCREENCAPTURE_DEFAULT_AUDIO_BIT_RATE;
725
726 AudioCaptureInfo &micConfig = asyncCtx->config_.audioInfo.micCapInfo;
727 AudioCaptureInfo &innerConfig = asyncCtx->config_.audioInfo.innerCapInfo;
728 AudioEncInfo &encoderConfig = asyncCtx->config_.audioInfo.audioEncInfo;
729
730 int32_t ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "audioSampleRate", audioSampleRate);
731 CHECK_AND_RETURN_RET(ret == MSERR_OK,
732 (asyncCtx->AVScreenCaptureSignError(ret, "getAudioSampleRate", "audioSampleRate"), ret));
733 ret = AVScreenCaptureNapi::CheckAudioSampleRate(audioSampleRate);
734 CHECK_AND_RETURN_RET(ret == MSERR_OK,
735 (asyncCtx->AVScreenCaptureSignError(ret, "getAudioSampleRate", "audioSampleRate"), ret));
736 micConfig.audioSampleRate = audioSampleRate;
737 innerConfig.audioSampleRate = audioSampleRate;
738 MEDIA_LOGI("input audioSampleRate %{public}d", micConfig.audioSampleRate);
739
740 ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "audioChannelCount", audioChannels);
741 CHECK_AND_RETURN_RET(ret == MSERR_OK,
742 (asyncCtx->AVScreenCaptureSignError(ret, "getAudioChannelCount", "audioChannelCount"), ret));
743 ret = AVScreenCaptureNapi::CheckAudioChannelCount(audioChannels);
744 CHECK_AND_RETURN_RET(ret == MSERR_OK,
745 (asyncCtx->AVScreenCaptureSignError(ret, "getAudioChannelCount", "audioChannelCount"), ret));
746 micConfig.audioChannels = audioChannels;
747 innerConfig.audioChannels = audioChannels;
748 MEDIA_LOGI("input audioChannelCount %{public}d", micConfig.audioChannels);
749 micConfig.audioSource = AudioCaptureSourceType::MIC;
750 innerConfig.audioSource = AudioCaptureSourceType::ALL_PLAYBACK;
751
752 ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "audioBitrate", audioBitrate);
753 CHECK_AND_RETURN_RET(ret == MSERR_OK,
754 (asyncCtx->AVScreenCaptureSignError(ret, "getAudioBitrate", "audioBitrate"), ret));
755 encoderConfig.audioBitrate = audioBitrate;
756 encoderConfig.audioCodecformat = AudioCodecFormat::AAC_LC;
757 MEDIA_LOGI("input audioBitrate %{public}d", encoderConfig.audioBitrate);
758 return MSERR_OK;
759 }
760
GetVideoInfo(std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,napi_env env,napi_value args)761 int32_t AVScreenCaptureNapi::GetVideoInfo(std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx,
762 napi_env env, napi_value args)
763 {
764 int32_t ret = GetVideoEncInfo(asyncCtx, env, args);
765 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "GetVideoEncInfo failed");
766 ret = GetVideoCaptureInfo(asyncCtx, env, args);
767 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "GetVideoCaptureInfo failed");
768 return MSERR_OK;
769 }
770
GetVideoEncInfo(std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,napi_env env,napi_value args)771 int32_t AVScreenCaptureNapi::GetVideoEncInfo(std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx,
772 napi_env env, napi_value args)
773 {
774 int32_t videoBitrate = AVSCREENCAPTURE_DEFAULT_VIDEO_BIT_RATE;
775 int32_t preset = AVScreenCaptureRecorderPreset::SCREEN_RECORD_PRESET_H264_AAC_MP4;
776 VideoEncInfo &encoderConfig = asyncCtx->config_.videoInfo.videoEncInfo;
777 // get videoBitrate
778 int32_t ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "videoBitrate", videoBitrate);
779 CHECK_AND_RETURN_RET(ret == MSERR_OK,
780 (asyncCtx->AVScreenCaptureSignError(ret, "getVideoBitrate", "videoBitrate"), ret));
781 encoderConfig.videoBitrate = videoBitrate;
782 encoderConfig.videoFrameRate = AVSCREENCAPTURE_DEFAULT_VIDEO_FRAME_RATE;
783 MEDIA_LOGI("input videoBitrate %{public}d", encoderConfig.videoBitrate);
784 // get preset
785 ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "preset", preset);
786 CHECK_AND_RETURN_RET(ret == MSERR_OK, (asyncCtx->AVScreenCaptureSignError(ret, "getPreset", "preset"), ret));
787 ret = AVScreenCaptureNapi::CheckVideoCodecFormat(preset);
788 CHECK_AND_RETURN_RET(ret == MSERR_OK, (asyncCtx->AVScreenCaptureSignError(ret, "getPreset", "preset"), ret));
789 encoderConfig.videoCodec = AVScreenCaptureNapi::GetVideoCodecFormat(preset);
790 MEDIA_LOGI("input videoCodec %{public}d", encoderConfig.videoCodec);
791 return MSERR_OK;
792 }
793
GetVideoCaptureInfo(std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,napi_env env,napi_value args)794 int32_t AVScreenCaptureNapi::GetVideoCaptureInfo(std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx,
795 napi_env env, napi_value args)
796 {
797 int32_t frameWidth = AVSCREENCAPTURE_DEFAULT_FRAME_WIDTH;
798 int32_t frameHeight = AVSCREENCAPTURE_DEFAULT_FRAME_HEIGHT;
799 int32_t displayId = AVSCREENCAPTURE_DEFAULT_DISPLAY_ID;
800 int32_t fillMode = AVScreenCaptureFillMode::PRESERVE_ASPECT_RATIO;
801 VideoCaptureInfo &videoConfig = asyncCtx->config_.videoInfo.videoCapInfo;
802 // get displayId
803 int32_t ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "displayId", displayId);
804 CHECK_AND_RETURN_RET(ret == MSERR_OK && displayId >= 0,
805 (asyncCtx->AVScreenCaptureSignError(MSERR_INVALID_VAL, "getDisplayId", "displayId"), MSERR_INVALID_VAL));
806 videoConfig.displayId = static_cast<uint64_t>(displayId);
807 if (videoConfig.displayId > 0) {
808 asyncCtx->config_.captureMode = CaptureMode::CAPTURE_SPECIFIED_SCREEN;
809 }
810 MEDIA_LOGI("input displayId %{public}" PRIu64, videoConfig.displayId);
811 // get video frame info (frameWidth and frameHeight)
812 ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "frameWidth", frameWidth);
813 CHECK_AND_RETURN_RET(ret == MSERR_OK,
814 (asyncCtx->AVScreenCaptureSignError(ret, "getFrameWidth", "frameWidth"), ret));
815 ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "frameHeight", frameHeight);
816 CHECK_AND_RETURN_RET(ret == MSERR_OK,
817 (asyncCtx->AVScreenCaptureSignError(ret, "getFrameHeight", "frameHeight"), ret));
818 MEDIA_LOGI("input frameWidth %{public}d, frameHeight %{public}d", frameWidth, frameHeight);
819 ret = AVScreenCaptureNapi::CheckVideoFrameFormat(frameWidth, frameHeight,
820 videoConfig.videoFrameWidth, videoConfig.videoFrameHeight);
821 CHECK_AND_RETURN_RET(ret == MSERR_OK,
822 (asyncCtx->AVScreenCaptureSignError(ret, "getVideoFrame", "VideoFrame"), ret));
823 MEDIA_LOGI("input formatted frameWidth %{public}d, frameHeight %{public}d",
824 videoConfig.videoFrameWidth, videoConfig.videoFrameHeight);
825 // get videoSource
826 videoConfig.videoSource = VideoSourceType::VIDEO_SOURCE_SURFACE_RGBA;
827 // get fillMode
828 ret = AVScreenCaptureNapi::GetPropertyInt32(env, args, "fillMode", fillMode);
829 CHECK_AND_RETURN_RET(ret == MSERR_OK, (asyncCtx->AVScreenCaptureSignError(
830 ret, "getScreenCaptureFillMode", "screenCaptureFillMode"), ret));
831 SetScreenCaptureFillMode(asyncCtx->config_.strategy, fillMode);
832 MEDIA_LOGI("input screenCaptureFillMode %{public}d", asyncCtx->config_.strategy.fillMode);
833 return MSERR_OK;
834 }
835
GetRecorderInfo(std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,napi_env env,napi_value args)836 int32_t AVScreenCaptureNapi::GetRecorderInfo(std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx,
837 napi_env env, napi_value args)
838 {
839 RecorderInfo &recorderConfig = asyncCtx->config_.recorderInfo;
840 recorderConfig.fileFormat = AVSCREENCAPTURE_DEFAULT_FILE_FORMAT;
841 int32_t fd = -1;
842 (void)CommonNapi::GetPropertyInt32(env, args, "fd", fd);
843 CHECK_AND_RETURN_RET(fd > 0, // 0 to 2 for system std log
844 (asyncCtx->AVScreenCaptureSignError(MSERR_INVALID_VAL, "GetRecorderInfo", "url"), MSERR_INVALID_VAL));
845 recorderConfig.url = "fd://" + std::to_string(fd);
846 CHECK_AND_RETURN_RET(recorderConfig.url != "",
847 (asyncCtx->AVScreenCaptureSignError(MSERR_INVALID_VAL, "GetRecorderInfo", "url"), MSERR_INVALID_VAL));
848 MEDIA_LOGI("input url %{public}s", recorderConfig.url.c_str());
849 return MSERR_OK;
850 }
851
GetOptionalPropertyBool(napi_env env,napi_value configObj,const std::string & type,bool & result)852 bool AVScreenCaptureNapi::GetOptionalPropertyBool(napi_env env, napi_value configObj, const std::string &type,
853 bool &result)
854 {
855 napi_value item = nullptr;
856 if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) {
857 MEDIA_LOGE("get %{public}s property fail", type.c_str());
858 return false;
859 }
860 if (napi_get_value_bool(env, item, &result) != napi_ok) {
861 MEDIA_LOGE("get %{public}s property value fail", type.c_str());
862 return false;
863 }
864 return true;
865 }
866
GetStrategy(std::unique_ptr<AVScreenCaptureAsyncContext> & asyncCtx,napi_env env,napi_value args)867 int32_t AVScreenCaptureNapi::GetStrategy(std::unique_ptr<AVScreenCaptureAsyncContext> &asyncCtx,
868 napi_env env, napi_value args)
869 {
870 ScreenCaptureStrategy &strategy = asyncCtx->config_.strategy;
871 napi_value strategyVal = nullptr;
872 bool exist = false;
873 napi_status status = napi_has_named_property(env, args, "strategy", &exist);
874 CHECK_AND_RETURN_RET_LOG((status == napi_ok && exist), MSERR_OK, "without strategy");
875 // return MSERR_OK, because strategy is optional.
876
877 CHECK_AND_RETURN_RET_LOG(napi_get_named_property(env, args, "strategy", &strategyVal) == napi_ok,
878 MSERR_INVALID_VAL, "get strategy property failed");
879 napi_valuetype valueType = napi_undefined;
880 status = napi_typeof(env, strategyVal, &valueType);
881 CHECK_AND_RETURN_RET_LOG(status == napi_ok, MSERR_INVALID_VAL, "get valueType failed");
882 CHECK_AND_RETURN_RET_LOG(valueType != napi_undefined, MSERR_INVALID_VAL, "strategy undefined");
883 // get enableDeviceLevelCapture
884 status = napi_has_named_property(env, strategyVal, "enableDeviceLevelCapture", &exist);
885 if (status == napi_ok && exist) {
886 CHECK_AND_RETURN_RET_LOG(GetOptionalPropertyBool(env, strategyVal, "enableDeviceLevelCapture",
887 strategy.enableDeviceLevelCapture), MSERR_INVALID_VAL, "enableDeviceLevelCapture invalid");
888 strategy.setByUser = true;
889 }
890 // get keepCaptureDuringCall
891 status = napi_has_named_property(env, strategyVal, "keepCaptureDuringCall", &exist);
892 if (status == napi_ok && exist) {
893 CHECK_AND_RETURN_RET_LOG(GetOptionalPropertyBool(env, strategyVal, "keepCaptureDuringCall",
894 strategy.keepCaptureDuringCall), MSERR_INVALID_VAL, "keepCaptureDuringCall invalid");
895 strategy.setByUser = true;
896 }
897 // get enableBFrame
898 status = napi_has_named_property(env, strategyVal, "enableBFrame", &exist);
899 if (status == napi_ok && exist) {
900 CHECK_AND_RETURN_RET_LOG(GetOptionalPropertyBool(env, strategyVal, "enableBFrame",
901 strategy.enableBFrame), MSERR_INVALID_VAL, "enableBFrame invalid");
902 strategy.setByUser = true;
903 }
904 MEDIA_LOGI("GetStrategy enableDeviceLevelCapture: %{public}d, keepCaptureDuringCall: %{public}d, "
905 "enableBFrame: %{public}d", strategy.enableDeviceLevelCapture, strategy.keepCaptureDuringCall,
906 strategy.enableBFrame);
907 return MSERR_OK;
908 }
909
CheckAudioSampleRate(const int32_t & audioSampleRate)910 int32_t AVScreenCaptureNapi::CheckAudioSampleRate(const int32_t &audioSampleRate)
911 {
912 if (audioSampleRate == 48000 || audioSampleRate == 16000) { // 16000 48000 AudioSampleRate options
913 return MSERR_OK;
914 }
915 return MSERR_INVALID_VAL;
916 }
917
CheckAudioChannelCount(const int32_t & audioChannelCount)918 int32_t AVScreenCaptureNapi::CheckAudioChannelCount(const int32_t &audioChannelCount)
919 {
920 if (audioChannelCount == 1 || audioChannelCount == 2) { // 1 2 channelCount number options
921 return MSERR_OK;
922 }
923 return MSERR_INVALID_VAL;
924 }
925
CheckVideoFrameFormat(const int32_t & frameWidth,const int32_t & frameHeight,int32_t & videoFrameWidth,int32_t & videoFrameHeight)926 int32_t AVScreenCaptureNapi::CheckVideoFrameFormat(const int32_t &frameWidth, const int32_t &frameHeight,
927 int32_t &videoFrameWidth, int32_t &videoFrameHeight)
928 {
929 #ifndef CROSS_PLATFORM
930 if (frameWidth == AVSCREENCAPTURE_DEFAULT_FRAME_WIDTH || frameHeight == AVSCREENCAPTURE_DEFAULT_FRAME_HEIGHT ||
931 !(frameWidth == 0 && frameHeight == 0)) { // 0 one of width height is zero, use default display
932 sptr<Rosen::Display> display = Rosen::DisplayManager::GetInstance().GetDefaultDisplaySync();
933 if (display == nullptr) {
934 return MSERR_INVALID_VAL;
935 }
936 MEDIA_LOGI("check video frame get displayInfo width:%{public}d,height:%{public}d,density:%{public}f",
937 display->GetWidth(), display->GetHeight(), display->GetVirtualPixelRatio());
938 if (frameWidth == AVSCREENCAPTURE_DEFAULT_FRAME_WIDTH || frameWidth == 0) { // 0 use default display
939 videoFrameWidth = display->GetWidth();
940 } else {
941 videoFrameWidth = frameWidth;
942 }
943 if (frameHeight == AVSCREENCAPTURE_DEFAULT_FRAME_HEIGHT || frameHeight == 0) { // 0 use default display
944 videoFrameHeight = display->GetHeight();
945 } else {
946 videoFrameHeight = frameHeight;
947 }
948 } else {
949 videoFrameWidth = frameWidth;
950 videoFrameHeight = frameHeight;
951 }
952 #else
953 videoFrameWidth = frameWidth;
954 videoFrameHeight = frameHeight;
955 #endif
956 return MSERR_OK;
957 }
958
CheckVideoCodecFormat(const int32_t & preset)959 int32_t AVScreenCaptureNapi::CheckVideoCodecFormat(const int32_t &preset)
960 {
961 if (static_cast<int32_t>(AVScreenCaptureRecorderPreset::SCREEN_RECORD_PRESET_H264_AAC_MP4) <= preset &&
962 static_cast<int32_t>(AVScreenCaptureRecorderPreset::SCREEN_RECORD_PRESET_H265_AAC_MP4) >= preset) {
963 return MSERR_OK;
964 }
965 return MSERR_INVALID_VAL;
966 }
967
GetVideoCodecFormat(const int32_t & preset)968 VideoCodecFormat AVScreenCaptureNapi::GetVideoCodecFormat(const int32_t &preset)
969 {
970 const std::map<AVScreenCaptureRecorderPreset, VideoCodecFormat> presetToCodecFormat = {
971 { AVScreenCaptureRecorderPreset::SCREEN_RECORD_PRESET_H264_AAC_MP4, VideoCodecFormat::H264 },
972 { AVScreenCaptureRecorderPreset::SCREEN_RECORD_PRESET_H265_AAC_MP4, VideoCodecFormat::H265 }
973 };
974 VideoCodecFormat codecFormat = VideoCodecFormat::H264;
975 auto iter = presetToCodecFormat.find(static_cast<AVScreenCaptureRecorderPreset>(preset));
976 if (iter != presetToCodecFormat.end()) {
977 codecFormat = iter->second;
978 }
979 return codecFormat;
980 }
981
SetScreenCaptureFillMode(ScreenCaptureStrategy & strategy,const int32_t & fillMode)982 int32_t AVScreenCaptureNapi::SetScreenCaptureFillMode(ScreenCaptureStrategy &strategy, const int32_t &fillMode)
983 {
984 MEDIA_LOGI("AVScreenCaptureNapi::SetScreenCaptureFillMode in!");
985 const std::map<int32_t, AVScreenCaptureFillMode> intToFillMode = {
986 { 0, AVScreenCaptureFillMode::PRESERVE_ASPECT_RATIO },
987 { 1, AVScreenCaptureFillMode::SCALE_TO_FILL }
988 };
989 auto iter = intToFillMode.find(fillMode);
990 int32_t ret = MSERR_INVALID_VAL;
991 if (iter != intToFillMode.end()) {
992 strategy.fillMode = iter->second;
993 strategy.setByUser = true;
994 ret = MSERR_OK;
995 }
996 MEDIA_LOGI("AVScreenCaptureNapi::SetScreenCaptureFillMode succeed, screenCaptureFillMode: %{public}d",
997 static_cast<int32_t>(strategy.fillMode));
998 return ret;
999 }
1000
ErrorCallback(int32_t errCode,const std::string & operate,const std::string & add)1001 void AVScreenCaptureNapi::ErrorCallback(int32_t errCode, const std::string &operate, const std::string &add)
1002 {
1003 MEDIA_LOGE("failed to %{public}s, errCode = %{public}d", operate.c_str(), errCode);
1004 CHECK_AND_RETURN_LOG(screenCaptureCb_ != nullptr, "screenCaptureCb_ is nullptr!");
1005 auto napiCb = std::static_pointer_cast<AVScreenCaptureCallback>(screenCaptureCb_);
1006
1007 MediaServiceExtErrCodeAPI9 err = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(errCode));
1008 std::string msg = MSExtErrorAPI9ToString(err, operate, "") + add;
1009 napiCb->SendErrorCallback(errCode, msg);
1010 }
1011
StateCallback(const AVScreenCaptureStateCode & stateCode)1012 void AVScreenCaptureNapi::StateCallback(const AVScreenCaptureStateCode &stateCode)
1013 {
1014 MEDIA_LOGI("Change state to %{public}d", stateCode);
1015 CHECK_AND_RETURN_LOG(screenCaptureCb_ != nullptr, "screenCaptureCb_ is nullptr!");
1016 auto napiCb = std::static_pointer_cast<AVScreenCaptureCallback>(screenCaptureCb_);
1017 napiCb->SendStateCallback(stateCode);
1018 }
1019
SetCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)1020 void AVScreenCaptureNapi::SetCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
1021 {
1022 eventCbMap_[callbackName] = ref;
1023 CHECK_AND_RETURN_LOG(screenCaptureCb_ != nullptr, "screenCaptureCb_ is nullptr!");
1024 auto napiCb = std::static_pointer_cast<AVScreenCaptureCallback>(screenCaptureCb_);
1025 napiCb->SaveCallbackReference(callbackName, ref);
1026 }
1027
CancelCallbackReference(const std::string & callbackName)1028 void AVScreenCaptureNapi::CancelCallbackReference(const std::string &callbackName)
1029 {
1030 CHECK_AND_RETURN_LOG(screenCaptureCb_ != nullptr, "screenCaptureCb_ is nullptr!");
1031 auto napiCb = std::static_pointer_cast<AVScreenCaptureCallback>(screenCaptureCb_);
1032 napiCb->CancelCallbackReference(callbackName);
1033 eventCbMap_[callbackName] = nullptr;
1034 }
1035
CancelCallback()1036 void AVScreenCaptureNapi::CancelCallback()
1037 {
1038 CHECK_AND_RETURN_LOG(screenCaptureCb_ != nullptr, "screenCaptureCb_ is nullptr!");
1039 auto napiCb = std::static_pointer_cast<AVScreenCaptureCallback>(screenCaptureCb_);
1040 napiCb->ClearCallbackReference();
1041 }
1042
GetPromiseTask(AVScreenCaptureNapi * avnapi,const std::string & opt)1043 std::shared_ptr<TaskHandler<RetInfo>> AVScreenCaptureNapi::GetPromiseTask(
1044 AVScreenCaptureNapi *avnapi, const std::string &opt)
1045 {
1046 return std::make_shared<TaskHandler<RetInfo>>([napi = avnapi, option = opt]() {
1047 MEDIA_LOGI("%{public}s Start", option.c_str());
1048 CHECK_AND_RETURN_RET(napi != nullptr && napi->screenCapture_ != nullptr,
1049 GetReturnInfo(MSERR_INVALID_OPERATION, option, ""));
1050
1051 RetInfo ret(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "");
1052 auto itFunc = taskQFuncs_.find(option);
1053 CHECK_AND_RETURN_RET_LOG(itFunc != taskQFuncs_.end(), ret, "%{public}s not found in map!", option.c_str());
1054 auto memberFunc = itFunc->second;
1055 CHECK_AND_RETURN_RET_LOG(memberFunc != nullptr, ret, "memberFunc is nullptr!");
1056 ret = (napi->*memberFunc)();
1057
1058 MEDIA_LOGI("%{public}s End", option.c_str());
1059 return ret;
1060 });
1061 }
1062
ExecuteByPromise(napi_env env,napi_callback_info info,const std::string & opt)1063 napi_value AVScreenCaptureNapi::ExecuteByPromise(napi_env env, napi_callback_info info, const std::string &opt)
1064 {
1065 MEDIA_LOGI("Js %{public}s Start", opt.c_str());
1066 napi_value result = nullptr;
1067 napi_get_undefined(env, &result);
1068 size_t argCount = 1; // Only callbackRef parameter
1069 napi_value args[1] = { nullptr }; // Only callbackRef parameter
1070
1071 auto asyncCtx = std::make_unique<AVScreenCaptureAsyncContext>(env);
1072 CHECK_AND_RETURN_RET_LOG(asyncCtx != nullptr, result, "failed to get AsyncContext");
1073 asyncCtx->napi = AVScreenCaptureNapi::GetJsInstanceAndArgs(env, info, argCount, args);
1074 CHECK_AND_RETURN_RET_LOG(asyncCtx->napi != nullptr, result, "failed to GetJsInstanceAndArgs");
1075 CHECK_AND_RETURN_RET_LOG(asyncCtx->napi->taskQue_ != nullptr, result, "taskQue is nullptr!");
1076
1077 asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
1078 asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
1079
1080 asyncCtx->task_ = AVScreenCaptureNapi::GetPromiseTask(asyncCtx->napi, opt);
1081 (void)asyncCtx->napi->taskQue_->EnqueueTask(asyncCtx->task_);
1082 asyncCtx->opt_ = opt;
1083
1084 napi_value resource = nullptr;
1085 napi_create_string_utf8(env, opt.c_str(), NAPI_AUTO_LENGTH, &resource);
1086 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
1087 AVScreenCaptureAsyncContext* asyncCtx = reinterpret_cast<AVScreenCaptureAsyncContext *>(data);
1088 CHECK_AND_RETURN_LOG(asyncCtx != nullptr, "asyncCtx is nullptr!");
1089
1090 if (asyncCtx->task_) {
1091 auto result = asyncCtx->task_->GetResult();
1092 if (result.Value().first != MSERR_EXT_API9_OK) {
1093 asyncCtx->SignError(result.Value().first, result.Value().second);
1094 }
1095
1096 if (result.Value().first == MSERR_EXT_API9_OK) {
1097 asyncCtx->JsResult = std::make_unique<MediaJsResultString>(result.Value().second);
1098 }
1099 }
1100 MEDIA_LOGI("The js thread of %{public}s finishes execution and returns", asyncCtx->opt_.c_str());
1101 }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
1102 NAPI_CALL(env, napi_queue_async_work_with_qos(env, asyncCtx->work, napi_qos_user_initiated));
1103 asyncCtx.release();
1104
1105 MEDIA_LOGI("Js %{public}s End", opt.c_str());
1106 return result;
1107 }
1108
GetPropertyInt32(napi_env env,napi_value configObj,const std::string & type,int32_t & result)1109 int32_t AVScreenCaptureNapi::GetPropertyInt32(napi_env env, napi_value configObj, const std::string &type,
1110 int32_t &result)
1111 {
1112 napi_value item = nullptr;
1113 bool exist = false;
1114 napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist);
1115 if (status != napi_ok || !exist) {
1116 MEDIA_LOGI("can not find %{public}s property", type.c_str());
1117 return MSERR_OK;
1118 }
1119
1120 if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) {
1121 MEDIA_LOGI("get %{public}s property fail", type.c_str());
1122 return MSERR_UNKNOWN;
1123 }
1124
1125 if (napi_get_value_int32(env, item, &result) != napi_ok) {
1126 std::string string = CommonNapi::GetStringArgument(env, item);
1127 if (string == "") {
1128 // This attribute has not been assigned
1129 return MSERR_OK;
1130 } else {
1131 MEDIA_LOGE("get %{public}s property value fail", type.c_str());
1132 return MSERR_INVALID_VAL;
1133 }
1134 }
1135
1136 MEDIA_LOGI("get %{public}s : %{public}d!", type.c_str(), result);
1137 return MSERR_OK;
1138 }
1139
AVScreenCaptureSignError(int32_t errCode,const std::string & operate,const std::string & param,const std::string & add)1140 void AVScreenCaptureAsyncContext::AVScreenCaptureSignError(int32_t errCode, const std::string &operate,
1141 const std::string ¶m, const std::string &add)
1142 {
1143 RetInfo retInfo = GetReturnInfo(errCode, operate, param, add);
1144 SignError(retInfo.first, retInfo.second);
1145 }
1146
1147 } // namespace Media
1148 } // namespace OHOS