RSS

(root)/iphone/tappity : /tappity/source/TappityServer.m (revision 49)

To get this branch, use:
bzr branch /browse/iphone/tappity
Line Revision Contents
1 46
//
2
//  TappityServer.m
3
//  Jigs
4
//
5
//  Created by döme on 25.10.2009.
6
//  Copyright 2009 __MyCompanyName__. All rights reserved.
7
//
8
9
#import "TappityServer.h"
10
#import "Tappity.h"
11 47
#import <QuartzCore/QuartzCore.h>
12 48
#import <OpenGLES/ES1/gl.h>
13 49
#import <CoreLocation/CoreLocation.h>
14 46
15
16
static void _setStandardSocketOpts(int socket)
17
{
18
    int yes = 1;
19
    setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
20
	int timeout = 2000;
21
	setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
22
	setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
23
}
24
25
26
@implementation TappityServer
27
28 48
- (id) init
29
{
30
	if (!(self = [super init]))
31
		return nil;
32
33
	desiredFrameInterval = 0.333;
34
	
35
	receiveDataOnMainThread = YES;
36
	
37
	return self;
38
}
39 46
40
- (void) acceptThread: (id) info
41
{
42
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
43
44
	@synchronized(self)
45
	{
46
		[self retain];
47
	}
48
49
	while ([self threadActive: info])
50
	{
51
52
		struct timeval tv;
53
		fd_set readfds;
54
		fd_set writefds;
55
		fd_set errorfds;
56
		int maxSocket = -1;
57
58
		tv.tv_sec = 1;
59
		tv.tv_usec = 0;
60
61
		FD_ZERO(&readfds);
62
		FD_ZERO(&writefds);
63
		FD_ZERO(&errorfds);
64
65
		FD_SET(listenSocket, &readfds);
66
		FD_SET(listenSocket, &errorfds);
67
		maxSocket = MAX(maxSocket, listenSocket);
68
		
69
		if (maxSocket < 0)
70
		{
71
			printf("No sockets, sleeping for a bit...\n");
72
			usleep(1000000);
73
			continue;
74
		}
75
		
76
		//NSLog(@"listening for connection...");
77
78
		if (select(maxSocket+1, &readfds, &writefds, &errorfds, &tv) < 0)
79
		{
80
			perror("select");
81
			break;
82
		}
83
84
		if (FD_ISSET(listenSocket, &readfds))
85
		{
86
			NSLog(@"Accepting connection...");
87
			// accept
88
			socklen_t	sinSize = sizeof(struct sockaddr_in);
89
			struct sockaddr_in	peerAddress;
90
			int newSocket = accept(listenSocket, (struct sockaddr *)&peerAddress, &sinSize);
91
			
92
			_setStandardSocketOpts(newSocket);
93
94
			
95
			if (newSocket == -1)
96
			{
97
				if (errno == EWOULDBLOCK)
98
				{
99
				}
100
				else
101
				{
102
					printf("Error accepting connection.\n");
103
					break;
104
				}
105
			}
106
			
107
			if (commsSocket)
108
				close(commsSocket);
109
110
			// add socket to sockets list
111
			commsSocket = newSocket;
112
			
113
			
114 48
			[netService stop];
115
			[netService release];
116
			netService = nil;
117
118 47
			if (!sendLock)
119
				sendLock = [[NSCondition alloc] init];
120
			
121
			[self runThreadWithSelector: @selector(sendingThread:)];
122
123 46
			[self runThreadWithSelector: @selector(receivingThread:)];
124
			
125 47
			[self performSelectorOnMainThread: @selector(startScreenieTimer) withObject: nil waitUntilDone: NO];
126
127
			//[self runThreadWithSelector: @selector(screenieThread:)];
128
			
129 48
			
130 46
			NSLog(@"Accepted connection.");
131
		}
132
133
	}
134
135
	@synchronized(self)
136
	{
137
		[self release];
138
	}
139
140
	[info release];
141
	[pool drain];
142
}
143
144 47
- (void) startScreenieTimer
145
{
146 49
	[captureTimer invalidate];
147 48
	captureTimer = [NSTimer scheduledTimerWithTimeInterval: desiredFrameInterval target: self selector: @selector(captureScreen) userInfo: nil repeats: YES];
148 47
	
149
	
150
	if (!capturedImagesCondition)
151
		capturedImagesCondition = [[NSCondition alloc] init];
152
153
	[self runThreadWithSelector: @selector(imageConversionThread:)];
154
}
155
156 46
- (BOOL) enableBonjourWithDomain:(NSString*)domain applicationProtocol:(NSString*)protocol name:(NSString*)name
157
{
158
	if(![domain length])
159
		domain = @""; //Will use default Bonjour registration doamins, typically just ".local"
160
	if(![name length])
161
		name = @""; //Will use default Bonjour name, e.g. the name assigned to the device in iTunes
162
	
163
	assert([protocol length] && listenSocket);
164
	
165
	NSLog(@"tappity port: %d", ntohs(myAddress.sin_port));
166
167
	netService = [[NSNetService alloc] initWithDomain: domain type: protocol name: name port: ntohs(myAddress.sin_port)];
168
	if(netService == nil)
169
		return NO;
170
	
171
	[netService setDelegate:self];
172
//	[netService scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
173
	[netService publish];
174
	
175
	return YES;
176
}
177
178 49
- (void) startListening
179 46
{
180
	myAddress.sin_family = AF_INET;					// host byte order
181
	myAddress.sin_port = htons(1234);				// short, network byte order, any port
182
	myAddress.sin_addr.s_addr = htonl(INADDR_ANY);	// auto-fill with my IP
183
184
	listenSocket = socket(PF_INET, SOCK_STREAM, 0);
185
	assert(listenSocket != -1);
186
187
	_setStandardSocketOpts(listenSocket);
188
189
	int err = bind(self->listenSocket, (struct sockaddr *)&myAddress, sizeof(myAddress));
190
	assert(-1 != err);
191
	
192
	err = listen(self->listenSocket, 1);
193
	assert(-1 != err);
194
195
	[self runThreadWithSelector: @selector(acceptThread:)];
196
	
197 48
	if([self enableBonjourWithDomain: @"" applicationProtocol: @"_tappity._tcp" name: serviceName])
198 46
		NSLog(@"tappity bounjour advertisments up and running");
199
200
}
201
202 49
- (void) startWithName: (NSString*) name
203
{
204
	NSLog(@"starting tappity server");
205
	
206
	[serviceName release];
207
	serviceName = [name retain];
208
	
209
	[self startListening];
210
211
}
212
213
/*
214 46
static size_t _read_i8(const void* buf, uint8_t* p)
215
{
216
	uint8_t v = 0;
217
	memcpy(&v, buf, 1);
218
	*p = v;
219
	return 1;
220
}
221
static size_t _read_i16(const void* buf, uint16_t* p)
222
{
223
	uint16_t v = 0;
224
	memcpy(&v, buf, 2);
225
	*p = CFSwapInt16BigToHost(v);
226
	return 2;
227
}
228
static size_t _read_i32(const void* buf, uint32_t* p)
229
{
230
	uint32_t v = 0;
231
	memcpy(&v, buf, 4);
232
	*p = CFSwapInt32BigToHost(v);
233
	return 4;
234
}
235
static size_t _read_i64(const void* buf, uint64_t* p)
236
{
237
	uint64_t v = 0;
238
	memcpy(&v, buf, 8);
239
	*p = CFSwapInt64BigToHost(v);
240
	return 8;
241
}
242
static size_t _read_float(const void* buf, float* p)
243
{
244
	CFSwappedFloat32 v;
245
	memcpy(&v, buf, 4);
246
	*p = CFConvertFloat32SwappedToHost(v);
247
	return 4;
248
}
249
250
static size_t _read_gspoint(const void* buf, GSTouchPointRef p)
251
{
252
	size_t bc = 0;
253
254
	bc += _read_i32(buf+bc, &p->unk0);
255
	bc += _read_float(buf+bc, &p->unk1);
256
	bc += _read_float(buf+bc, &p->touchSize);
257
	bc += _read_float(buf+bc, &p->x);
258
	bc += _read_float(buf+bc, &p->y);
259
	bc += _read_i32(buf+bc, (uint32_t*)&p->window);
260
	
261
	return bc;
262
}
263
264
- (GSEvent*) gsEventWithData: (NSData*) data
265
{
266
	GSEvent* gse = [[[GSEvent alloc] init] autorelease];
267
	
268
	size_t bc = 0;
269
	const void* buf = [data bytes];
270
	
271
	bc += _read_i32(buf+bc, &gse->type0);
272
	bc += _read_i32(buf+bc, &gse->type1);
273
	bc += _read_i32(buf+bc, &gse->r3);
274
	bc += _read_float(buf+bc, &gse->avgX0);
275
	bc += _read_float(buf+bc, &gse->avgY0);
276
	bc += _read_float(buf+bc, &gse->avgX1);
277
	bc += _read_float(buf+bc, &gse->avgY1);
278
	bc += _read_i32(buf+bc, &gse->processId);
279
	bc += _read_i64(buf+bc, &gse->timestamp);
280
	bc += _read_i32(buf+bc, (uint32_t*)&gse->window);
281
	bc += _read_i32(buf+bc, &gse->r11);
282
	bc += _read_i32(buf+bc, &gse->type12);
283
	bc += _read_i32(buf+bc, &gse->gesture13);
284
	bc += _read_i32(buf+bc, &gse->gesture14);
285
	bc += _read_i16(buf+bc, &gse->numInitialTouches);
286
	bc += _read_i16(buf+bc, &gse->numCurrentTouches);
287
	bc += _read_i32(buf+bc, &gse->r16);
288
	bc += _read_i32(buf+bc, &gse->r17);
289
	bc += _read_i32(buf+bc, &gse->r18);
290
	bc += _read_i32(buf+bc, &gse->r19);
291
	bc += _read_i32(buf+bc, &gse->r20);
292
	bc += _read_i32(buf+bc, &gse->r21);
293
	bc += _read_i8(buf+bc, &gse->r22_0);
294
	bc += _read_i8(buf+bc, &gse->numPoints);
295
	bc += _read_i16(buf+bc, &gse->r22_2);
296
	for (size_t i = 0; i < gse->numPoints; ++i)
297
		bc += _read_gspoint(buf+bc, gse->points + i);
298
299
	return gse;
300
}
301 49
*/
302
303
- (void) doEventPlayback
304
{
305
	[[UIApplication sharedApplication] _playbackEvents: queuedEvents atPlaybackRate: 1.0f messageWhenDone: self withSelector: @selector(eventPlaybackDone:)];
306
	
307
	[queuedEvents autorelease];
308
	queuedEvents = nil;
309
	eventPlaybackBusy = YES;
310
}
311
- (void) eventPlaybackDone:(NSDictionary*)detail
312
{
313
	if ([queuedEvents count])
314
	{
315
		[self doEventPlayback];
316
	}
317
	else
318
		eventPlaybackBusy = NO;
319
}
320 46
321 47
- (void) dataReceived: (NSData*) tapData
322 46
{
323
	assert([tapData length] > 4);
324
	
325
	
326
	NSDictionary* tapDict = [NSPropertyListSerialization propertyListFromData: tapData mutabilityOption:NSPropertyListImmutable format: NULL errorDescription: NULL];
327
	assert(tapDict);
328
	switch([[tapDict objectForKey: TapIdKey] intValue])
329
	{
330 49
/*
331 46
		case kTapTouchEvent:
332
		{
333
			NSLog(@"TOUCH EVENT");
334
			
335
			GSEvent* gse = [self gsEventWithData: [tapDict objectForKey: TapGSEventKey]];
336
			UIWindow* window = [[UIApplication sharedApplication] keyWindow];
337
			gse->window = window;
338
			for (size_t i = 0; i < gse->numPoints; ++i)
339
				gse->points[i].window = window;
340
			
341
			int phase = [[tapDict objectForKey: TapTouchPhaseKey] intValue];
342
			NSSet* touches = [UITouch _createTouchesWithGSEvent: gse phase: phase view: [[UIApplication sharedApplication] keyWindow]];
343
			
344
			assert([[UIApplication sharedApplication] keyWindow]);
345
			
346
			NSLog(@"%@", touches);
347
348
			UIEvent* event = [UIEvent alloc];
349
			
350
			Class touchesEventClass = objc_getClass("UITouchesEvent");
351
			if (touchesEventClass && ![[event class] isEqual: touchesEventClass])
352
			{
353
				event = [touchesEventClass alloc];
354
			}
355
			
356
			[event _initWithEvent: gse touches: touches];
357
			
358
			assert(event);
359
			
360
			[[UIApplication sharedApplication] sendEvent: event];
361
						
362
			
363
			break;
364
		}
365 49
*/
366 46
		case kTapRecordedEvent:
367 49
		{			
368 46
			NSDictionary* eventDict = [tapDict objectForKey: TapRecordedEventKey];
369
			
370 49
			if (!queuedEvents)
371
				queuedEvents = [[NSMutableArray alloc] init];
372 46
373 49
			[queuedEvents addObject: eventDict];
374
			
375
			if (!eventPlaybackBusy)
376
			{
377
				[self doEventPlayback];
378
			}
379 46
			break;
380
		}
381 48
		case kTapAcceleration:
382 49
		{			
383 48
			NSArray* accel = [tapDict objectForKey: TapAccelerationKey];
384
			
385
			UIAccelerometer* accm = [UIAccelerometer sharedAccelerometer];
386
			float x = [[accel objectAtIndex: 0] floatValue];
387
			float y = [[accel objectAtIndex: 1] floatValue];
388
			float z = [[accel objectAtIndex: 2] floatValue];
389
			[accm _acceleratedInX: x y: y z: z timestamp: [[accel objectAtIndex: 3] doubleValue]];
390
			
391
			break;
392
		}
393 49
		case kTapLocation:
394
		{
395
			static CLLocation* oldLoc = nil;
396
			CLLocation* loc = [NSKeyedUnarchiver unarchiveObjectWithData: [tapDict objectForKey: TapLocationKey]];
397
			if ([locationDelegate respondsToSelector: @selector(locationManager:didUpdateToLocation:fromLocation:)])
398
			{
399
				[locationDelegate locationManager: (id)self didUpdateToLocation: loc fromLocation: oldLoc];
400
			}
401
			oldLoc = loc;
402
			break;
403
		}
404
		case kTapCompass:
405
		{
406
			CLHeading* hdg = [NSKeyedUnarchiver unarchiveObjectWithData: [tapDict objectForKey: TapCompassKey]];
407
			if ([headingDelegate respondsToSelector: @selector(locationManager:didUpdateHeading:)])
408
			{
409
				[headingDelegate locationManager: (id)self didUpdateHeading: hdg];
410
			}
411
			break;
412
		}
413 46
	}
414
	
415 47
	[tapData release];
416
	
417
}
418
419
- (UIImage *) imageFromView: (UIView *) theView
420
{
421
	UIGraphicsBeginImageContext(theView.frame.size);
422
	CGContextRef context = UIGraphicsGetCurrentContext();
423
//	[theView.layer drawInContext:context];
424
	[theView.layer renderInContext:context];
425
	UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
426
	UIGraphicsEndImageContext();
427
	return theImage;
428
}
429
430
- (void) convertAndSendImage: (UIImage*) img
431
{		
432
	[capturedImagesCondition lock];
433
434
	if (!capturedImagesQueue)
435
		capturedImagesQueue = [[NSMutableArray alloc] init];
436
437
	[capturedImagesQueue addObject: img];
438
	
439
	[capturedImagesCondition signal];
440
	[capturedImagesCondition unlock];
441
		
442
}
443
444
- (void) captureScreen
445
{
446 48
	NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
447
	
448
	if (now < lastGlUpdate + 2.0*desiredFrameInterval)
449
		return;
450
		
451
	// return if any gl has been updated at all
452
	if (lastGlUpdate)
453
		return;
454
	
455 47
	[self performSelectorOnMainThread: @selector(getWindowToCapture) withObject: nil waitUntilDone: NO];
456
457
	UIWindow* window = windowToCapture;
458
	
459
	UIImage* img = [self imageFromView: window];
460
	
461 48
	lastQuartzUpdate = now;
462
	
463 47
	if (img)
464
		[self convertAndSendImage: img];
465
}
466
467
- (void) imageConversionThread: (id) info
468
{
469
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
470
471
	@synchronized(self)
472
	{
473
		[self retain];
474
	}
475
476
	while ([self threadActive: info])
477
	{
478
		NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
479
480
		[capturedImagesCondition lock];
481
			while (![capturedImagesQueue count])
482
				[capturedImagesCondition wait];
483
				
484
		//NSLog(@"sending");
485
		
486
		UIImage* img = [[[capturedImagesQueue objectAtIndex: 0] retain] autorelease];
487
		[capturedImagesQueue removeObjectAtIndex: 0];
488
		
489
		[capturedImagesCondition unlock];
490
491
		NSData* imgData = UIImagePNGRepresentation(img);
492
	
493
		if (imgData)
494
			[self sendData: imgData];
495
496
		
497
		[pool drain];
498
499
	}
500
	
501
502
	[self threadWillExit: info];
503
504
	@synchronized(self)
505
	{
506
		[self release];
507
	}
508
509
	[info release];
510
	[pool drain];
511
}
512
513
514
515
516
- (void) getWindowToCapture
517
{
518
	@synchronized(self)
519
	{
520
		[windowToCapture release];
521
		windowToCapture = [[[UIApplication sharedApplication] keyWindow] retain];
522
	}
523
}
524
- (void) screenieThread: (id) info
525
{
526
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
527
528
	@synchronized(self)
529
	{
530
		[self retain];
531
	}
532
533
534
	while ([self threadActive: info])
535
	{
536
		[self captureScreen];
537
		usleep(200);
538
	}
539
540 48
	[self threadWillExit: info];
541
542 47
	@synchronized(self)
543
	{
544
		[self release];
545
	}
546
547
	[info release];
548
	[pool drain];
549
}
550
551 46
552
553
/*
554
- (void)performTouches: (NSSet*) touches inView: (UIView *)view
555
{
556
    UITouch *touch = [[UITouch alloc] initInView:view];
557
    UIEvent *eventDown = [[UIEvent alloc] initWithTouch:touch];
558
    
559
    [touch.view touchesBegan:[eventDown allTouches] withEvent:eventDown];
560
    
561
    [touch setPhase:UITouchPhaseEnded];
562
    UIEvent *eventUp = [[UIEvent alloc] initWithTouch:touch];
563
    
564
    [touch.view touchesEnded:[eventUp allTouches] withEvent:eventUp];
565
    
566
    [eventDown release];
567
    [eventUp release];
568
    [touch release];
569
}
570
*/
571
572 48
static UIImage* imageFromGLData(NSData* data)
573
{
574
    // make data provider with data.
575
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, [data bytes], [data length], NULL);
576
   
