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