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