1 /*
2 * Copyright (c) 2022-2023 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 "1.0/include/dscreen.h"
17
18 #include "avcodec_info.h"
19 #include "avcodec_list.h"
20 #include <pthread.h>
21
22 #include "dscreen_constants.h"
23 #include "dscreen_errcode.h"
24 #include "dscreen_hisysevent.h"
25 #include "dscreen_json_util.h"
26 #include "dscreen_log.h"
27 #include "dscreen_util.h"
28 #include "common/include/screen_manager_adapter.h"
29 #include "screen_source_trans.h"
30
31 namespace OHOS {
32 namespace DistributedHardware {
33 namespace V1_0 {
34 constexpr const char* TASK_THREAD = "TaskThread";
DScreen(const std::string & devId,const std::string & dhId,std::shared_ptr<IDScreenCallback> dscreenCallback)35 DScreen::DScreen(const std::string &devId, const std::string &dhId,
36 std::shared_ptr<IDScreenCallback> dscreenCallback)
37 {
38 DHLOGD("DScreen construct, devId: %s, dhId: %s", GetAnonyString(devId).c_str(),
39 GetAnonyString(dhId).c_str());
40 devId_ = devId;
41 dhId_ = dhId;
42 dscreenCallback_ = dscreenCallback;
43 SetState(DISABLED);
44 taskThreadRunning_ = true;
45 taskQueueThread_ = std::thread(&DScreen::TaskThreadLoop, this);
46 }
47
~DScreen()48 DScreen::~DScreen()
49 {
50 DHLOGD("DScreen deconstruct, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(),
51 GetAnonyString(dhId_).c_str());
52 taskThreadRunning_ = false;
53 taskQueueCond_.notify_all();
54 if (taskQueueThread_.joinable()) {
55 taskQueueThread_.join();
56 }
57 int32_t ret = DH_SUCCESS;
58 if (sourceTrans_ != nullptr) {
59 ret = sourceTrans_->Release();
60 }
61 if (ret != DH_SUCCESS) {
62 DHLOGE("source trans release failed. ret: %" PRId32, ret);
63 }
64
65 if (screenId_ != SCREEN_ID_INVALID) {
66 ret = ScreenMgrAdapter::GetInstance().RemoveVirtualScreen(screenId_);
67 }
68
69 if (ret != DH_SUCCESS) {
70 DHLOGE("remove virtual screen failed.");
71 }
72 videoParam_ = nullptr;
73 sourceTrans_ = nullptr;
74 DHLOGD("DScreen deconstruct end.");
75 }
76
OnTransError(int32_t err,const std::string & content)77 void DScreen::OnTransError(int32_t err, const std::string &content)
78 {
79 DHLOGD("OnTransError, err: %" PRId32, err);
80 AddTask(std::make_shared<Task>(TaskType::TASK_DISCONNECT, ""));
81 ScreenMgrAdapter::GetInstance().RemoveScreenFromGroup(screenId_);
82 }
83
SetVideoParam(std::shared_ptr<VideoParam> & videoParam)84 void DScreen::SetVideoParam(std::shared_ptr<VideoParam> &videoParam)
85 {
86 videoParam_ = videoParam;
87 }
88
GetVideoParam()89 std::shared_ptr<VideoParam> DScreen::GetVideoParam()
90 {
91 return videoParam_;
92 }
93
SetState(DScreenState state)94 void DScreen::SetState(DScreenState state)
95 {
96 std::lock_guard<std::mutex> lock(stateMtx_);
97 curState_ = state;
98 }
99
GetState() const100 DScreenState DScreen::GetState() const
101 {
102 return curState_;
103 }
104
GetScreenId() const105 uint64_t DScreen::GetScreenId() const
106 {
107 return screenId_;
108 }
109
SetScreenVersion(const std::string & version)110 void DScreen::SetScreenVersion(const std::string &version)
111 {
112 version_ = version;
113 }
114
GetScreenVersion()115 std::string DScreen::GetScreenVersion()
116 {
117 return version_;
118 }
119
GetDHId() const120 std::string DScreen::GetDHId() const
121 {
122 return dhId_;
123 }
124
GetDevId() const125 std::string DScreen::GetDevId() const
126 {
127 return devId_;
128 }
129
AddTask(const std::shared_ptr<Task> & task)130 int32_t DScreen::AddTask(const std::shared_ptr<Task> &task)
131 {
132 DHLOGI("DScreen::AddTask, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(),
133 GetAnonyString(dhId_).c_str());
134 if (task == nullptr) {
135 DHLOGE("AddTask, task is invalid.");
136 return ERR_DH_SCREEN_SA_DSCREEN_TASK_NOT_VALID;
137 }
138 DHLOGI("AddTask, task type: %" PRId32, task->GetTaskType());
139 {
140 std::lock_guard<std::mutex> lock(taskQueueMtx_);
141 taskQueue_.push(task);
142 }
143 taskQueueCond_.notify_all();
144 return DH_SUCCESS;
145 }
146
TaskThreadLoop()147 void DScreen::TaskThreadLoop()
148 {
149 DHLOGI("DScreen taskThread start. devId: %s, dhId: %s", GetAnonyString(devId_).c_str(),
150 GetAnonyString(dhId_).c_str());
151 int32_t ret = pthread_setname_np(pthread_self(), TASK_THREAD);
152 if (ret != DH_SUCCESS) {
153 DHLOGE("Dscreen set thread name failed, ret %" PRId32, ret);
154 }
155 while (taskThreadRunning_) {
156 std::shared_ptr<Task> task;
157 {
158 std::unique_lock<std::mutex> lock(taskQueueMtx_);
159 taskQueueCond_.wait_for(lock, std::chrono::seconds(TASK_WAIT_SECONDS),
160 [this]() { return !taskQueue_.empty(); });
161 if (taskQueue_.empty()) {
162 continue;
163 }
164 task = taskQueue_.front();
165 taskQueue_.pop();
166 }
167
168 if (task == nullptr) {
169 DHLOGD("task is null.");
170 continue;
171 }
172
173 DHLOGD("run task, task queue size: %zu", taskQueue_.size());
174 HandleTask(task);
175 }
176 }
177
HandleTask(const std::shared_ptr<Task> & task)178 void DScreen::HandleTask(const std::shared_ptr<Task> &task)
179 {
180 int32_t taskType = task->GetTaskType();
181 DHLOGI("HandleTask, devId: %s, dhId: %s, task type: %" PRId32, GetAnonyString(devId_).c_str(),
182 GetAnonyString(dhId_).c_str(), taskType);
183 switch (taskType) {
184 case TaskType::TASK_ENABLE:
185 HandleEnable(task->GetTaskParam(), task->GetTaskId());
186 break;
187 case TaskType::TASK_DISABLE:
188 HandleDisable(task->GetTaskId());
189 break;
190 case TaskType::TASK_CONNECT:
191 HandleConnect();
192 break;
193 case TaskType::TASK_DISCONNECT:
194 HandleDisconnect();
195 break;
196 default:
197 DHLOGD("task type unkown.");
198 }
199 }
200
HandleEnable(const std::string & param,const std::string & taskId)201 void DScreen::HandleEnable(const std::string ¶m, const std::string &taskId)
202 {
203 if (dscreenCallback_ == nullptr) {
204 DHLOGE("DScreen::HandleEnable, dscreenCallback_ is nullptr");
205 return;
206 }
207 DHLOGI("HandleEnable, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str());
208 if (curState_ == ENABLED || curState_ == ENABLING || curState_ == CONNECTING || curState_ == CONNECTED) {
209 dscreenCallback_->OnRegResult(shared_from_this(), taskId, DH_SUCCESS, "dscreen enable success.");
210 return;
211 }
212
213 SetState(ENABLING);
214 if (videoParam_ == nullptr) {
215 videoParam_ = std::make_shared<VideoParam>();
216 }
217
218 json attrJson = json::parse(param, nullptr, false);
219 if (attrJson.is_discarded()) {
220 DHLOGE("HandleEnable attrJson is invalid");
221 SetState(DISABLED);
222 return;
223 }
224 int32_t ret = CheckJsonData(attrJson);
225 if (ret != DH_SUCCESS) {
226 dscreenCallback_->OnRegResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_ENABLE_FAILED,
227 "enable param json is invalid.");
228 ReportRegisterFail(DSCREEN_REGISTER_FAIL, ERR_DH_SCREEN_SA_ENABLE_FAILED, GetAnonyString(devId_).c_str(),
229 GetAnonyString(dhId_).c_str(), "check json data failed.");
230 return;
231 }
232
233 videoParam_->SetScreenWidth(attrJson[KEY_SCREEN_WIDTH].get<uint32_t>());
234 videoParam_->SetScreenHeight(attrJson[KEY_SCREEN_HEIGHT].get<uint32_t>());
235
236 // negotiate codecType
237 ret = NegotiateCodecType(attrJson[KEY_CODECTYPE]);
238 if (ret != DH_SUCCESS) {
239 dscreenCallback_->OnRegResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_ENABLE_FAILED,
240 "negotiate codec type failed.");
241 ReportRegisterFail(DSCREEN_REGISTER_FAIL, ERR_DH_SCREEN_SA_ENABLE_FAILED, GetAnonyString(devId_).c_str(),
242 GetAnonyString(dhId_).c_str(), "negotiate codec type failed.");
243 return;
244 }
245
246 uint64_t screenId = ScreenMgrAdapter::GetInstance().CreateVirtualScreen(devId_, dhId_, videoParam_);
247 if (screenId == SCREEN_ID_INVALID) {
248 dscreenCallback_->OnRegResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_ENABLE_FAILED,
249 "create virtual screen failed.");
250 ReportRegisterFail(DSCREEN_REGISTER_FAIL, ERR_DH_SCREEN_SA_ENABLE_FAILED, GetAnonyString(devId_).c_str(),
251 GetAnonyString(dhId_).c_str(), "create virtual screen failed.");
252 return;
253 }
254 screenId_ = screenId;
255 SetState(ENABLED);
256 dscreenCallback_->OnRegResult(shared_from_this(), taskId, DH_SUCCESS, "dscreen enable success.");
257 ReportRegisterScreenEvent(DSCREEN_REGISTER, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
258 "dscreen enable success.");
259 }
260
CheckJsonData(json & attrJson)261 int32_t DScreen::CheckJsonData(json &attrJson)
262 {
263 if (attrJson.is_discarded()) {
264 DHLOGE("enable param json is invalid.");
265 return ERR_DH_SCREEN_SA_ENABLE_JSON_ERROR;
266 }
267
268 if (!IsUInt32(attrJson, KEY_SCREEN_WIDTH) || !IsUInt32(attrJson, KEY_SCREEN_HEIGHT) ||
269 !attrJson.contains(KEY_CODECTYPE)) {
270 DHLOGE("enable param is invalid.");
271 return ERR_DH_SCREEN_SA_ENABLE_JSON_ERROR;
272 }
273 return DH_SUCCESS;
274 }
275
NegotiateCodecType(const std::string & remoteCodecInfoStr)276 int32_t DScreen::NegotiateCodecType(const std::string &remoteCodecInfoStr)
277 {
278 json remoteCodecArray = json::parse(remoteCodecInfoStr, nullptr, false);
279 if (remoteCodecArray.is_discarded() || !remoteCodecArray.is_array()) {
280 DHLOGE("remoteCodecInfoStrjson is invalid.");
281 return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
282 }
283
284 std::vector<std::string> localCodecArray;
285 // query local support encoder type
286 std::shared_ptr<Media::AVCodecList> codecList = Media::AVCodecListFactory::CreateAVCodecList();
287 if (codecList == nullptr) {
288 DHLOGE("codecList is nullptr.");
289 return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
290 }
291 std::vector<std::shared_ptr<Media::VideoCaps>> caps = codecList->GetVideoEncoderCaps();
292 for (const auto &cap : caps) {
293 if (cap == nullptr) {
294 continue;
295 }
296 std::shared_ptr<Media::AVCodecInfo> codecInfo = cap->GetCodecInfo();
297 if (codecInfo == nullptr) {
298 continue;
299 }
300 localCodecArray.push_back(codecInfo->GetName());
301 }
302
303 std::vector<std::string> codecTypeCandidates;
304 for (const auto &remoteCodecType : remoteCodecArray) {
305 if (std::find(localCodecArray.begin(), localCodecArray.end(),
306 remoteCodecType) != localCodecArray.end()) {
307 codecTypeCandidates.push_back(remoteCodecType);
308 }
309 }
310
311 if (std::find(codecTypeCandidates.begin(), codecTypeCandidates.end(),
312 CODEC_NAME_H265) != codecTypeCandidates.end()) {
313 videoParam_->SetCodecType(VIDEO_CODEC_TYPE_VIDEO_H265);
314 videoParam_->SetVideoFormat(VIDEO_DATA_FORMAT_NV12);
315 videoParam_->SetPartialRefreshFlag(true);
316 } else if (std::find(codecTypeCandidates.begin(), codecTypeCandidates.end(),
317 CODEC_NAME_H264) != codecTypeCandidates.end()) {
318 videoParam_->SetCodecType(VIDEO_CODEC_TYPE_VIDEO_H264);
319 videoParam_->SetVideoFormat(VIDEO_DATA_FORMAT_NV12);
320 videoParam_->SetPartialRefreshFlag(true);
321 } else if (std::find(codecTypeCandidates.begin(), codecTypeCandidates.end(),
322 CODEC_NAME_MPEG4) != codecTypeCandidates.end()) {
323 videoParam_->SetCodecType(VIDEO_CODEC_TYPE_VIDEO_MPEG4);
324 videoParam_->SetVideoFormat(VIDEO_DATA_FORMAT_RGBA8888);
325 } else {
326 DHLOGI("codec type not support.");
327 return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
328 }
329
330 return DH_SUCCESS;
331 }
332
HandleDisable(const std::string & taskId)333 void DScreen::HandleDisable(const std::string &taskId)
334 {
335 if (dscreenCallback_ == nullptr) {
336 DHLOGE("DScreen::HandleDisable, dscreenCallback_ is nullptr");
337 return;
338 }
339 DHLOGI("HandleDisable, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str());
340 SetState(DISABLING);
341 int32_t ret = ScreenMgrAdapter::GetInstance().RemoveVirtualScreen(screenId_);
342 if (ret != DH_SUCCESS) {
343 DHLOGE("remove virtual screen failed.");
344 dscreenCallback_->OnUnregResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_DISABLE_FAILED,
345 "remove virtual screen failed.");
346 ReportUnRegisterFail(DSCREEN_UNREGISTER_FAIL, ERR_DH_SCREEN_SA_DISABLE_FAILED, GetAnonyString(devId_).c_str(),
347 GetAnonyString(dhId_).c_str(), "remove virtual screen failed.");
348 return;
349 }
350 SetState(DISABLED);
351 dscreenCallback_->OnUnregResult(shared_from_this(), taskId, DH_SUCCESS, "");
352 ReportUnRegisterScreenEvent(DSCREEN_UNREGISTER, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
353 "dscreen disable success.");
354 }
355
HandleConnect()356 void DScreen::HandleConnect()
357 {
358 DHLOGI("HandleConnect, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(),
359 GetAnonyString(dhId_).c_str());
360
361 int32_t ret = SetUp();
362 if (ret != DH_SUCCESS) {
363 SetState(ENABLED);
364 ScreenMgrAdapter::GetInstance().RemoveScreenFromGroup(screenId_);
365 DHLOGE("dScreen SetUp failed.");
366 return;
367 }
368
369 ret = Start();
370 if (ret != DH_SUCCESS) {
371 SetState(ENABLED);
372 ScreenMgrAdapter::GetInstance().RemoveScreenFromGroup(screenId_);
373 DHLOGE("dScreen Start failed.");
374 return;
375 }
376 SetState(CONNECTED);
377 ReportScreenMirrorEvent(DSCREEN_PROJECT_START, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
378 "dscreen connect success");
379 }
380
HandleDisconnect()381 void DScreen::HandleDisconnect()
382 {
383 DHLOGD("HandleDisconnect, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(),
384 GetAnonyString(dhId_).c_str());
385 if (curState_ != CONNECTED) {
386 DHLOGE("dscreen is not connected, cannot disconnect");
387 return;
388 }
389 SetState(DISCONNECTING);
390 int32_t ret = Stop();
391 if (ret != DH_SUCCESS) {
392 SetState(CONNECTED);
393 DHLOGE("dScreen Stop failed.");
394 return;
395 }
396 SetState(ENABLED);
397 ReportScreenMirrorEvent(DSCREEN_PROJECT_END, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
398 "dscreen disconnect success");
399 }
400
SetUp()401 int32_t DScreen::SetUp()
402 {
403 DHLOGD("SetUp, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(),
404 GetAnonyString(dhId_).c_str());
405
406 if (sourceTrans_ == nullptr) {
407 sourceTrans_ = std::make_shared<ScreenSourceTrans>();
408 }
409 sourceTrans_->SetScreenVersion(version_);
410 sourceTrans_->RegisterStateCallback(shared_from_this());
411 int32_t ret = sourceTrans_->SetUp(*videoParam_, *videoParam_, devId_);
412 if (ret != DH_SUCCESS) {
413 DHLOGE("source trans SetUp failed.");
414 return ret;
415 }
416 DHLOGI("DScreen SetUp success.");
417 return DH_SUCCESS;
418 }
419
Start()420 int32_t DScreen::Start()
421 {
422 DHLOGD("Start, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(),
423 GetAnonyString(dhId_).c_str());
424 if (sourceTrans_ == nullptr) {
425 DHLOGE("source trans not init.");
426 return ERR_DH_SCREEN_SA_SOURCETRANS_NOT_INIT;
427 }
428 int32_t ret = sourceTrans_->Start();
429 if (ret != DH_SUCCESS) {
430 DHLOGE("source trans start failed.");
431 return ret;
432 }
433 sptr<OHOS::Surface> windowSurface = sourceTrans_->GetImageSurface();
434 if (windowSurface == nullptr) {
435 DHLOGE("DScreen SetUp failed.");
436 return ERR_DH_SCREEN_SA_DSCREEN_SETUP_FAILED;
437 }
438 ScreenMgrAdapter::GetInstance().SetImageSurface(screenId_, windowSurface);
439 return DH_SUCCESS;
440 }
441
Stop()442 int32_t DScreen::Stop()
443 {
444 DHLOGD("Stop, devId: %s, dhId: %s", GetAnonyString(devId_).c_str(),
445 GetAnonyString(dhId_).c_str());
446 if (sourceTrans_ == nullptr) {
447 DHLOGE("source trans not init.");
448 return ERR_DH_SCREEN_SA_SOURCETRANS_NOT_INIT;
449 }
450
451 int32_t ret = sourceTrans_->Stop();
452 if (ret != DH_SUCCESS) {
453 DHLOGE("source trans stop failed.");
454 return ret;
455 }
456
457 ret = sourceTrans_->Release();
458 if (ret != DH_SUCCESS) {
459 DHLOGE("source trans release failed.");
460 return ret;
461 }
462
463 sourceTrans_ = nullptr;
464 return DH_SUCCESS;
465 }
466 } // namespace V1_0
467 } // namespace DistributedHardware
468 } // namespace OHOS