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