• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &param,
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 &param, 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