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