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 }