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 & param,const std::string & taskId)206 void DScreen::HandleEnable(const std::string &param, 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     return DH_SUCCESS;
277 }
278 
NegotiateCodecType(const std::string & remoteCodecInfoStr)279 int32_t DScreen::NegotiateCodecType(const std::string &remoteCodecInfoStr)
280 {
281     json remoteCodecArray = json::parse(remoteCodecInfoStr, nullptr, false);
282     if (remoteCodecArray.is_discarded() || !remoteCodecArray.is_array()) {
283         DHLOGE("remoteCodecInfoStrjson is invalid.");
284         return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
285     }
286 
287     std::vector<std::string> localCodecArray;
288     // query local support encoder type
289     std::shared_ptr<MediaAVCodec::AVCodecList> codecList = MediaAVCodec::AVCodecListFactory::CreateAVCodecList();
290     if (codecList == nullptr) {
291         DHLOGE("Create avCodecList failed.");
292         return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
293     }
294     const std::vector<std::string> encoderName = {std::string(MediaAVCodec::CodecMimeType::VIDEO_AVC),
295                                                   std::string(MediaAVCodec::CodecMimeType::VIDEO_HEVC)};
296     for (const auto &coder : encoderName) {
297         MediaAVCodec::CapabilityData *capData = codecList->GetCapability(coder, true,
298             MediaAVCodec::AVCodecCategory::AVCODEC_HARDWARE);
299             if (capData == nullptr) {
300                 continue;
301             }
302         std::string mimeType = capData->mimeType;
303         localCodecArray.push_back(mimeType);
304     }
305 
306     std::vector<std::string> codecTypeCandidates;
307     for (const auto &remoteCodecType : remoteCodecArray) {
308         if (std::find(localCodecArray.begin(), localCodecArray.end(),
309             remoteCodecType) != localCodecArray.end()) {
310             codecTypeCandidates.push_back(remoteCodecType);
311         }
312     }
313 
314     if (std::find(codecTypeCandidates.begin(), codecTypeCandidates.end(),
315         std::string(MediaAVCodec::CodecMimeType::VIDEO_AVC)) != codecTypeCandidates.end()) {
316         videoParam_->SetCodecType(VIDEO_CODEC_TYPE_VIDEO_H264);
317     } else if (std::find(codecTypeCandidates.begin(), codecTypeCandidates.end(),
318         std::string(MediaAVCodec::CodecMimeType::VIDEO_HEVC)) != codecTypeCandidates.end()) {
319         videoParam_->SetCodecType(VIDEO_CODEC_TYPE_VIDEO_H265);
320     } else {
321         DHLOGI("codec type not support.");
322         return ERR_DH_SCREEN_SA_DSCREEN_NEGOTIATE_CODEC_FAIL;
323     }
324     videoParam_->SetVideoFormat(VIDEO_DATA_FORMAT_RGBA8888);
325     videoParam_->SetPartialRefreshFlag(true);
326     return DH_SUCCESS;
327 }
328 
HandleDisable(const std::string & taskId)329 void DScreen::HandleDisable(const std::string &taskId)
330 {
331     if (dscreenCallback_ == nullptr) {
332         DHLOGE("DScreen::HandleDisable, dscreenCallback_ is nullptr");
333         return;
334     }
335     DHLOGI("HandleDisable, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
336         GetAnonyString(dhId_).c_str());
337     SetState(DISABLING);
338     int32_t ret = ScreenMgrAdapter::GetInstance().RemoveVirtualScreen(screenId_);
339     if (ret != DH_SUCCESS) {
340         DHLOGE("remove virtual screen failed.");
341         dscreenCallback_->OnUnregResult(shared_from_this(), taskId, ERR_DH_SCREEN_SA_DISABLE_FAILED,
342             "remove virtual screen failed.");
343         ReportUnRegisterFail(DSCREEN_UNREGISTER_FAIL, ERR_DH_SCREEN_SA_DISABLE_FAILED, GetAnonyString(devId_).c_str(),
344             GetAnonyString(dhId_).c_str(), "remove virtual screen failed.");
345         return;
346     }
347     SetState(DISABLED);
348     dscreenCallback_->OnUnregResult(shared_from_this(), taskId, DH_SUCCESS, "dscreen disable success.");
349     ReportUnRegisterScreenEvent(DSCREEN_UNREGISTER, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
350         "dscreen disable success.");
351 }
352 
HandleConnect()353 void DScreen::HandleConnect()
354 {
355     DHLOGI("HandleConnect, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
356         GetAnonyString(dhId_).c_str());
357 
358     int32_t ret = SetUp();
359     if (ret != DH_SUCCESS) {
360         SetState(ENABLED);
361         ScreenMgrAdapter::GetInstance().RemoveScreenFromGroup(screenId_);
362         DHLOGE("dScreen SetUp failed.");
363         return;
364     }
365 
366     ret = Start();
367     if (ret != DH_SUCCESS) {
368         SetState(ENABLED);
369         ScreenMgrAdapter::GetInstance().RemoveScreenFromGroup(screenId_);
370         DHLOGE("dScreen Start failed.");
371         return;
372     }
373     SetState(CONNECTED);
374     ReportScreenMirrorEvent(DSCREEN_PROJECT_START, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
375         "dscreen connect success");
376 }
377 
HandleDisconnect()378 void DScreen::HandleDisconnect()
379 {
380     DHLOGD("HandleDisconnect, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
381         GetAnonyString(dhId_).c_str());
382     if (curState_ != CONNECTED) {
383         DHLOGE("dscreen is not connected, cannot disconnect");
384         return;
385     }
386     SetState(DISCONNECTING);
387     int32_t ret = Stop();
388     if (ret != DH_SUCCESS) {
389         SetState(CONNECTED);
390         DHLOGE("dScreen Stop failed.");
391         return;
392     }
393     SetState(ENABLED);
394     Rosen::RSInterfaces::GetInstance().SetVirtualScreenUsingStatus(false);
395     ReportScreenMirrorEvent(DSCREEN_PROJECT_END, GetAnonyString(devId_).c_str(), GetAnonyString(dhId_).c_str(),
396         "dscreen disconnect success");
397 }
398 
SetUp()399 int32_t DScreen::SetUp()
400 {
401     DHLOGD("SetUp, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
402         GetAnonyString(dhId_).c_str());
403 
404     if (sourceTrans_ == nullptr) {
405         sourceTrans_ = std::make_shared<ScreenSourceTrans>();
406     }
407     sourceTrans_->SetScreenVersion(version_);
408     sourceTrans_->RegisterStateCallback(shared_from_this());
409     int32_t ret = sourceTrans_->SetUp(*videoParam_, *videoParam_, devId_);
410     if (ret != DH_SUCCESS) {
411         DHLOGE("source trans SetUp failed.");
412         return ret;
413     }
414     DHLOGI("DScreen SetUp success.");
415     return DH_SUCCESS;
416 }
417 
Start()418 int32_t DScreen::Start()
419 {
420     DHLOGD("Start, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
421         GetAnonyString(dhId_).c_str());
422     if (sourceTrans_ == nullptr) {
423         DHLOGE("source trans not init.");
424         return ERR_DH_SCREEN_SA_SOURCETRANS_NOT_INIT;
425     }
426     int32_t ret = sourceTrans_->Start();
427     if (ret != DH_SUCCESS) {
428         DHLOGE("source trans start failed.");
429         return ret;
430     }
431     sptr<OHOS::Surface> windowSurface = sourceTrans_->GetImageSurface();
432     if (windowSurface == nullptr) {
433         DHLOGE("DScreen SetUp failed.");
434         return ERR_DH_SCREEN_SA_DSCREEN_SETUP_FAILED;
435     }
436     ScreenMgrAdapter::GetInstance().SetImageSurface(screenId_, windowSurface);
437     return DH_SUCCESS;
438 }
439 
Stop()440 int32_t DScreen::Stop()
441 {
442     DHLOGD("Stop, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId_).c_str(),
443         GetAnonyString(dhId_).c_str());
444     if (sourceTrans_ == nullptr) {
445         DHLOGE("source trans not init.");
446         return ERR_DH_SCREEN_SA_SOURCETRANS_NOT_INIT;
447     }
448 
449     int32_t ret = sourceTrans_->Stop();
450     if (ret != DH_SUCCESS) {
451         DHLOGE("source trans stop failed.");
452         return ret;
453     }
454 
455     ret = sourceTrans_->Release();
456     if (ret != DH_SUCCESS) {
457         DHLOGE("source trans release failed.");
458         return ret;
459     }
460 
461     sourceTrans_ = nullptr;
462     return DH_SUCCESS;
463 }
464 } // namespace V1_0
465 } // namespace DistributedHardware
466 } // namespace OHOS