577
    // prep the ingredients
578
    int bitsPerComponent = 8;
579
    int bitsPerPixel = 32;
580
    int bytesPerRow = 4 * 320;
581
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
582
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
583
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
584
   
585
    // make the cgimage
586
    CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
587
   
588
    // then make the uiimage from that
589
    UIImage *myImage = [UIImage imageWithCGImage:imageRef];
590
    return myImage;
591
}
592
593
static NSData* dataFromGL(void)
594
{
595
    NSInteger myDataLength = 320 * 480 * 4;
596
	
597
	NSMutableData* data = [NSMutableData dataWithLength: myDataLength];
598
   
599
    // allocate array and read pixels into it.
600
    void* buffer = [data mutableBytes];
601
    glReadPixels(0, 0, 320, 480, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
602
	
603
	size_t bpr = 4*320;
604
	void* rowbuf = calloc(1, bpr);
605
	
606
	// swap image in Y
607
	for (size_t i = 0; i < 480/2; ++i)
608
	{
609
		memcpy(rowbuf, buffer + i*bpr, bpr);
610
		memcpy(buffer + i*bpr, buffer + (480-i-1)*bpr, bpr);
611
		memcpy(buffer + (480-i-1)*bpr, rowbuf, bpr);
612
	}
613
	
614
	free(rowbuf);
615
 
616
	return data;
617
}
618
619
- (void) glGrabPoint
620
{
621
	if (!commsSocket)
622
		return;
623
624
	NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
625
	if (lastGlUpdate + desiredFrameInterval < now)
626
	{
627
		NSData* rawData = dataFromGL();
628
		UIImage* image = imageFromGLData(rawData);
629
		
630
		NSData* data = UIImagePNGRepresentation(image);
631
		
632
		[self sendData: data];
633
		
634
		lastGlUpdate = now;
635
	}
636
}
637
638
+ (void) glGrabPoint
639
{
640
	[[self sharedServer] glGrabPoint];
641
}
642
643
+ (id) sharedServer
644
{
645
	static id sharedInstance = nil;
646
	if (!sharedInstance)
647
		sharedInstance = [[TappityServer alloc] init];
648
	
649
	
650
	return sharedInstance;
651
}
652
653 46
- (void) dealloc
654
{
655 48
	[serviceName release];
656
	[captureTimer invalidate];
657
	[capturedImagesCondition release];
658
	[capturedImagesQueue release];
659
660 46
	[netService stop];
661
	[netService release];
662
663
	[activeThreads release];
664
665
	[super dealloc];
666
}
667
668 49
@synthesize locationDelegate, headingDelegate;
669
670 46
@end

Loggerhead 1.17 is a web-based interface for Bazaar branches