1 /*
2 * Copyright (c) 2022-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 "screen_source_trans.h"
17
18 #include <chrono>
19 #include <pthread.h>
20
21 #include "distributed_hardware_errno.h"
22 #include "dscreen_constants.h"
23 #include "dscreen_errcode.h"
24 #include "dscreen_fwkkit.h"
25 #include "dscreen_hisysevent.h"
26 #include "dscreen_hitrace.h"
27 #include "dscreen_log.h"
28 #include "ffrt_inner.h"
29 #include "image_source_processor.h"
30 #include "screen_data_channel_impl.h"
31 namespace OHOS {
32 namespace DistributedHardware {
SetUp(const VideoParam & localParam,const VideoParam & remoteParam,const std::string & peerDevId)33 int32_t ScreenSourceTrans::SetUp(const VideoParam &localParam, const VideoParam &remoteParam,
34 const std::string &peerDevId)
35 {
36 DHLOGI("%{public}s: SetUp.", DSCREEN_LOG_TAG);
37 int32_t ret = CheckTransParam(localParam, remoteParam, peerDevId);
38 if (ret != DH_SUCCESS) {
39 DHLOGE("%{public}s: SetUp failed param error ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
40 return ret;
41 }
42 ret = InitScreenTrans(localParam, remoteParam, peerDevId);
43 if (ret != DH_SUCCESS) {
44 DHLOGE("%{public}s: SetUp failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
45 return ret;
46 }
47 ret = SetConsumerSurface();
48 if (ret != DH_SUCCESS) {
49 DHLOGE("sourcetrans set image surface failed.");
50 return ret;
51 }
52 ret = screenDecisionCenter_->SetJpegSurface(consumerSurface_);
53 if (ret != DH_SUCCESS) {
54 DHLOGE("screenDecisionCenter set jpeg surface failed.");
55 return ret;
56 }
57 DHLOGI("%{public}s: SetUp success.", DSCREEN_LOG_TAG);
58 return DH_SUCCESS;
59 }
60
SetConsumerSurface()61 int32_t ScreenSourceTrans::SetConsumerSurface()
62 {
63 DHLOGI("%{public}s: SetConsumerSurface.", DSCREEN_LOG_TAG);
64 consumerSurface_ = imageProcessor_->GetConsumerSurface();
65 if (consumerSurface_ == nullptr) {
66 DHLOGE("%{public}s: consumerSurface is nullptr", DSCREEN_LOG_TAG);
67 return ERR_DH_SCREEN_SURFACE_INVALIED;
68 }
69 return DH_SUCCESS;
70 }
71
Release()72 int32_t ScreenSourceTrans::Release()
73 {
74 DHLOGI("%{public}s: Release.", DSCREEN_LOG_TAG);
75 if (imageProcessor_ == nullptr) {
76 DHLOGE("%{public}s: Processor or channel is null, Setup first.", DSCREEN_LOG_TAG);
77 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
78 }
79
80 int32_t ret = imageProcessor_->ReleaseImageProcessor();
81 if (ret != DH_SUCCESS) {
82 DHLOGD("%{public}s: Release image processor failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
83 }
84 imageProcessor_ = nullptr;
85
86 {
87 std::unique_lock<std::mutex> lck(channelMtx_);
88 if (screenChannel_ == nullptr) {
89 DHLOGE("%{public}s: Processor or channel is null, Setup first.", DSCREEN_LOG_TAG);
90 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
91 }
92 StartTrace(DSCREEN_HITRACE_LABEL, DSCREEN_SOURCE_RELEASE_SESSION_START);
93 ret = screenChannel_->ReleaseSession();
94 FinishTrace(DSCREEN_HITRACE_LABEL);
95 if (ret != DH_SUCCESS) {
96 DHLOGD("%{public}s: Release channel session failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
97 }
98 screenChannel_ = nullptr;
99 }
100
101 std::lock_guard<std::mutex> lck(dataQueueMtx_);
102 while (!dataQueue_.empty()) {
103 dataQueue_.pop();
104 }
105
106 DHLOGI("%{public}s: Release success.", DSCREEN_LOG_TAG);
107 return DH_SUCCESS;
108 }
109
Start()110 int32_t ScreenSourceTrans::Start()
111 {
112 DHLOGI("%{public}s: Start.", DSCREEN_LOG_TAG);
113 if (screenChannel_ == nullptr) {
114 DHLOGE("%{public}s: channel is null, Setup first.", DSCREEN_LOG_TAG);
115 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
116 }
117
118 StartTrace(DSCREEN_HITRACE_LABEL, DSCREEN_SOURCE_OPEN_SESSION_START);
119 std::shared_ptr<IScreenChannelListener> listener = shared_from_this();
120 if (listener == nullptr) {
121 DHLOGE("%{public}s: Channel listener is null", DSCREEN_LOG_TAG);
122 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
123 }
124 if (screenChannel_ == nullptr) {
125 DHLOGE("%{public}s: Channel is null", DSCREEN_LOG_TAG);
126 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
127 }
128 int32_t ret = screenChannel_->OpenSession(listener);
129 if (ret != DH_SUCCESS) {
130 DHLOGE("%{public}s: Open channel session failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
131 return ret;
132 }
133
134 DHLOGI("%{public}s: Wait for channel session opened.", DSCREEN_LOG_TAG);
135 std::unique_lock<std::mutex> lck(sessionMtx_);
136 auto status =
137 sessionCond_.wait_for(lck, std::chrono::seconds(SESSION_WAIT_SECONDS), [this]() { return isChannelReady_; });
138 if (!status) {
139 DHLOGE("%{public}s: Open channel session timeout(%{public}" PRId32 "s).", DSCREEN_LOG_TAG,
140 SESSION_WAIT_SECONDS);
141 return ERR_DH_SCREEN_TRANS_TIMEOUT;
142 }
143
144 DHLOGI("%{public}s: Source start enable low latency.", DSCREEN_LOG_TAG);
145 std::shared_ptr<DistributedHardwareFwkKit> dhFwkKit = DScreenFwkKit::GetInstance().GetDHFwkKit();
146 if (dhFwkKit != nullptr) {
147 ret = dhFwkKit->PublishMessage(DHTopic::TOPIC_LOW_LATENCY, ENABLE_LOW_LATENCY.dump());
148 if (ret != DH_FWK_SUCCESS) {
149 DHLOGE("%{public}s: Source start enable low latency failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
150 }
151 }
152
153 DHLOGI("%{public}s: Start success.", DSCREEN_LOG_TAG);
154 FinishTrace(DSCREEN_HITRACE_LABEL);
155 return DH_SUCCESS;
156 }
157
Stop()158 int32_t ScreenSourceTrans::Stop()
159 {
160 DHLOGI("%{public}s: Stop.", DSCREEN_LOG_TAG);
161 if (imageProcessor_ == nullptr || screenChannel_ == nullptr) {
162 DHLOGE("%{public}s: Processor or channel is null, Setup first.", DSCREEN_LOG_TAG);
163 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
164 }
165
166 bool stopStatus = true;
167 int32_t ret = imageProcessor_->StopImageProcessor();
168 if (ret != DH_SUCCESS) {
169 DHLOGD("%{public}s: Stop image processor failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
170 stopStatus = false;
171 }
172
173 DHLOGI("%{public}s: Source stop enable low latency.", DSCREEN_LOG_TAG);
174 std::shared_ptr<DistributedHardwareFwkKit> dhFwkKit = DScreenFwkKit::GetInstance().GetDHFwkKit();
175 if (dhFwkKit != nullptr) {
176 ret = dhFwkKit->PublishMessage(DHTopic::TOPIC_LOW_LATENCY, DISABLE_LOW_LATENCY.dump());
177 if (ret != DH_FWK_SUCCESS) {
178 DHLOGE("%{public}s: Source stop enable low latency failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
179 }
180 }
181
182 isChannelReady_ = false;
183 StartTrace(DSCREEN_HITRACE_LABEL, DSCREEN_SOURCE_CLOSE_SESSION_START);
184 {
185 std::unique_lock<std::mutex> lck(channelMtx_);
186 ret = screenChannel_->CloseSession();
187 }
188 FinishTrace(DSCREEN_HITRACE_LABEL);
189 if (ret != DH_SUCCESS) {
190 DHLOGD("%{public}s: Close Session failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
191 stopStatus = false;
192 }
193
194 if (!stopStatus) {
195 DHLOGE("%{public}s: Stop source trans failed.", DSCREEN_LOG_TAG);
196 return ERR_DH_SCREEN_TRANS_ERROR;
197 }
198 DHLOGI("%{public}s: Stop success.", DSCREEN_LOG_TAG);
199 return DH_SUCCESS;
200 }
201
RegisterStateCallback(const std::shared_ptr<IScreenSourceTransCallback> & callback)202 int32_t ScreenSourceTrans::RegisterStateCallback(const std::shared_ptr<IScreenSourceTransCallback> &callback)
203 {
204 DHLOGI("%{public}s:RegisterStateCallback.", DSCREEN_LOG_TAG);
205 if (callback == nullptr) {
206 DHLOGE("%{public}s: Trans callback is null.", DSCREEN_LOG_TAG);
207 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
208 }
209 transCallback_ = callback;
210
211 return DH_SUCCESS;
212 }
213
GetImageSurface()214 sptr<Surface> ScreenSourceTrans::GetImageSurface()
215 {
216 DHLOGI("%{public}s:GetImageSurface.", DSCREEN_LOG_TAG);
217 return imageProcessor_->GetImageSurface();
218 }
219
SetScreenVersion(const std::string & version)220 void ScreenSourceTrans::SetScreenVersion(const std::string &version)
221 {
222 version_ = version;
223 }
224
CheckVideoParam(const VideoParam & param)225 int32_t ScreenSourceTrans::CheckVideoParam(const VideoParam ¶m)
226 {
227 if ((param.GetCodecType() != VIDEO_CODEC_TYPE_VIDEO_H264) &&
228 (param.GetCodecType() != VIDEO_CODEC_TYPE_VIDEO_H265) &&
229 (param.GetCodecType() != VIDEO_CODEC_TYPE_VIDEO_MPEG4)) {
230 DHLOGE("%{public}s: Invalid codec type.", DSCREEN_LOG_TAG);
231 return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
232 }
233
234 if ((param.GetVideoFormat() != VIDEO_DATA_FORMAT_YUVI420) &&
235 (param.GetVideoFormat() != VIDEO_DATA_FORMAT_NV12) &&
236 (param.GetVideoFormat() != VIDEO_DATA_FORMAT_NV21) &&
237 (param.GetVideoFormat() != VIDEO_DATA_FORMAT_RGBA8888)) {
238 DHLOGE("%{public}s: Invalid video data format.", DSCREEN_LOG_TAG);
239 return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
240 }
241
242 if ((param.GetVideoWidth() > DSCREEN_MAX_VIDEO_DATA_WIDTH) ||
243 (param.GetVideoHeight() > DSCREEN_MAX_VIDEO_DATA_HEIGHT)) {
244 DHLOGE("%{public}s: Invalid video data size.", DSCREEN_LOG_TAG);
245 return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
246 }
247
248 if ((param.GetScreenWidth() > DSCREEN_MAX_SCREEN_DATA_WIDTH) ||
249 (param.GetScreenHeight() > DSCREEN_MAX_SCREEN_DATA_HEIGHT)) {
250 DHLOGE("%{public}s: Invalid screen data size.", DSCREEN_LOG_TAG);
251 return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
252 }
253
254 return DH_SUCCESS;
255 }
256
CheckTransParam(const VideoParam & localParam,const VideoParam & remoteParam,const std::string & peerDevId)257 int32_t ScreenSourceTrans::CheckTransParam(const VideoParam &localParam, const VideoParam &remoteParam,
258 const std::string &peerDevId)
259 {
260 DHLOGI("%{public}s:CheckTransParam.", DSCREEN_LOG_TAG);
261 if (peerDevId.empty()) {
262 DHLOGE("%{public}s: Remote device id is null.", DSCREEN_LOG_TAG);
263 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
264 }
265
266 int32_t ret = CheckVideoParam(localParam);
267 if (ret != DH_SUCCESS) {
268 DHLOGE("%{public}s: check localParam param failed.", DSCREEN_LOG_TAG);
269 return ret;
270 }
271
272 ret = CheckVideoParam(remoteParam);
273 if (ret != DH_SUCCESS) {
274 DHLOGE("%{public}s: check remoteParam param failed.", DSCREEN_LOG_TAG);
275 return ret;
276 }
277 return DH_SUCCESS;
278 }
279
InitScreenTrans(const VideoParam & localParam,const VideoParam & remoteParam,const std::string & peerDevId)280 int32_t ScreenSourceTrans::InitScreenTrans(const VideoParam &localParam, const VideoParam &remoteParam,
281 const std::string &peerDevId)
282 {
283 DHLOGI("%{public}s:InitScreenTrans.", DSCREEN_LOG_TAG);
284 {
285 std::unique_lock<std::mutex> lck(channelMtx_);
286 screenChannel_ = std::make_shared<ScreenDataChannelImpl>(peerDevId);
287 }
288 if (std::atoi(version_.c_str()) > DSCREEN_MIN_VERSION) {
289 screenChannel_->SetJpegSessionFlag(true);
290 }
291 int32_t ret = RegisterChannelListener();
292 if (ret != DH_SUCCESS) {
293 DHLOGE("%{public}s: Register channel listener failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
294 {
295 std::unique_lock<std::mutex> lck(channelMtx_);
296 screenChannel_ = nullptr;
297 }
298 return ret;
299 }
300 screenDecisionCenter_ = std::make_shared<ScreenDecisionCenter>(localParam);
301 imageProcessor_ = std::make_shared<ImageSourceProcessor>();
302 ret = RegisterProcessorListener(localParam, remoteParam);
303 if (ret != DH_SUCCESS) {
304 DHLOGE("%{public}s: Register data processor listener failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
305 {
306 std::unique_lock<std::mutex> lck(channelMtx_);
307 screenChannel_ = nullptr;
308 }
309 imageProcessor_ = nullptr;
310 return ret;
311 }
312
313 return DH_SUCCESS;
314 }
315
RegisterChannelListener()316 int32_t ScreenSourceTrans::RegisterChannelListener()
317 {
318 DHLOGI("%{public}s: RegisterChannelListener.", DSCREEN_LOG_TAG);
319 return DH_SUCCESS;
320 }
321
RegisterProcessorListener(const VideoParam & localParam,const VideoParam & remoteParam)322 int32_t ScreenSourceTrans::RegisterProcessorListener(const VideoParam &localParam, const VideoParam &remoteParam)
323 {
324 DHLOGI("%{public}s: RegisterProcessorListener.", DSCREEN_LOG_TAG);
325 std::shared_ptr<IImageSourceProcessorListener> listener = shared_from_this();
326 if (listener == nullptr) {
327 DHLOGE("%{public}s: Processor listener is null", DSCREEN_LOG_TAG);
328 return ERR_DH_SCREEN_TRANS_ERROR;
329 }
330
331 if (imageProcessor_ == nullptr) {
332 DHLOGE("%{public}s: imageProcessor is null", DSCREEN_LOG_TAG);
333 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
334 }
335 int32_t ret = imageProcessor_->ConfigureImageProcessor(localParam, remoteParam, listener);
336 if (ret != DH_SUCCESS) {
337 DHLOGE("%{public}s: Config image processor failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
338 ReportOptFail(DSCREEN_OPT_FAIL, ret, "Config image processor failed.");
339 return ret;
340 }
341 ret = screenDecisionCenter_->ConfigureDecisionCenter(listener, imageProcessor_);
342 if (ret != DH_SUCCESS) {
343 DHLOGE("%{public}s: Config decision center failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
344 return ret;
345 }
346 return DH_SUCCESS;
347 }
348
OnSessionOpened()349 void ScreenSourceTrans::OnSessionOpened()
350 {
351 DHLOGI("%{public}s: OnChannelSessionOpened.", DSCREEN_LOG_TAG);
352 if (imageProcessor_ == nullptr) {
353 DHLOGE("%{public}s: imageProcessor is null", DSCREEN_LOG_TAG);
354 return;
355 }
356 int32_t ret = imageProcessor_->StartImageProcessor();
357 if (ret != DH_SUCCESS) {
358 DHLOGE("%{public}s: Start image processor failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
359 return;
360 }
361
362 isChannelReady_ = true;
363 DHLOGI("%{public}s: Start thread.", DSCREEN_LOG_TAG);
364 std::weak_ptr<ScreenSourceTrans> trans = shared_from_this();
365 ffrt::submit([trans] {
366 auto screenTrans = trans.lock();
367 if (screenTrans) {
368 screenTrans->FeedChannelData();
369 }
370 });
371 std::unique_lock<std::mutex> lck(sessionMtx_);
372 sessionCond_.notify_all();
373 }
374
OnSessionClosed()375 void ScreenSourceTrans::OnSessionClosed()
376 {
377 DHLOGI("%{public}s: OnChannelSessionClosed.", DSCREEN_LOG_TAG);
378 isChannelReady_ = false;
379
380 std::shared_ptr<IScreenSourceTransCallback> callback = transCallback_.lock();
381 if (callback == nullptr) {
382 DHLOGE("%{public}s: Trans callback is null.", DSCREEN_LOG_TAG);
383 return;
384 }
385 callback->OnError(ERR_DH_SCREEN_TRANS_SESSION_CLOSED, "OnChannelSessionClosed");
386 }
387
OnDataReceived(const std::shared_ptr<DataBuffer> & data)388 void ScreenSourceTrans::OnDataReceived(const std::shared_ptr<DataBuffer> &data)
389 {
390 (void) data;
391 DHLOGI("%{public}s: OnChannelDataReceived source trans not support.", DSCREEN_LOG_TAG);
392 }
393
OnDamageProcessDone(sptr<SurfaceBuffer> & surfaceBuffer,const std::vector<OHOS::Rect> & damages)394 void ScreenSourceTrans::OnDamageProcessDone(sptr<SurfaceBuffer> &surfaceBuffer, const std::vector<OHOS::Rect> &damages)
395 {
396 DHLOGI("%{public}s: OnDamageProcessDone.", DSCREEN_LOG_TAG);
397 if (surfaceBuffer == nullptr) {
398 DHLOGE("%{public}s: Trans surfaceBuffer is null.", DSCREEN_LOG_TAG);
399 return;
400 }
401 if (std::atoi(version_.c_str()) == DSCREEN_MIN_VERSION) {
402 DHLOGI("%{public}s: not support partial refresh, run full full image process.", DSCREEN_LOG_TAG);
403 imageProcessor_->ProcessFullImage(surfaceBuffer);
404 } else {
405 DHLOGI("%{public}s: run partial refresh image process.", DSCREEN_LOG_TAG);
406 screenDecisionCenter_->InputBufferImage(surfaceBuffer, damages);
407 }
408 }
409
OnImageProcessDone(const std::shared_ptr<DataBuffer> & data)410 void ScreenSourceTrans::OnImageProcessDone(const std::shared_ptr<DataBuffer> &data)
411 {
412 DHLOGD("%{public}s: OnImageProcessDone.", DSCREEN_LOG_TAG);
413 std::lock_guard<std::mutex> lck(dataQueueMtx_);
414 while (dataQueue_.size() >= DATA_QUEUE_MAX_SIZE) {
415 DHLOGE("%{public}s: Data queue overflow.", DSCREEN_LOG_TAG);
416 dataQueue_.pop();
417 }
418 dataQueue_.push(data);
419 dataCond_.notify_all();
420 }
421
OnProcessorStateNotify(int32_t state)422 void ScreenSourceTrans::OnProcessorStateNotify(int32_t state)
423 {
424 DHLOGI("%{public}s:OnProcessorStateNotify.", DSCREEN_LOG_TAG);
425 std::shared_ptr<IScreenSourceTransCallback> callback = transCallback_.lock();
426 if (callback == nullptr) {
427 DHLOGE("%{public}s: Trans callback is null.", DSCREEN_LOG_TAG);
428 return;
429 }
430 callback->OnError(state, "OnProcessorStateNotify");
431 }
432
FeedChannelData()433 void ScreenSourceTrans::FeedChannelData()
434 {
435 while (isChannelReady_) {
436 std::shared_ptr<DataBuffer> screenData;
437 {
438 std::unique_lock<std::mutex> lock(dataQueueMtx_);
439 auto status = dataCond_.wait_for(
440 lock, std::chrono::seconds(DATA_WAIT_SECONDS), [this]() { return !dataQueue_.empty(); });
441 if (!status) {
442 DHLOGD("%{public}s: Data queue wait timeout after %{public}d seconds.", DSCREEN_LOG_TAG,
443 DATA_WAIT_SECONDS);
444 continue;
445 }
446 if (dataQueue_.empty()) {
447 DHLOGD("%{public}s:Data queue is empty.", DSCREEN_LOG_TAG);
448 continue;
449 }
450 screenData = dataQueue_.front();
451 dataQueue_.pop();
452 }
453 if (screenData == nullptr) {
454 DHLOGE("%{public}s: Screen data is null", DSCREEN_LOG_TAG);
455 continue;
456 }
457 {
458 std::unique_lock<std::mutex> lck(channelMtx_);
459 if (screenChannel_ == nullptr) {
460 DHLOGE("%{public}s: Channel is null", DSCREEN_LOG_TAG);
461 return;
462 }
463 DHLOGD("%{public}s: FeedChannelData.", DSCREEN_LOG_TAG);
464 if (screenChannel_->SendData(screenData) != DH_SUCCESS) {
465 DHLOGD("%{public}s:Send data failed.", DSCREEN_LOG_TAG);
466 }
467 }
468 }
469 }
470 } // namespace DistributedHardware
471 } // namespace OHOS