add libvncserver
[presencevnc] / libvnc / test / encodingstest.c
1 #ifdef __STRICT_ANSI__
2 #define _BSD_SOURCE
3 #endif
4 #include <time.h>
5 #include <stdarg.h>
6 #include <rfb/rfb.h>
7 #include <rfb/rfbclient.h>
8
9 #ifndef LIBVNCSERVER_HAVE_LIBPTHREAD
10 #error This test need pthread support (otherwise the client blocks the client)
11 #endif
12
13 #define ALL_AT_ONCE
14 /*#define VERY_VERBOSE*/
15
16 static MUTEX(frameBufferMutex);
17
18 typedef struct { int id; char* str; } encoding_t;
19 static encoding_t testEncodings[]={
20         { rfbEncodingRaw, "raw" },
21         { rfbEncodingRRE, "rre" },
22         /* TODO: fix corre */
23         /* { rfbEncodingCoRRE, "corre" }, */
24         { rfbEncodingHextile, "hextile" },
25 #ifdef LIBVNCSERVER_HAVE_LIBZ
26         { rfbEncodingZlib, "zlib" },
27         { rfbEncodingZlibHex, "zlibhex" },
28         { rfbEncodingZRLE, "zrle" },
29 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
30         { rfbEncodingTight, "tight" },
31 #endif
32 #endif
33         { 0, NULL }
34 };
35
36 #define NUMBER_OF_ENCODINGS_TO_TEST (sizeof(testEncodings)/sizeof(encoding_t)-1)
37 /*#define NUMBER_OF_ENCODINGS_TO_TEST 1*/
38
39 /* Here come the variables/functions to handle the test output */
40
41 static const int width=400,height=300;
42 static struct { int x1,y1,x2,y2; } lastUpdateRect;
43 static unsigned int statistics[2][NUMBER_OF_ENCODINGS_TO_TEST];
44 static unsigned int totalFailed,totalCount;
45 static unsigned int countGotUpdate;
46 static MUTEX(statisticsMutex);
47
48 static void initStatistics(void) {
49         memset(statistics[0],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST);
50         memset(statistics[1],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST);
51         totalFailed=totalCount=0;
52         lastUpdateRect.x1=0;
53         lastUpdateRect.y1=0;
54         lastUpdateRect.x2=width;
55         lastUpdateRect.y2=height;
56         INIT_MUTEX(statisticsMutex);
57 }
58
59 static void updateServerStatistics(int x1,int y1,int x2,int y2) {
60         LOCK(statisticsMutex);
61         countGotUpdate=0;
62         lastUpdateRect.x1=x1;
63         lastUpdateRect.y1=y1;
64         lastUpdateRect.x2=x2;
65         lastUpdateRect.y2=y2;
66         UNLOCK(statisticsMutex);
67 }
68
69 static void updateStatistics(int encodingIndex,rfbBool failed) {
70         LOCK(statisticsMutex);
71         if(failed) {
72                 statistics[1][encodingIndex]++;
73                 totalFailed++;
74         }
75         statistics[0][encodingIndex]++;
76         totalCount++;
77         countGotUpdate++;
78         UNLOCK(statisticsMutex);
79 }
80
81         
82
83 /* Here begin the functions for the client. They will be called in a
84  * pthread. */
85
86 /* maxDelta=0 means they are expected to match exactly;
87  * maxDelta>0 means that the average difference must be lower than maxDelta */
88 static rfbBool doFramebuffersMatch(rfbScreenInfo* server,rfbClient* client,
89                 int maxDelta)
90 {
91         int i,j,k;
92         unsigned int total=0,diff=0;
93         if(server->width!=client->width || server->height!=client->height)
94                 return FALSE;
95         LOCK(frameBufferMutex);
96         /* TODO: write unit test for colour transformation, use here, too */
97         for(i=0;i<server->width;i++)
98                 for(j=0;j<server->height;j++)
99                         for(k=0;k<3/*server->serverFormat.bitsPerPixel/8*/;k++) {
100                                 unsigned char s=server->frameBuffer[k+i*4+j*server->paddedWidthInBytes];
101                                 unsigned char cl=client->frameBuffer[k+i*4+j*client->width*4];
102                                 
103                                 if(maxDelta==0 && s!=cl) {
104                                         UNLOCK(frameBufferMutex);
105                                         return FALSE;
106                                 } else {
107                                         total++;
108                                         diff+=(s>cl?s-cl:cl-s);
109                                 }
110                         }
111         UNLOCK(frameBufferMutex);
112         if(maxDelta>0 && diff/total>=maxDelta)
113                 return FALSE;
114         return TRUE;
115 }
116
117 static rfbBool resize(rfbClient* cl) {
118         if(cl->frameBuffer)
119                 free(cl->frameBuffer);
120         cl->frameBuffer=(char*)malloc(cl->width*cl->height*cl->format.bitsPerPixel/8);
121         if(!cl->frameBuffer)
122                 return FALSE;
123         SendFramebufferUpdateRequest(cl,0,0,cl->width,cl->height,FALSE);
124         return TRUE;
125 }
126
127 typedef struct clientData {
128         int encodingIndex;
129         rfbScreenInfo* server;
130         char* display;
131 } clientData;
132
133 static void update(rfbClient* client,int x,int y,int w,int h) {
134         clientData* cd=(clientData*)client->clientData;
135         int maxDelta=0;
136         
137 #ifndef VERY_VERBOSE
138         static const char* progress="|/-\\";
139         static int counter=0;
140
141         if(++counter>sizeof(progress)) counter=0;
142         fprintf(stderr,"%c\r",progress[counter]);
143 #else
144         rfbClientLog("Got update (encoding=%s): (%d,%d)-(%d,%d)\n",
145                         testEncodings[cd->encodingIndex].str,
146                         x,y,x+w,y+h);
147 #endif
148
149         /* only check if this was the last update */
150         if(x+w!=lastUpdateRect.x2 || y+h!=lastUpdateRect.y2) {
151 #ifdef VERY_VERBOSE
152                 rfbClientLog("Waiting (%d!=%d or %d!=%d)\n",
153                                 x+w,lastUpdateRect.x2,y+h,lastUpdateRect.y2);
154 #endif
155                 return;
156         }
157
158 #ifdef LIBVNCSERVER_HAVE_LIBZ
159         if(testEncodings[cd->encodingIndex].id==rfbEncodingTight)
160                 maxDelta=5;
161 #endif
162         
163         updateStatistics(cd->encodingIndex,
164                         !doFramebuffersMatch(cd->server,client,maxDelta));
165 }
166
167 static void* clientLoop(void* data) {
168         rfbClient* client=(rfbClient*)data;
169         clientData* cd=(clientData*)client->clientData;
170
171         client->appData.encodingsString=strdup(testEncodings[cd->encodingIndex].str);
172         
173         sleep(1);
174         rfbClientLog("Starting client (encoding %s, display %s)\n",
175                         testEncodings[cd->encodingIndex].str,
176                         cd->display);
177         if(!rfbInitClient(client,NULL,NULL)) {
178                 rfbClientErr("Had problems starting client (encoding %s)\n",
179                                 testEncodings[cd->encodingIndex].str);
180                 updateStatistics(cd->encodingIndex,TRUE);
181                 return NULL;
182         }
183         while(1) {
184                 if(WaitForMessage(client,50)>=0)
185                         if(!HandleRFBServerMessage(client))
186                                 break;
187         }
188         free(((clientData*)client->clientData)->display);
189         free(client->clientData);
190         if(client->frameBuffer)
191                 free(client->frameBuffer);
192         rfbClientCleanup(client);
193         return NULL;
194 }
195
196 static void startClient(int encodingIndex,rfbScreenInfo* server) {
197         rfbClient* client=rfbGetClient(8,3,4);
198         clientData* cd;
199         pthread_t clientThread;
200         
201         client->clientData=malloc(sizeof(clientData));
202         client->MallocFrameBuffer=resize;
203         client->GotFrameBufferUpdate=update;
204
205         cd=(clientData*)client->clientData;
206         cd->encodingIndex=encodingIndex;
207         cd->server=server;
208         cd->display=(char*)malloc(6);
209         sprintf(cd->display,":%d",server->port-5900);
210
211         lastUpdateRect.x1=lastUpdateRect.y1=0;
212         lastUpdateRect.x2=server->width;
213         lastUpdateRect.y2=server->height;
214
215         pthread_create(&clientThread,NULL,clientLoop,(void*)client);
216 }
217
218 /* Here begin the server functions */
219
220 static void idle(rfbScreenInfo* server)
221 {
222         int c;
223         rfbBool goForward;
224
225         LOCK(statisticsMutex);
226 #ifdef ALL_AT_ONCE
227         goForward=(countGotUpdate==NUMBER_OF_ENCODINGS_TO_TEST);
228 #else
229         goForward=(countGotUpdate==1);
230 #endif
231         /* if(lastUpdateRect.x2==354)
232                 rfbLog("server checked: countGotUpdate=%d\n",countGotUpdate); */
233         UNLOCK(statisticsMutex);
234         if(!goForward)
235                 return;
236         countGotUpdate=0;
237
238         LOCK(frameBufferMutex);
239         {
240                 int i,j;
241                 int x1=(rand()%(server->width-1)),x2=(rand()%(server->width-1)),
242                 y1=(rand()%(server->height-1)),y2=(rand()%(server->height-1));
243                 if(x1>x2) { i=x1; x1=x2; x2=i; }
244                 if(y1>y2) { i=y1; y1=y2; y2=i; }
245                 x2++; y2++;
246                 for(c=0;c<3;c++) {
247                         for(i=x1;i<x2;i++)
248                                 for(j=y1;j<y2;j++)
249                                         server->frameBuffer[i*4+c+j*server->paddedWidthInBytes]=255*(i-x1+j-y1)/(x2-x1+y2-y1);
250                 }
251                 rfbMarkRectAsModified(server,x1,y1,x2,y2);
252
253                 lastUpdateRect.x1=x1;
254                 lastUpdateRect.y1=y1;
255                 lastUpdateRect.x2=x2;
256                 lastUpdateRect.y2=y2;
257 #ifdef VERY_VERBOSE
258                 rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);
259 #endif
260         }
261         UNLOCK(frameBufferMutex);
262 }
263
264 /* log function (to show what messages are from the client) */
265
266 static void
267 rfbTestLog(const char *format, ...)
268 {
269         va_list args;
270         char buf[256];
271         time_t log_clock;
272
273         if(!rfbEnableClientLogging)
274                 return;
275
276         va_start(args, format);
277
278         time(&log_clock);
279         strftime(buf, 255, "%d/%m/%Y %X (client) ", localtime(&log_clock));
280         fprintf(stderr,buf);
281
282         vfprintf(stderr, format, args);
283         fflush(stderr);
284
285         va_end(args);
286 }
287
288 /* the main function */
289
290 int main(int argc,char** argv)
291 {                                                                
292         int i,j;
293         time_t t;
294         rfbScreenInfoPtr server;
295
296         rfbClientLog=rfbTestLog;
297         rfbClientErr=rfbTestLog;
298
299         /* Initialize server */
300         server=rfbGetScreen(&argc,argv,width,height,8,3,4);
301
302         server->frameBuffer=malloc(400*300*4);
303         server->cursor=NULL;
304         for(j=0;j<400*300*4;j++)
305                 server->frameBuffer[j]=j;
306         rfbInitServer(server);
307         rfbProcessEvents(server,0);
308
309         initStatistics();
310
311 #ifndef ALL_AT_ONCE
312         for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) {
313 #else
314         /* Initialize clients */
315         for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
316 #endif
317                 startClient(i,server);
318
319         t=time(NULL);
320         /* test 20 seconds */
321         while(time(NULL)-t<20) {
322
323                 idle(server);
324
325                 rfbProcessEvents(server,1);
326         }
327         rfbLog("%d failed, %d received\n",totalFailed,totalCount);
328 #ifndef ALL_AT_ONCE
329         {
330                 rfbClientPtr cl;
331                 rfbClientIteratorPtr iter=rfbGetClientIterator(server);
332                 while((cl=rfbClientIteratorNext(iter)))
333                         rfbCloseClient(cl);
334                 rfbReleaseClientIterator(iter);
335         }
336         }
337 #endif
338
339         free(server->frameBuffer);
340         rfbScreenCleanup(server);
341
342         rfbLog("Statistics:\n");
343         for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
344                 rfbLog("%s encoding: %d failed, %d received\n",
345                                 testEncodings[i].str,statistics[1][i],statistics[0][i]);
346         if(totalFailed)
347                 return 1;
348         return(0);
349 }
350
351