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