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