1 /*
2 * Copyright (c) 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 "VirtualScreenImpl.h"
17
18 #include <cinttypes>
19 #define boolean jpegboolean
20 #include "jpeglib.h"
21 #undef boolean
22
23 #include "CommandLineInterface.h"
24 #include "CommandParser.h"
25 #include "PreviewerEngineLog.h"
26 #include "TraceTool.h"
27 #include <sstream>
28
GetInstance()29 VirtualScreenImpl& VirtualScreenImpl::GetInstance()
30 {
31 static VirtualScreenImpl virtualScreen;
32 return virtualScreen;
33 }
34
SendBufferOnTimer()35 void VirtualScreenImpl::SendBufferOnTimer()
36 {
37 GetInstance().SetLoadDocFlag(VirtualScreen::LoadDocType::NORMAL);
38 if (GetInstance().loadDocTempBuffer == nullptr) {
39 PrintLoadDocFinishedLog("onRender timeout,no buffer to send");
40 return;
41 }
42 VirtualScreen::isStartCount = true;
43 {
44 std::lock_guard<std::mutex> guard(WebSocketServer::GetInstance().mutex);
45 if (GetInstance().loadDocCopyBuffer != nullptr) {
46 delete [] GetInstance().loadDocCopyBuffer;
47 GetInstance().loadDocCopyBuffer = nullptr;
48 }
49 GetInstance().loadDocCopyBuffer = new(std::nothrow) uint8_t[GetInstance().lengthTemp];
50 if (!GetInstance().loadDocCopyBuffer) {
51 ELOG("Memory allocation failed : loadDocCopyBuffer.");
52 return;
53 }
54 std::copy(GetInstance().loadDocTempBuffer,
55 GetInstance().loadDocTempBuffer + GetInstance().lengthTemp,
56 GetInstance().loadDocCopyBuffer);
57 }
58 VirtualScreenImpl::GetInstance().protocolVersion =
59 static_cast<uint16_t>(VirtualScreen::ProtocolVersion::LOADDOCRGBA);
60 GetInstance().bufferSize = GetInstance().lengthTemp + GetInstance().headSize;
61 GetInstance().wholeBuffer = new(std::nothrow) uint8_t[LWS_PRE + GetInstance().bufferSize];
62 if (!GetInstance().wholeBuffer) {
63 ELOG("Memory allocation failed : wholeBuffer.");
64 return;
65 }
66 GetInstance().screenBuffer = GetInstance().wholeBuffer + LWS_PRE;
67 GetInstance().SendPixmap(GetInstance().loadDocCopyBuffer, GetInstance().lengthTemp,
68 GetInstance().widthTemp, GetInstance().heightTemp);
69 }
70
PrintLoadDocFinishedLog(const std::string & logStr)71 void VirtualScreenImpl::PrintLoadDocFinishedLog(const std::string& logStr)
72 {
73 ILOG("loadDoc: LoadDocFlag2:finished %s, onRenderTime:%" PRIu64 ", flushEmptyTime:%" PRIu64 ", \
74 onRenderTimeStamp:%" PRIu64 " flushEmptyTimeStamp:%" PRIu64 "", logStr.c_str(),
75 GetInstance().onRenderTime, GetInstance().flushEmptyTime,
76 GetInstance().timeStampTemp, GetInstance().flushEmptyTimeStamp);
77 }
78
FlushEmptyFunc(std::chrono::system_clock::time_point endTime,int64_t timePassed)79 bool VirtualScreenImpl::FlushEmptyFunc(std::chrono::system_clock::time_point endTime, int64_t timePassed)
80 {
81 if (GetInstance().onRenderTime > GetInstance().flushEmptyTime) {
82 if (GetInstance().timeStampTemp < GetInstance().flushEmptyTimeStamp) {
83 SendBufferOnTimer(); // 有收到结束标记,且flushEmpty后有继续出图
84 PrintLoadDocFinishedLog("flushEmpty normal, onRender normal");
85 return true;
86 }
87 } else {
88 // flushEmpty后没有继续出图,计时100ms,如果仍没有onRender,发送上一次的的onRender buffer
89 int64_t timePassed2 = std::chrono::duration_cast<std::chrono::milliseconds>(endTime -
90 GetInstance().flushEmptyTime).count();
91 if (timePassed2 > TIMEOUT_ONRENDER_DURATION_MS) {
92 if (GetInstance().timeStampTemp < GetInstance().flushEmptyTimeStamp) {
93 SendBufferOnTimer();
94 PrintLoadDocFinishedLog("flushEmpty normal, onRender timeout");
95 return true;
96 }
97 }
98 }
99 if (timePassed >= TIMEOUT_NINE_S) { // 有结束点,无出图
100 PrintLoadDocFinishedLog("flushEmpty normal, onRender timeout");
101 return true; // 有收到结束标记,且超过最大时限还没有出图则结束
102 }
103 return false;
104 }
105
NoFlushEmptyFunc(int64_t timePassed)106 bool VirtualScreenImpl::NoFlushEmptyFunc(int64_t timePassed)
107 {
108 if (timePassed >= SEND_IMG_DURATION_MS &&
109 GetInstance().onRenderTime != std::chrono::system_clock::time_point::min()) {
110 SendBufferOnTimer(); // 没有收到结束标记,300ms内有出图选取最后一张图
111 PrintLoadDocFinishedLog("async load, flushEmpty timeout, onRender normal");
112 return true;
113 }
114 if (timePassed >= TIMEOUT_NINE_S) {
115 SendBufferOnTimer();
116 PrintLoadDocFinishedLog("flushEmpty timeout, onRender unknown");
117 return true; // 没有收到结束标记,且超过最大时限还没有出图则结束
118 }
119 return false;
120 }
121
122
StartTimer()123 void VirtualScreenImpl::StartTimer()
124 {
125 while (true) {
126 auto endTime = std::chrono::system_clock::now();
127 int64_t timePassed = std::chrono::duration_cast<std::chrono::milliseconds>(endTime -
128 VirtualScreenImpl::GetInstance().startTime).count();
129 bool ret = false;
130 if (GetInstance().isFlushEmpty) {
131 ret = FlushEmptyFunc(endTime, timePassed);
132 } else {
133 ret = NoFlushEmptyFunc(timePassed);
134 }
135 if (ret) {
136 return;
137 }
138 }
139 }
140
LoadDocCallback(const void * data,const size_t length,const int32_t width,const int32_t height,const uint64_t timeStamp)141 bool VirtualScreenImpl::LoadDocCallback(const void* data, const size_t length, const int32_t width,
142 const int32_t height, const uint64_t timeStamp)
143 {
144 if (timeStamp < GetInstance().loadDocTimeStamp) {
145 return false;
146 }
147 if (GetInstance().GetLoadDocFlag() == VirtualScreen::LoadDocType::FINISHED) {
148 {
149 std::lock_guard<std::mutex> guard(WebSocketServer::GetInstance().mutex);
150 if (GetInstance().loadDocTempBuffer != nullptr) {
151 delete [] GetInstance().loadDocTempBuffer;
152 GetInstance().loadDocTempBuffer = nullptr;
153 }
154 GetInstance().lengthTemp = length;
155 GetInstance().widthTemp = width;
156 GetInstance().heightTemp = height;
157 GetInstance().timeStampTemp = timeStamp;
158 if (length <= 0) {
159 return false;
160 }
161 GetInstance().loadDocTempBuffer = new(std::nothrow) uint8_t[length];
162 if (!GetInstance().loadDocTempBuffer) {
163 ELOG("Memory allocation failed : loadDocTempBuffer.");
164 return false;
165 }
166 uint8_t* dataPtr = reinterpret_cast<uint8_t*>(const_cast<void*>(data));
167 std::copy(dataPtr, dataPtr + length, GetInstance().loadDocTempBuffer);
168 GetInstance().onRenderTime = std::chrono::system_clock::now();
169 }
170 if (VirtualScreen::isStartCount) {
171 VirtualScreen::isStartCount = false;
172 VirtualScreen::startTime = std::chrono::system_clock::now();
173 std::thread timerThread(std::ref(VirtualScreenImpl::StartTimer));
174 timerThread.detach();
175 }
176 return false;
177 }
178 return true;
179 }
180
Callback(const void * data,const size_t length,const int32_t width,const int32_t height,const uint64_t timeStamp)181 bool VirtualScreenImpl::Callback(const void* data, const size_t length,
182 const int32_t width, const int32_t height, const uint64_t timeStamp)
183 {
184 if (VirtualScreenImpl::GetInstance().StopSendStaticCardImage(STOP_SEND_CARD_DURATION_MS)) {
185 return false; // 静态卡片
186 }
187 if (VirtualScreenImpl::GetInstance().GetLoadDocFlag() < VirtualScreen::LoadDocType::FINISHED) {
188 return false;
189 }
190 if (VirtualScreenImpl::GetInstance().JudgeAndDropFrame()) {
191 return false; // 丢帧*
192 }
193 bool staticRet = VirtualScreen::JudgeStaticImage(SEND_IMG_DURATION_MS);
194 if (!staticRet) {
195 return false; // 平行世界
196 }
197 if (!LoadDocCallback(data, length, width, height, timeStamp)) {
198 return false; // 组件预览
199 }
200
201 GetInstance().bufferSize = length + GetInstance().headSize;
202 GetInstance().wholeBuffer = new(std::nothrow) uint8_t[LWS_PRE + GetInstance().bufferSize];
203 if (!GetInstance().wholeBuffer) {
204 ELOG("Memory allocation failed : wholeBuffer.");
205 return false;
206 }
207 GetInstance().screenBuffer = GetInstance().wholeBuffer + LWS_PRE;
208
209 return GetInstance().SendPixmap(data, length, width, height);
210 }
211
FlushEmptyCallback(const uint64_t timeStamp)212 bool VirtualScreenImpl::FlushEmptyCallback(const uint64_t timeStamp)
213 {
214 if (timeStamp < GetInstance().loadDocTimeStamp) {
215 return false;
216 }
217 ILOG("loadDoc: flushEmptyTimeStamp:%" PRIu64 ", loadDocTimeStamp:%" PRIu64 "",
218 timeStamp, GetInstance().loadDocTimeStamp);
219 GetInstance().isFlushEmpty = true;
220 GetInstance().flushEmptyTime = std::chrono::system_clock::now();
221 GetInstance().flushEmptyTimeStamp = timeStamp;
222 return true;
223 }
224
InitFlushEmptyTime()225 void VirtualScreenImpl::InitFlushEmptyTime()
226 {
227 GetInstance().isFlushEmpty = false;
228 GetInstance().flushEmptyTime = std::chrono::system_clock::time_point::min();
229 GetInstance().onRenderTime = std::chrono::system_clock::time_point::min();
230 GetInstance().flushEmptyTimeStamp = 0;
231 struct timespec ts;
232 clock_gettime(CLOCK_MONOTONIC, &ts);
233 loadDocTimeStamp = ts.tv_sec * SEC_TO_NANOSEC + ts.tv_nsec;
234 ILOG("loadDoc: loadDocTimeStamp:%" PRIu64 "", loadDocTimeStamp);
235 }
236
PageCallback(const std::string currentRouterPath)237 bool VirtualScreenImpl::PageCallback(const std::string currentRouterPath)
238 {
239 std::string currentRouter = currentRouterPath.substr(0, currentRouterPath.size() - 3);
240 ILOG("PageCallback currentPage is : %s", currentRouter.c_str());
241 GetInstance().SetCurrentRouter(currentRouter);
242 Json2::Value val;
243 CommandLineInterface::GetInstance().CreatCommandToSendData("CurrentRouter", val, "get");
244 return true;
245 }
246
LoadContentCallback(const std::string currentRouterPath)247 bool VirtualScreenImpl::LoadContentCallback(const std::string currentRouterPath)
248 {
249 ILOG("LoadContentCallback currentPage is : %s", currentRouterPath.c_str());
250 GetInstance().SetAbilityCurrentRouter(currentRouterPath);
251 Json2::Value val;
252 CommandLineInterface::GetInstance().CreatCommandToSendData("LoadContent", val, "get");
253 return true;
254 }
255
FastPreviewCallback(const std::string & jsonStr)256 void VirtualScreenImpl::FastPreviewCallback(const std::string& jsonStr)
257 {
258 GetInstance().SetFastPreviewMsg(jsonStr);
259 Json2::Value val;
260 CommandLineInterface::GetInstance().CreatCommandToSendData("FastPreviewMsg", val, "get");
261 }
262
InitAll(std::string pipeName,std::string pipePort)263 void VirtualScreenImpl::InitAll(std::string pipeName, std::string pipePort)
264 {
265 VirtualScreen::InitPipe(pipeName, pipePort);
266 }
267
VirtualScreenImpl()268 VirtualScreenImpl::VirtualScreenImpl()
269 : isFirstSend(true),
270 isFirstRender(true),
271 writed(0),
272 wholeBuffer(nullptr),
273 screenBuffer(nullptr),
274 bufferSize(0),
275 currentPos(0)
276 {
277 }
278
~VirtualScreenImpl()279 VirtualScreenImpl::~VirtualScreenImpl()
280 {
281 FreeJpgMemory();
282 if (WebSocketServer::GetInstance().firstImageBuffer) {
283 delete [] WebSocketServer::GetInstance().firstImageBuffer;
284 WebSocketServer::GetInstance().firstImageBuffer = nullptr;
285 }
286 if (VirtualScreenImpl::GetInstance().loadDocTempBuffer != nullptr) {
287 delete [] VirtualScreenImpl::GetInstance().loadDocTempBuffer;
288 VirtualScreenImpl::GetInstance().loadDocTempBuffer = nullptr;
289 }
290 if (VirtualScreenImpl::GetInstance().loadDocCopyBuffer != nullptr) {
291 delete [] VirtualScreenImpl::GetInstance().loadDocCopyBuffer;
292 VirtualScreenImpl::GetInstance().loadDocCopyBuffer = nullptr;
293 }
294 }
295
Send(const void * data,int32_t retWidth,int32_t retHeight)296 void VirtualScreenImpl::Send(const void* data, int32_t retWidth, int32_t retHeight)
297 {
298 if (CommandParser::GetInstance().GetScreenMode() == CommandParser::ScreenMode::STATIC
299 && VirtualScreen::isOutOfSeconds) {
300 return;
301 }
302
303 if (retWidth < 1 || retHeight < 1) {
304 FLOG("VirtualScreenImpl::RgbToJpg the retWidth or height is invalid value");
305 return;
306 }
307 unsigned char* dataTemp = new(std::nothrow) unsigned char[retWidth * retHeight * jpgPix];
308 if (!dataTemp) {
309 ELOG("Memory allocation failed : dataTemp.");
310 return;
311 }
312 for (int i = 0; i < retHeight; i++) {
313 for (int j = 0; j < retWidth; j++) {
314 int inputBasePos = i * retWidth * pixelSize + j * pixelSize;
315 int nowBasePos = i * retWidth * jpgPix + j * jpgPix;
316 dataTemp[nowBasePos + redPos] = *((char*)data + inputBasePos + redPos);
317 dataTemp[nowBasePos + greenPos] = *((char*)data + inputBasePos + greenPos);
318 dataTemp[nowBasePos + bluePos] = *((char*)data + inputBasePos + bluePos);
319 }
320 }
321 VirtualScreen::RgbToJpg(dataTemp, retWidth, retHeight);
322 delete [] dataTemp;
323 if (jpgBufferSize > bufferSize - headSize) {
324 FLOG("VirtualScreenImpl::Send length must < %d", bufferSize - headSize);
325 return;
326 }
327
328 std::copy(jpgScreenBuffer, jpgScreenBuffer + jpgBufferSize, screenBuffer + headSize);
329 writed = WebSocketServer::GetInstance().WriteData(screenBuffer, headSize + jpgBufferSize);
330 BackupAndDeleteBuffer(jpgBufferSize);
331 }
332
SendRgba(const void * data,size_t length)333 void VirtualScreenImpl::SendRgba(const void* data, size_t length)
334 {
335 const char* charData = reinterpret_cast<const char*>(data);
336 std::copy(charData, charData + length, screenBuffer + headSize);
337 writed = WebSocketServer::GetInstance().WriteData(screenBuffer, headSize + length);
338 BackupAndDeleteBuffer(length);
339 }
340
BackupAndDeleteBuffer(const unsigned long imageBufferSize)341 void VirtualScreenImpl::BackupAndDeleteBuffer(const unsigned long imageBufferSize)
342 {
343 std::lock_guard<std::mutex> guard(WebSocketServer::GetInstance().mutex);
344 if (WebSocketServer::GetInstance().firstImageBuffer) {
345 delete [] WebSocketServer::GetInstance().firstImageBuffer;
346 WebSocketServer::GetInstance().firstImageBuffer = nullptr;
347 }
348 WebSocketServer::GetInstance().firstImageBuffer = new(std::nothrow) uint8_t[LWS_PRE + bufferSize];
349 if (!WebSocketServer::GetInstance().firstImageBuffer) {
350 ELOG("Memory allocation failed : firstImageBuffer.");
351 return;
352 }
353 WebSocketServer::GetInstance().firstImagebufferSize = headSize + jpgBufferSize;
354 std::copy(screenBuffer,
355 screenBuffer + headSize + imageBufferSize,
356 WebSocketServer::GetInstance().firstImageBuffer + LWS_PRE);
357
358 FreeJpgMemory();
359 }
360
JudgeBeforeSend(const void * data)361 bool VirtualScreenImpl::JudgeBeforeSend(const void* data)
362 {
363 if (data == nullptr) {
364 ELOG("render callback data is null.");
365 invalidFrameCountPerMinute++;
366 return false;
367 }
368 if (!isWebSocketConfiged) {
369 ELOG("image socket is not ready");
370 return false;
371 }
372 return true;
373 }
374
SendPixmap(const void * data,size_t length,int32_t retWidth,int32_t retHeight)375 bool VirtualScreenImpl::SendPixmap(const void* data, size_t length, int32_t retWidth, int32_t retHeight)
376 {
377 if (!JudgeBeforeSend(data)) {
378 return false;
379 }
380 if (isFirstRender) {
381 ILOG("Get first render buffer");
382 TraceTool::GetInstance().HandleTrace("Get first render buffer");
383 isFirstRender = false;
384 }
385 isFrameUpdated = true;
386 currentPos = 0;
387 WriteBuffer(headStart);
388 WriteBuffer(retWidth);
389 WriteBuffer(retHeight);
390 WriteBuffer(retWidth);
391 WriteBuffer(retHeight);
392 if (!CommandParser::GetInstance().IsRegionRefresh()) {
393 for (size_t i = 0; i < headReservedSize / sizeof(int32_t); i++) {
394 WriteBuffer(static_cast<uint32_t>(0));
395 }
396 } else {
397 uint16_t x1 = 0;
398 uint16_t y1 = 0;
399 uint16_t width = static_cast<uint16_t>(retWidth);
400 uint16_t height = static_cast<uint16_t>(retHeight);
401 WriteBuffer(protocolVersion);
402 WriteBuffer(x1);
403 WriteBuffer(y1);
404 WriteBuffer(width);
405 WriteBuffer(height);
406 for (size_t i = 0; i < 10 / sizeof(uint16_t); i++) { // fill 10bytes for header
407 WriteBuffer(static_cast<uint16_t>(0));
408 }
409 }
410 if (CommandParser::GetInstance().IsComponentMode()) {
411 SendRgba(data, length);
412 } else {
413 Send(data, retWidth, retHeight);
414 }
415 if (isFirstSend) {
416 ILOG("Send first buffer finish");
417 TraceTool::GetInstance().HandleTrace("Send first buffer finish");
418 isFirstSend = false;
419 }
420 validFrameCountPerMinute++;
421 sendFrameCountPerMinute++;
422 return writed == length;
423 }
424
FreeJpgMemory()425 void VirtualScreenImpl::FreeJpgMemory()
426 {
427 if (wholeBuffer != nullptr) {
428 delete [] wholeBuffer;
429 wholeBuffer = nullptr;
430 screenBuffer = nullptr;
431 }
432 if (jpgScreenBuffer != nullptr) {
433 free(jpgScreenBuffer);
434 jpgScreenBuffer = NULL;
435 jpgBufferSize = 0;
436 }
437 if (loadDocCopyBuffer != nullptr) {
438 delete [] loadDocCopyBuffer;
439 loadDocCopyBuffer = nullptr;
440 }
441 if (loadDocTempBuffer != nullptr) {
442 delete [] loadDocTempBuffer;
443 loadDocTempBuffer = nullptr;
444 }
445 }
446
GetScreenInfo()447 ScreenInfo VirtualScreenImpl::GetScreenInfo()
448 {
449 ScreenInfo info;
450 info.orignalResolutionWidth = GetOrignalWidth();
451 info.orignalResolutionHeight = GetOrignalHeight();
452 info.compressionResolutionWidth = GetCompressionWidth();
453 info.compressionResolutionHeight = GetCompressionHeight();
454 info.foldStatus = GetFoldStatus();
455 info.foldable = GetFoldable();
456 info.foldWidth = GetFoldWidth();
457 info.foldHeight = GetFoldHeight();
458 return info;
459 }
460
InitFoldParams()461 void VirtualScreenImpl::InitFoldParams()
462 {
463 CommandParser& parser = CommandParser::GetInstance();
464 FoldInfo info;
465 parser.GetFoldInfo(info);
466 if (parser.IsSet("foldable")) {
467 SetFoldable(info.foldable);
468 }
469 if (parser.IsSet("foldStatus")) {
470 SetFoldStatus(info.foldStatus);
471 }
472 if (parser.IsSet("fr")) {
473 SetFoldResolution(info.foldResolutionWidth, info.foldResolutionHeight);
474 }
475 }