• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &param, 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