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 &param)
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