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_callback.h"
17 #include "scope_guard.h"
18 #include "media_log.h"
19
20 namespace {
21 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_SCREENCAPTURE, "AVScreenCaptureCallback"};
22 }
23
24 namespace OHOS {
25 namespace Media {
AVScreenCaptureCallback(napi_env env)26 AVScreenCaptureCallback::AVScreenCaptureCallback(napi_env env) : env_(env)
27 {
28 MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances create", FAKE_POINTER(this));
29 }
30
~AVScreenCaptureCallback()31 AVScreenCaptureCallback::~AVScreenCaptureCallback()
32 {
33 MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances destroy", FAKE_POINTER(this));
34 }
35
SendErrorCallback(int32_t errCode,const std::string & msg)36 void AVScreenCaptureCallback::SendErrorCallback(int32_t errCode, const std::string &msg)
37 {
38 std::lock_guard<std::mutex> lock(mutex_);
39 if (refMap_.find(AVScreenCaptureEvent::EVENT_ERROR) == refMap_.end()) {
40 MEDIA_LOGW("can not find error callback!");
41 return;
42 }
43
44 AVScreenCaptureJsCallback *cb = new(std::nothrow) AVScreenCaptureJsCallback();
45 CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
46 cb->autoRef = refMap_.at(AVScreenCaptureEvent::EVENT_ERROR);
47 cb->callbackName = AVScreenCaptureEvent::EVENT_ERROR;
48 cb->errorCode = errCode;
49 cb->errorMsg = msg;
50 return OnJsErrorCallBack(cb);
51 }
52
SendStateCallback(AVScreenCaptureStateCode stateCode)53 void AVScreenCaptureCallback::SendStateCallback(AVScreenCaptureStateCode stateCode)
54 {
55 std::lock_guard<std::mutex> lock(mutex_);
56 if (refMap_.find(AVScreenCaptureEvent::EVENT_STATE_CHANGE) == refMap_.end()) {
57 MEDIA_LOGW("can not find stateChange callback!");
58 return;
59 }
60
61 AVScreenCaptureJsCallback *cb = new(std::nothrow) AVScreenCaptureJsCallback();
62 CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
63 cb->autoRef = refMap_.at(AVScreenCaptureEvent::EVENT_STATE_CHANGE);
64 cb->callbackName = AVScreenCaptureEvent::EVENT_STATE_CHANGE;
65 cb->stateCode = stateCode;
66 return OnJsStateChangeCallBack(cb);
67 }
68
SaveCallbackReference(const std::string & name,std::weak_ptr<AutoRef> ref)69 void AVScreenCaptureCallback::SaveCallbackReference(const std::string &name, std::weak_ptr<AutoRef> ref)
70 {
71 std::lock_guard<std::mutex> lock(mutex_);
72 refMap_[name] = ref;
73 MEDIA_LOGI("Set callback type: %{public}s", name.c_str());
74 }
75
CancelCallbackReference(const std::string & name)76 void AVScreenCaptureCallback::CancelCallbackReference(const std::string &name)
77 {
78 std::lock_guard<std::mutex> lock(mutex_);
79 auto iter = refMap_.find(name);
80 if (iter != refMap_.end()) {
81 refMap_.erase(iter);
82 }
83 MEDIA_LOGI("Cancel callback type: %{public}s", name.c_str());
84 }
85
ClearCallbackReference()86 void AVScreenCaptureCallback::ClearCallbackReference()
87 {
88 std::lock_guard<std::mutex> lock(mutex_);
89 refMap_.clear();
90 MEDIA_LOGI("ClearCallback!");
91 }
92
OnError(ScreenCaptureErrorType errorType,int32_t errorCode)93 void AVScreenCaptureCallback::OnError(ScreenCaptureErrorType errorType, int32_t errorCode)
94 {
95 MEDIA_LOGI("OnError is called, name: %{public}d, error message: %{public}d", errorType, errorCode);
96 SendErrorCallback(errorCode, "Screen capture failed.");
97 }
98
OnStateChange(AVScreenCaptureStateCode stateCode)99 void AVScreenCaptureCallback::OnStateChange(AVScreenCaptureStateCode stateCode)
100 {
101 MEDIA_LOGI("OnStateChange() is called, stateCode: %{public}d", stateCode);
102 SendStateCallback(stateCode);
103 }
104
OnJsErrorCallBack(AVScreenCaptureJsCallback * jsCb) const105 void AVScreenCaptureCallback::OnJsErrorCallBack(AVScreenCaptureJsCallback *jsCb) const
106 {
107 ON_SCOPE_EXIT(0) {
108 delete jsCb;
109 };
110
111 uv_loop_s *loop = nullptr;
112 napi_get_uv_event_loop(env_, &loop);
113 CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to get uv event loop");
114
115 uv_work_t *work = new(std::nothrow) uv_work_t;
116 CHECK_AND_RETURN_LOG(work != nullptr, "fail to new uv_work_t");
117 ON_SCOPE_EXIT(1) {
118 delete work;
119 };
120
121 work->data = reinterpret_cast<void *>(jsCb);
122 // async callback, jsWork and jsWork->data should be heap object.
123 int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {
124 MEDIA_LOGD("OnJsErrorCallBack uv_queue_work_with_qos");
125 }, OnJsErrorCallBackWork, uv_qos_user_initiated);
126 CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work_with_qos task");
127
128 CANCEL_SCOPE_EXIT_GUARD(0);
129 CANCEL_SCOPE_EXIT_GUARD(1);
130 }
131
OnJsErrorCallBackWork(uv_work_t * work,int status)132 void AVScreenCaptureCallback::OnJsErrorCallBackWork(uv_work_t *work, int status)
133 {
134 // Js Thread
135 CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
136 if (work->data == nullptr) {
137 delete work;
138 MEDIA_LOGE("workdata is nullptr error");
139 return;
140 }
141 AVScreenCaptureJsCallback *event = reinterpret_cast<AVScreenCaptureJsCallback *>(work->data);
142 std::string request = event->callbackName;
143 MEDIA_LOGI("uv_queue_work_with_qos start, errorcode:%{public}d , errormessage:%{public}s:",
144 event->errorCode, event->errorMsg.c_str());
145 do {
146 CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
147 std::shared_ptr<AutoRef> ref = event->autoRef.lock();
148 CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
149
150 napi_handle_scope scope = nullptr;
151 napi_open_handle_scope(ref->env_, &scope);
152 CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
153 ON_SCOPE_EXIT(0) {
154 napi_close_handle_scope(ref->env_, scope);
155 };
156
157 napi_value jsCallback = nullptr;
158 napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
159 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
160 request.c_str());
161
162 napi_value msgValStr = nullptr;
163 nstatus = napi_create_string_utf8(ref->env_, event->errorMsg.c_str(), NAPI_AUTO_LENGTH, &msgValStr);
164 CHECK_AND_BREAK_LOG(nstatus == napi_ok && msgValStr != nullptr, "create error message str fail");
165
166 napi_value args[1] = { nullptr };
167 nstatus = napi_create_error(ref->env_, nullptr, msgValStr, &args[0]);
168 CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr, "create error callback fail");
169
170 nstatus = CommonNapi::FillErrorArgs(ref->env_, event->errorCode, args[0]);
171 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "create error callback fail");
172
173 // Call back function
174 napi_value result = nullptr;
175 nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
176 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
177 } while (0);
178 delete event;
179 delete work;
180 }
181
OnJsStateChangeCallBack(AVScreenCaptureJsCallback * jsCb) const182 void AVScreenCaptureCallback::OnJsStateChangeCallBack(AVScreenCaptureJsCallback *jsCb) const
183 {
184 ON_SCOPE_EXIT(0) {
185 delete jsCb;
186 };
187
188 uv_loop_s *loop = nullptr;
189 napi_get_uv_event_loop(env_, &loop);
190 CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to get uv event loop");
191
192 uv_work_t *work = new(std::nothrow) uv_work_t;
193 CHECK_AND_RETURN_LOG(work != nullptr, "fail to new uv_work_t");
194 ON_SCOPE_EXIT(1) {
195 delete work;
196 };
197
198 work->data = reinterpret_cast<void *>(jsCb);
199 int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {
200 MEDIA_LOGD("OnJsStateChangeCallBack uv_queue_work_with_qos");
201 }, [] (uv_work_t *work, int status) {
202 // Js Thread
203 CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
204 AVScreenCaptureJsCallback *event = reinterpret_cast<AVScreenCaptureJsCallback *>(work->data);
205 std::string request = event->callbackName;
206 do {
207 CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
208 std::shared_ptr<AutoRef> ref = event->autoRef.lock();
209 CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
210
211 napi_handle_scope scope = nullptr;
212 napi_open_handle_scope(ref->env_, &scope);
213 CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
214 ON_SCOPE_EXIT(0) {
215 napi_close_handle_scope(ref->env_, scope);
216 };
217
218 napi_value jsCallback = nullptr;
219 napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
220 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
221 request.c_str());
222
223 napi_value args[1] = { nullptr };
224 nstatus = napi_create_int32(ref->env_, event->stateCode, &args[0]);
225 CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
226 "%{public}s fail to create callback", request.c_str());
227
228 const size_t argCount = 1;
229 napi_value result = nullptr;
230 nstatus = napi_call_function(ref->env_, nullptr, jsCallback, argCount, args, &result);
231 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
232 } while (0);
233 delete event;
234 delete work;
235 }, uv_qos_user_initiated);
236 CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work_with_qos task");
237
238 CANCEL_SCOPE_EXIT_GUARD(0);
239 CANCEL_SCOPE_EXIT_GUARD(1);
240 }
241
242 } // namespace Media
243 } // namespace OHOS