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 "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: %{public}s, dhId: %{public}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([this] { this->TaskThreadLoop(); });
46 }
47
~DScreen()48 DScreen::~DScreen()
49 {
50 DHLOGD("DScreen deconstruct, devId: %{public}s, dhId: %{public}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: %{public}" 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 DHLOGW("OnTransError, err: %{public}" 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: %{public}s, dhId: %{public}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: %{public}" 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: %{public}s, dhId: %{public}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 %{public}" PRId32, ret);
154 }
155 while (taskThreadRunning_) {
156 std::shared_ptr<Task> task;
157 {
158 std::unique_lock<std::mutex> lock(taskQueueMtx_);
159 auto status = taskQueueCond_.wait_for(lock, std::chrono::seconds(TASK_WAIT_SECONDS),
160 [this]() { return !taskQueue_.empty(); });
161 if (!status) {
162 DHLOGD("Task queue wait timeout after %{public}d seconds.", TASK_WAIT_SECONDS);
163 continue;
164 }
165 if (taskQueue_.empty()) {
166 continue;
167 }
168 task = taskQueue_.front();
169 taskQueue_.pop();
170 }
171
172 if (task == nullptr) {
173 DHLOGD("task is null.");
174 continue;
175 }
176
177 DHLOGD("run task, task queue size: %{public}zu", taskQueue_.size());
178 HandleTask(task);
179 }
180 }
181
HandleTask(const std::shared_ptr<Task> &task)182 void DScreen::HandleTask(const std::shared_ptr<Task> &task)
183 {
184 int32_t taskType = task->GetTaskType();
185 DHLOGI("HandleTask, devId: %{public}s, dhId: %{public}s, task type: %{public}" PRId32,
186 GetAnonyString(devId_).c_str(),
187 GetAnonyString(dhId_).c_str(), taskType);
188 switch (taskType) {
189 case TaskType::TASK_ENABLE:
190 HandleEnable(task->GetTaskParam(), task->GetTaskId());
191 break;
192 case TaskType::TASK_DISABLE:
193 HandleDisable(task->GetTaskId());
194 break;
195 case TaskType::TASK_CONNECT:
196 HandleConnect();
197 break;
198 case TaskType::TASK_DISCONNECT:
199 HandleDisconnect();
200 break;
201 default:
202 DHLOGD("task type unkown.");
203 }
204 }
205
HandleEnable(const std::string ¶m, const std::string &taskId)206 void DScreen::HandleEnable(const std::string ¶m, const std::string &taskId)
207 {
208 json attrJson = json::parse(param, nullptr, false);
209 if (attrJson.is_discarded()) {
210 DHLOGE("HandleEnable attrJson is invalid");
211 return;
212 }
213 if (dscreenCallback_ == nullptr) {
214 DHLOGE("DScreen::HandleEnable, dscreenCallback_ is nullptr");
215 return;
216 }
217 DHLOGI("HandleEnable, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
218 GetAnonyString(dhId_).c_str());
219 if (curState_ == ENABLED || curState_ == ENABLING || curState_ == CONNECTING || curState_ == CONNECTED) {
220 dscreenCallback_->OnRegResult(shared_from_this(), taskId, DH_SUCCESS, "dscreen enable success.");
221 return;
222 }
223 SetState(ENABLING);
224 if (videoParam_ == nullptr) {
225 videoParam_ = std::make_shared<VideoParam>();
226 }
227
228 int32_t ret = CheckJsonData(attrJson);
229 if (ret != DH_SUCCESS) {
230 dscreenCallback_->OnRegResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_ENABLE_FAILED,
231 "enable param json is invalid.");
232 ReportRegisterFail(DSCREEN_REGISTER_FAIL, ERR_DH_SCREEN_SA_ENABLE_FAILED, GetAnonyString(devId_).c_str(),
233 GetAnonyString(dhId_).c_str(), "check json data failed.");
234 return;
235 }
236
237 videoParam_->SetScreenWidth(attrJson[KEY_SCREEN_WIDTH].get<uint32_t>());
238 videoParam_->SetScreenHeight(attrJson[KEY_SCREEN_HEIGHT].get<uint32_t>());
239
240 // negotiate codecType
241 ret = NegotiateCodecType(attrJson[KEY_CODECTYPE]);
242 if (ret != DH_SUCCESS) {
243 dscreenCallback_->OnRegResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_ENABLE_FAILED,
244 "negotiate codec type failed.");
245 ReportRegisterFail(DSCREEN_REGISTER_FAIL, ERR_DH_SCREEN_SA_ENABLE_FAILED, GetAnonyString(devId_).c_str(),
246 GetAnonyString(dhId_).c_str(), "negotiate codec type failed.");
247 return;
248 }
249
250 screenId_ = ScreenMgrAdapter::GetInstance().CreateVirtualScreen(devId_, dhId_, videoParam_);
251 if (screenId_ == SCREEN_ID_INVALID) {
252 dscreenCallback_->OnRegResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_ENABLE_FAILED,
253 "create virtual screen failed.");
254 ReportRegisterFail(DSCREEN_REGISTER_FAIL, ERR_DH_SCREEN_SA_ENABLE_FAILED, GetAnonyString(devId_).c_str(),
255 GetAnonyString(dhId_).c_str(), "create virtual screen failed.");
256 return;
257 }
258 SetState(ENABLED);
259 dscreenCallback_->OnRegResult(shared_from_this(), taskId, DH_SUCCESS, "dscreen enable success.");
260 ReportRegisterScreenEvent(DSCREEN_REGISTER, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
261 "dscreen enable success.");
262 }
263
CheckJsonData(json &attrJson)264 int32_t DScreen::CheckJsonData(json &attrJson)
265 {
266 if (attrJson.is_discarded()) {
267 DHLOGE("enable param json is invalid.");
268 return ERR_DH_SCREEN_SA_ENABLE_JSON_ERROR;
269 }
270
271 if (!IsUInt32(attrJson, KEY_SCREEN_WIDTH) || !IsUInt32(attrJson, KEY_SCREEN_HEIGHT) ||
272 !attrJson.contains(KEY_CODECTYPE)) {
273 DHLOGE("enable param is invalid.");
274 return ERR_DH_SCREEN_SA_ENABLE_JSON_ERROR;
275 }
276
277 if ((attrJson[KEY_SCREEN_WIDTH].get<uint32_t>() > DSCREEN_MAX_SCREEN_DATA_WIDTH) ||
278 (attrJson[KEY_SCREEN_HEIGHT].get<uint32_t>() > DSCREEN_MAX_SCREEN_DATA_HEIGHT)) {
279 DHLOGE("Screen width or height is out of range.");
280 return ERR_DH_SCREEN_SA_ENABLE_JSON_ERROR;
281 }
282 return DH_SUCCESS;
283 }
284
NegotiateCodecType(const std::string &remoteCodecInfoStr)285 int32_t DScreen::NegotiateCodecType(const std::string &remoteCodecInfoStr)
286 {
287 json remoteCodecArray = json::parse(remoteCodecInfoStr, nullptr, false);
288 if (remoteCodecArray.is_discarded() || !remoteCodecArray.is_array()) {
289 DHLOGE("remoteCodecInfoStrjson is invalid.");
290 return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
291 }
292
293 std::vector<std::string> localCodecArray;
294 // query local support encoder type
295 std::shared_ptr<MediaAVCodec::AVCodecList> codecList = MediaAVCodec::AVCodecListFactory::CreateAVCodecList();
296 if (codecList == nullptr) {
297 DHLOGE("Create avCodecList failed.");
298 return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
299 }
300 const std::vector<std::string> encoderName = {std::string(MediaAVCodec::CodecMimeType::VIDEO_AVC),
301 std::string(MediaAVCodec::CodecMimeType::VIDEO_HEVC)};
302 for (const auto &coder : encoderName) {
303 MediaAVCodec::CapabilityData *capData = codecList->GetCapability(coder, true,
304 MediaAVCodec::AVCodecCategory::AVCODEC_HARDWARE);
305 if (capData == nullptr) {
306 continue;
307 }
308 std::string mimeType = capData->mimeType;
309 localCodecArray.push_back(mimeType);
310 }
311
312 std::vector<std::string> codecTypeCandidates;
313 for (const auto &remoteCodecType : remoteCodecArray) {
314 if (std::find(localCodecArray.begin(), localCodecArray.end(),
315 remoteCodecType) != localCodecArray.end()) {
316 codecTypeCandidates.push_back(remoteCodecType);
317 }
318 }
319
320 if (std::find(codecTypeCandidates.begin(), codecTypeCandidates.end(),
321 std::string(MediaAVCodec::CodecMimeType::VIDEO_AVC)) != codecTypeCandidates.end()) {
322 videoParam_->SetCodecType(VIDEO_CODEC_TYPE_VIDEO_H264);
323 } else if (std::find(codecTypeCandidates.begin(), codecTypeCandidates.end(),
324 std::string(MediaAVCodec::CodecMimeType::VIDEO_HEVC)) != codecTypeCandidates.end()) {
325 videoParam_->SetCodecType(VIDEO_CODEC_TYPE_VIDEO_H265);
326 } else {
327 DHLOGI("codec type not support.");
328 return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
329 }
330 videoParam_->SetVideoFormat(VIDEO_DATA_FORMAT_RGBA8888);
331 videoParam_->SetPartialRefreshFlag(true);
332 return DH_SUCCESS;
333 }
334
HandleDisable(const std::string &taskId)335 void DScreen::HandleDisable(const std::string &taskId)
336 {
337 if (dscreenCallback_ == nullptr) {
338 DHLOGE("DScreen::HandleDisable, dscreenCallback_ is nullptr");
339 return;
340 }
341 DHLOGI("HandleDisable, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
342 GetAnonyString(dhId_).c_str());
343 SetState(DISABLING);
344 int32_t ret = ScreenMgrAdapter::GetInstance().RemoveVirtualScreen(screenId_);
345 if (ret != DH_SUCCESS) {
346 DHLOGE("remove virtual screen failed.");
347 dscreenCallback_->OnUnregResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_DISABLE_FAILED,
348 "remove virtual screen failed.");
349 ReportUnRegisterFail(DSCREEN_UNREGISTER_FAIL, ERR_DH_SCREEN_SA_DISABLE_FAILED, GetAnonyString(devId_).c_str(),
350 GetAnonyString(dhId_).c_str(), "remove virtual screen failed.");
351 return;
352 }
353 SetState(DISABLED);
354 dscreenCallback_->OnUnregResult(shared_from_this(), taskId, DH_SUCCESS, "dscreen disable success.");
355 ReportUnRegisterScreenEvent(DSCREEN_UNREGISTER, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
356 "dscreen disable success.");
357 }
358
HandleConnect()359 void DScreen::HandleConnect()
360 {
361 DHLOGI("HandleConnect, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
362 GetAnonyString(dhId_).c_str());
363
364 int32_t ret = SetUp();
365 if (ret != DH_SUCCESS) {
366 SetState(ENABLED);
367 ScreenMgrAdapter::GetInstance().RemoveScreenFromGroup(screenId_);
368 DHLOGE("dScreen SetUp failed.");
369 return;
370 }
371
372 ret = Start();
373 if (ret != DH_SUCCESS) {
374 SetState(ENABLED);
375 ScreenMgrAdapter::GetInstance().RemoveScreenFromGroup(screenId_);
376 DHLOGE("dScreen Start failed.");
377 return;
378 }
379 SetState(CONNECTED);
380 ReportScreenMirrorEvent(DSCREEN_PROJECT_START, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
381 "dscreen connect success");
382 }
383
HandleDisconnect()384 void DScreen::HandleDisconnect()
385 {
386 DHLOGD("HandleDisconnect, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
387 GetAnonyString(dhId_).c_str());
388 if (curState_ != CONNECTED) {
389 DHLOGE("dscreen is not connected, cannot disconnect");
390 return;
391 }
392 SetState(DISCONNECTING);
393 int32_t ret = Stop();
394 if (ret != DH_SUCCESS) {
395 SetState(CONNECTED);
396 DHLOGE("dScreen Stop failed.");
397 return;
398 }
399 SetState(ENABLED);
400 Rosen::RSInterfaces::GetInstance().SetVirtualScreenUsingStatus(false);
401 ReportScreenMirrorEvent(DSCREEN_PROJECT_END, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
402 "dscreen disconnect success");
403 }
404
SetUp()405 int32_t DScreen::SetUp()
406 {
407 DHLOGD("SetUp, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
408 GetAnonyString(dhId_).c_str());
409
410 if (sourceTrans_ == nullptr) {
411 sourceTrans_ = std::make_shared<ScreenSourceTrans>();
412 }
413 sourceTrans_->SetScreenVersion(version_);
414 sourceTrans_->RegisterStateCallback(shared_from_this());
415 int32_t ret = sourceTrans_->SetUp(*videoParam_, *videoParam_, devId_);
416 if (ret != DH_SUCCESS) {
417 DHLOGE("source trans SetUp failed.");
418 return ret;
419 }
420 DHLOGI("DScreen SetUp success.");
421 return DH_SUCCESS;
422 }
423
Start()424 int32_t DScreen::Start()
425 {
426 DHLOGD("Start, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
427 GetAnonyString(dhId_).c_str());
428 if (sourceTrans_ == nullptr) {
429 DHLOGE("source trans not init.");
430 return ERR_DH_SCREEN_SA_SOURCETRANS_NOT_INIT;
431 }
432 int32_t ret = sourceTrans_->Start();
433 if (ret != DH_SUCCESS) {
434 DHLOGE("source trans start failed.");
435 return ret;
436 }
437 sptr<OHOS::Surface> windowSurface = sourceTrans_->GetImageSurface();
438 if (windowSurface == nullptr) {
439 DHLOGE("DScreen SetUp failed.");
440 return ERR_DH_SCREEN_SA_DSCREEN_SETUP_FAILED;
441 }
442 ScreenMgrAdapter::GetInstance().SetImageSurface(screenId_, windowSurface);
443 return DH_SUCCESS;
444 }
445
Stop()446 int32_t DScreen::Stop()
447 {
448 DHLOGD("Stop, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
449 GetAnonyString(dhId_).c_str());
450 if (sourceTrans_ == nullptr) {
451 DHLOGE("source trans not init.");
452 return ERR_DH_SCREEN_SA_SOURCETRANS_NOT_INIT;
453 }
454
455 int32_t ret = sourceTrans_->Stop();
456 if (ret != DH_SUCCESS) {
457 DHLOGE("source trans stop failed.");
458 return ret;
459 }
460
461 ret = sourceTrans_->Release();
462 if (ret != DH_SUCCESS) {
463 DHLOGE("source trans release failed.");
464 return ret;
465 }
466
467 sourceTrans_ = nullptr;
468 return DH_SUCCESS;
469 }
470 } // namespace V1_0
471 } // namespace DistributedHardware
472 } // namespace OHOS