1 /*
2 * Copyright (c) 2022 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
20 #include "dscreen_errcode.h"
21 #include "dscreen_hisysevent.h"
22 #include "dscreen_hitrace.h"
23 #include "dscreen_log.h"
24 #include "image_source_processor.h"
25 #include "screen_data_channel_impl.h"
26
27 namespace OHOS {
28 namespace DistributedHardware {
SetUp(const VideoParam & localParam,const VideoParam & remoteParam,const std::string & peerDevId)29 int32_t ScreenSourceTrans::SetUp(const VideoParam &localParam, const VideoParam &remoteParam,
30 const std::string &peerDevId)
31 {
32 DHLOGI("%s: SetUp.", LOG_TAG);
33 int32_t ret = CheckTransParam(localParam, remoteParam, peerDevId);
34 if (ret != DH_SUCCESS) {
35 DHLOGE("%s: SetUp failed param error ret: %d.", LOG_TAG, ret);
36 return ret;
37 }
38
39 ret = InitScreenTrans(localParam, remoteParam, peerDevId);
40 if (ret != DH_SUCCESS) {
41 DHLOGE("%s: SetUp failed ret: %d.", LOG_TAG, ret);
42 return ret;
43 }
44
45 DHLOGI("%s: SetUp success.", LOG_TAG);
46 return DH_SUCCESS;
47 }
48
Release()49 int32_t ScreenSourceTrans::Release()
50 {
51 DHLOGI("%s: Release.", LOG_TAG);
52 if (imageProcessor_ == nullptr || screenChannel_ == nullptr) {
53 DHLOGE("%s: Processor or channel is null, Setup first.", LOG_TAG);
54 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
55 }
56
57 int32_t ret = imageProcessor_->ReleaseImageProcessor();
58 if (ret != DH_SUCCESS) {
59 DHLOGD("%s: Release image processor failed ret: %d.", LOG_TAG, ret);
60 }
61 imageProcessor_ = nullptr;
62
63 StartTrace(DSCREEN_HITRACE_LABEL, DSCREEN_SOURCE_RELEASE_SESSION_START);
64 ret = screenChannel_->ReleaseSession();
65 FinishTrace(DSCREEN_HITRACE_LABEL);
66 if (ret != DH_SUCCESS) {
67 DHLOGD("%s: Release channel session failed ret: %d.", LOG_TAG, ret);
68 }
69 screenChannel_ = nullptr;
70
71 std::lock_guard<std::mutex> lck(dataQueueMtx_);
72 while (!dataQueue_.empty()) {
73 dataQueue_.pop();
74 }
75
76 DHLOGI("%s: Release success.", LOG_TAG);
77 return DH_SUCCESS;
78 }
79
Start()80 int32_t ScreenSourceTrans::Start()
81 {
82 DHLOGI("%s: Start.", LOG_TAG);
83 if (imageProcessor_ == nullptr || screenChannel_ == nullptr) {
84 DHLOGE("%s: Processor or channel is null, Setup first.", LOG_TAG);
85 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
86 }
87
88 StartTrace(DSCREEN_HITRACE_LABEL, DSCREEN_SOURCE_OPEN_SESSION_START);
89 int32_t ret = screenChannel_->OpenSession();
90 if (ret != DH_SUCCESS) {
91 DHLOGE("%s: Open channel session failed ret: %d.", LOG_TAG, ret);
92 return ret;
93 }
94
95 DHLOGI("%s: Wait for channel session opened.", LOG_TAG);
96 std::unique_lock<std::mutex> lck(sessionMtx_);
97 auto status =
98 sessionCond_.wait_for(lck, std::chrono::seconds(SESSION_WAIT_SECONDS), [this]() { return isChannelReady_; });
99 if (!status) {
100 DHLOGE("%s: Open channel session timeout(%ds).", LOG_TAG, SESSION_WAIT_SECONDS);
101 return ERR_DH_SCREEN_TRANS_TIMEOUT;
102 }
103
104 DHLOGI("%s: Start success.", LOG_TAG);
105 FinishTrace(DSCREEN_HITRACE_LABEL);
106 return DH_SUCCESS;
107 }
108
Stop()109 int32_t ScreenSourceTrans::Stop()
110 {
111 DHLOGI("%s: Stop.", LOG_TAG);
112 if (imageProcessor_ == nullptr || screenChannel_ == nullptr) {
113 DHLOGE("%s: Processor or channel is null, Setup first.", LOG_TAG);
114 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
115 }
116
117 bool stopStatus = true;
118 int32_t ret = imageProcessor_->StopImageProcessor();
119 if (ret != DH_SUCCESS) {
120 DHLOGD("%s: Stop image processor failed ret: %d.", LOG_TAG, ret);
121 stopStatus = false;
122 }
123
124 StartTrace(DSCREEN_HITRACE_LABEL, DSCREEN_SOURCE_CLOSE_SESSION_START);
125 ret = screenChannel_->CloseSession();
126 FinishTrace(DSCREEN_HITRACE_LABEL);
127 if (ret != DH_SUCCESS) {
128 DHLOGD("%s: Close Session failed ret: %d.", LOG_TAG, ret);
129 stopStatus = false;
130 }
131 isChannelReady_ = false;
132 if (sendDataThread_.joinable()) {
133 sendDataThread_.join();
134 }
135
136 if (!stopStatus) {
137 DHLOGE("%s: Stop source trans failed.", LOG_TAG);
138 return ERR_DH_SCREEN_TRANS_ERROR;
139 }
140 DHLOGI("%s: Stop success.", LOG_TAG);
141 return DH_SUCCESS;
142 }
143
RegisterStateCallback(const std::shared_ptr<IScreenSourceTransCallback> & callback)144 int32_t ScreenSourceTrans::RegisterStateCallback(const std::shared_ptr<IScreenSourceTransCallback> &callback)
145 {
146 DHLOGI("%s:RegisterStateCallback.", LOG_TAG);
147 if (callback == nullptr) {
148 DHLOGE("%s: Trans callback is null.", LOG_TAG);
149 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
150 }
151 transCallback_ = callback;
152
153 return DH_SUCCESS;
154 }
155
GetImageSurface()156 sptr<Surface> &ScreenSourceTrans::GetImageSurface()
157 {
158 DHLOGI("%s:GetImageSurface.", LOG_TAG);
159 return encoderSurface_;
160 }
161
CheckVideoParam(const VideoParam & param)162 int32_t ScreenSourceTrans::CheckVideoParam(const VideoParam ¶m)
163 {
164 if ((param.GetCodecType() != VIDEO_CODEC_TYPE_VIDEO_H264) &&
165 (param.GetCodecType() != VIDEO_CODEC_TYPE_VIDEO_H265) &&
166 (param.GetCodecType() != VIDEO_CODEC_TYPE_VIDEO_MPEG4)) {
167 DHLOGE("%s: Invalid codec type.", LOG_TAG);
168 return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
169 }
170
171 if ((param.GetVideoFormat() != VIDEO_DATA_FORMAT_YUVI420) &&
172 (param.GetVideoFormat() != VIDEO_DATA_FORMAT_NV12) &&
173 (param.GetVideoFormat() != VIDEO_DATA_FORMAT_NV21) &&
174 (param.GetVideoFormat() != VIDEO_DATA_FORMAT_RGBA8888)) {
175 DHLOGE("%s: Invalid video data format.", LOG_TAG);
176 return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
177 }
178
179 if ((param.GetVideoWidth() > DSCREEN_MAX_VIDEO_DATA_WIDTH) ||
180 (param.GetVideoHeight() > DSCREEN_MAX_VIDEO_DATA_HEIGHT)) {
181 DHLOGE("%s: Invalid video data size.", LOG_TAG);
182 return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
183 }
184
185 if ((param.GetScreenWidth() > DSCREEN_MAX_SCREEN_DATA_WIDTH) ||
186 (param.GetScreenHeight() > DSCREEN_MAX_SCREEN_DATA_HEIGHT)) {
187 DHLOGE("%s: Invalid screen data size.", LOG_TAG);
188 return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
189 }
190
191 return DH_SUCCESS;
192 }
193
CheckTransParam(const VideoParam & localParam,const VideoParam & remoteParam,const std::string & peerDevId)194 int32_t ScreenSourceTrans::CheckTransParam(const VideoParam &localParam, const VideoParam &remoteParam,
195 const std::string &peerDevId)
196 {
197 DHLOGI("%s:CheckTransParam.", LOG_TAG);
198 if (peerDevId.empty()) {
199 DHLOGE("%s: Remote device id is null.", LOG_TAG);
200 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
201 }
202
203 int32_t ret = CheckVideoParam(localParam);
204 if (ret != DH_SUCCESS) {
205 DHLOGE("%s: check localParam param failed.", LOG_TAG);
206 return ret;
207 }
208
209 ret = CheckVideoParam(remoteParam);
210 if (ret != DH_SUCCESS) {
211 DHLOGE("%s: check remoteParam param failed.", LOG_TAG);
212 return ret;
213 }
214
215 DHLOGI("%s: Local: codecType(%u), videoFormat(%u), videoSize(%ux%u), screenSize(%ux%u).", LOG_TAG,
216 localParam.GetCodecType(), localParam.GetVideoFormat(), localParam.GetVideoWidth(),
217 localParam.GetVideoHeight(), localParam.GetScreenWidth(), localParam.GetScreenHeight());
218 DHLOGI("%s: Remote: codecType(%u), videoFormat(%u), videoSize(%ux%u), screenSize(%ux%u).", LOG_TAG,
219 remoteParam.GetCodecType(), remoteParam.GetVideoFormat(), remoteParam.GetVideoWidth(),
220 remoteParam.GetVideoHeight(), remoteParam.GetScreenWidth(), remoteParam.GetScreenHeight());
221 return DH_SUCCESS;
222 }
223
InitScreenTrans(const VideoParam & localParam,const VideoParam & remoteParam,const std::string & peerDevId)224 int32_t ScreenSourceTrans::InitScreenTrans(const VideoParam &localParam, const VideoParam &remoteParam,
225 const std::string &peerDevId)
226 {
227 DHLOGI("%s:InitScreenTrans.", LOG_TAG);
228 screenChannel_ = std::make_shared<ScreenDataChannelImpl>(peerDevId);
229
230 int32_t ret = RegisterChannelListener();
231 if (ret != DH_SUCCESS) {
232 DHLOGE("%s: Register channel listener failed ret: %d.", LOG_TAG, ret);
233 screenChannel_ = nullptr;
234 return ret;
235 }
236
237 imageProcessor_ = std::make_shared<ImageSourceProcessor>();
238
239 ret = RegisterProcessorListener(localParam, remoteParam);
240 if (ret != DH_SUCCESS) {
241 DHLOGE("%s: Register data processor listener failed ret: %d.", LOG_TAG, ret);
242 screenChannel_ = nullptr;
243 imageProcessor_ = nullptr;
244 return ret;
245 }
246
247 return DH_SUCCESS;
248 }
249
RegisterChannelListener()250 int32_t ScreenSourceTrans::RegisterChannelListener()
251 {
252 DHLOGI("%s: RegisterChannelListener.", LOG_TAG);
253 std::shared_ptr<IScreenChannelListener> listener = shared_from_this();
254 if (listener == nullptr) {
255 DHLOGE("%s: Channel listener is null", LOG_TAG);
256 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
257 }
258
259 if (screenChannel_ == nullptr) {
260 DHLOGE("%s: Channel is null", LOG_TAG);
261 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
262 }
263 int32_t ret = screenChannel_->CreateSession(listener);
264 if (ret != DH_SUCCESS) {
265 DHLOGE("%s: Create session failed ret: %d.", LOG_TAG);
266 ReportOptFail(DSCREEN_OPT_FAIL, ret, "dscreen source Create session failed.");
267 return ret;
268 }
269
270 return DH_SUCCESS;
271 }
272
RegisterProcessorListener(const VideoParam & localParam,const VideoParam & remoteParam)273 int32_t ScreenSourceTrans::RegisterProcessorListener(const VideoParam &localParam, const VideoParam &remoteParam)
274 {
275 DHLOGI("%s: RegisterProcessorListener.", LOG_TAG);
276 std::shared_ptr<IImageSourceProcessorListener> listener = shared_from_this();
277 if (listener == nullptr) {
278 DHLOGE("%s: Processor listener is null", LOG_TAG);
279 return ERR_DH_SCREEN_TRANS_ERROR;
280 }
281
282 if (imageProcessor_ == nullptr) {
283 DHLOGE("%s: imageProcessor is null", LOG_TAG);
284 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
285 }
286 int32_t ret = imageProcessor_->ConfigureImageProcessor(localParam, remoteParam, listener);
287 if (ret != DH_SUCCESS) {
288 DHLOGE("%s: Config image processor failed ret: %d.", LOG_TAG, ret);
289 ReportOptFail(DSCREEN_OPT_FAIL, ret, "Config image processor failed.");
290 return ret;
291 }
292
293 encoderSurface_ = imageProcessor_->GetImageSurface();
294 if (encoderSurface_ == nullptr) {
295 DHLOGE("%s: Surface is null.", LOG_TAG);
296 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
297 }
298
299 return DH_SUCCESS;
300 }
301
OnSessionOpened()302 void ScreenSourceTrans::OnSessionOpened()
303 {
304 DHLOGI("%s: OnChannelSessionOpened.", LOG_TAG);
305 if (imageProcessor_ == nullptr) {
306 DHLOGE("%s: imageProcessor is null", LOG_TAG);
307 return;
308 }
309 int32_t ret = imageProcessor_->StartImageProcessor();
310 if (ret != DH_SUCCESS) {
311 DHLOGE("%s: Start image processor failed ret: %d.", LOG_TAG, ret);
312 return;
313 }
314
315 isChannelReady_ = true;
316 DHLOGI("%s: Start thread.", LOG_TAG);
317 sendDataThread_ = std::thread(&ScreenSourceTrans::FeedChannelData, this);
318
319 std::unique_lock<std::mutex> lck(sessionMtx_);
320 sessionCond_.notify_all();
321 }
322
OnSessionClosed()323 void ScreenSourceTrans::OnSessionClosed()
324 {
325 DHLOGI("%s: OnChannelSessionClosed.", LOG_TAG);
326 isChannelReady_ = false;
327 if (sendDataThread_.joinable()) {
328 sendDataThread_.join();
329 }
330
331 std::shared_ptr<IScreenSourceTransCallback> callback = transCallback_.lock();
332 if (callback == nullptr) {
333 DHLOGE("%s: Trans callback is null.", LOG_TAG);
334 return;
335 }
336 callback->OnError(ERR_DH_SCREEN_TRANS_SESSION_CLOSED, "OnChannelSessionClosed");
337 }
338
OnDataReceived(const std::shared_ptr<DataBuffer> & data)339 void ScreenSourceTrans::OnDataReceived(const std::shared_ptr<DataBuffer> &data)
340 {
341 (void) data;
342 DHLOGI("%s: OnChannelDataReceived source trans not support.", LOG_TAG);
343 }
344
OnImageProcessDone(const std::shared_ptr<DataBuffer> & data)345 void ScreenSourceTrans::OnImageProcessDone(const std::shared_ptr<DataBuffer> &data)
346 {
347 DHLOGD("%s: OnProcessorDataReceived received data from data processor.", LOG_TAG);
348 std::lock_guard<std::mutex> lck(dataQueueMtx_);
349 while (dataQueue_.size() >= DATA_QUEUE_MAX_SIZE) {
350 DHLOGE("%s: Data queue overflow.", LOG_TAG);
351 dataQueue_.pop();
352 }
353 dataQueue_.push(data);
354 dataCond_.notify_all();
355 }
356
OnProcessorStateNotify(int32_t state)357 void ScreenSourceTrans::OnProcessorStateNotify(int32_t state)
358 {
359 DHLOGI("%s:OnProcessorStateNotify.", LOG_TAG);
360 std::shared_ptr<IScreenSourceTransCallback> callback = transCallback_.lock();
361 if (callback == nullptr) {
362 DHLOGE("%s: Trans callback is null.", LOG_TAG);
363 return;
364 }
365 callback->OnError(state, "OnProcessorStateNotify");
366 }
367
FeedChannelData()368 void ScreenSourceTrans::FeedChannelData()
369 {
370 while (isChannelReady_) {
371 std::shared_ptr<DataBuffer> screenData;
372 {
373 std::unique_lock<std::mutex> lock(dataQueueMtx_);
374 dataCond_.wait_for(lock, std::chrono::seconds(DATA_WAIT_SECONDS), [this]() { return !dataQueue_.empty(); });
375 if (dataQueue_.empty()) {
376 DHLOGD("%s:Data queue is empty.", LOG_TAG);
377 continue;
378 }
379 screenData = dataQueue_.front();
380 dataQueue_.pop();
381 }
382
383 if (screenChannel_ == nullptr) {
384 DHLOGE("%s: Channel is null", LOG_TAG);
385 return;
386 }
387 if (screenData == nullptr) {
388 DHLOGE("%s: Screen data is null", LOG_TAG);
389 continue;
390 }
391
392 DHLOGD("%s: FeedChannelData.", LOG_TAG);
393 int32_t ret = screenChannel_->SendData(screenData);
394 if (ret != DH_SUCCESS) {
395 DHLOGD("%s:Send data failed.", LOG_TAG);
396 }
397 DHLOGD("%s: FeedChannelData success.", LOG_TAG);
398 }
399 }
400 } // namespace DistributedHardware
401 } // namespace OHOS