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 &param)216 int32_t ScreenSourceTrans::CheckVideoParam(const VideoParam &param)
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