Here's all the code you need to support TCP for OSC

Send us your feedback or ask for features.
dhjdhj
Newbie
Posts:11
Joined:18 Jul 2012 13:26
Here's all the code you need to support TCP for OSC

Post by dhjdhj » 02 Nov 2012 01:23

Dear "Whoever is in charge of Lemur"

Sending text messages to Lemur over UDP is unreliable therefore there really needs to be TCP support for OSC available.


It turns out that to support OSC over TCP, you don't need to do much work as all you need to do is echo received TCP packets to your UDP port on localhost.

All you really need is 4 methods that will
a) Initialize a socket for listening
b) Listen for incoming connections and spawn off a connection
c) Wait for data to arrive (it's all asynchronous so you won't get blocked)
d) FORWARD the received NSData to the listening UDP port on LOCALHOST

That's it! This can be nicely isolated from the rest of the LEMUR system and you shouldn't have to change any of your existing code.


The GCDAsyncSocket library (freely available for iOS) can trivially handle this.

Example (Taken from an example that comes with GCDAsyncSocket - I've removed the obvious error checking to make this code clear)

@interface TCPstuff : GCDAsyncSocketDelegate, GCDAsyncUdpSocketDelegate> // add any ViewController stuff as well
{
dispatch_queue_t socketQueue;
GCDAsyncSocket *listenSocket;
NSMutableArray *connectedSockets;
}

-(void) initTCP
{
socketQueue = dispatch_queue_create("socketQueue", NULL);
listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:socketQueue];
// Setup an array to store all accepted client connections
connectedSockets = [[NSMutableArray alloc] initWithCapacity:1];
}

-(void) startListening
{
[listenSocket acceptOnPort:tcpPort error:&error];
}

// Delegates --- this one accepts a new connection
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
// This method is executed on the socketQueue (not the main thread)

@synchronized(connectedSockets)
{
[connectedSockets addObject:newSocket];
}

// Now wait for a CRLF terminated line to come in --- this is non-blocking
[newSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
}


// A line has been received, forward it via udp to localhost
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
// If you're using the GCDAsyncSocket library then the following line will work, otherwise
// just take the NSData stuff and send it out with your existing udp stuff

[udpSocket sendData:data toHost:@"127.0.0.1" port:udpPort withTimeout:-1 tag:0];

// And now start waiting again
[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
}



Yes, I realize I have simplified it a little, you'll need to check for errors and add some UI to allow the desired TCP port to be defined but that's pretty much all there is to it.

How about it?

Post Reply