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