eyeball messenger sdk webrtc developer reference guide

180
Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved. Eyeball Messenger Interoperable with WebRTC Developer Reference Guide Last Modified: February 2014 Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Upload: eyeball-networks

Post on 15-Jul-2015

830 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Eyeball Messenger

Interoperable with WebRTC

Developer Reference Guide

Last Modified: February 2014

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Page 2: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Introduction

Thanks for using Messenger! We hope you find Messenger to be both powerful and easy to use. If you have any questions or encounter any difficulties, please get in touch with us.

What is Messenger?

Messenger is a collection of libraries that enable you to create reliable UDP media streams between peers, regardless of the peer's network configuration and environment. Messenger traverses every possible firewall/NAT combination to guarantee connection establishment. It uses IETF/IANA standards to provide the broadest compatiblity with third-party components.

What platforms does Messenger support?

Messenger has libraries for JavaScript, iOS, Java, Mac, Mono, .NET, .NET Compact, Unity, Windows Phone, Windows 8, Xamarin.Android and Xamarin.iOS. If you have a particular platform need, please let us know.

Does Messenger support WebRTC?

Yes! Messenger's network tunneling strategies are identical to the ones recommended by the WebRTC specification. The WebRTC extension bundled with Messenger provides a full audio/video/data-channel stack that is fully interoperable with modern WebRTC implementations.

What about older web browsers?

Messenger comes bundled with a Java applet that includes a complete WebRTC implementation. It is integrated with the JavaScript SDK tightly so that the browser will automatically fall-back to use the applet if native WebRTC functionality is unavailable. This graceful degradation is completely seamless. You never have to touch a single line of Java code.

What are you waiting for? Start building your P2P app!

Page 3: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Signaling

Before a P2P link can be established, peers must exchange some information - a description of the streams and formats that will be used, called the offer/answer, and a set of network "candidates". (The initiating peer creates what is called the offer, and the other peer creates an answer in response. Both peers create candidates.) A well-known protocol called SDP (Session Description Protocol) is used to define both the offer/answer and candidates.

Messenger will generate the offers/answers and candidates, but it needs some external messaging system to send them from one peer to another. We use WebSync in all our examples. Other options include SIP, XMPP, and Google's Channel API.

The process itself is simple. Messenger starts out with a Conference. Whenever Messenger generates an OfferAnswer or Candidate, the Conference fires an event (OnOfferAnswer or OnCandidate). Your responsibility as the developer is to ensure that:

1. Whenever an OfferAnswer or Candidate is raised, the SDP message in the event arguments is sent to the other peer.

2. Whenever an SDP message is received from a peer, either ReceiveOfferAnswer or ReceiveCandidate is called.

P2P links are often encrypted, and for this reason, we highly recommend using a secure channel to send SDP offers/answers and candidates between peers. If you are going to use WebSync, make sure you have a valid SSL certificate installed on your server and you use HTTPS to connect your clients.

Page 4: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Conferences

Conferences are the core of Messenger. Whether you are creating a link to one peer or several, you start by creating a Conference.

Conferences are associated with an Messenger server and a number of stream descriptions. The Messenger server is used when connecting to a new peer to facilitate network discovery (and possibly relay data for highly restrictive firewalls). The stream descriptions are used to create the offer/answer that will be used to describe the types of data/media that will be exchanged.

Conferences make sure that links between peers are created seamlessly with a consistent eventing structure. Each link that is created goes through a simple event cycle:

1. LinkInit is fired when a new link is about to start. The initiating peer triggers this event explicitly by calling Conference.Link, perhaps as the result of dialing a number or double-clicking on a contact. The other peer triggers this event implicitly by calling Conference.ReceiveOfferAnswer when an SDP offer/answer arrives on your signalling connection.

2. LinkUp is fired when a link has been successfully established. If this link fires, it does so after LinkInit has been fired. This event provides a reference to the negotiated stream formats that both peers had in common.

3. LinkDown is fired when either (a) a link could not be established or (b) a link was established, but went down. The WasUp property lets you differentiate between the two.

Each event will fire at most once for each unique link. After a link goes down, it is discarded. A reconnection will result in the creation of a new link.

Page 5: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

WebRTC

Where possible, Messenger providers a WebRTC extension that allows you to create WebRTC-compatible audio/video/data streams between peers, including web browsers.

What is WebRTC? In a nutshell, it's an open project backed by Google, Mozilla, Ericsson, and other industry leaders that is attempting to standardize real-time P2P audio/video/data communications and make them accessible in a web browser without the use of plug-ins.

Messenger's network traversal strategy is identical to the one recommended by WebRTC. Building on this, the WebRTC extension for Messenger provides a complete audio/video/data-channel stack that lets you send/receive P2P data between a web browser and a desktop client, all without plugins. We do all the heavy lifting:

Stream formatting.

RTP packet processing.

RTCP packet processing.

Audio encoding and decoding (G.711u, G.711a).

Video encoding and decoding (VP8, Motion-JPEG).

Audio capturing from device microphone.

Video capturing from device camera.

Audio rendering to device speakers.

Video rendering to screen container.

For audio/video feeds, first get a reference to the device's local media stream by calling UserMedia.GetMedia. If successful, create a WebRTC AudioStream, VideoStream, and/or DataChannelStream and use those stream definitions when creating your Conference. The rest is automatic! We even include a LayoutManager for each platform that helps you position your video feed controls in your interface.

Page 6: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Creating a Conference: iOS and Mac

The iOS/Mac SDK provides a complete peer-to-peer (P2P) streaming solution, including a

complete WebRTC stack for rapidly creating audio, video, and data-channel streams that can be

consumed natively in modern web browsers.

To get started, you'll need to add some static libraries and headers from the SDK to your project (Xcode):

libEyeball.a + Eyeball.h (supporting code) libEyeballMessenger.a + EyeballMessenger.h (Messenger core) libEyeballMessengerWebRTC.a + EyeballMessengerWebRTC.h (WebRTC stack, optional)

Also add a few Apple framework dependencies:

libz.dylib

Security.framework CFNetwork.framework (iOS only)

For WebRTC only, some additional dependencies are required:

AudioToolbox.framework

AudioUnit.framework (Mac only) AVFoundation.framework

CoreAudio.framework

CoreGraphics.framework CoreMedia.framework

CoreVideo.framework GLKit.framework (iOS only) OpenGLES.framework (iOS only)

Finally, add "-all_load" to "Other Linker Flags" under the target's build settings.

Now let's write some code! (See iOS/Mac.Client, iOS/Mac.Client.WebRTC, and

iOS/Mac.Client.DataChannels in the SDK Examples folder.)

Part 1: Stream Descriptions

The first step is to describe the streams we want to use. Stream descriptions are used to define the types

of media we are going to be sending back and forth between peers in a conference. Messenger allows us

to createcustom streams with any number of possible data formats. The WebRTC extension allows us to

Page 7: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

create audio, video, and data-channel streams. You can mix and match custom and WebRTC streams,

but only WebRTC streams can be consumed natively by web browsers.

Part 1a: Custom Stream Descriptions

Custom stream descriptions require a "stream type" and one or more "stream formats". The stream type

is used in the SDP offer/answer to help differentiate between multiple streams (audio, video,

application/binary, etc.). The stream format is used in the SDP offer/answer to help differentiate between

multiple data formats supported for a given stream (i.e. G.711, G.722, Opus, etc. for audio).

// Create a custom stream description that indicates text

// data will be sent using a format labelled "utf8".

EyeballMessengerStream *customStream = [EyeballMessengerStream streamWithType:EyeballMessengerStreamTypeText format:[EyeballMessengerStreamFormat streamFormatWithEncodingName:@"utf8"]];

[customStream addOnLinkReceiveRTPWithValueBlock:^(EyeballMessengerStreamLinkReceiveRTPArgs *e)

{

NSLog(@"%@", [[EyeballEncoding utf8] getStringWithBytes:e.packet.payload]);

}];

// To send custom stream data, use EyeballMessengerConference.sendRTPWithFormat:packet:

// once you have created a conference (see Part 2):

// <code>

// [conference sendRTPWithFormat:customStream.format packet:[EyeballMessengerRTPPacket rtpPacketWithPayload:[EyeballEncoding.utf8 getBytesWithS:@"Hello, world!"]]];

// </code>

// TO BE CONTINUED...

Part 1b: WebRTC Data-Channel Stream Description

Page 8: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

WebRTC data-channel streams are easy. Describe one or more data channels (name + message

handler) and pass them into the stream description.

// Create a WebRTC data channel description, including a

// handler for processing received messages.

EyeballMessengerWebRTCDataChannelInfo *dataChannelInfo = [EyeballMessengerWebRTCDataChannelInfo dataChannelInfoWithLabel:@"mydatachannel"];

[dataChannelInfo setOnReceiveBlock:^(EyeballMessengerWebRTCDataChannelReceiveArgs *e)

{

NSLog(@"%@", e.data);

}];

// Create a WebRTC data channel stream description using

// our data channel.

EyeballMessengerWebRTCDataChannelStream *dataChannelStream = [EyeballMessengerWebRTCDataChannelStream dataChannelStreamWithChannelInfo:dataChannelInfo];

// To send data-channel stream data, use EyeballMessengerConference.sendDataWithChannelInfo:data:

// once you have created a conference (see Part 2):

// <code>

// [conference sendDataWithChannelInfo:dataChannelInfo data:@"Hello, world!"];

// </code>

// TO BE CONTINUED...

Part 1c: WebRTC Audio/Video Stream Descriptions

Page 9: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

WebRTC audio and video stream descriptions require a reference to the local media (microphone,

camera, or both), obtained by calling [EyeballMessengerWebRTCUserMedia

getMediaWithGetMediaArgs:].

// WebRTC has chosen VP8 as its mandatory video codec.

// Since video encoding is best done using native code,

// reference the video codec at the application-level.

// This is required when using a WebRTC video stream.

[EyeballMessengerWebRTCVideoStream registerCodecWithEncodingName:@"VP8" createCodecBlock:^()

{

return [[[Vp8Codec alloc] init] autorelease];

} preferred:YES];

// WebRTC audio and video streams require us to first get access to

// the local media (microphone, camera, or both).

EyeballMessengerWebRTCGetMediaArgs *getMediaArgs = [EyeballMessengerWebRTCGetMediaArgs getMediaArgsWithAudio:YES video:YES];

[getMediaArgs setVideoWidth:320]; // optional

[getMediaArgs setVideoHeight:240]; // optional

[getMediaArgs setVideoFrameRate:30]; // optional

[getMediaArgs setOnFailureBlock:^(EyeballMessengerWebRTCGetMediaFailureArgs *e)

{

[self alert:@"Could not get media. %@", e.exception.message];

}];

[getMediaArgs setOnSuccessBlock:^(EyeballMessengerWebRTCGetMediaSuccessArgs *e)

{

// We have successfully acquired access to the local

// audio/video device! Grab a reference to the media.

Page 10: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Internally, it maintains access to the local audio

// and video feeds coming from the device hardware.

EyeballMessengerWebRTCLocalMediaStream *localMedia = e.localStream;

// This is our local video control, a UIView (iOS) or

// and NSView (Mac). It is constantly updated with our

// live video feed since we requested video above. Add

// it directly to the UI or use the Messenger layout manager,

// which we do below.

NSObject *localVideoControl = e.localVideoControl;

// Create an Messenger layout manager, which makes the task

// of arranging video controls easy. Give it a reference

// to a UIView (iOS) or NSView (Mac) that can be filled

// with video feeds.

EyeballMessengerWebRTCLayoutManager *layoutManager = [EyeballMessengerWebRTCLayoutManager layoutManagerWithContainer:container];

// Position and display the local video control on-screen

// by passing it to the layout manager created above.

[layoutManager setLocalVideoControlWithLocalVideoControl:localVideoControl];

// Create a WebRTC audio stream description (requires a

// reference to the local audio feed).

EyeballMessengerWebRTCAudioStream *audioStream = [EyeballMessengerWebRTCAudioStream audioStreamWithLocalStream:localMedia];

// Create a WebRTC video stream description (requires a

Page 11: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// reference to the local video feed). Whenever a P2P link

// initializes using this description, position and display

// the remote video control on-screen by passing it to the

// layout manager created above. Whenever a P2P link goes

// down, remove it.

EyeballMessengerWebRTCVideoStream *videoStream = [EyeballMessengerWebRTCVideoStream videoStreamWithLocalStream:localMedia];

[videoStream addOnLinkInitWithValueBlock:^(EyeballMessengerStreamLinkInitArgs *e)

{

NSObject *remoteVideoControl = [e.link getRemoteVideoControl];

[layoutManager addRemoteVideoControlWithPeerId:e.peerId remoteVideoControl:remoteVideoControl];

}];

[videoStream addOnLinkDownWithValueBlock:^(EyeballMessengerStreamLinkDownArgs *e)

{

[layoutManager removeRemoteVideoControlWithPeerId:e.peerId];

}];

// TO BE CONTINUED...

Part 2: The Conference

Now that we have some stream descriptions, we are ready to create a conference - the hub that

manages your P2P links.

Conferences require the address/port of a STUN/TURN server. STUN provides a way for peers to discover

their public IP addresses, and TURN provides a way to relay data through highly restrictive firewalls.

Messenger comes bundled with a STUN/TURN server implementation, so you can run your own if you

have access to a computer that is directly exposed to the public Internet. Alternatively, there

are several public STUN servers that are free-to-use. Free TURN servers are more difficult to find, since

relaying with TURN can consume significant server bandwidth.

Page 12: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// CONTINUED FROM ABOVE...

// Create a conference using our stream descriptions. Replace

// 127.0.0.1 : 3478 with your STUN/TURN (Messenger) server address.

NSMutableArray *streams = [NSMutableArray arrayWithObjects:audioStream, videoStream, dataChannelStream, nil];

EyeballMessengerConference *conference = [EyeballMessengerConference conferenceWithServerAddress:@"127.0.0.1"

serverPort:3478

streams:streams];

// Supply TURN relay credentials in case we are behind a

// highly restrictive firewall. These credentials will be

// verified by the TURN server.

[conference setRelayUsername:@"test"];

[conference setRelayPassword:@"pa55w0rd!"];

// Add a few event handlers to the conference so we can see

// when a new P2P link is created or changes state.

[conference addOnLinkInitWithValueBlock:^(EyeballMessengerLinkInitArgs *e)

{

NSLog(@"Link to peer initializing...");

}];

[conference addOnLinkUpWithValueBlock:^(EyeballMessengerLinkUpArgs *e)

{

NSLog(@"Link to peer is UP.");

}];

Page 13: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

[conference addOnLinkDownWithValueBlock:^(EyeballMessengerLinkDownArgs *e)

{

NSLog([NSString stringWithFormat:@"Link to peer is DOWN. %@", e.exception.message]);

}];

// TO BE CONTINUED...

Part 3: Signalling

With our conference in hand, we are almost done! Just one more thing to set up.

Before we can create a P2P link, the peers have to exchange some information - specifically descriptions

of the streams (called the offer/answer) and some local network addresses (called candidates).

Messengergenerates this information automatically, but you are responsible for distributing it to the

peer as quickly as possible. This is called "signalling".

We're going to use WebSync here, but other popular options include SIP and XMPP - any real-time

messaging system will do. We use WebSync since it uses HTTP (WebSockets/long-polling) and therefore

has no issues with firewalls or connecting from JavaScript-based web applications.

// CONTINUED FROM ABOVE...

// Create a WebSync client and establish a persistent

// connection to the server. Replace localhost with your

// WebSync server address.

EyeballWebSyncClient *client = [EyeballWebSyncClient clientWithRequestUrl:@"http://localhost/websync.ashx"];

EyeballWebSyncConnectArgs *connectArgs = [EyeballWebSyncConnectArgs connectArgs];

[connectArgs setOnFailureBlock:^(EyeballWebSyncConnectFailureArgs *e)

{

NSLog(@"Could not connect to WebSync. %@", e.exception.message);

Page 14: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

}];

[client connectWithConnectArgs:connectArgs];

// Add a couple event handlers to the conference to send

// generated offers/answers and candidates to a peer.

// The peer ID is something we define later. In this case,

// it represents the remote WebSync client ID. WebSync's

// "notify" method is used to send data to a specific client.

[conference addOnLinkOfferAnswerWithValueBlock:^(EyeballMessengerLinkOfferAnswerArgs *e)

{

[client notifyWithNotifyArgs:[EyeballWebSyncNotifyArgs notifyArgsWithClientId:[EyeballGuid guidWithG:e.peerId]

dataJson:[e.offerAnswer toJson]

tag:@"offeranswer"]];

}];

[conference addOnLinkCandidateWithValueBlock:^(EyeballMessengerLinkCandidateArgs *e)

{

[client notifyWithNotifyArgs:[EyeballWebSyncNotifyArgs notifyArgsWithClientId:[EyeballGuid guidWithG:e.peerId]

dataJson:[e.candidate toJson]

tag:@"candidate"]];

}];

// Add an event handler to the WebSync client to receive

// incoming offers/answers and candidates from a peer.

Page 15: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Call the "receiveOfferAnswer" or "receiveCandidate"

// method to pass the information to the conference.

[client addOnNotifyWithValueBlock:^(EyeballWebSyncNotifyReceiveArgs *e)

{

NSString *peerId = [e.notifyingClient.clientId toString];

NSObject *peerState = e.notifyingClient.boundRecords;

if ([e.tag isEqualToString:@"offeranswer"])

{

[conference receiveOfferAnswerWithOfferAnswer:[EyeballMessengerOfferAnswer fromJsonWithOfferAnswerJson:e.dataJson]

peerId:peerId

peerState:peerState];

}

else if ([e.tag isEqualToString:@"candidate"])

{

[conference receiveCandidateWithCandidate:[EyeballMessengerCandidate fromJsonWithCandidateJson:e.dataJson]

peerId:peerId];

}

}];

// TO BE CONTINUED...

Part 4: Kicking It Off

Everything is set now. We just need to start the process by having one of the peers

call Conference.Link. That peer becomes the "controlling agent". The other peer becomes the

"controlled agent" and creates a P2P link automatically when it receives the controlling agent's offer.

Here's a detailed breakdown of what happens:

Page 16: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Peer A: The conference will raise the OnLinkInit event.

Peer A: Messenger will generate an offer and raise the OnOfferAnswer event. Peer A: Our event handler will use WebSync's Notify method to send that offer to the peer.

Peer B: Our event handler will receive that offer and call Conference.ReceiveOfferAnswer. Peer B: The conference will raise the OnLinkInit event.

Peer B: Messenger will generate an answer and raise the OnOfferAnswer event.

Peer B: Our event handler will use WebSync's Notify method to send that answer to the peer. Peer A: Our event handler will receive that answer and call Conference.ReceiveOfferAnswer.

Peer A/B: Messenger will generate candidates and raise the OnCandidate event. Peer A/B: Our event handler will use WebSync's Notify method to send those candidates to the peer.

Peer A/B: Our event handler will receive those candidates and call Conference.ReceiveCandidate. Peer A/B: Messenger will successfully establish a P2P link.

Peer A/B: The conference will raise the OnLinkUp event.

If the P2P link could not be established, the conference will raise the OnLinkDown event. The event

arguments will include an Exception property with details. The most common reason for a link failure is

a misconfiguration on the server. (Server address or port is wrong, server firewall is blocking UDP traffic,

server is on the same network as one of the clients, server is not publicly accessible, etc.)

If you are having trouble setting up your Messenger server, try using our public server, located

at messenger.eyeball.com : 3478.

A common scenario when using a pub-sub framework like WebSync is to create a P2P link whenever two

peers join the same channel (and destroy that link when one peer leaves).

// CONTINUED FROM ABOVE...

// Subscribe to a WebSync channel. When another client joins the same

// channel, create a P2P link. When a client leaves, destroy it.

EyeballWebSyncSubscribeArgs *subscribeArgs = [EyeballWebSyncSubscribeArgs subscribeArgsWithChannel:@"/mychannel"];

[subscribeArgs setOnFailureBlock:^(EyeballWebSyncSubscribeFailureArgs *e)

{

NSLog(@"Could not subscribe to %@. %@", e.channel, e.exception.message);

}];

[subscribeArgs setOnReceiveBlock:^(EyeballWebSyncSubscribeReceiveArgs *e) { }];

Page 17: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

[subscribeArgs setOnClientSubscribeWithOnClientSubscribeBlock:^(EyeballWebSyncSubscribersClientSubscribeArgs *e)

{

NSString *peerId = [e.subscribedClient.clientId toString];

NSObject *peerState = e.subscribedClient.boundRecords;

[conference linkWithPeerId:peerId peerState:peerState];

}];

[subscribeArgs setOnClientUnsubscribeWithOnClientUnsubscribeBlock:^(EyeballWebSyncSubscribersClientUnsubscribeArgs *e)

{

NSString *peerId = [e.unsubscribedClient.clientId toString];

[conference unlinkWithPeerId:peerId];

}];

[client subscribeWithSubscribeArgs:subscribeArgs];

}];

[EyeballMessengerWebRTCUserMedia getMediaWithGetMediaArgs:getMediaArgs];

Note that when calling Conference.Link, you must supply a unique peer ID. This string can be anything

that uniquely identifies the remote peer. This should be the remote WebSync client ID when using

WebSync, the remote SIP client ID when using SIP, the remote XMPP client ID when using XMPP... You

get the idea.

That's it! Load 'er up and watch the magic!

Page 18: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Creating a Conference: Java

The Java SDK provides a complete peer-to-peer (P2P) streaming solution, including a

complete WebRTC stack for rapidly creating audio, video, and data-channel streams that can be

consumed natively in modern web browsers.

To get started, you'll need to add some JARs from the SDK to your project classpath (IntelliJ

IDEA, Eclipse, command-line):

eyeball.jar (supporting code) eyeball.messenger.jar (Messenger core) eyeball.messenger.webrtc.jar (WebRTC stack, optional)

Now let's write some code! (See Java.Client, Java.Client.WebRTC, and Java.Client.DataChannels in the

SDK Examples folder.)

Part 1: Stream Descriptions

The first step is to describe the streams we want to use. Stream descriptions are used to define the types

of media we are going to be sending back and forth between peers in a conference. Messenger allows us

to createcustom streams with any number of possible data formats. The WebRTC extension allows us to

create audio, video, and data-channel streams. You can mix and match custom and WebRTC streams,

but only WebRTC streams can be consumed natively by web browsers.

Part 1a: Custom Stream Descriptions

Custom stream descriptions require a "stream type" and one or more "stream formats". The stream type

is used in the SDP offer/answer to help differentiate between multiple streams (audio, video,

application/binary, etc.). The stream format is used in the SDP offer/answer to help differentiate between

multiple data formats supported for a given stream (i.e. G.711, G.722, Opus, etc. for audio).

// Create a custom stream description that indicates text

// data will be sent using a format labelled "utf8".

Stream customStream = new eyeball.messenger.Stream(StreamType.Application, new StreamFormat("utf8"));

customStream.addOnLinkReceiveRTP(new SingleAction<StreamLinkReceiveRTPArgs>()

Page 19: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

public void invoke(StreamLinkReceiveRTPArgs e)

{

alert(Encoding.getUTF8().getString(e.getPacket().getPayload()));

}

});

// To send custom stream data, use Conference.sendRTP

// once you have created a conference (see Part 2):

// <code>

// conference.sendRTP(customStream.getFormat(), new RTPPacket(Encoding.getUTF8().getBytes("Hello, world!")));

// </code>

// TO BE CONTINUED...

Part 1b: WebRTC Data-Channel Stream Description

WebRTC data-channel streams are easy. Describe one or more data channels (name + message

handler) and pass them into the stream description.

// Create a WebRTC data channel description, including a

// handler for processing received messages.

DataChannelInfo dataChannelInfo = new eyeball.messenger.webrtc.DataChannelInfo("mydatachannel")

{{

setOnReceive(new SingleAction<DataChannelReceiveArgs>()

{

public void invoke(DataChannelReceiveArgs e)

{

Page 20: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

alert(e.getData());

}

});

}};

// Create a WebRTC data channel stream description using

// our data channel.

DataChannelStream dataChannelStream = new eyeball.messenger.webrtc.DataChannelStream(dataChannelInfo);

// To send data-channel stream data, use ConferenceExtensions.sendData

// once you have created a conference (see Part 2):

// <code>

// ConferenceExtensions.sendData(conference, dataChannelInfo, "Hello, world!");

// </code>

// TO BE CONTINUED...

Part 1c: WebRTC Audio/Video Stream Descriptions

WebRTC audio and video stream descriptions require a reference to the local media (microphone,

camera, or both), obtained by calling UserMedia.getMedia.

// WebRTC has chosen VP8 as its mandatory video codec.

// Since video encoding is best done using native code,

// reference the video codec at the application-level.

// This is required when using a WebRTC video stream.

eyeball.messenger.webrtc.VideoStream.registerCodec("VP8", new EmptyFunction<VideoCodec>()

{

Page 21: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

public VideoCodec invoke()

{

return new Vp8Codec();

}

}, true);

// Android requires an Activity context to create Views.

// Since the default WebRTC video providers must create

// Views, supply a reference to the current activity.

// This is required when using a WebRTC video stream on

// the Android platform.

eyeball.messenger.webrtc.DefaultProviders.setAndroidActivity(this);

// WebRTC audio and video streams require us to first get access to

// the local media (microphone, camera, or both).

eyeball.messenger.webrtc.UserMedia.getMedia(new GetMediaArgs(true, true)

{{

setVideoWidth(320); // optional

setVideoHeight(240); // optional

setVideoFrameRate(30); // optional

setOnFailure(new SingleAction<GetMediaFailureArgs>()

{

public void invoke(GetMediaFailureArgs e)

{

alert("Could not get media. %s", e.getException().getMessage());

}

});

Page 22: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

setOnSuccess(new SingleAction<GetMediaSuccessArgs>()

{

public void invoke(GetMediaSuccessArgs e)

{

// We have successfully acquired access to the local

// audio/video device! Grab a reference to the media.

// Internally, it maintains access to the local audio

// and video feeds coming from the device hardware.

LocalMediaStream localMedia = e.getLocalStream();

// This is our local video control, a Java Component

// or Android View. It is constantly updated with our

// live video feed since we requested video above. Add

// it directly to the UI or use the Messenger layout manager,

// which we do below.

Object localVideoControl = e.getLocalVideoControl();

// Create an Messenger layout manager, which makes the task

// of arranging video controls easy. Give it a reference

// to a Java Container that can be filled with video feeds.

// For Android users, the WebRTC extension includes

// AndroidLayoutManager, which accepts an Android ViewGroup.

LayoutManager layoutManager = new eyeball.messenger.webrtc.LayoutManager(container);

// Position and display the local video control on-screen

// by passing it to the layout manager created above.

Page 23: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

layoutManager.setLocalVideoControl(localVideoControl);

// Create a WebRTC audio stream description (requires a

// reference to the local audio feed).

AudioStream audioStream = new eyeball.messenger.webrtc.AudioStream(localMedia);

// Create a WebRTC video stream description (requires a

// reference to the local video feed). Whenever a P2P link

// initializes using this description, position and display

// the remote video control on-screen by passing it to the

// layout manager created above. Whenever a P2P link goes

// down, remove it.

VideoStream videoStream = new eyeball.messenger.webrtc.VideoStream(localMedia);

videoStream.addOnLinkInit(new SingleAction<StreamLinkInitArgs>()

{

public void invoke(final StreamLinkInitArgs e)

{

Object remoteVideoControl = LinkExtensions.getRemoteVideoControl(e.getLink());

layoutManager.addRemoteVideoControl(e.getPeerId(), remoteVideoControl);

}

});

videoStream.addOnLinkDown(new SingleAction<StreamLinkDownArgs>()

{

public void invoke(final StreamLinkDownArgs e)

{

Page 24: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

layoutManager.removeRemoteVideoControl(e.getPeerId());

}

});

// TO BE CONTINUED...

Part 2: The Conference

Now that we have some stream descriptions, we are ready to create a conference - the hub that

manages your P2P links.

Conferences require the address/port of a STUN/TURN server. STUN provides a way for peers to discover

their public IP addresses, and TURN provides a way to relay data through highly restrictive firewalls.

Messenger comes bundled with a STUN/TURN server implementation, so you can run your own if you

have access to a computer that is directly exposed to the public Internet. Alternatively, there

are several public STUN servers that are free-to-use. Free TURN servers are more difficult to find, since

relaying with TURN can consume significant server bandwidth.

// CONTINUED FROM ABOVE...

// Create a conference using our stream descriptions. Replace

// 127.0.0.1 : 3478 with your STUN/TURN (Messenger) server address.

Conference conference = new eyeball.messenger.Conference("127.0.0.1", 3478, new Stream[] { audioStream, videoStream, dataChannelStream });

// Supply TURN relay credentials in case we are behind a

// highly restrictive firewall. These credentials will be

// verified by the TURN server.

conference.setRelayUsername("test");

conference.setRelayPassword("pa55w0rd!");

Page 25: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Add a few event handlers to the conference so we can see

// when a new P2P link is created or changes state.

conference.addOnLinkInit(new SingleAction<LinkInitArgs>()

{

public void invoke(LinkInitArgs e)

{

writeLine("Link to peer initializing...");

}

});

conference.addOnLinkUp(new SingleAction<LinkUpArgs>()

{

public void invoke(LinkUpArgs e)

{

writeLine("Link to peer is UP.");

}

});

conference.addOnLinkDown(new SingleAction<LinkDownArgs>()

{

public void invoke(LinkDownArgs e)

{

writeLine("Link to peer is DOWN. " + e.getException().getMessage());

}

});

// TO BE CONTINUED...

Part 3: Signalling

Page 26: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

With our conference in hand, we are almost done! Just one more thing to set up.

Before we can create a P2P link, the peers have to exchange some information - specifically descriptions

of the streams (called the offer/answer) and some local network addresses (called candidates).

Messengergenerates this information automatically, but you are responsible for distributing it to the

peer as quickly as possible. This is called "signalling".

We're going to use WebSync here, but other popular options include SIP and XMPP - any real-time

messaging system will do. We use WebSync since it uses HTTP (WebSockets/long-polling) and therefore

has no issues with firewalls or connecting from JavaScript-based web applications.

// CONTINUED FROM ABOVE...

// Create a WebSync client and establish a persistent

// connection to the server. Replace localhost with your

// WebSync server address.

Client client = new eyeball.websync.Client("http://localhost/websync.ashx");

client.connect(new ConnectArgs()

{{

setOnFailure(new SingleAction()

{

public void invoke(ConnectFailureArgs e)

{

alert("Could not connect to WebSync. " + e.getException().getMessage());

}

});

}});

Page 27: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Add a couple event handlers to the conference to send

// generated offers/answers and candidates to a peer.

// The peer ID is something we define later. In this case,

// it represents the remote WebSync client ID. WebSync's

// "notify" method is used to send data to a specific client.

conference.addOnLinkOfferAnswer(new SingleAction<LinkOfferAnswerArgs>()

{

public void invoke(LinkOfferAnswerArgs e)

{

try

{

client.notify(new NotifyArgs(new Guid(e.getPeerId()), e.getOfferAnswer().toJson(), "offeranswer"));

}

catch (Exception ex)

{

ex.printStackTrace();

}

}

});

conference.addOnLinkCandidate(new SingleAction<LinkCandidateArgs>()

{

public void invoke(LinkCandidateArgs e)

{

try

{

client.notify(new NotifyArgs(new Guid(e.getPeerId()), e.getCandidate().toJson(), "candidate"));

Page 28: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

}

catch (Exception ex)

{

ex.printStackTrace();

}

}

});

// Add an event handler to the WebSync client to receive

// incoming offers/answers and candidates from a peer.

// Call the "receiveOfferAnswer" or "receiveCandidate"

// method to pass the information to the conference.

client.addOnNotify(new SingleAction<NotifyReceiveArgs>()

{

public void invoke(NotifyReceiveArgs e)

{

try

{

String peerId = e.getNotifyingClient().getClientId().toString();

Object peerState = e.getNotifyingClient().getBoundRecords();

if (e.getTag().equals("offeranswer"))

{

conference.receiveOfferAnswer(OfferAnswer.fromJson(e.getDataJson()), peerId, peerState);

}

else if (e.getTag().equals("candidate"))

Page 29: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

conference.receiveCandidate(Candidate.fromJson(e.getDataJson()), peerId);

}

}

catch (Exception ex)

{

ex.printStackTrace();

}

}

});

// TO BE CONTINUED...

Part 4: Kicking It Off

Everything is set now. We just need to start the process by having one of the peers

call Conference.Link. That peer becomes the "controlling agent". The other peer becomes the

"controlled agent" and creates a P2P link automatically when it receives the controlling agent's offer.

Here's a detailed breakdown of what happens:

Peer A: The conference will raise the OnLinkInit event.

Peer A: Messenger will generate an offer and raise the OnOfferAnswer event. Peer A: Our event handler will use WebSync's Notify method to send that offer to the peer.

Peer B: Our event handler will receive that offer and call Conference.ReceiveOfferAnswer. Peer B: The conference will raise the OnLinkInit event.

Peer B: Messenger will generate an answer and raise the OnOfferAnswer event.

Peer B: Our event handler will use WebSync's Notify method to send that answer to the peer. Peer A: Our event handler will receive that answer and call Conference.ReceiveOfferAnswer.

Peer A/B: Messenger will generate candidates and raise the OnCandidate event. Peer A/B: Our event handler will use WebSync's Notify method to send those candidates to the peer.

Peer A/B: Our event handler will receive those candidates and call Conference.ReceiveCandidate.

Peer A/B: Messenger will successfully establish a P2P link. Peer A/B: The conference will raise the OnLinkUp event.

Page 30: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

If the P2P link could not be established, the conference will raise the OnLinkDown event. The event

arguments will include an Exception property with details. The most common reason for a link failure is

a misconfiguration on the server. (Server address or port is wrong, server firewall is blocking UDP traffic,

server is on the same network as one of the clients, server is not publicly accessible, etc.)

If you are having trouble setting up your Messenger server, try using our public server, located

at messenger.eyeball.com : 3478.

A common scenario when using a pub-sub framework like WebSync is to create a P2P link whenever two

peers join the same channel (and destroy that link when one peer leaves).

// CONTINUED FROM ABOVE...

// Subscribe to a WebSync channel. When another client joins the same

// channel, create a P2P link. When a client leaves, destroy it.

SubscribeArgs subscribeArgs = new SubscribeArgs("/mychannel")

{{

setOnFailure(new SingleAction<SubscribeFailureArgs>()

{

public void invoke(SubscribeFailureArgs e)

{

alert("Could not subscribe to " + e.getChannel() + ". " + e.getException().getMessage());

}

});

setOnReceive(new SingleAction<SubscribeReceiveArgs>()

{

public void invoke(SubscribeReceiveArgs e) { }

});

}};

Page 31: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

SubscribeArgsExtensions.setOnClientSubscribe(subscribeArgs, new SingleAction<ClientSubscribeArgs>()

{

public void invoke(ClientSubscribeArgs e)

{

try

{

String peerId = e.getSubscribedClient().getClientId().toString();

Object peerState = e.getSubscribedClient().getBoundRecords();

conference.link(peerId, peerState);

}

catch (Exception ex)

{

ex.printStackTrace();

}

}

});

SubscribeArgsExtensions.setOnClientUnsubscribe(subscribeArgs, new SingleAction<ClientUnsubscribeArgs>()

{

public void invoke(ClientUnsubscribeArgs e)

{

try

{

String peerId = e.getUnsubscribedClient().getClientId().toString();

conference.unlink(peerId);

}

Page 32: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

catch (Exception ex)

{

ex.printStackTrace();

}

}

});

client.subscribe(subscribeArgs);

}

});

}});

Note that when calling Conference.Link, you must supply a unique peer ID. This string can be anything

that uniquely identifies the remote peer. This should be the remote WebSync client ID when using

WebSync, the remote SIP client ID when using SIP, the remote XMPP client ID when using XMPP... You

get the idea.

That's it! Load 'er up and watch the magic!

Creating a Conference: JavaScript

JavaScript

Page 33: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

The JavaScript SDK provides a complete WebRTC-based peer-to-peer (P2P) streaming solution, including

support for audio, video, and data channels. Native WebRTC implementations, such as those found in

Chrome and Firefox, are used if present. For all other cases, the SDK automatically and seamlessly falls

back to an embedded Java applet that provides a complete WebRTC stack. This graceful degradation is

completely transparent to you as the developer.

There are two ways to use the JavaScript client. The first is completely object-oriented, like Java or .NET.

var getMediaArgs = new eyeball.messenger.webrtc.getMediaArgs();

getMediaArgs.setAudio(true);

getMediaArgs.setVideo(true);

getMediaArgs.setOnSuccess(function(e) {

...

});

eyeball.messenger.webrtc.userMedia.getMedia(getMediaArgs);

The second uses a more JavaScript-style syntax to accomplish the same thing.

eyeball.messenger.webrtc.userMedia.getMedia({

audio: true,

video: true,

onSuccess: function(e) {

...

}

});

Properties on the getMedia config object (such as "audio", "video", etc) are mapped automatically to the

appropriate "setter" methods (such as "setAudio", "setVideo", etc). Just make sure the property names

match up to a setter method, and the rest is automatic!

To get started, you'll need to add some scripts from the SDK to your page:

Page 34: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

<!-- supporting code -->

<script type="text/javascript" src="eyeball.js"></script>

<!-- Messenger core -->

<script type="text/javascript" src="eyeball.messenger.js"></script>

<!-- WebRTC stack -->

<script type="text/javascript" src="eyeball.messenger.webrtc.js"></script>

Now let's write some code! (See JavaScript.Client.WebRTC and JavaScript.Client.DataChannels in the SDK

Examples folder.)

Part 1: Stream Descriptions

The first step is to describe the streams we want to use. Stream descriptions are used to define the types

of media we are going to be sending back and forth between peers in a conference. The WebRTC

extension allows us to create audio, video, and data-channel streams. For this example, we'll create

all three.

// For backwards-compability with browsers that do not yet support

// WebRTC, provide a reference to eyeball.messenger.webrtc.applet.jar, a

// Java applet that provides a full WebRTC stack through the exact

// same JavaScript API you use for modern browsers. You can set this

// for all browsers - only the ones that need it will use it.

eyeball.messenger.webrtc.setApplet({

path: './eyeball.messenger.webrtc.applet.jar',

name: 'Messenger WebRTC for JavaScript'

});

Page 35: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// TO BE CONTINUED...

Part 1a: WebRTC Data-Channel Stream Description

WebRTC data-channel stream descriptions are easy. Describe one or more data channels (name +

message handler) and pass them into the stream description.

// Create a data channel description, including a handler for

// processing received messages.

var dataChannelInfo = new eyeball.messenger.webrtc.dataChannelInfo({

label: 'mydatachannel',

onReceive: function(e)

{

alert(e.getData());

}

});

// Create a data channel stream description using our data channel.

var dataChannelStream = new eyeball.messenger.webrtc.dataChannelStream([ dataChannelInfo ]);

// To send data-channel stream data, use conference.sendData

// once you have created a conference (see Part 2):

// <code>

// conference.sendData({

channelInfo: dataChannelInfo,

data: 'Hello, world!'

});

// </code>

Page 36: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// TO BE CONTINUED...

Part 1b: WebRTC Audio/Video Stream Descriptions

WebRTC audio and video stream descriptions require a reference to the local media (microphone,

camera, or both), obtained by calling userMedia.getMedia.

// WebRTC audio and video streams require us to first get access to

// the local media (microphone, camera, or both).

eyeball.messenger.webrtc.userMedia.getMedia({

audio: true, // required if you want to send audio

video: true, // required if you want to send video

videoWidth: 320, // optional

videoHeight: 240, // optional

videoFrameRate: 30, // optional

onFailure: function(e)

{

alert('Could not get media. ' + e.getException().message);

},

onSuccess: function(e)

{

// We have successfully acquired access to the local

// audio/video device! Grab a reference to the media.

// Internally, it maintains access to the local audio

// and video feeds coming from the device hardware.

var localMedia = e.getLocalStream();

// This is our local video control, a simple DOM element.

Page 37: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// It is constantly updated with our live video feed

// since we requested video above. To add it to the DOM,

// either call XXX.appendChild(localVideoControl) or use

// the Messenger layout manager, which we do below.

var localVideoControl = e.getLocalVideoControl();

// Create an Messenger layout manager, which makes the task

// of arranging video controls easy. Give it a reference

// to a DOM element that can be filled with video feeds.

var layoutManager = new eyeball.messenger.webrtc.layoutManager(document.getElementById('container'));

// Position and display the local video control on-screen

// by passing it to the layout manager created above.

layoutManager.setLocalVideoControl(localVideoControl);

// Create an audio stream description (requires a reference

// to the local audio feed).

var audioStream = new eyeball.messenger.webrtc.audioStream(localMedia);

// Create a video stream description (requires a reference

// to the local video feed). Whenever a P2P link initializes

// using this description, position and display the remote

// video control on-screen by passing it to the layout manager

// created above. Whenever a P2P link goes down, remove it.

var videoStream = new eyeball.messenger.webrtc.videoStream(localMedia);

videoStream.addOnLinkInit(function(e)

Page 38: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

var remoteVideoControl = e.getLink().getRemoteVideoControl();

layoutManager.addRemoteVideoControl(e.getPeerId(), remoteVideoControl);

});

videoStream.addOnLinkDown(function(e)

{

layoutManager.removeRemoteVideoControl(e.getPeerId());

});

// TO BE CONTINUED...

Part 2: The Conference

Now that we have some stream descriptions, we are ready to create a conference - the hub that

manages your P2P links.

Conferences require the address/port of a STUN/TURN server. STUN provides a way for peers to discover

their public IP addresses, and TURN provides a way to relay data through highly restrictive firewalls.

Messenger comes bundled with a STUN/TURN server implementation, so you can run your own if you

have access to a computer that is directly exposed to the public Internet. Alternatively, there

are several public STUN servers that are free-to-use. Free TURN servers are more difficult to find, since

relaying with TURN can consume significant server bandwidth.

// CONTINUED FROM ABOVE...

// Create a conference using our stream descriptions. Replace

// 127.0.0.1 : 3478 with your STUN/TURN (Messenger) server address.

var conference = new eyeball.messenger.conference('127.0.0.1', 3478, [ audioStream, videoStream, dataChannelStream ]);

// Supply TURN relay credentials in case we are behind a

Page 39: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// highly restrictive firewall. These credentials will be

// verified by the TURN server.

conference.setRelayUsername('test');

conference.setRelayPassword('pa55w0rd!');

// Add a few event handlers to the conference so we can see

// when a new P2P link is created or changes state.

conference.addOnLinkInit(function(e)

{

if (console && console.log) console.log('Link to peer initializing...');

});

conference.addOnLinkUp(function(e)

{

if (console && console.log) console.log('Link to peer is UP.');

});

conference.addOnLinkDown(function(e)

{

if (console && console.log) console.log('Link to peer is DOWN. ' + e.getException().message);

});

// TO BE CONTINUED...

Part 3: Signalling

With our conference in hand, we are almost done! Just one more thing to set up.

Before we can create a P2P link, the peers have to exchange some information - specifically descriptions

of the streams (called the offer/answer) and some local network addresses (called candidates).

Page 40: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Messengergenerates this information automatically, but you are responsible for distributing it to the

peer as quickly as possible. This is called "signalling".

We're going to use WebSync here, but other popular options include SIP and XMPP - any real-time

messaging system will do. We use WebSync since it uses HTTP (WebSockets/long-polling) and therefore

has no issues with firewalls or connecting from JavaScript-based web applications.

// CONTINUED FROM ABOVE...

// Create a WebSync client and establish a persistent

// connection to the server. Replace localhost with your

// WebSync server address.

var client = new eyeball.websync.client('http://localhost/websync.ashx');

client.connect({

onFailure: function(e)

{

alert('Could not connect to WebSync. ' + e.getException().message);

}

});

// Add a couple event handlers to the conference to send

// generated offers/answers and candidates to a peer.

// The peer ID is something we define later. In this case,

// it represents the remote WebSync client ID. WebSync's

// "notify" method is used to send data to a specific client.

conference.addOnLinkOfferAnswer(function(e)

{

client.notify({

Page 41: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

clientId: e.getPeerId(),

dataJson: e.getOfferAnswer().toJson(),

tag: 'offeranswer'

});

});

conference.addOnLinkCandidate(function(e)

{

client.notify({

clientId: e.getPeerId(),

dataJson: e.getCandidate().toJson(),

tag: 'candidate'

});

});

// Add an event handler to the WebSync client to receive

// incoming offers/answers and candidates from a peer.

// Call the "receiveOfferAnswer" or "receiveCandidate"

// method to pass the information to the conference.

client.addOnNotify(function(e)

{

var peerId = e.getNotifyingClient().getClientId().toString();

var peerState = e.getNotifyingClient().getBoundRecords(); // optional

if (e.getTag() == 'offeranswer')

{

conference.receiveOfferAnswer(eyeball.messenger.offerAnswer.fromJson(e.getDataJson()), peerId, peerState);

}

Page 42: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

else if (e.getTag() == 'candidate')

{

conference.receiveCandidate(eyeball.messenger.candidate.fromJson(e.getDataJson()), peerId);

}

});

// TO BE CONTINUED...

Part 4: Kicking It Off

Everything is set now. We just need to start the process by having one of the peers

call Conference.Link. That peer becomes the "controlling agent". The other peer becomes the

"controlled agent" and creates a P2P link automatically when it receives the controlling agent's offer.

Here's a detailed breakdown of what happens:

Peer A: The conference will raise the OnLinkInit event.

Peer A: Messenger will generate an offer and raise the OnOfferAnswer event. Peer A: Our event handler will use WebSync's Notify method to send that offer to the peer.

Peer B: Our event handler will receive that offer and call Conference.ReceiveOfferAnswer. Peer B: The conference will raise the OnLinkInit event.

Peer B: Messenger will generate an answer and raise the OnOfferAnswer event.

Peer B: Our event handler will use WebSync's Notify method to send that answer to the peer. Peer A: Our event handler will receive that answer and call Conference.ReceiveOfferAnswer.

Peer A/B: Messenger will generate candidates and raise the OnCandidate event. Peer A/B: Our event handler will use WebSync's Notify method to send those candidates to the peer.

Peer A/B: Our event handler will receive those candidates and call Conference.ReceiveCandidate.

Peer A/B: Messenger will successfully establish a P2P link. Peer A/B: The conference will raise the OnLinkUp event.

If the P2P link could not be established, the conference will raise the OnLinkDown event. The event

arguments will include an Exception property with details. The most common reason for a link failure is

a misconfiguration on the server. (Server address or port is wrong, server firewall is blocking UDP traffic,

server is on the same network as one of the clients, server is not publicly accessible, etc.)

If you are having trouble setting up your Messenger server, try using our public server, located

at messenger.eyeball.com : 3478.

Page 43: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

A common scenario when using a pub-sub framework like WebSync is to create a P2P link whenever two

peers join the same channel (and destroy that link when one peer leaves).

// CONTINUED FROM ABOVE...

// Subscribe to a WebSync channel. When another client joins the same

// channel, create a P2P link. When a client leaves, destroy it.

client.subscribe({

channel: '/mychannel',

onFailure: function(e)

{

alert('Could not subscribe to ' + e.getChannel() + '. ' + e.getException().message);

},

onReceive: function(e) { },

onClientSubscribe: function(e)

{

var peerId = e.getSubscribedClient().getClientId().toString();

var peerState = e.getSubscribedClient().getBoundRecords();

conference.link(peerId, peerState);

},

onClientUnsubscribe: function(e)

{

var peerId = e.getUnsubscribedClient().getClientId().toString();

conference.unlink(peerId);

}

});

}

Page 44: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

});

Note that when calling Conference.Link, you must supply a unique peer ID. This string can be anything

that uniquely identifies the remote peer. This should be the remote WebSync client ID when using

WebSync, the remote SIP client ID when using SIP, the remote XMPP client ID when using XMPP... You

get the idea.

That's it! Load 'er up and watch the magic!

Creating a Conference: Xamarin.Android

Please read peer-to-peer (P2P) streaming solution, including a partial WebRTC stack for rapidly creating

data-channel streams that can be consumed natively in modern web browsers.

To get started, you'll need to add some assemblies from the SDK to your project references (Xamarin

Studio, Visual Studio, MonoDevelop):

Eyeball.dll (supporting code) Eyeball.Messenger.dll (Messenger core) Eyeball.Messenger.WebRTC.dll (WebRTC stack, optional)

Now let's write some code! (See Xamarin.Android.Client and Xamarin.Android.Client.DataChannels in the

SDK Examples folder.)

Part 1: Stream Descriptions

Page 45: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

The first step is to describe the streams we want to use. Stream descriptions are used to define the types

of media we are going to be sending back and forth between peers in a conference. Messenger allows us

to createcustom streams with any number of possible data formats. The WebRTC extension allows us to

create audio, video, and data-channel streams. You can mix and match custom and WebRTC streams,

but only WebRTC streams can be consumed natively by web browsers.

Part 1a: Custom Stream Descriptions

Custom stream descriptions require a "stream type" and one or more "stream formats". The stream type

is used in the SDP offer/answer to help differentiate between multiple streams (audio, video,

application/binary, etc.). The stream format is used in the SDP offer/answer to help differentiate between

multiple data formats supported for a given stream (i.e. G.711, G.722, Opus, etc. for audio).

// Create a custom stream description that indicates text

// data will be sent using a format labelled "utf8".

var customStream = new Eyeball.Messenger.Stream(StreamType.Application, new StreamFormat("utf8"));

customStream.OnLinkReceiveRTP += (e)

{

Alert(Encoding.UTF8.GetString(e.Packet.Payload));

};

// To send custom stream data, use Conference.SendRTP

// once you have created a conference (see Part 2):

// <code>

// conference.SendRTP(customStream.Format, new RTPPacket(Encoding.UTF8.GetBytes("Hello, world!")));

// </code>

// TO BE CONTINUED...

Part 1b: WebRTC Data-Channel Stream Description

Page 46: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

WebRTC data-channel streams are easy. Describe one or more data channels (name + message

handler) and pass them into the stream description.

// Create a WebRTC data channel description, including a

// handler for processing received messages.

var dataChannelInfo = new Eyeball.Messenger.WebRTC.DataChannelInfo("mydatachannel")

{

OnReceive = (e) =>

{

Alert(e.Data);

}

};

// Create a WebRTC data channel stream description using

// our data channel.

var dataChannelStream = new Eyeball.Messenger.WebRTC.DataChannelStream(dataChannelInfo);

// To send data-channel stream data, use Conference.SendData

// once you have created a conference (see Part 2):

// <code>

// conference.SendData(dataChannelInfo, "Hello, world!");

// </code>

// TO BE CONTINUED...

Part 2: The Conference

Page 47: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Now that we have some stream descriptions, we are ready to create a conference - the hub that

manages your P2P links.

Conferences require the address/port of a STUN/TURN server. STUN provides a way for peers to discover

their public IP addresses, and TURN provides a way to relay data through highly restrictive firewalls.

Messenger comes bundled with a STUN/TURN server implementation, so you can run your own if you

have access to a computer that is directly exposed to the public Internet. Alternatively, there

are several public STUN servers that are free-to-use. Free TURN servers are more difficult to find, since

relaying with TURN can consume significant server bandwidth.

// CONTINUED FROM ABOVE...

// Create a conference using our stream descriptions. Replace

// 127.0.0.1 : 3478 with your STUN/TURN (Messenger) server address.

var conference = new Eyeball.Messenger.Conference("127.0.0.1", 3478, dataChannelStream);

// Supply TURN relay credentials in case we are behind a

// highly restrictive firewall. These credentials will be

// verified by the TURN server.

conference.RelayUsername = "test";

conference.RelayPassword = "pa55w0rd!";

// Add a few event handlers to the conference so we can see

// when a new P2P link is created or changes state.

conference.OnLinkInit += (e) =>

{

Console.WriteLine("Link to peer initializing...");

};

Page 48: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

conference.OnLinkUp += (e) =>

{

Console.WriteLine("Link to peer is UP.");

};

conference.OnLinkDown += (e) =>

{

Console.WriteLine("Link to peer is DOWN. " + e.Exception.Message);

};

// TO BE CONTINUED...

Part 3: Signalling

With our conference in hand, we are almost done! Just one more thing to set up.

Before we can create a P2P link, the peers have to exchange some information - specifically descriptions

of the streams (called the offer/answer) and some local network addresses (called candidates).

Messengergenerates this information automatically, but you are responsible for distributing it to the

peer as quickly as possible. This is called "signalling".

We're going to use WebSync here, but other popular options include SIP and XMPP - any real-time

messaging system will do. We use WebSync since it uses HTTP (WebSockets/long-polling) and therefore

has no issues with firewalls or connecting from JavaScript-based web applications.

// CONTINUED FROM ABOVE...

// Create a WebSync client and establish a persistent

// connection to the server. Replace localhost with your

// WebSync server address.

var client = new Eyeball.WebSync.Client("http://localhost/websync.ashx");

client.Connect(new ConnectArgs()

Page 49: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

OnFailure = (e) =>

{

Alert("Could not connect to WebSync. " + e.Exception.Message);

});

});

// Add a couple event handlers to the conference to send

// generated offers/answers and candidates to a peer.

// The peer ID is something we define later. In this case,

// it represents the remote WebSync client ID. WebSync's

// "notify" method is used to send data to a specific client.

conference.OnLinkOfferAnswer += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.OfferAnswer.ToJson(), "offeranswer"));

};

conference.OnLinkCandidate += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.Candidate.ToJson(), "candidate"));

};

// Add an event handler to the WebSync client to receive

// incoming offers/answers and candidates from a peer.

// Call the "ReceiveOfferAnswer" or "ReceiveCandidate"

// method to pass the information to the conference.

client.OnNotify += (e) =>

Page 50: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

var peerId = e.NotifyingClient.ClientId.ToString();

var peerState = e.NotifyingClient.BoundRecords;

if (e.Tag == "offeranswer")

{

conference.ReceiveOfferAnswer(OfferAnswer.FromJson(e.DataJson), peerId, peerState);

}

else if (e.Tag == "candidate")

{

conference.ReceiveCandidate(Candidate.FromJson(e.DataJson), peerId);

}

};

// TO BE CONTINUED...

Part 4: Kicking It Off

Everything is set now. We just need to start the process by having one of the peers

call Conference.Link. That peer becomes the "controlling agent". The other peer becomes the

"controlled agent" and creates a P2P link automatically when it receives the controlling agent's offer.

Here's a detailed breakdown of what happens:

Peer A: The conference will raise the OnLinkInit event.

Peer A: Messenger will generate an offer and raise the OnOfferAnswer event. Peer A: Our event handler will use WebSync's Notify method to send that offer to the peer.

Peer B: Our event handler will receive that offer and call Conference.ReceiveOfferAnswer. Peer B: The conference will raise the OnLinkInit event.

Peer B: Messenger will generate an answer and raise the OnOfferAnswer event.

Peer B: Our event handler will use WebSync's Notify method to send that answer to the peer. Peer A: Our event handler will receive that answer and call Conference.ReceiveOfferAnswer.

Peer A/B: Messenger will generate candidates and raise the OnCandidate event. Peer A/B: Our event handler will use WebSync's Notify method to send those candidates to the peer.

Peer A/B: Our event handler will receive those candidates and call Conference.ReceiveCandidate.

Peer A/B: Messenger will successfully establish a P2P link.

Page 51: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Peer A/B: The conference will raise the OnLinkUp event.

If the P2P link could not be established, the conference will raise the OnLinkDown event. The event

arguments will include an Exception property with details. The most common reason for a link failure is

a misconfiguration on the server. (Server address or port is wrong, server firewall is blocking UDP traffic,

server is on the same network as one of the clients, server is not publicly accessible, etc.)

If you are having trouble setting up your Messenger server, try using our public server, located

at messenger.eyeball.com : 3478.

A common scenario when using a pub-sub framework like WebSync is to create a P2P link whenever two

peers join the same channel (and destroy that link when one peer leaves).

// CONTINUED FROM ABOVE...

// Subscribe to a WebSync channel. When another client joins the same

// channel, create a P2P link. When a client leaves, destroy it.

client.Subscribe(new SubscribeArgs("/mychannel")

{

OnFailure = (e) =>

{

Alert("Could not subscribe to " + e.Channel + ". " + e.Exception.Message);

},

OnReceive = (e) => { }

}

.SetOnClientSubscribe((e) =>

{

var peerId = e.SubscribedClient.ClientId.ToString();

var peerState = e.SubscribedClient.BoundRecords;

conference.Link(peerId, peerState);

Page 52: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

})

.SetOnClientUnsubscribe((e) =>

{

var peerId = e.UnsubscribedClient.ClientId.ToString();

conference.Unlink(peerId);

}));

Note that when calling Conference.Link, you must supply a unique peer ID. This string can be anything

that uniquely identifies the remote peer. This should be the remote WebSync client ID when using

WebSync, the remote SIP client ID when using SIP, the remote XMPP client ID when using XMPP... You

get the idea. That's it! Load 'er up and watch the magic!

Creating a Conference: Xamarin.iOS

The Xamarin.iOS SDK provides a complete peer-to-peer (P2P) streaming solution, including a

partial WebRTC stack for rapidly creating data-channel streams that can be consumed natively in modern

web browsers.

To get started, you'll need to add some assemblies from the SDK to your project references (Xamarin

Studio, Visual Studio, MonoDevelop):

Eyeball.dll (supporting code) Eyeball.Messenger.dll (Messenger core) Eyeball.Messenger.WebRTC.dll (WebRTC stack, optional)

Now let's write some code! (See Xamarin.iOS.Client and Xamarin.iOS.Client.DataChannels in the SDK

Examples folder.)

Part 1: Stream Descriptions

The first step is to describe the streams we want to use. Stream descriptions are used to define the types

of media we are going to be sending back and forth between peers in a conference. Messenger allows us

to createcustom streams with any number of possible data formats. The WebRTC extension allows us to

Page 53: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

create audio, video, and data-channel streams. You can mix and match custom and WebRTC streams,

but only WebRTC streams can be consumed natively by web browsers.

Part 1a: Custom Stream Descriptions

Custom stream descriptions require a "stream type" and one or more "stream formats". The stream type

is used in the SDP offer/answer to help differentiate between multiple streams (audio, video,

application/binary, etc.). The stream format is used in the SDP offer/answer to help differentiate between

multiple data formats supported for a given stream (i.e. G.711, G.722, Opus, etc. for audio).

// Create a custom stream description that indicates text

// data will be sent using a format labelled "utf8".

var customStream = new Eyeball.Messenger.Stream(StreamType.Application, new StreamFormat("utf8"));

customStream.OnLinkReceiveRTP += (e)

{

Alert(Encoding.UTF8.GetString(e.Packet.Payload));

};

// To send custom stream data, use Conference.SendRTP

// once you have created a conference (see Part 2):

// <code>

// conference.SendRTP(customStream.Format, new RTPPacket(Encoding.UTF8.GetBytes("Hello, world!")));

// </code>

// TO BE CONTINUED...

Part 1b: WebRTC Data-Channel Stream Description

WebRTC data-channel streams are easy. Describe one or more data channels (name + message

handler) and pass them into the stream description.

Page 54: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Create a WebRTC data channel description, including a

// handler for processing received messages.

var dataChannelInfo = new Eyeball.Messenger.WebRTC.DataChannelInfo("mydatachannel")

{

OnReceive = (e) =>

{

Alert(e.Data);

}

};

// Create a WebRTC data channel stream description using

// our data channel.

var dataChannelStream = new Eyeball.Messenger.WebRTC.DataChannelStream(dataChannelInfo);

// To send data-channel stream data, use Conference.SendData

// once you have created a conference (see Part 2):

// <code>

// conference.SendData(dataChannelInfo, "Hello, world!");

// </code>

// TO BE CONTINUED...

Part 2: The Conference

Now that we have some stream descriptions, we are ready to create a conference - the hub that

manages your P2P links.

Page 55: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Conferences require the address/port of a STUN/TURN server. STUN provides a way for peers to discover

their public IP addresses, and TURN provides a way to relay data through highly restrictive firewalls.

Messenger comes bundled with a STUN/TURN server implementation, so you can run your own if you

have access to a computer that is directly exposed to the public Internet. Alternatively, there

are several public STUN servers that are free-to-use. Free TURN servers are more difficult to find, since

relaying with TURN can consume significant server bandwidth.

// CONTINUED FROM ABOVE...

// Create a conference using our stream descriptions. Replace

// 127.0.0.1 : 3478 with your STUN/TURN (Messenger) server address.

var conference = new Eyeball.Messenger.Conference("127.0.0.1", 3478, dataChannelStream);

// Supply TURN relay credentials in case we are behind a

// highly restrictive firewall. These credentials will be

// verified by the TURN server.

conference.RelayUsername = "test";

conference.RelayPassword = "pa55w0rd!";

// Add a few event handlers to the conference so we can see

// when a new P2P link is created or changes state.

conference.OnLinkInit += (e) =>

{

Console.WriteLine("Link to peer initializing...");

};

conference.OnLinkUp += (e) =>

{

Console.WriteLine("Link to peer is UP.");

Page 56: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

};

conference.OnLinkDown += (e) =>

{

Console.WriteLine("Link to peer is DOWN. " + e.Exception.Message);

};

// TO BE CONTINUED...

Part 3: Signalling

With our conference in hand, we are almost done! Just one more thing to set up.

Before we can create a P2P link, the peers have to exchange some information - specifically descriptions

of the streams (called the offer/answer) and some local network addresses (called candidates).

Messengergenerates this information automatically, but you are responsible for distributing it to the

peer as quickly as possible. This is called "signalling".

We're going to use WebSync here, but other popular options include SIP and XMPP - any real-time

messaging system will do. We use WebSync since it uses HTTP (WebSockets/long-polling) and therefore

has no issues with firewalls or connecting from JavaScript-based web applications.

// CONTINUED FROM ABOVE...

// Create a WebSync client and establish a persistent

// connection to the server. Replace localhost with your

// WebSync server address.

var client = new Eyeball.WebSync.Client("http://localhost/websync.ashx");

client.Connect(new ConnectArgs()

{

OnFailure = (e) =>

{

Page 57: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Alert("Could not connect to WebSync. " + e.Exception.Message);

});

});

// Add a couple event handlers to the conference to send

// generated offers/answers and candidates to a peer.

// The peer ID is something we define later. In this case,

// it represents the remote WebSync client ID. WebSync's

// "notify" method is used to send data to a specific client.

conference.OnLinkOfferAnswer += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.OfferAnswer.ToJson(), "offeranswer"));

};

conference.OnLinkCandidate += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.Candidate.ToJson(), "candidate"));

};

// Add an event handler to the WebSync client to receive

// incoming offers/answers and candidates from a peer.

// Call the "ReceiveOfferAnswer" or "ReceiveCandidate"

// method to pass the information to the conference.

client.OnNotify += (e) =>

{

var peerId = e.NotifyingClient.ClientId.ToString();

var peerState = e.NotifyingClient.BoundRecords;

Page 58: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

if (e.Tag == "offeranswer")

{

conference.ReceiveOfferAnswer(OfferAnswer.FromJson(e.DataJson), peerId, peerState);

}

else if (e.Tag == "candidate")

{

conference.ReceiveCandidate(Candidate.FromJson(e.DataJson), peerId);

}

};

// TO BE CONTINUED...

Part 4: Kicking It Off

Everything is set now. We just need to start the process by having one of the peers

call Conference.Link. That peer becomes the "controlling agent". The other peer becomes the

"controlled agent" and creates a P2P link automatically when it receives the controlling agent's offer.

Here's a detailed breakdown of what happens:

Peer A: The conference will raise the OnLinkInit event. Peer A: Messenger will generate an offer and raise the OnOfferAnswer event.

Peer A: Our event handler will use WebSync's Notify method to send that offer to the peer. Peer B: Our event handler will receive that offer and call Conference.ReceiveOfferAnswer.

Peer B: The conference will raise the OnLinkInit event.

Peer B: Messenger will generate an answer and raise the OnOfferAnswer event. Peer B: Our event handler will use WebSync's Notify method to send that answer to the peer.

Peer A: Our event handler will receive that answer and call Conference.ReceiveOfferAnswer. Peer A/B: Messenger will generate candidates and raise the OnCandidate event.

Peer A/B: Our event handler will use WebSync's Notify method to send those candidates to the peer. Peer A/B: Our event handler will receive those candidates and call Conference.ReceiveCandidate.

Peer A/B: Messenger will successfully establish a P2P link.

Peer A/B: The conference will raise the OnLinkUp event.

If the P2P link could not be established, the conference will raise the OnLinkDown event. The event

arguments will include an Exception property with details. The most common reason for a link failure is

Page 59: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

a misconfiguration on the server. (Server address or port is wrong, server firewall is blocking UDP traffic,

server is on the same network as one of the clients, server is not publicly accessible, etc.)

If you are having trouble setting up your Messenger server, try using our public server, located

at messenger.eyeball.com : 3478.

A common scenario when using a pub-sub framework like WebSync is to create a P2P link whenever two

peers join the same channel (and destroy that link when one peer leaves).

// CONTINUED FROM ABOVE...

// Subscribe to a WebSync channel. When another client joins the same

// channel, create a P2P link. When a client leaves, destroy it.

client.Subscribe(new SubscribeArgs("/mychannel")

{

OnFailure = (e) =>

{

Alert("Could not subscribe to " + e.Channel + ". " + e.Exception.Message);

},

OnReceive = (e) => { }

}

.SetOnClientSubscribe((e) =>

{

var peerId = e.SubscribedClient.ClientId.ToString();

var peerState = e.SubscribedClient.BoundRecords;

conference.Link(peerId, peerState);

})

.SetOnClientUnsubscribe((e) =>

{

Page 60: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

var peerId = e.UnsubscribedClient.ClientId.ToString();

conference.Unlink(peerId);

}));

Note that when calling Conference.Link, you must supply a unique peer ID. This string can be anything

that uniquely identifies the remote peer. This should be the remote WebSync client ID when using

WebSync, the remote SIP client ID when using SIP, the remote XMPP client ID when using XMPP... You

get the idea. That's it! Load 'er up and watch the magic!

Page 61: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Creating a Conference: .NET, .NET Compact, and Mono

The .NET SDK provides a complete peer-to-peer (P2P) streaming solution, including a

complete WebRTC stack for rapidly creating audio, video, and data-channel streams that can be

consumed natively in modern web browsers.

To get started, you'll need to add some assemblies from the SDK to your project references (Visual

Studio, MonoDevelop):

Eyeball.dll (supporting code) Eyeball.Messenger.dll (Messenger core) Eyeball.Messenger.WebRTC.dll (WebRTC stack, optional)

Now let's write some code! (See NET.Client, NET.Client.WebRTC, and NET.Client.DataChannels in the

SDK Examples folder.)

Part 1: Stream Descriptions

The first step is to describe the streams we want to use. Stream descriptions are used to define the types

of media we are going to be sending back and forth between peers in a conference. Messenger allows us

to createcustom streams with any number of possible data formats. The WebRTC extension allows us to

create audio, video, and data-channel streams. You can mix and match custom and WebRTC streams,

but only WebRTC streams can be consumed natively by web browsers.

Part 1a: Custom Stream Descriptions

Page 62: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Custom stream descriptions require a "stream type" and one or more "stream formats". The stream type

is used in the SDP offer/answer to help differentiate between multiple streams (audio, video,

application/binary, etc.). The stream format is used in the SDP offer/answer to help differentiate between

multiple data formats supported for a given stream (i.e. G.711, G.722, Opus, etc. for audio).

// Create a custom stream description that indicates text

// data will be sent using a format labelled "utf8".

var customStream = new Eyeball.Messenger.Stream(StreamType.Application, new StreamFormat("utf8"));

customStream.OnLinkReceiveRTP += (e)

{

Alert(Encoding.UTF8.GetString(e.Packet.Payload));

};

// To send custom stream data, use Conference.SendRTP

// once you have created a conference (see Part 2):

// <code>

// conference.SendRTP(customStream.Format, new RTPPacket(Encoding.UTF8.GetBytes("Hello, world!")));

// </code>

// TO BE CONTINUED...

Part 1b: WebRTC Data-Channel Stream Description

WebRTC data-channel streams are easy. Describe one or more data channels (name + message

handler) and pass them into the stream description.

// Create a WebRTC data channel description, including a

// handler for processing received messages.

var dataChannelInfo = new Eyeball.Messenger.WebRTC.DataChannelInfo("mydatachannel")

Page 63: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

OnReceive = (e) =>

{

Alert(e.Data);

}

};

// Create a WebRTC data channel stream description using

// our data channel.

var dataChannelStream = new Eyeball.Messenger.WebRTC.DataChannelStream(dataChannelInfo);

// To send data-channel stream data, use Conference.SendData

// once you have created a conference (see Part 2):

// <code>

// conference.SendData(dataChannelInfo, "Hello, world!");

// </code>

// TO BE CONTINUED...

Part 1c: WebRTC Audio/Video Stream Descriptions

WebRTC audio and video stream descriptions require a reference to the local media (microphone,

camera, or both), obtained by calling UserMedia.GetMedia.

// WebRTC has chosen VP8 as its mandatory video codec.

// Since video encoding is best done using native code,

// reference the video codec at the application-level.

// This is required when using a WebRTC video stream.

Page 64: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Eyeball.Messenger.WebRTC.VideoStream.RegisterCodec("VP8", () =>

{

return new Win.VP8.Codec();

}, true);

// WebRTC audio and video streams require us to first get access to

// the local media (microphone, camera, or both).

Eyeball.Messenger.WebRTC.UserMedia.GetMedia(new GetMediaArgs(true, true)

{

// Specify an audio capture provider, a video

// capture provider, an audio render provider,

// and a video render provider. The Messenger

// SDK comes bundled with video support for

// WinForms and WPF, and uses NAudio for audio

// support. For lower latency audio, use ASIO.

AudioCaptureProvider = new NAudioCaptureProvider(),

VideoCaptureProvider = new AForgeVideoCaptureProvider(),

CreateAudioRenderProvider = () =>

{

return new NAudioRenderProvider();

},

CreateVideoRenderProvider = () =>

{

return new PictureBoxVideoRenderProvider();

},

VideoWidth = 320, // optional

VideoHeight = 240, // optional

Page 65: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

VideoFrameRate = 30, // optional

OnFailure = (e) =>

{

Alert("Could not get media. {0}", e.Exception.Message);

},

OnSuccess = (ea) =>

{

// We have successfully acquired access to the local

// audio/video device! Grab a reference to the media.

// Internally, it maintains access to the local audio

// and video feeds coming from the device hardware.

var localMedia = ea.LocalStream;

// This is our local video control, a WinForms Control or

// WPF FrameworkElement. It is constantly updated with

// our live video feed since we requested video above.

// Add it directly to the UI or use the Messenger layout

// manager, which we do below.

var localVideoControl = ea.LocalVideoControl;

// Create an Messenger layout manager, which makes the task

// of arranging video controls easy. Give it a reference

// to a WinForms control that can be filled with video feeds.

// For WPF users, the WebRTC extension includes

// WpfLayoutManager, which accepts a Canvas.

var layoutManager = new Eyeball.Messenger.WebRTC.LayoutManager(container);

Page 66: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Position and display the local video control on-screen

// by passing it to the layout manager created above.

layoutManager.SetLocalVideoControl(localVideoControl);

// Create a WebRTC audio stream description (requires a

// reference to the local audio feed).

var audioStream = new Eyeball.Messenger.WebRTC.AudioStream(localMedia);

// Create a WebRTC video stream description (requires a

// reference to the local video feed). Whenever a P2P link

// initializes using this description, position and display

// the remote video control on-screen by passing it to the

// layout manager created above. Whenever a P2P link goes

// down, remove it.

var videoStream = new Eyeball.Messenger.WebRTC.VideoStream(localMedia);

videoStream.OnLinkInit += (e) =>

{

var remoteVideoControl = e.Link.GetRemoteVideoControl();

layoutManager.AddRemoteVideoControl(e.PeerId, remoteVideoControl);

};

videoStream.OnLinkDown += (e) =>

{

layoutManager.RemoveRemoteVideoControl(e.PeerId);

};

// TO BE CONTINUED...

Page 67: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Part 2: The Conference

Now that we have some stream descriptions, we are ready to create a conference - the hub that

manages your P2P links.

Conferences require the address/port of a STUN/TURN server. STUN provides a way for peers to discover

their public IP addresses, and TURN provides a way to relay data through highly restrictive firewalls.

Messenger comes bundled with a STUN/TURN server implementation, so you can run your own if you

have access to a computer that is directly exposed to the public Internet. Alternatively, there

are several public STUN servers that are free-to-use. Free TURN servers are more difficult to find, since

relaying with TURN can consume significant server bandwidth.

// CONTINUED FROM ABOVE...

// Create a conference using our stream descriptions. Replace

// 127.0.0.1 : 3478 with your STUN/TURN (Messenger) server address.

var conference = new Eyeball.Messenger.Conference("127.0.0.1", 3478, new[] { audioStream, videoStream, dataChannelStream });

// Supply TURN relay credentials in case we are behind a

// highly restrictive firewall. These credentials will be

// verified by the TURN server.

conference.RelayUsername = "test";

conference.RelayPassword = "pa55w0rd!";

// Add a few event handlers to the conference so we can see

// when a new P2P link is created or changes state.

conference.OnLinkInit += (e) =>

{

Console.WriteLine("Link to peer initializing...");

Page 68: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

};

conference.OnLinkUp += (e) =>

{

Console.WriteLine("Link to peer is UP.");

};

conference.OnLinkDown += (e) =>

{

Console.WriteLine("Link to peer is DOWN. " + e.Exception.Message);

};

// TO BE CONTINUED...

Part 3: Signalling

With our conference in hand, we are almost done! Just one more thing to set up.

Before we can create a P2P link, the peers have to exchange some information - specifically descriptions

of the streams (called the offer/answer) and some local network addresses (called candidates).

Messengergenerates this information automatically, but you are responsible for distributing it to the

peer as quickly as possible. This is called "signalling".

We're going to use WebSync here, but other popular options include SIP and XMPP - any real-time

messaging system will do. We use WebSync since it uses HTTP (WebSockets/long-polling) and therefore

has no issues with firewalls or connecting from JavaScript-based web applications.

// CONTINUED FROM ABOVE...

// Create a WebSync client and establish a persistent

// connection to the server. Replace localhost with your

// WebSync server address.

var client = new Eyeball.WebSync.Client("http://localhost/websync.ashx");

Page 69: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

client.Connect(new ConnectArgs()

{

OnFailure = (e) =>

{

Alert("Could not connect to WebSync. " + e.Exception.Message);

});

});

// Add a couple event handlers to the conference to send

// generated offers/answers and candidates to a peer.

// The peer ID is something we define later. In this case,

// it represents the remote WebSync client ID. WebSync's

// "notify" method is used to send data to a specific client.

conference.OnLinkOfferAnswer += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.OfferAnswer.ToJson(), "offeranswer"));

};

conference.OnLinkCandidate += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.Candidate.ToJson(), "candidate"));

};

// Add an event handler to the WebSync client to receive

// incoming offers/answers and candidates from a peer.

// Call the "ReceiveOfferAnswer" or "ReceiveCandidate"

// method to pass the information to the conference.

Page 70: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

client.OnNotify += (e) =>

{

var peerId = e.NotifyingClient.ClientId.ToString();

var peerState = e.NotifyingClient.BoundRecords;

if (e.Tag == "offeranswer")

{

conference.ReceiveOfferAnswer(OfferAnswer.FromJson(e.DataJson), peerId, peerState);

}

else if (e.Tag == "candidate")

{

conference.ReceiveCandidate(Candidate.FromJson(e.DataJson), peerId);

}

};

// TO BE CONTINUED...

Part 4: Kicking It Off

Everything is set now. We just need to start the process by having one of the peers

call Conference.Link. That peer becomes the "controlling agent". The other peer becomes the

"controlled agent" and creates a P2P link automatically when it receives the controlling agent's offer.

Here's a detailed breakdown of what happens:

Peer A: The conference will raise the OnLinkInit event. Peer A: Messenger will generate an offer and raise the OnOfferAnswer event.

Peer A: Our event handler will use WebSync's Notify method to send that offer to the peer. Peer B: Our event handler will receive that offer and call Conference.ReceiveOfferAnswer.

Peer B: The conference will raise the OnLinkInit event.

Peer B: Messenger will generate an answer and raise the OnOfferAnswer event. Peer B: Our event handler will use WebSync's Notify method to send that answer to the peer.

Peer A: Our event handler will receive that answer and call Conference.ReceiveOfferAnswer. Peer A/B: Messenger will generate candidates and raise the OnCandidate event.

Peer A/B: Our event handler will use WebSync's Notify method to send those candidates to the peer.

Page 71: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Peer A/B: Our event handler will receive those candidates and call Conference.ReceiveCandidate.

Peer A/B: Messenger will successfully establish a P2P link. Peer A/B: The conference will raise the OnLinkUp event.

If the P2P link could not be established, the conference will raise the OnLinkDown event. The event

arguments will include an Exception property with details. The most common reason for a link failure is

a misconfiguration on the server. (Server address or port is wrong, server firewall is blocking UDP traffic,

server is on the same network as one of the clients, server is not publicly accessible, etc.)

If you are having trouble setting up your Messenger server, try using our public server, located

at messenger.eyeball.com : 3478.

A common scenario when using a pub-sub framework like WebSync is to create a P2P link whenever two

peers join the same channel (and destroy that link when one peer leaves).

// CONTINUED FROM ABOVE...

// Subscribe to a WebSync channel. When another client joins the same

// channel, create a P2P link. When a client leaves, destroy it.

client.Subscribe(new SubscribeArgs("/mychannel")

{

OnFailure = (e) =>

{

Alert("Could not subscribe to " + e.Channel + ". " + e.Exception.Message);

},

OnReceive = (e) => { }

}

.SetOnClientSubscribe((e) =>

{

var peerId = e.SubscribedClient.ClientId.ToString();

var peerState = e.SubscribedClient.BoundRecords;

Page 72: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

conference.Link(peerId, peerState);

})

.SetOnClientUnsubscribe((e) =>

{

var peerId = e.UnsubscribedClient.ClientId.ToString();

conference.Unlink(peerId);

}));

}

});

Note that when calling Conference.Link, you must supply a unique peer ID. This string can be anything

that uniquely identifies the remote peer. This should be the remote WebSync client ID when using

WebSync, the remote SIP client ID when using SIP, the remote XMPP client ID when using XMPP... You

get the idea.

That's it! Load 'er up and watch the magic!

Page 73: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Creating a Conference: Windows Phone

The Windows Phone SDK provides a complete peer-to-peer (P2P) streaming solution, including a

partial WebRTC stack for rapidly creating data-channel streams that can be consumed natively in modern

web browsers.

To get started, you'll need to add some assemblies from the SDK to your project references (Visual

Studio):

Eyeball.dll (supporting code) Eyeball.Messenger.dll (Messenger core) Eyeball.Messenger.WebRTC.dll (WebRTC stack, optional)

Now let's write some code! (See WindowsPhone.Client and WindowsPhone.Client.DataChannels in the

SDK Examples folder.)

Part 1: Stream Descriptions

The first step is to describe the streams we want to use. Stream descriptions are used to define the types

of media we are going to be sending back and forth between peers in a conference. Messenger allows us

to createcustom streams with any number of possible data formats. The WebRTC extension allows us to

create audio, video, and data-channel streams. You can mix and match custom and WebRTC streams,

but only WebRTC streams can be consumed natively by web browsers.

Part 1a: Custom Stream Descriptions

Custom stream descriptions require a "stream type" and one or more "stream formats". The stream type

is used in the SDP offer/answer to help differentiate between multiple streams (audio, video,

Page 74: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

application/binary, etc.). The stream format is used in the SDP offer/answer to help differentiate between

multiple data formats supported for a given stream (i.e. G.711, G.722, Opus, etc. for audio).

// Create a custom stream description that indicates text

// data will be sent using a format labelled "utf8".

var customStream = new Eyeball.Messenger.Stream(StreamType.Application, new StreamFormat("utf8"));

customStream.OnLinkReceiveRTP += (e)

{

Alert(Encoding.UTF8.GetString(e.Packet.Payload));

};

// To send custom stream data, use Conference.SendRTP

// once you have created a conference (see Part 2):

// <code>

// conference.SendRTP(customStream.Format, new RTPPacket(Encoding.UTF8.GetBytes("Hello, world!")));

// </code>

// TO BE CONTINUED...

Part 1b: WebRTC Data-Channel Stream Description

WebRTC data-channel streams are easy. Describe one or more data channels (name + message

handler) and pass them into the stream description.

// Create a WebRTC data channel description, including a

// handler for processing received messages.

var dataChannelInfo = new Eyeball.Messenger.WebRTC.DataChannelInfo("mydatachannel")

{

OnReceive = (e) =>

Page 75: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

Alert(e.Data);

}

};

// Create a WebRTC data channel stream description using

// our data channel.

var dataChannelStream = new Eyeball.Messenger.WebRTC.DataChannelStream(dataChannelInfo);

// To send data-channel stream data, use Conference.SendData

// once you have created a conference (see Part 2):

// <code>

// conference.SendData(dataChannelInfo, "Hello, world!");

// </code>

// TO BE CONTINUED...

Part 2: The Conference

Now that we have some stream descriptions, we are ready to create a conference - the hub that

manages your P2P links.

Conferences require the address/port of a STUN/TURN server. STUN provides a way for peers to discover

their public IP addresses, and TURN provides a way to relay data through highly restrictive firewalls.

Messenger comes bundled with a STUN/TURN server implementation, so you can run your own if you

have access to a computer that is directly exposed to the public Internet. Alternatively, there

are several public STUN servers that are free-to-use. Free TURN servers are more difficult to find, since

relaying with TURN can consume significant server bandwidth.

// CONTINUED FROM ABOVE...

Page 76: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Create a conference using our stream descriptions. Replace

// 127.0.0.1 : 3478 with your STUN/TURN (Messenger) server address.

var conference = new Eyeball.Messenger.Conference("127.0.0.1", 3478, dataChannelStream);

// Supply TURN relay credentials in case we are behind a

// highly restrictive firewall. These credentials will be

// verified by the TURN server.

conference.RelayUsername = "test";

conference.RelayPassword = "pa55w0rd!";

// Add a few event handlers to the conference so we can see

// when a new P2P link is created or changes state.

conference.OnLinkInit += (e) =>

{

Console.WriteLine("Link to peer initializing...");

};

conference.OnLinkUp += (e) =>

{

Console.WriteLine("Link to peer is UP.");

};

conference.OnLinkDown += (e) =>

{

Console.WriteLine("Link to peer is DOWN. " + e.Exception.Message);

};

Page 77: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// TO BE CONTINUED...

Part 3: Signalling

With our conference in hand, we are almost done! Just one more thing to set up.

Before we can create a P2P link, the peers have to exchange some information - specifically descriptions

of the streams (called the offer/answer) and some local network addresses (called candidates).

Messengergenerates this information automatically, but you are responsible for distributing it to the

peer as quickly as possible. This is called "signalling".

We're going to use WebSync here, but other popular options include SIP and XMPP - any real-time

messaging system will do. We use WebSync since it uses HTTP (WebSockets/long-polling) and therefore

has no issues with firewalls or connecting from JavaScript-based web applications.

// CONTINUED FROM ABOVE...

// Create a WebSync client and establish a persistent

// connection to the server. Replace localhost with your

// WebSync server address.

var client = new Eyeball.WebSync.Client("http://localhost/websync.ashx");

client.Connect(new ConnectArgs()

{

OnFailure = (e) =>

{

Alert("Could not connect to WebSync. " + e.Exception.Message);

});

});

// Add a couple event handlers to the conference to send

// generated offers/answers and candidates to a peer.

Page 78: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// The peer ID is something we define later. In this case,

// it represents the remote WebSync client ID. WebSync's

// "notify" method is used to send data to a specific client.

conference.OnLinkOfferAnswer += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.OfferAnswer.ToJson(), "offeranswer"));

};

conference.OnLinkCandidate += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.Candidate.ToJson(), "candidate"));

};

// Add an event handler to the WebSync client to receive

// incoming offers/answers and candidates from a peer.

// Call the "ReceiveOfferAnswer" or "ReceiveCandidate"

// method to pass the information to the conference.

client.OnNotify += (e) =>

{

var peerId = e.NotifyingClient.ClientId.ToString();

var peerState = e.NotifyingClient.BoundRecords;

if (e.Tag == "offeranswer")

{

conference.ReceiveOfferAnswer(OfferAnswer.FromJson(e.DataJson), peerId, peerState);

}

else if (e.Tag == "candidate")

Page 79: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

conference.ReceiveCandidate(Candidate.FromJson(e.DataJson), peerId);

}

};

// TO BE CONTINUED...

Part 4: Kicking It Off

Everything is set now. We just need to start the process by having one of the peers

call Conference.Link. That peer becomes the "controlling agent". The other peer becomes the

"controlled agent" and creates a P2P link automatically when it receives the controlling agent's offer.

Here's a detailed breakdown of what happens:

Peer A: The conference will raise the OnLinkInit event. Peer A: Messenger will generate an offer and raise the OnOfferAnswer event.

Peer A: Our event handler will use WebSync's Notify method to send that offer to the peer. Peer B: Our event handler will receive that offer and call Conference.ReceiveOfferAnswer.

Peer B: The conference will raise the OnLinkInit event.

Peer B: Messenger will generate an answer and raise the OnOfferAnswer event. Peer B: Our event handler will use WebSync's Notify method to send that answer to the peer.

Peer A: Our event handler will receive that answer and call Conference.ReceiveOfferAnswer. Peer A/B: Messenger will generate candidates and raise the OnCandidate event.

Peer A/B: Our event handler will use WebSync's Notify method to send those candidates to the peer. Peer A/B: Our event handler will receive those candidates and call Conference.ReceiveCandidate.

Peer A/B: Messenger will successfully establish a P2P link.

Peer A/B: The conference will raise the OnLinkUp event.

If the P2P link could not be established, the conference will raise the OnLinkDown event. The event

arguments will include an Exception property with details. The most common reason for a link failure is

a misconfiguration on the server. (Server address or port is wrong, server firewall is blocking UDP traffic,

server is on the same network as one of the clients, server is not publicly accessible, etc.)

If you are having trouble setting up your Messenger server, try using our public server, located

at messenger.eyeball.com : 3478.

Page 80: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

A common scenario when using a pub-sub framework like WebSync is to create a P2P link whenever two

peers join the same channel (and destroy that link when one peer leaves).

// CONTINUED FROM ABOVE...

// Subscribe to a WebSync channel. When another client joins the same

// channel, create a P2P link. When a client leaves, destroy it.

client.Subscribe(new SubscribeArgs("/mychannel")

{

OnFailure = (e) =>

{

Alert("Could not subscribe to " + e.Channel + ". " + e.Exception.Message);

},

OnReceive = (e) => { }

}

.SetOnClientSubscribe((e) =>

{

var peerId = e.SubscribedClient.ClientId.ToString();

var peerState = e.SubscribedClient.BoundRecords;

conference.Link(peerId, peerState);

})

.SetOnClientUnsubscribe((e) =>

{

var peerId = e.UnsubscribedClient.ClientId.ToString();

conference.Unlink(peerId);

}));

Page 81: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Note that when calling Conference.Link, you must supply a unique peer ID. This string can be anything

that uniquely identifies the remote peer. This should be the remote WebSync client ID when using

WebSync, the remote SIP client ID when using SIP, the remote XMPP client ID when using XMPP... You

get the idea. That's it! Load 'er up and watch the magic!

Creating a Conference: Windows 8

The Windows 8 SDK provides a complete peer-to-peer (P2P) streaming solution, including a

partial WebRTC stack for rapidly creating data-channel streams that can be consumed natively in modern

web browsers.

To get started, you'll need to add some assemblies from the SDK to your project references (Visual

Studio):

Eyeball.dll (supporting code) Eyeball.Messenger.dll (Messenger core) Eyeball.Messenger.WebRTC.dll (WebRTC stack, optional)

Now let's write some code! (See Windows8.Client and Windows8.Client.DataChannels in the SDK

Examples folder.)

Part 1: Stream Descriptions

The first step is to describe the streams we want to use. Stream descriptions are used to define the types

of media we are going to be sending back and forth between peers in a conference. Messenger allows us

to createcustom streams with any number of possible data formats. The WebRTC extension allows us to

create audio, video, and data-channel streams. You can mix and match custom and WebRTC streams,

but only WebRTC streams can be consumed natively by web browsers.

Part 1a: Custom Stream Descriptions

Custom stream descriptions require a "stream type" and one or more "stream formats". The stream type

is used in the SDP offer/answer to help differentiate between multiple streams (audio, video,

application/binary, etc.). The stream format is used in the SDP offer/answer to help differentiate between

multiple data formats supported for a given stream (i.e. G.711, G.722, Opus, etc. for audio).

Page 82: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Create a custom stream description that indicates text

// data will be sent using a format labelled "utf8".

var customStream = new Eyeball.Messenger.Stream(StreamType.Application, new StreamFormat("utf8"));

customStream.OnLinkReceiveRTP += (e)

{

Alert(Encoding.UTF8.GetString(e.Packet.Payload));

};

// To send custom stream data, use Conference.SendRTP

// once you have created a conference (see Part 2):

// <code>

// conference.SendRTP(customStream.Format, new RTPPacket(Encoding.UTF8.GetBytes("Hello, world!")));

// </code>

// TO BE CONTINUED...

Part 1b: WebRTC Data-Channel Stream Description

WebRTC data-channel streams are easy. Describe one or more data channels (name + message

handler) and pass them into the stream description.

// Create a WebRTC data channel description, including a

// handler for processing received messages.

var dataChannelInfo = new Eyeball.Messenger.WebRTC.DataChannelInfo("mydatachannel")

{

OnReceive = (e) =>

{

Alert(e.Data);

Page 83: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

}

};

// Create a WebRTC data channel stream description using

// our data channel.

var dataChannelStream = new Eyeball.Messenger.WebRTC.DataChannelStream(dataChannelInfo);

// To send data-channel stream data, use Conference.SendData

// once you have created a conference (see Part 2):

// <code>

// conference.SendData(dataChannelInfo, "Hello, world!");

// </code>

// TO BE CONTINUED...

Part 2: The Conference

Now that we have some stream descriptions, we are ready to create a conference - the hub that

manages your P2P links.

Conferences require the address/port of a STUN/TURN server. STUN provides a way for peers to discover

their public IP addresses, and TURN provides a way to relay data through highly restrictive firewalls.

Messenger comes bundled with a STUN/TURN server implementation, so you can run your own if you

have access to a computer that is directly exposed to the public Internet. Alternatively, there

are several public STUN servers that are free-to-use. Free TURN servers are more difficult to find, since

relaying with TURN can consume significant server bandwidth.

// CONTINUED FROM ABOVE...

// Create a conference using our stream descriptions. Replace

Page 84: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// 127.0.0.1 : 3478 with your STUN/TURN (Messenger) server address.

var conference = new Eyeball.Messenger.Conference("127.0.0.1", 3478, dataChannelStream);

// Supply TURN relay credentials in case we are behind a

// highly restrictive firewall. These credentials will be

// verified by the TURN server.

conference.RelayUsername = "test";

conference.RelayPassword = "pa55w0rd!";

// Add a few event handlers to the conference so we can see

// when a new P2P link is created or changes state.

conference.OnLinkInit += (e) =>

{

Console.WriteLine("Link to peer initializing...");

};

conference.OnLinkUp += (e) =>

{

Console.WriteLine("Link to peer is UP.");

};

conference.OnLinkDown += (e) =>

{

Console.WriteLine("Link to peer is DOWN. " + e.Exception.Message);

};

// TO BE CONTINUED...

Part 3: Signalling

Page 85: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

With our conference in hand, we are almost done! Just one more thing to set up.

Before we can create a P2P link, the peers have to exchange some information - specifically descriptions

of the streams (called the offer/answer) and some local network addresses (called candidates).

Messengergenerates this information automatically, but you are responsible for distributing it to the

peer as quickly as possible. This is called "signalling".

We're going to use WebSync here, but other popular options include SIP and XMPP - any real-time

messaging system will do. We use WebSync since it uses HTTP (WebSockets/long-polling) and therefore

has no issues with firewalls or connecting from JavaScript-based web applications.

// CONTINUED FROM ABOVE...

// Create a WebSync client and establish a persistent

// connection to the server. Replace localhost with your

// WebSync server address.

var client = new Eyeball.WebSync.Client("http://localhost/websync.ashx");

client.Connect(new ConnectArgs()

{

OnFailure = (e) =>

{

Alert("Could not connect to WebSync. " + e.Exception.Message);

});

});

// Add a couple event handlers to the conference to send

// generated offers/answers and candidates to a peer.

// The peer ID is something we define later. In this case,

// it represents the remote WebSync client ID. WebSync's

Page 86: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// "notify" method is used to send data to a specific client.

conference.OnLinkOfferAnswer += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.OfferAnswer.ToJson(), "offeranswer"));

};

conference.OnLinkCandidate += (e) =>

{

client.Notify(new NotifyArgs(new Guid(e.PeerId), e.Candidate.ToJson(), "candidate"));

};

// Add an event handler to the WebSync client to receive

// incoming offers/answers and candidates from a peer.

// Call the "ReceiveOfferAnswer" or "ReceiveCandidate"

// method to pass the information to the conference.

client.OnNotify += (e) =>

{

var peerId = e.NotifyingClient.ClientId.ToString();

var peerState = e.NotifyingClient.BoundRecords;

if (e.Tag == "offeranswer")

{

conference.ReceiveOfferAnswer(OfferAnswer.FromJson(e.DataJson), peerId, peerState);

}

else if (e.Tag == "candidate")

{

conference.ReceiveCandidate(Candidate.FromJson(e.DataJson), peerId);

Page 87: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

}

};

// TO BE CONTINUED...

Part 4: Kicking It Off

Everything is set now. We just need to start the process by having one of the peers

call Conference.Link. That peer becomes the "controlling agent". The other peer becomes the

"controlled agent" and creates a P2P link automatically when it receives the controlling agent's offer.

Here's a detailed breakdown of what happens:

Peer A: The conference will raise the OnLinkInit event. Peer A: Messenger will generate an offer and raise the OnOfferAnswer event.

Peer A: Our event handler will use WebSync's Notify method to send that offer to the peer. Peer B: Our event handler will receive that offer and call Conference.ReceiveOfferAnswer.

Peer B: The conference will raise the OnLinkInit event.

Peer B: Messenger will generate an answer and raise the OnOfferAnswer event. Peer B: Our event handler will use WebSync's Notify method to send that answer to the peer.

Peer A: Our event handler will receive that answer and call Conference.ReceiveOfferAnswer. Peer A/B: Messenger will generate candidates and raise the OnCandidate event.

Peer A/B: Our event handler will use WebSync's Notify method to send those candidates to the peer. Peer A/B: Our event handler will receive those candidates and call Conference.ReceiveCandidate.

Peer A/B: Messenger will successfully establish a P2P link.

Peer A/B: The conference will raise the OnLinkUp event.

If the P2P link could not be established, the conference will raise the OnLinkDown event. The event

arguments will include an Exception property with details. The most common reason for a link failure is

a misconfiguration on the server. (Server address or port is wrong, server firewall is blocking UDP traffic,

server is on the same network as one of the clients, server is not publicly accessible, etc.)

If you are having trouble setting up your Messenger server, try using our public server, located

at messenger.eyeball.com : 3478.

A common scenario when using a pub-sub framework like WebSync is to create a P2P link whenever two

peers join the same channel (and destroy that link when one peer leaves).

// CONTINUED FROM ABOVE...

Page 88: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Subscribe to a WebSync channel. When another client joins the same

// channel, create a P2P link. When a client leaves, destroy it.

client.Subscribe(new SubscribeArgs("/mychannel")

{

OnFailure = (e) =>

{

Alert("Could not subscribe to " + e.Channel + ". " + e.Exception.Message);

},

OnReceive = (e) => { }

}

.SetOnClientSubscribe((e) =>

{

var peerId = e.SubscribedClient.ClientId.ToString();

var peerState = e.SubscribedClient.BoundRecords;

conference.Link(peerId, peerState);

})

.SetOnClientUnsubscribe((e) =>

{

var peerId = e.UnsubscribedClient.ClientId.ToString();

conference.Unlink(peerId);

}));

Note that when calling Conference.Link, you must supply a unique peer ID. This string can be anything

that uniquely identifies the remote peer. This should be the remote WebSync client ID when using

WebSync, the remote SIP client ID when using SIP, the remote XMPP client ID when using XMPP... You

get the idea.

Page 89: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

That's it! Load 'er up and watch the magic!

Creating a Server: iOS and MAC

Running an Messenger server on iOS or Mac is simple. Remember that the server runs on port 3478 by

default, and this port must be publicly accessible for incoming UDP packets.

Page 90: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

1. Add libraries to your project:

1. libEyeball.a 2. libEyeballMessenger.a

2. Add headers to your project: 0. Eyeball.h

1. EyeballMessenger.h

3. Add dependencies to your project: 0. libz.dylib

1. iOS only: 1. CFNetwork.framework

4. Add "-all_load" to "Other Linker Flags" under the target's build settings. 5. Write some code!

#import "Eyeball.h"

#import "EyeballMessenger.h"

...

- (void)run

{

// Create a new Messenger server.

_server = [[EyeballMessengerServer alloc] init];

// It is not always possible to establish a direct connection

// between peers. If both clients are using symmetric firewalls,

// or if one client is using a symmetric firewall and the other

// is using a port-restricted cone firewall, the only way for

// them to communicate is through a relay. An Messenger server is

// capable of relaying data packets, but it requires that client

// requests be authenticated. (Otherwise, a malicious user could

// launch a Denial-of-Service attack by sending a steady flow

// of unauthenticated socket allocation requests.) You can

Page 91: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// hard-code a username/password into your client application

// or use dynamic credentials, but some form of authentication

// must exist.

[_server enableRelayWithRelayAuthenticateBlock:^EyeballMessengerRelayAuthenticateResult *(EyeballMessengerRelayAuthenticateArgs *e)

{

// This is our authentication callback. It will be invoked

// whenever a request is received that changes the state of

// the relay (allocating a socket on the relay, creating a

// new permission for a socket on the relay, etc.). The

// Username and Realm properties of the event arguments are

// those supplied by the client. If the Username or Realm

// is invalid, simply return null. Otherwise, return a new

// RelayAuthenticateResult which will be used to authenticate

// the request.

if ([e.username isEqualToString:@"test"])

{

// Option A: return the MD5 hash of the following string:

// "username:realm:password"

// This is only possible if you are storing this hash

// somewhere, calculated at a time when the user supplied

// you momentarily with their password. This hash is

// known as a long-term key, and a utility method is

// available in the EyeballMessengerSTUN class to create one.

return [[[EyeballMessengerRelayAuthenticateResult alloc] initWithLongTermKeyBytes:[EyeballMessengerSTUN createLongTermKeyWithUsername:e.username realm:e.realm password:@"pa55w0rd!"]] autorelease];

Page 92: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Option B: return the user's password in plain-text.

// This is only possible if you are storing the user's

// password somewhere in plain-text, so this approach

// has obvious security risk if your server is hacked.

//return [[[EyeballMessengerRelayAuthenticateResult alloc] initWithPassword:@"pa55w0rd!"] autorelease];

// This method of authentication is required by the TURN

// specification which Messenger implements for third-party

// compatibility. Either option is acceptable according to

// TURN, so the choice of which one to use is up to you.

}

return nil;

}];

// Start the Messenger server on the default port (3478). Make sure

// this port is open for incoming UDP packets in your firewall.

[_server start];

}

Creating a Server: Java

Running an Messenger server on Java is simple. Remember that the server runs on port 3478 by default,

and this port must be publicly accessible for incoming UDP packets.

Page 93: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

1. Add libraries to your project:

1. eyeball.jar 2. eyeball.messenger.jar

2. Write some code!

import eyeball.*;

import eyeball.messenger.*;

...

public void run()

{

// Create a new Messenger server.

Server server = new Server();

// It is not always possible to establish a direct connection

// between peers. If both clients are using symmetric firewalls,

// or if one client is using a symmetric firewall and the other

// is using a port-restricted cone firewall, the only way for

// them to communicate is through a relay. An Messenger server is

// capable of relaying data packets, but it requires that client

// requests be authenticated. (Otherwise, a malicious user could

// launch a Denial-of-Service attack by sending a steady flow

// of unauthenticated socket allocation requests.) You can

// hard-code a username/password into your client application

// or use dynamic credentials, but some form of authentication

// must exist.

server.enableRelay(new SingleFunction()

{

Page 94: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

public RelayAuthenticateResult invoke(RelayAuthenticateArgs e)

{

// This is our authentication callback. It will be invoked

// whenever a request is received that changes the state of

// the relay (allocating a socket on the relay, creating a

// new permission for a socket on the relay, etc.). The

// Username and Realm properties of the event arguments are

// those supplied by the client. If the Username or Realm

// is invalid, simply return null. Otherwise, return a new

// RelayAuthenticateResult which will be used to authenticate

// the request.

if (e.getUsername().equals("test"))

{

// Option A: return the MD5 hash of the following string:

// "username:realm:password"

// This is only possible if you are storing this hash

// somewhere, calculated at a time when the user supplied

// you momentarily with their password. This hash is

// known as a long-term key, and a utility method is

// available in the STUN class to create one.

return new RelayAuthenticateResult(STUN.createLongTermKey(e.getUsername(), e.getRealm(), "pa55w0rd!"));

// Option B: return the user's password in plain-text.

// This is only possible if you are storing the user's

// password somewhere in plain-text, so this approach

// has obvious security risk if your server is hacked.

Page 95: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

//return new RelayAuthenticateResult("pa55w0rd!");

// This method of authentication is required by the TURN

// specification which Messenger implements for third-party

// compatibility. Either option is acceptable according to

// TURN, so the choice of which one to use is up to you.

}

return null;

}

});

// Start the Messenger server on the default port (3478). Make sure

// this port is open for incoming UDP packets in your firewall.

server.start();

}

Creating a Server: Xamarin.Android

Note: when using the Android simulator, localhost is accessible through IP 10.0.2.2.

Page 96: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Running an Messenger server on Xamarin.Android is simple. Remember that the server runs on port 3478

by default, and this port must be publicly accessible for incoming UDP packets.

1. Add libraries to your project: 1. Eyeball.dll

2. Eyeball.Messenger.dll 2. Write some code!

using Eyeball;

using Eyeball.Messenger;

...

public void Run()

{

// Create a new Messenger server.

var server = new Eyeball.Messenger.Server();

// It is not always possible to establish a direct connection

// between peers. If both clients are using symmetric firewalls,

// or if one client is using a symmetric firewall and the other

// is using a port-restricted cone firewall, the only way for

// them to communicate is through a relay. An Messenger server is

// capable of relaying data packets, but it requires that client

// requests be authenticated. (Otherwise, a malicious user could

// launch a Denial-of-Service attack by sending a steady flow

// of unauthenticated socket allocation requests.) You can

// hard-code a username/password into your client application

// or use dynamic credentials, but some form of authentication

// must exist.

Page 97: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

server.EnableRelay((e) =>

{

// This is our authentication callback. It will be invoked

// whenever a request is received that changes the state of

// the relay (allocating a socket on the relay, creating a

// new permission for a socket on the relay, etc.). The

// Username and Realm properties of the event arguments are

// those supplied by the client. If the Username or Realm

// is invalid, simply return null. Otherwise, return a new

// RelayAuthenticateResult which will be used to authenticate

// the request.

if (e.Username == "test")

{

// Option A: return the MD5 hash of the following string:

// "username:realm:password"

// This is only possible if you are storing this hash

// somewhere, calculated at a time when the user supplied

// you momentarily with their password. This hash is

// known as a long-term key, and a utility method is

// available in the STUN class to create one.

return new RelayAuthenticateResult(STUN.CreateLongTermKey(e.Username, e.Realm, "pa55w0rd!"));

// Option B: return the user's password in plain-text.

// This is only possible if you are storing the user's

// password somewhere in plain-text, so this approach

// has obvious security risk if your server is hacked.

Page 98: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

//return new RelayAuthenticateResult("pa55w0rd!");

// This method of authentication is required by the TURN

// specification which Messenger implements for third-party

// compatibility. Either option is acceptable according to

// TURN, so the choice of which one to use is up to you.

}

return null;

});

// Start the Messenger server on the default port (3478). Make sure

// this port is open for incoming UDP packets in your firewall.

server.Start();

}

Creating a Server: Xamarin.iOS

Running an Messenger server on Xamarin.iOS is simple. Remember that the server runs on port 3478 by

default, and this port must be publicly accessible for incoming UDP packets.

1. Add libraries to your project:

1. Eyeball.dll 2. Eyeball.Messenger.dll

2. Write some code!

Page 99: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

using Eyeball;

using Eyeball.Messenger;

...

public void Run()

{

// Create a new Messenger server.

var server = new Eyeball.Messenger.Server();

// It is not always possible to establish a direct connection

// between peers. If both clients are using symmetric firewalls,

// or if one client is using a symmetric firewall and the other

// is using a port-restricted cone firewall, the only way for

// them to communicate is through a relay. An Messenger server is

// capable of relaying data packets, but it requires that client

// requests be authenticated. (Otherwise, a malicious user could

// launch a Denial-of-Service attack by sending a steady flow

// of unauthenticated socket allocation requests.) You can

// hard-code a username/password into your client application

// or use dynamic credentials, but some form of authentication

// must exist.

server.EnableRelay((e) =>

{

// This is our authentication callback. It will be invoked

// whenever a request is received that changes the state of

// the relay (allocating a socket on the relay, creating a

Page 100: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// new permission for a socket on the relay, etc.). The

// Username and Realm properties of the event arguments are

// those supplied by the client. If the Username or Realm

// is invalid, simply return null. Otherwise, return a new

// RelayAuthenticateResult which will be used to authenticate

// the request.

if (e.Username == "test")

{

// Option A: return the MD5 hash of the following string:

// "username:realm:password"

// This is only possible if you are storing this hash

// somewhere, calculated at a time when the user supplied

// you momentarily with their password. This hash is

// known as a long-term key, and a utility method is

// available in the STUN class to create one.

return new RelayAuthenticateResult(STUN.CreateLongTermKey(e.Username, e.Realm, "pa55w0rd!"));

// Option B: return the user's password in plain-text.

// This is only possible if you are storing the user's

// password somewhere in plain-text, so this approach

// has obvious security risk if your server is hacked.

//return new RelayAuthenticateResult("pa55w0rd!");

// This method of authentication is required by the TURN

// specification which Messenger implements for third-party

// compatibility. Either option is acceptable according to

Page 101: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// TURN, so the choice of which one to use is up to you.

}

return null;

});

// Start the Messenger server on the default port (3478). Make sure

// this port is open for incoming UDP packets in your firewall.

server.Start();

}

Creating a Server: .NET, .NET Compact, and Mono

Running an Messenger server on .NET, .NET Compact, or Mono is simple. Remember that the server runs

on port 3478 by default, and this port must be publicly accessible for incoming UDP packets.

1. Add libraries to your project: 1. Eyeball.dll

2. Eyeball.Messenger.dll

Page 102: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

2. Write some code!

using Eyeball;

using Eyeball.Messenger;

...

public void Run()

{

// Create a new Messenger server.

var server = new Eyeball.Messenger.Server();

// It is not always possible to establish a direct connection

// between peers. If both clients are using symmetric firewalls,

// or if one client is using a symmetric firewall and the other

// is using a port-restricted cone firewall, the only way for

// them to communicate is through a relay. An Messenger server is

// capable of relaying data packets, but it requires that client

// requests be authenticated. (Otherwise, a malicious user could

// launch a Denial-of-Service attack by sending a steady flow

// of unauthenticated socket allocation requests.) You can

// hard-code a username/password into your client application

// or use dynamic credentials, but some form of authentication

// must exist.

server.EnableRelay((e) =>

{

// This is our authentication callback. It will be invoked

Page 103: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// whenever a request is received that changes the state of

// the relay (allocating a socket on the relay, creating a

// new permission for a socket on the relay, etc.). The

// Username and Realm properties of the event arguments are

// those supplied by the client. If the Username or Realm

// is invalid, simply return null. Otherwise, return a new

// RelayAuthenticateResult which will be used to authenticate

// the request.

if (e.Username == "test")

{

// Option A: return the MD5 hash of the following string:

// "username:realm:password"

// This is only possible if you are storing this hash

// somewhere, calculated at a time when the user supplied

// you momentarily with their password. This hash is

// known as a long-term key, and a utility method is

// available in the STUN class to create one.

return new RelayAuthenticateResult(STUN.CreateLongTermKey(e.Username, e.Realm, "pa55w0rd!"));

// Option B: return the user's password in plain-text.

// This is only possible if you are storing the user's

// password somewhere in plain-text, so this approach

// has obvious security risk if your server is hacked.

//return new RelayAuthenticateResult("pa55w0rd!");

// This method of authentication is required by the TURN

Page 104: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// specification which Messenger implements for third-party

// compatibility. Either option is acceptable according to

// TURN, so the choice of which one to use is up to you.

}

return null;

});

// Start the Messenger server on the default port (3478). Make sure

// this port is open for incoming UDP packets in your firewall.

server.Start();

}

Creating a Server: Windows Phone

Running an Messenger server on Windows Phone is simple. Remember that the server runs on port 3478

by default, and this port must be publicly accessible for incoming UDP packets.

1. Add libraries to your project:

1. Eyeball.dll 2. Eyeball.Messenger.dll

Page 105: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

2. Write some code!

using Eyeball;

using Eyeball.Messenger;

...

public void Run()

{

// Create a new Messenger server.

var server = new Eyeball.Messenger.Server();

// It is not always possible to establish a direct connection

// between peers. If both clients are using symmetric firewalls,

// or if one client is using a symmetric firewall and the other

// is using a port-restricted cone firewall, the only way for

// them to communicate is through a relay. An Messenger server is

// capable of relaying data packets, but it requires that client

// requests be authenticated. (Otherwise, a malicious user could

// launch a Denial-of-Service attack by sending a steady flow

// of unauthenticated socket allocation requests.) You can

// hard-code a username/password into your client application

// or use dynamic credentials, but some form of authentication

// must exist.

server.EnableRelay((e) =>

{

// This is our authentication callback. It will be invoked

Page 106: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// whenever a request is received that changes the state of

// the relay (allocating a socket on the relay, creating a

// new permission for a socket on the relay, etc.). The

// Username and Realm properties of the event arguments are

// those supplied by the client. If the Username or Realm

// is invalid, simply return null. Otherwise, return a new

// RelayAuthenticateResult which will be used to authenticate

// the request.

if (e.Username == "test")

{

// Option A: return the MD5 hash of the following string:

// "username:realm:password"

// This is only possible if you are storing this hash

// somewhere, calculated at a time when the user supplied

// you momentarily with their password. This hash is

// known as a long-term key, and a utility method is

// available in the STUN class to create one.

return new RelayAuthenticateResult(STUN.CreateLongTermKey(e.Username, e.Realm, "pa55w0rd!"));

// Option B: return the user's password in plain-text.

// This is only possible if you are storing the user's

// password somewhere in plain-text, so this approach

// has obvious security risk if your server is hacked.

//return new RelayAuthenticateResult("pa55w0rd!");

// This method of authentication is required by the TURN

Page 107: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// specification which Messenger implements for third-party

// compatibility. Either option is acceptable according to

// TURN, so the choice of which one to use is up to you.

}

return null;

});

// Start the Messenger server on the default port (3478). Make sure

// this port is open for incoming UDP packets in your firewall.

server.Start();

}

Creating a Server: Windows 8

Running an Messenger server on Windows 8 is simple. Remember that the server runs on port 3478 by

default, and this port must be publicly accessible for incoming UDP packets.

1. Add libraries to your project:

1. Eyeball.dll 2. Eyeball.Messenger.dll

Page 108: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

2. Enable Capabilities in your package manifest (Package.appxmanifest):

0. Internet (Client) 1. Internet (Client & Server)

2. Home or Work Networking 3. Write some code!

using Eyeball;

using Eyeball.Messenger;

...

public void Run()

{

// Create a new Messenger server.

var server = new Eyeball.Messenger.Server();

// It is not always possible to establish a direct connection

// between peers. If both clients are using symmetric firewalls,

// or if one client is using a symmetric firewall and the other

// is using a port-restricted cone firewall, the only way for

// them to communicate is through a relay. An Messenger server is

// capable of relaying data packets, but it requires that client

// requests be authenticated. (Otherwise, a malicious user could

// launch a Denial-of-Service attack by sending a steady flow

// of unauthenticated socket allocation requests.) You can

// hard-code a username/password into your client application

// or use dynamic credentials, but some form of authentication

// must exist.

server.EnableRelay((e) =>

Page 109: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

// This is our authentication callback. It will be invoked

// whenever a request is received that changes the state of

// the relay (allocating a socket on the relay, creating a

// new permission for a socket on the relay, etc.). The

// Username and Realm properties of the event arguments are

// those supplied by the client. If the Username or Realm

// is invalid, simply return null. Otherwise, return a new

// RelayAuthenticateResult which will be used to authenticate

// the request.

if (e.Username == "test")

{

// Option A: return the MD5 hash of the following string:

// "username:realm:password"

// This is only possible if you are storing this hash

// somewhere, calculated at a time when the user supplied

// you momentarily with their password. This hash is

// known as a long-term key, and a utility method is

// available in the STUN class to create one.

return new RelayAuthenticateResult(STUN.CreateLongTermKey(e.Username, e.Realm, "pa55w0rd!"));

// Option B: return the user's password in plain-text.

// This is only possible if you are storing the user's

// password somewhere in plain-text, so this approach

// has obvious security risk if your server is hacked.

//return new RelayAuthenticateResult("pa55w0rd!");

Page 110: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// This method of authentication is required by the TURN

// specification which Messenger implements for third-party

// compatibility. Either option is acceptable according to

// TURN, so the choice of which one to use is up to you.

}

return null;

});

// Start the Messenger server on the default port (3478). Make sure

// this port is open for incoming UDP packets in your firewall.

server.Start();

}

Enabling Logging: iOS and MAC

To enable logging for iOS or Mac, simply assign a log provider using [EyeballLog setProvider:]. An

EyeballNSLogProvider implementation is included that writes log statements to the output window.

#import "Eyeball.h"

...

Page 111: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

- (void)run

{

[EyeballLog setProvider:[[[EyeballNSLogProvider alloc] initWithLogLevel:EyeballLogLevelInfo] autorelease]];

}

Enabling Logging: Java

To enable logging for Java, simply assign a log provider using Log.setProvider. A ConsoleLogProvider

implementation is included that writes log statements to the output window.

import eyeball.*;

Page 112: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

...

public void run()

{

Log.setProvider(new ConsoleLogProvider(LogLevel.Info));

}

Enabling Logging: Javascript

To enable logging for JavaScript, simply assign a log provider using Log.setProvider. A domLogProvider

implementation is included that writes log statements to an element in the DOM (p, div, etc.).

<script type="text/javascript" src="eyeball.js"></script>

Page 113: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

...

<script type="text/javascript">

eyeball.log.setProvider(new eyeball.domLogProvider(document.getElementById('log'), eyeball.logLevel.Info));

</script>

Enabling Logging: Xamarin.Android

To enable logging for Xamarin.Android, simply assign a log provider to Log.Provider. A

ConsoleLogProvider implementation is included that writes log statements to the output window.

using Eyeball;

Page 114: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

...

public void Run()

{

Log.Provider = new ConsoleLogProvider(LogLevel.Info);

}

Enabling Logging: Xamarin.iOS

To enable logging for Xamarin.iOS, simply assign a log provider to Log.Provider. A ConsoleLogProvider

implementation is included that writes log statements to the output window.

using Eyeball;

...

Page 115: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

public void Run()

{

Log.Provider = new ConsoleLogProvider(LogLevel.Info);

}

Enabling Logging: .NET, .NET Compact, and Mono

To enable logging for .NET, .NET Compact, or Mono, simply assign a log provider to Log.Provider. A

ConsoleLogProvider implementation is included that writes log statements to the output window.

using Eyeball;

Page 116: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

...

public void Run()

{

Log.Provider = new ConsoleLogProvider(LogLevel.Info);

}

Enabling Logging: Windows Phone

To enable logging for Windows Phone, simply assign a log provider to Log.Provider. A

ConsoleLogProvider implementation is included that writes log statements to the output window.

using Eyeball;

...

Page 117: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

public void Run()

{

Log.Provider = new ConsoleLogProvider(LogLevel.Info);

}

Enabling Logging: Windows 8

To enable logging for Windows 8, simply assign a log provider to Log.Provider. A ConsoleLogProvider

implementation is included that writes log statements to the output window.

using Eyeball;

...

public void Run()

Page 118: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

Log.Provider = new ConsoleLogProvider(LogLevel.Info);

}

Further Concepts

SDP

SDP stands for Session Description Protocol. It is a standard format (IETF RFC 4566) used for describing

media streams in real-time applications, and the one we use in Messenger for exchanging information

between two peers while establishing a direct connection.

When an Messenger connection is created, one peer takes the role of offerer (also known as the

controlling agent) and one peer takes the role of answerer (also known as the controlled agent) for the

Page 119: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

purposes of exchanging information. The offerer has the responsibility of creating the initial offer as an

SDP message and sending it to the answerer through a third-party signalling mechanism (like WebSync

or SIP). When an offer is received, the answerer is reponsible for creating an answer, also as an SDP

message, and sending it back to the offerer, again through a third-party signalling mechanism (like

WebSync or SIP).

The SDP-formatted offers and answers include information about the identity of the peers, what media

streams and formats are supported, and any other information relevant to creating a new session. Media

streams are encrypted by default in Messenger, so the offer/answer will also typically include the

cryptographic details necessary for one peer to decrypt information sent by the other. For this reason,

we strongly recommend using an HTTPS (SSL) endpoint when creating the WebSync clients that will

exchange these messages.

After an offer or answer has been created, Messenger will start locating potential candidates (IP

address/port combinations) what could potentially be used for the peer-to-peer communication. Each

candidate Messenger finds is raised as an SDP attribute that must be sent to the peer through a third-

party signalling mechanism (like WebSync or SIP).

NAT

NAT stands for Network Address Translation. In general, it is the process used by routers to modify IP

information by translating local IP addresses on a private subnet to public IP addresses typically assigned

by an Internet service provider (ISP). They present a major challenge when attempting to establish direct

connections between clients on a network.

There are four types of NATs present in today's routers, presented in order from least restrictive to most

restrictive:

Page 120: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Full cone

Once an internal address (iAddr:iPort) is mapped to an external address (eAddr:ePort), any packets

from iAddr:iPort will be sent through eAddr:ePort. Any external host can send packets to iAddr:iPort

by sending packets to eAddr:ePort.

Address-restricted cone

Once an internal address (iAddr:iPort) is mapped to an external address (eAddr:ePort), any packets

from iAddr:iPort will be sent through eAddr:ePort. An external host (hAddr:any) can send packets to

iAddr:iPort by sending packets to eAddr:ePort only if iAddr:iPort has previously sent a packet to

hAddr:any. "Any" means the port number doesn't matter.

Port-restricted cone (like address-restricted cone, but the restriction includes port numbers)

Once an internal address (iAddr:iPort) is mapped to an external address (eAddr:ePort), any packets

from iAddr:iPort will be sent through eAddr:ePort. An external host (hAddr:hPort) can send packets to

iAddr:iPort by sending packets to eAddr:ePort only if iAddr:iPort has previously sent a packet to

hAddr:hPort.

Symmetric

Each request from the same internal IP address and port to a specific destination IP address and port

is mapped to a unique external source IP address and port, if the same internal host sends a packet

even with the same source address and port but to a different destination, a different mapping is

used. Only an external host that receives a packet from an internal host can send a packet back.

The techniques necessary to establish a direct connection between peers become more challenging as

the NATs between them become more restrictive. In the worst case, a relay with a public IP address is

needed to exchange packets between peers.

Router/NAT Type Full Cone Address-Restricted Cone Port-Restricted Cone Symmetric

Full Cone Direct Direct Direct Direct

Address-Restricted Cone Direct Direct Direct Direct

Port-Restricted Cone Direct Direct Direct Relay

Symmetric Direct Direct Relay Relay

Direct links can be discovered using STUN alone. Relay links can only be discovered through the use of

TURN.

Page 121: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

STUN

STUN stands for Session Traversal Utilities for NAT. It is a network protocol/packet format (IETF RFC

5389) used by NAT traversal algorithms to assist in the discovery of network environment details.

Messenger uses STUN packets when communicating with the Messenger server and other Messenger

clients.

If the routers between peers use full cone, address-restricted, or port-restricted NAT, then a direct link

can be discovered with STUN alone. If either one of the routers use symmetric NAT, then a link can be

discovered with STUN packets only if the other router does not use symmetric or port-restricted NAT. Not

Page 122: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

to fear, though! If this is the case, Messenger will automatically discover a relayed path through the use

of TURN.

TURN

TURN stands for Traversal Using Relays around NAT. Like STUN, it is a network protocol/packet format

(IETF RFC 5766) used to assist in the discovery of paths between peers on the Internet. It differs from

STUN in that it uses a public intermediary relay to relay packets between peers. Messenger uses TURN to

exchange media stream packets when no other option is available since it consumes server resources and

has an increased latency due to the extra step.

Page 123: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

The only time when TURN is necessary is when one of the peers is behind a symmetric NAT and the

other peer is behind either a symmetric NAT or port-restricted NAT. The frequency of cases where a relay

is necessary is difficult to pin down, but is estimated to be around 8% (source).

RTP/SRTP

RTP stands for Real-time Transport Protocol. It is a standard packet format (IETF RFC 3550) for

exchanging real-time data over streaming connections. SRTP stands for Secure Real-time Transport

Protocol. It is a standard RTP profile (IETF RFC 3711) that extends RTP by providing encryption and

message authentication for RTP and RTCP packets. Messenger uses SRTP for all media streams by

default. If encryption is disabled for a particular media stream, RTP is used instead.

Page 124: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Each RTP packet has a 7-bit payload type (0-127) and a binary payload. The payload type is used to

identify the format of the payload, and is defined when constructing an Messenger connection. IANA has

set aside some payload types for specific formats. If you are using an encoding format recognized by

IANA, it is recommended that you use the corresponding payload type. If you are using an encoding

format NOT recognized by IANA, it is recommended that you use a value in the range 96-127, per their

recommendations. The only restriction enforced by Messenger is that payload types 72-76 are reserved

for RTCP. These payload types may not be used as it would interfere with internal RTCP processing.

SRTP packets are secured using 128-bit AES encryption and either 80-bit (strong) or 32-bit (weak)

HMAC-SHA1 authentication. In general, we recommend using strong authentication for all media streams.

However, there are applications where weak authentication makes sense - where the packets are

frequent and small (and thus the extra 6 bytes cause a substantial increase in bandwidth) and where a

forged packet is unlikely and inconsequential. For example, a voice telephony application that uses 20-ms

packets will send 50 packets per second. Weak authentication will save 300 bytes per second in

bandwidth, with the likelihood of a forged packet being only one in 2^32 (IETF RFC 3711).

ICE

ICE stands for Interactive Connectivity Establishment. It defines a technique that uses SDP, STUN, and

TURN to discover a network path between peers on the Internet. Messenger implements the ICE

specification (IETF RFC 5245) and as such, is compatible with other clients that implement the same

spec.

Page 125: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Each RTP packet has a 7-bit payload type (0-127) and a binary payload. The payload type is used to

identify the format of the payload, and is defined when constructing an Messenger connection. IANA has

set aside some payload types for specific formats. If you are using an encoding format recognized by

IANA, it is recommended that you use the corresponding payload type. If you are using an encoding

format NOT recognized by IANA, it is recommended that you use a value in the range 96-127, per their

recommendations. The only restriction enforced by Messenger is that payload types 72-76 are reserved

for RTCP. These payload types may not be used as it would interfere with internal RTCP processing.

Platform Considerations

iOS and Mac

Page 126: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Messenger requires an autorelease pool and run loop to function properly. Most iOS and Mac applications

take care of this automatically, but if your code is building and running, but not doing anything, make

sure that your application initializes an autorelease pool and runs a run loop in its startup code

(e.g. main.m):

// use autorelease

@autoreleasepool

{

Application *app = [Application new];

[app run];

[[NSRunLoop currentRunLoop] run];

}

Xamarin.Android

While Xamarin has done an excellent job integrating support for native libraries, it can still be finicky

when relying on native code like VP8 in the WebRTC example.

When including a native library (i.e. libvpx.so, libvpxJNI.so) in your project, make sure that the following

Properties are set:

1. Build Action: AndroidNativeLibrary

2. Copy to Output Directory: Copy always

If you don't do this, you will probably see messages like the following in your logs:

Cannot load library[1234]: 1985 'libvpxJNI.o failed'

.NET, .NET Compact, and Mono

.NET applications must use a Visual C++/CLI library to provide VP8 codec support. This library (Win.VP8)

is provided for you in the SDK. Make sure that the Win.VP8 project uses the correct Platform Toolset for

Page 127: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

your installed version of Visual Studio. This can be configured in the Win.VP8 Project Properties under

General > Platform Toolset.

When building for distribution to computers that do not have Visual Studio installed, make

sure you:

1. Build in Release mode.

2. Package the Visual C++ runtime DLL with your executable.

1. msvcr90.dll when using the Visual Studio 2008 (9.0) Platform Toolset and .NET 3.5. 2. msvcr100.dll when using the Visual Studio 2010 (10.0) Platform Toolset and .NET 4.0.

3. msvcr110.dll when using the Visual Studio 2012 (11.0) Platform Toolset and .NET 4.5. 4. etc...

.NET

Version

Visual

Studio

Visual

C++ Platform

Toolset

Visual C++ Runtime DLL

3.5 2008 9.0 C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\(architecture)\Microsoft.VC90.CRT\msvcr90.dll

4.0 2010 10.0 C:\Program Files (x86)\Microsoft Visual Studio

10.0\VC\redist\(architecture)\Microsoft.VC100.CRT\msvcr100.dll

4.5 2012 11.0 C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\redist\(architecture)\Microsoft.VC110.CRT\msvcr110.dll

Pay careful attention to warnings from Visual Studio when building applications in .NET that use Visual

C++ libraries. The application and library must be built using the same target architecture (x86/Win32 or

x64).

.NET Application Architecture Visual C++ Library Architecture

x86 Win32

x64 x64

Any CPU Incompatible

Code Snippets

Page 128: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Audio-Only in Audio/Video Conference

Messenger's audio/video engine is completely pluggable, so if you want an audio-only client to join an

audio/video conference, this can be done relatively easily with a custom video capture provider.

(Consider, for example, a client that wants to join an audio/video conference, but doesn't have a webcam

or doesn't have the processing power to encode real-time video.)

// Get standard audio/video media.

UserMedia.GetMedia(new GetMediaArgs(true, true)

{

OnFailure = (fe1) =>

{

// The video device is most likely unavailable. Let's try

// again, but using a custom video provider that always

// succeeds, but never sends frames.

UserMedia.GetMedia(new GetMediaArgs(true, true)

{

VideoCaptureProvider = new EmptyVideoCaptureProvider(),

OnFailure = (fe2) =>

{

// The audio device is unavailable. :(

},

OnSuccess = (e) =>

{

// Good to go. Create AudioStream, VideoStream, and Conference.

// This code should be identical to the other OnSuccess handler (below).

}

Page 129: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

});

},

OnSuccess = (e) =>

{

// Good to go. Create AudioStream, VideoStream, and Conference.

// This code should be identical to the other OnSuccess handler (above).

}

});

// Define this class somewhere. It's a custom video capture

// provider that does nothing but indicate that it works. It

// never calls RaiseFrame, so data is never sent to the

// processing engine and hence never sent to peers.

class EmptyVideoCaptureProvider : VideoCaptureProvider

{

public override void Initialize(VideoCaptureInitializeArgs e) { }

public override void Start() { RaiseReady(); }

public override void Stop() { }

public override void Destroy() { }

public override string[] GetDeviceNames() { return null; }

public override string GetLabel() { return "Empty"; }

}

Custom Layouts

Page 130: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

The layout managers included with the WebRTC extension for Messenger, while completely optional, can

be extremely useful in rapidly developing your application. They provide a sensible default layout

algorithm together with control and UI thread management to make your development as easy as

possible. It is possible to customize this layout algorithm by hooking into the layout manager's OnLayout

callback. The Layout property of the event arguments defines the layout structure that will be executed

and can be customized to your heart's content.

layoutManager.OnLayout = (e) =>

{

// If there are remote video controls, always

// keep the local preview in the top left corner.

if (e.RemoteCount > 0)

{

e.Layout.LocalFrame.X = 10;

e.Layout.LocalFrame.Y = 10;

}

};

Custom Port Range

Messenger allows you to customize the port range used when opening UDP sockets for P2P

communications. Simply set the RtpPortMin and RtpPortMax properties at the conference- or link-level.

// constrain to 40XXX

conference.RtpPortMin = 40000; // minimum value, inclusive

conference.RtpPortMax = 40998; // maximum value, inclusive

Detecting Packet Loss

Page 131: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Messenger's eventing system allows direct access to the underlying RTP packet stream. Simply attach to

the ReceiveRTP event at the layer of your choice (stream/conference/link). A common use case is to

detect packet loss or re-ordering and adjust the quality of the video codec in your application.

videoStream.OnLinkReceiveRTP += (e) =>

{

var lastSequenceNumber = e.NegotiatedStream.LastSequenceNumber;

if (lastSequenceNumber > -1)

{

var sequenceNumberDelta = RTPPacket.GetSequenceNumberDelta(

e.Packet.SequenceNumber, lastSequenceNumber);

if (sequenceNumberDelta > 1)

{

// a packet was lost or is arriving out of order

}

}

};

Disabling DTLS

DTLS provides secure key exchange over the P2P UDP connection, but adds additional overhead to the

connection establishment process. If your offers/answers are sent securely (for example, over HTTPS or

a secure WebSocket), then you can disable DTLS for faster connection establishment:

var audioStream = new AudioStream(localMedia, false); // set offerDtls to false

var videoStream = new VideoStream(localMedia, false); // set offerDtls to false

Page 132: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Disabling Use of the Relay

Use of the relay can be disabled by suppressing relay candidates.

Simply set the SuppressRelayCandidates flag to true:

// By suppressing relay candidates, we

// effectively disable use of the relay

// for the current device.

conference.SuppressRelayCandidates = true;

Distributing Relay Load

The Messenger server is completely scalable. Depending on the size of your application, one server may

not be sufficient for relaying data packets. Exactly how many links can be relayed per server depends on

the bandwidth requirements of your application. Proper testing will help you discover the exact limits.

Each Messenger client is equipped with an Messenger server IP address when linking to a peer. At the

application-level, you can distribute relay load across your Messenger servers by handing out server IPs

in a round-robin fashion when initializing new Messenger clients. A simple HTTP request should be all

that is needed for a client to retrieve the next server IP address. A more robust solution would involve

Virtual IP (VIP) load balancing.

Within Messenger itself, there are mechanisms built-in that allow you to redirect clients to a new server under any condition that can be checked from code. In the RequestReceived event handler, allocate

requests can be redirected if the server is overloaded by simply throwing a 'Try-Alternate' exception with the IP address of a different server.

server.RequestReceived += (s, e) =>

{

// A STUNAllocateRequest is the STUN-compatible client request used to

// allocate a socket on the server for relaying. If the server is under

// heavy load when a new allocate request arrives, we can throw a

Page 133: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// STUNTryAlternateException with an alternate server IP address. The

// client connection process will then attempt its socket allocation

// request on the alternate server.

if (e.Request is STUNAllocateRequest && s.RelayAllocationCount > 20000)

{

var alternateServer = new STUNAlternateServerAttribute("server IP address", 3478);

throw new STUNTryAlternateException(alternateServer);

}

};

Enabling Stale-Nonce Security

The TURN spec describes a nonce-based security algorithm. By default, it is disabled in our

implementation since it is not supported by any web browsers at the time of this writing, but it can be

enabled if desired.

server.StaleNonceSecurity = true;

Forcing Use of the Relay

Use of the relay can be forced by suppressing private and public link candidates (leaving only relayed

candidates).

Simply set the SuppressPrivateCandidates and SuppressPublicCandidates flags to true:

// By suppressing both private (host) and public

// (edge, a.k.a. server-reflexive) candidates, we

// are left with only relayed candidates for this

// device.

Page 134: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

conference.SuppressPrivateCandidates = true;

conference.SuppressPublicCandidates = true;

Getting a Conference Link

Individual links in a conference can be retrieved when needed.

conference.GetLink(peerId);

Multiple Servers

To address high-availability needs, it is possible to provide a Conference with the addresses of multiple

servers that will be tried in succession. It is also possible to have Messenger randomize the order of the

servers for each link that is created to distribute the load:

// Server addresses are formatted as {address} or

// {address}:{port}. If the port is not specified,

// it will default to 3478.

var conference = new Conference(new[] { "stun1.mydomain.com", "stun2.mydomain.com", "stun3.mydomain.com:19302" }, ...);

// Optionally, you can randomize the server list

// for each new link by setting the following flag.

conference.RandomizeServers = true;

Muting and Unmuting

Page 135: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

The WebRTC extension allows you to mute/unmute audio/video at any time. To mute your local audio or

video, simply call LocalMediaStream.MuteAudio/Video. To unmute, call

LocalMediaStream.UnmuteAudio/Video:

// The local media stream is created by the call to UserMedia.GetMedia.

// Muting the video immediately halts the capturing of video frames

// from the local capture provider.

localStream.MuteVideo();

// Muting the audio immediately halts the capturing of audio frames

// from the local capture provider.

localStream.MuteAudio();

You can also stop the rendering of incoming remote audio/video by calling Link.MuteRemoteAudio/Video.

To start rendering again, call Link.UnmuteRemoteAudio/Video.

// Remote media streams are created when a link is established.

// Muting the video immediately halts the rendering of video frames

// from the remote peer.

link.MuteRemoteVideo(); // In Java: LinkExtensions.MuteRemoveVideo(link);

link.RenderVideoBuffer(blankImage); // In Java: LinkExtensions.RenderVideoBuffer(link, blankImage);

// Muting the audio immediately halts the rendering of audio frames

// from the remote peer.

link.MuteRemoteAudio(); // In Java: LinkExtensions.MuteRemoteAudio(link);

Page 136: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Note that we call RenderVideoBuffer after muting the remote video feed. The last received video frame

from the peer is displayed in the video control until a new image is supplied by this call.

Null Encryption

Messenger streams use AES 128-bit encryption by default with strong 80-bit HMAC-SHA1 message

authentication. To disable encryption and authentication, set the encryption mode

to EncryptionMode.Null when creating the stream definition. To disable just encryption and leave

message authentication enabled, use EncryptionMode.NullStrong. To disable encryption and weaken

message authentication from 80-bit to 32-bit, useEncryptionMode.NullWeak.

var stream = new Stream(StreamType.Text, new StreamFormat("utf8"), EncryptionMode.Null);

Warning: Unencrypted packets can be intercepted and read by a third-party listening to network traffic.

Using null encryption improves performance due to reduced computation, but do so at your

Parsing SDP Candidates

Messenger uses SDP for signalling (offers/answers and candidates) which makes it easy to parse SDP

candidates coming in and going out to determine local and remote IP addresses (and ports).

conference.OnLinkCandidate += (e) =>

{

// Parse the SDP candidate string.

var sdpCandidate = (SDPCandidateAttribute)SDPAttribute.Parse(candidate.SdpCandidateAttribute);

// "Host" candidates represent local/private IP address/port combinations.

if (sdpCandidate.CandidateType == SDPCandidateType.Host)

Page 137: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

var localIP = sdpCandidate.ConnectionAddress;

var localPort = sdpCandidate.Port;

}

// "Reflexive" candidates represent public IP address/port combinations.

if (sdpCandidate.CandidateType == SDPCandidateType.ServerReflexive ||

sdpCandidate.CandidateType == SDPCandidateType.PeerReflexive)

{

var externalIP = sdpCandidate.ConnectionAddress;

var externalPort = sdpCandidate.Port;

var internalIP = sdpCandidate.RelatedAddress;

var internalPort = sdpCandidate.RelatedPort;

}

// "Relayed" candidates represent public IP address/port combinations *on a TURN relay*.

if (sdpCandidate.CandidateType == SDPCandidateType.Relayed)

{

var externalIP = sdpCandidate.ConnectionAddress;

var externalPort = sdpCandidate.Port;

var internalIP = sdpCandidate.RelatedAddress;

var internalPort = sdpCandidate.RelatedPort;

}

};

Relay Authentication

Page 138: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

It is not always possible to establish a direct connection between peers. (This happens approximately 8%

of the time, according to Google.) If both clients are using symmetric firewalls, or if one client is using a

symmetric firewall and the other is using a port-restricted cone firewall, the only way for them to

communicate is through a relay. An Messenger server is capable of relaying data packets, but it requires

that client requests be authenticated. (Otherwise, a malicious user could launch a Denial-of-Service

attack by sending a steady flow of unauthenticated socket allocation requests.) You can hard-code a

username/password into your client application or use dynamic credentials, but some form of

authentication must exist.

server.EnableRelay((e) =>

{

// This is our authentication callback. It will be invoked

// whenever a request is received that changes the state of

// the relay (allocating a socket on the relay, creating a

// new permission for a socket on the relay, etc.). The

// Username and Realm properties of the event arguments are

// those supplied by the client. If the Username or Realm

// is invalid, simply return null. Otherwise, return a new

// RelayAuthenticateResult which will be used to authenticate

// the request.

if (e.Username == "test")

{

// Option A: return the MD5 hash of the following string:

// "username:realm:password"

// This is only possible if you are storing this hash

// somewhere, calculated at a time when the user supplied

// you momentarily with their password. This hash is

// known as a long-term key, and a utility method is

Page 139: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// available in the STUN class to create one.

return new RelayAuthenticateResult(STUN.CreateLongTermKey(e.Username, e.Realm, "pa55w0rd!"));

// Option B: return the user's password in plain-text.

// This is only possible if you are storing the user's

// password somewhere in plain-text, so this approach

// has obvious security risk if your server is hacked.

//return new RelayAuthenticateResult("pa55w0rd!");

// This method of authentication is required by the TURN

// specification which Messenger implements for third-party

// compatibility. Either option is acceptable according to

// TURN, so the choice of which one to use is up to you.

}

return null;

});

Sending a Private Conference Packet

The usual intention when sending a packet to a conference is for the packet to be sent to all peer links.

However, an overload is provided that allows you to send to a specific link. All you need is the peer ID.

conference.SendRTP(stream.Format, packet, peerId);

Page 140: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Signing the Java Applet or ActiveX Control

The Enterprise editions of Messenger include an unsigned Java applet and unsigned ActiveX control so

you can use your own code-signing certificate.

To sign the Java applet, use the jarsigner utility included with the JDK.

jarsigner -storetype pkcs12 -keystore your_certificate.p12 -storepass your_password -tsa http://tsa.starfieldtech.com/ eyeball.messenger.webrtc.applet.jar keystore_alias

To sign the ActiveX control, use the SignTool utility included with the Windows SDK.

signtool.exe sign /f your_certificate.p12 /p your_password /t http://tsa.starfieldtech.com/ Eyeball.Messenger.WebRTC.ActiveX.cab

Supressing Candidates

Messenger defines three candidate types:

Private

IP address/port combinations on your host device (i.e. your LAN addresses)

Public

IP address/port combinations on your network edge device (e.g. your WAN addresses)

Relay

IP address/port combinations on your Messenger relay server

It can sometimes be desirable to suppress a specific candidate type from consideration. Say, for example,

that you wanted to record all audio/video conversations and archive them on your server. You could do

the recording client-side and upload afterwards, or you could suppress private and public candidates,

thereby forcing use of the relay, and do the recording server-side. Alternatively, if you don't want to host

a relay server and are willing to have your clients use UPnP or port forwarding to make themselves

publicly accessible, you could suppress relay candidates.

Page 141: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Whatever the situation, Messenger provides three properties on conferences and links that allow you to

suppress each of the three candidate types:

SuppressPrivateCandidates SuppressPublicCandidates

SuppressRelayCandidates

// force use of the relay for server recording

connection.SuppressPrivateCandidates = true;

connection.SuppressPublicCandidates = true;

Switching Cameras

Switching cameras and/or microphones in the middle of a live conference is easy. Several methods are

available on LocalMediaStream to assist you:

// To set the video device number, use:

localMedia.SetVideoDeviceNumber(...);

// You can get the front/rear video device numbers using:

localMedia.GetFrontVideoDeviceNumber();

localMedia.GetRearVideoDeviceNumber();

// We provide you with a couple shortcuts:

localMedia.UseFrontVideoDevice();

localMedia.UseRearVideoDevice();

Page 142: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// Or if you just want to toggle between devices, use:

localMedia.UseNextVideoDevice();

Using Links Directly

While we normally recommend using the Conference API, there are some cases (like integration with

third-party software) that require you to go a level deeper and use the underlying Link API to fine-tune

behaviour.

Creating a Link

var link = new eyeball.messenger.link();

link.setPeerId(...); // optional, can be used to identify the peer associated with this link

link.setPeerState(...); // optional, can be used to store details about the peer (i.e. username)

link.initialize(serverAddress, serverPort, [ stream1, stream2, ... ], function(link)

{

// link is ready for negotiation!

});

Attaching Events

link.addOnInit(function(e)

{

// fires when the link is being set up.

// this is always the first event to fire.

});

Page 143: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

link.addOnUp(function(e)

{

// fires when link is up and connected.

// this will only fire once, and always after Init.

});

link.addOnDown(function(e)

{

// fires when link is down and disconnected.

// this will only fire once, and always after Init or Up.

});

link.addOnCandidate(function(e)

{

// fires when a candidate has been discovered and should be sent to the peer (via signalling).

// this can fire multiple times, and always after Init.

// for convenience, we provide a simple way to serialize the candidate to JSON.

// (includes SDP candidate attribute and SDP media index)

var candidateJson = e.getCandidate().toJson();

});

Creating an Offer or Answer

// to create an offer, use link.createOffer. (link will be controlling)

// to create an answer, use link.createAnswer. (link will be controlled)

Page 144: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// the syntax/arguments are identical.

link.createOffer({

onSuccess: function(e)

{

// fires when the offer (or answer) is ready.

// for convenience, we provide a simple way to serialize the offer (or answer) to JSON.

// (includes SDP offer (or answer), isOffer flag, and tie breaker string)

var offerAnswerJson = e.getOfferAnswer().toJson();

},

onFailure: function(e)

{

var error = e.getException().message;

alert(error);

}

});

Accepting an Offer or Answer

// to accept an offer (or answer), use link.accept.

// the offer (or answer) should arrive via signalling.

link.accept({

offerAnswer: eyeball.messenger.offerAnswer.fromJson(offerAnswerJson),

onSuccess: function(e)

{

// fires when the offer (or answer) has been accepted.

},

Page 145: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

onFailure: function(e)

{

var error = e.getException().message;

alert(error);

}

});

Adding a Remote Candidate

// to add a remote candidate, use link.addRemoteCandidate.

// the candidate should arrive via signalling.

link.addRemoteCandidate(eyeball.messenger.candidate.fromJson(candidateJson));

Weak Encryption

Messenger streams use AES 128-bit encryption by default with strong 80-bit HMAC-SHA1 message

authentication. In some applications, it may be desirable to weaken the message authentication to 32-

bits, particularly if bandwidth is a concern and the cost of packet injection is not critical (for example, a

simple telephony application). To weaken authentication, simply set the encryption mode

to EncryptionMode.AES128Weak when creating the stream definition.

var stream = new Stream(StreamType.Audio, new StreamFormat("speex"), EncryptionMode.AES128Weak);

WebRTC Audio

WebRTC audio streams allow you to share an audio feed directly between peers, including web browsers.

To add an audio stream to your conference, first use UserMedia to get a reference to the local device

media stream, then create a WebRTC AudioStream.

Audio and video can be combined by requesting both audio and video from UserMedia.GetMedia.

Page 146: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

eyeball.messenger.webrtc.userMedia.getMedia({

audio: true,

onSuccess: function(e)

{

var audioStream = new eyeball.messenger.webrtc.audioStream(e.getLocalStream());

// the AudioStream can be used like any other Messenger stream

var conference = new eyeball.messenger.conference(serverAddressMessenger, serverPortMessenger, [ audioStream ]);

...

}

});

WebRTC Data Channels

WebRTC data channels allow you to transfer arbitrary data directly between peers, including web

browsers. To send messages between peers using data channels, create a WebRTC DataChannelStream.

TheDataChannelStream takes an array of DataChannelInfo instances, each of which describes a single

data channel with a handler for incoming messages.

var dataChannelInfo = new eyeball.messenger.webrtc.dataChannelInfo({

label: 'mydatachannel',

onReceive: function(e) {

alert(e.getPacket().getData());

}

});

Page 147: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

var dataChannelStream = new eyeball.messenger.webrtc.dataChannelStream([ dataChannelInfo ]);

// the DataChannelStream can be used like any other Messenger stream

var conference = new eyeball.messenger.conference(serverAddressMessenger, serverPortMessenger, [ dataChannelStream ]);

...

To send data to a specific channel, use Conference.SendData(DataChannelInfo,

DataChannelPacket).

conference.sendData({

channelInfo: dataChannelInfo,

packet: 'Hello, WebRTC!'

});

WebRTC Video

WebRTC video streams allow you to share a video feed directly between peers, including web browsers.

To add a video stream to your conference, first use UserMedia to get a reference to the local device

media stream, then create a WebRTC VideoStream.

Video streams are more complicated than audio streams since they have to interact with your user

interface. To make this as easy as possible, Messenger includes a LayoutManager that automatically

positions your local video feed and any remote video feeds in a sensible manner. All it requires is a target

container in which to arrange the controls. In JavaScript, this can be any DOM element.

Audio and video can be combined by requesting both audio and video from UserMedia.GetMedia.

eyeball.messenger.webrtc.userMedia.getMedia({

video: true,

Page 148: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

videoWidth: 320,

videoHeight: 240,

videoFrameRate: 15,

onSuccess: function(e)

{

var layoutManager = new eyeball.messenger.webrtc.layoutManager(document.getElementById('container'));

layoutManager.setLocalVideoControl(e.getLocalVideoControl());

var videoStream = new eyeball.messenger.webrtc.videoStream(e.getLocalStream());

videoStream.addOnLinkInit(function(e)

{

// Add the remote video control to the layout.

layoutManager.addRemoteVideoControl(e.getPeerId(), e.getLink().getRemoteVideoControl());

});

videoStream.addOnLinkDown(function(e)

{

// Remove the remote video control from the layout.

layoutManager.removeRemoteVideoControl(e.getPeerId());

});

// the VideoStream can be used like any other Messenger stream

var conference = new eyeball.messenger.conference(serverAddressMessenger, serverPortMessenger, [ videoStream ]);

...

}

});

Page 149: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Diagrams

Page 150: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Page 151: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Page 152: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Extensibility

WebRTC Capturing and Rendering

Messenger's WebRTC extension offers complete flexibility when capturing and rendering audio and video.

Some platforms, like iOS/Mac, provide built-in framework support to easily capture audio samples and

video frames from attached hardware. Other platforms, like Java, provide little to no framework support

by default and rely on native bindings or the Android SDK.

To allow for every scenario, we use a simple provider model - one provider each for audio/video

capturing/rendering.

AudioCaptureProvider VideoCaptureProvider AudioRenderProvider VideoRenderProvider

Writing a Provider

Let's walk through creating a set of providers that use NAudio for audio capture and

rendering, AForge.NET for video capture, and the WinForms PictureBox control for video rendering.

Create an AudioCaptureProvider

implementation

Writing an AudioCaptureProvider requires implementing five methods (presented in the order they are

invoked):

Initialize Initializes the provider. Arguments to this method include details about the desired device number,

output clock rate, and number of channels. Start

Starts polling the audio hardware for samples, invoking RaiseFrame whenever a buffer of samples

has been captured. GetLabel

Purely for debugging purposes. Should return the name of the audio device if possible. Stop

Called when the stream is no longer required - no more frames should be raised at this point. Destroy

Allows you to release unmanaged resources and tie up any loose ends.

Page 153: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

NAudio provides support for a slew of sound capture APIs. For this example, we'll use the WaveIn classes

since they have the broadest platform support, but there are a variety of other options that are less

universal, but more suitable for real-time audio recording (read: lower latency), such as ASIO or Core

Audio for Windows.

class NAudioCaptureProvider : AudioCaptureProvider

{

private WasapiCapture WasapiIn = null;

private WaveInEvent WaveIn = null;

private string Label = null;

private int? DesiredDeviceNumber = null;

private int ClockRate = 0;

private int Channels = 0;

public override void Initialize(AudioCaptureInitializeArgs captureArgs)

{

DesiredDeviceNumber = captureArgs.DeviceNumber;

ClockRate = captureArgs.ClockRate;

Channels = captureArgs.Channels;

}

public override void Start()

{

try

{

MMDevice selectedDevice = null;

var deviceEnumerator = new MMDeviceEnumerator();

Page 154: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

if (DesiredDeviceNumber.HasValue)

{

var deviceCollection = deviceEnumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active);

if (DesiredDeviceNumber.Value < deviceCollection.Count)

{

selectedDevice = deviceCollection[DesiredDeviceNumber.Value];

}

}

if (selectedDevice == null)

{

selectedDevice = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Console);

}

Label = selectedDevice.DeviceFriendlyName;

WasapiIn = new WasapiCapture(selectedDevice);

if (WasapiIn.WaveFormat.BitsPerSample != 32 && WasapiIn.WaveFormat.BitsPerSample != 16)

{

throw new Exception(string.Format("WASAPI wave format not supported ({0} bits per sample).", WasapiIn.WaveFormat.BitsPerSample));

}

WasapiIn.DataAvailable += new EventHandler<WaveInEventArgs>(Capture_DataAvailable);

WasapiIn.StartRecording();

}

Page 155: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

catch (Exception ex)

{

if (Log.IsDebugEnabled)

{

Log.DebugFormat("Could not load WASAPI audio capture. {0}", ex.Message);

}

WaveIn = new WaveInEvent();

WaveIn.BufferMilliseconds = 20;

WaveIn.DataAvailable += new EventHandler<WaveInEventArgs>(WaveIn_DataAvailable);

if (DesiredDeviceNumber.HasValue)

{

WaveIn.DeviceNumber = DesiredDeviceNumber.Value;

}

WaveIn.WaveFormat = new WaveFormat((int)ClockRate, 16, Channels);

Label = WaveInEvent.GetCapabilities(WaveIn.DeviceNumber).ProductName;

WaveIn.StartRecording();

}

}

private void Capture_DataAvailable(object sender, WaveInEventArgs e)

{

if (!IsMuted)

{

Page 156: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

using (var inputStream = new MemoryStream())

{

if (WasapiIn.WaveFormat.BitsPerSample == 32)

{

// convert to shorts

int i, j;

var bytes = new byte[e.BytesRecorded / 2];

for (i = 0, j = 0; i < e.BytesRecorded; i += 4)

{

var floatValue = BitAssistant.ToFloat(e.Buffer, i);

var shortValue = (short)(floatValue * 32767.0f);

var shortBytes = BitAssistant.GetShortBytes(shortValue);

bytes[j++] = shortBytes[0];

bytes[j++] = shortBytes[1];

}

inputStream.Write(bytes, 0, bytes.Length);

}

else

{

inputStream.Write(e.Buffer, 0, e.BytesRecorded);

}

inputStream.Seek(0, SeekOrigin.Begin);

var inputStreamFormat = new WaveFormat(WasapiIn.WaveFormat.SampleRate, 16, WasapiIn.WaveFormat.Channels);

using (var inputWaveStream = new RawSourceWaveStream(inputStream, inputStreamFormat))

{

Page 157: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

var outputStreamFormat = new WaveFormat(ClockRate, 16, Channels);

using (var outputStream = new WaveFormatConversionStream(outputStreamFormat, inputWaveStream))

{

byte[] output = new byte[outputStream.Length];

outputStream.Read(output, 0, (int)outputStream.Length);

RaiseFrame(new AudioBuffer(output, 0, (int)outputStream.Length));

}

}

}

}

}

private void WaveIn_DataAvailable(object sender, WaveInEventArgs e)

{

if (!IsMuted)

{

RaiseFrame(new AudioBuffer(e.Buffer, 0, e.BytesRecorded));

}

}

public override void Stop()

{

if (WasapiIn != null)

{

WasapiIn.StopRecording();

}

Page 158: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

if (WaveIn != null)

{

WaveIn.StopRecording();

}

}

public override string GetLabel()

{

return Label;

}

public override void Destroy()

{

if (WasapiIn != null)

{

WasapiIn.Dispose();

}

if (WaveIn != null)

{

WaveIn.Dispose();

}

}

}

Create a VideoCaptureProvider

implementation

Page 159: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Writing a VideoCaptureProvider requires implementing six methods (presented in the order they are

invoked):

Initialize Initializes the provider. Arguments to this method include details about the desired device number,

output clock rate, and desired frame rate/size. Start

Starts polling the video hardware for frames, invoking RaiseFrame whenever an image has been

captured. GetPreviewControl

Should return a control that always shows the latest captured frame. GetLabel

Purely for debugging purposes. Should return the name of the video device if possible. Stop

Called when the stream is no longer required - no more frames should be raised at this point. Destroy

Allows you to release unmanaged resources and tie up any loose ends.

One of AForge.NET's quirks is that it does not supply frames from camera devices that are in use by

another application. To work around this, we wait up to CameraTimeout milliseconds (2000) to receive a

frame before considering it locked and moving on to the next device.

class AForgeVideoCaptureProvider : VideoCaptureProvider

{

private VideoCaptureDevice CaptureDevice = null;

private string Label = null;

private int? DesiredDeviceNumber = null;

private int DesiredFrameRate = 0;

private Size DesiredFrameSize = Size.Empty;

private int ClockRate = 0;

private string AttemptedMonikerString = null;

private TimeoutTimer NoVideoTimer = null;

private List<string> NoVideoMonikerStrings = new List<string>();

Page 160: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

private PictureBoxVideoRenderProvider Preview = null;

public AForgeVideoCaptureProvider()

{

Preview = new PictureBoxVideoRenderProvider();

}

public override void Initialize(VideoCaptureInitializeArgs captureArgs)

{

DesiredDeviceNumber = captureArgs.DeviceNumber;

DesiredFrameRate = captureArgs.FrameRate;

DesiredFrameSize = new Size(captureArgs.Width, captureArgs.Height);

ClockRate = captureArgs.ClockRate;

InitializeCamera();

}

private bool InitializeCamera()

{

var videoDevice = GetVideoDevice();

if (videoDevice == null)

{

return false;

}

CaptureDevice = new VideoCaptureDevice(videoDevice.MonikerString);

Page 161: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

CaptureDevice.DesiredFrameRate = DesiredFrameRate;

CaptureDevice.DesiredFrameSize = DesiredFrameSize;

CaptureDevice.NewFrame += CaptureDevice_NewFrame;

AttemptedMonikerString = videoDevice.MonikerString;

Label = videoDevice.Name;

return true;

}

private FilterInfo GetVideoDevice()

{

// try get to get the desired device first

var deviceNumber = 0;

var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

if (DesiredDeviceNumber.HasValue)

{

foreach (FilterInfo videoDevice in videoDevices)

{

if (deviceNumber == DesiredDeviceNumber.Value && !NoVideoMonikerStrings.Contains(videoDevice.MonikerString))

{

return videoDevice;

}

deviceNumber++;

}

}

Page 162: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

// if that fails, get the first available

foreach (FilterInfo videoDevice in videoDevices)

{

if (!NoVideoMonikerStrings.Contains(videoDevice.MonikerString))

{

return videoDevice;

}

}

return null;

}

private void CaptureDevice_NewFrame(object sender, NewFrameEventArgs e)

{

if (NoVideoTimer != null)

{

if (!NoVideoTimer.Stop())

{

return;

}

RaiseReady();

NoVideoTimer = null;

}

if (!IsMuted)

{

// create video buffer

Page 163: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

var videoBuffer = ImageUtility.BitmapToBuffer(e.Frame);

// update preview

Preview.RenderBitmap((Bitmap)e.Frame.Clone());

// raise event

RaiseFrame(videoBuffer);

}

}

public override void Start()

{

if (CaptureDevice != null)

{

NoVideoTimer = new TimeoutTimer();

NoVideoTimer.Start(CameraTimeout, NoVideoTimeout, null);

CaptureDevice.Start();

}

}

private void NoVideoTimeout(object state)

{

CaptureDevice.NewFrame -= CaptureDevice_NewFrame;

CaptureDevice.Stop();

// try again with the next one

NoVideoMonikerStrings.Add(AttemptedMonikerString);

Page 164: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

if (InitializeCamera())

{

Start();

}

else

{

RaiseBusy();

}

}

public override void Stop()

{

if (CaptureDevice != null)

{

CaptureDevice.SignalToStop();

}

}

public override string GetLabel()

{

return Label;

}

public override void Destroy()

{ }

public override object GetPreviewControl()

Page 165: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

{

return Preview.GetControl();

}

}

Create an AudioRenderProvider implementation

Writing an AudioRenderProvider requires implementing three methods (presented in the order they are

invoked):

Initialize Initializes the provider. Arguments to this method include details about the output clock rate and

number of channels. Render

Should render an audio frame to the output stream. Destroy

Allows you to release unmanaged resources and tie up any loose ends.

NAudio provides support for a variety of sound render APIs. For this example, we'll use the WaveOut

classes since they have the broadest platform support, but there are a variety of other options that are

less universal, but more suitable for real-time audio recording (read: lower latency), such as ASIO or Core

Audio for Windows.

class NAudioRenderProvider : AudioRenderProvider

{

private WasapiOut WasapiOut = null;

private WaveOutEvent WaveOut = null;

private BufferedWaveProvider WaveProvider = null;

public override void Initialize(AudioRenderInitializeArgs renderArgs)

{

int clockRate = renderArgs.ClockRate;

int channel = renderArgs.Channels;

Page 166: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

WaveProvider = new BufferedWaveProvider(new WaveFormat(clockRate, 16, channel));

WaveProvider.DiscardOnBufferOverflow = true;

// WaveProvider.BufferDuration = new TimeSpan(0, 0, 0, 0, 300);

try

{

WasapiOut = new WasapiOut(AudioClientShareMode.Shared, 0);

WasapiOut.Init(WaveProvider);

WasapiOut.Play();

}

catch (Exception ex)

{

if (Log.IsDebugEnabled)

{

Log.DebugFormat("Could not load WASAPI audio render. {0}", ex.Message);

}

WaveOut = new WaveOutEvent();

WaveOut.DesiredLatency = 100;

WaveOut.DeviceNumber = 0;

WaveOut.Init(WaveProvider);

WaveOut.Play();

}

}

Page 167: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

public override void Render(AudioBuffer buffer)

{

WaveProvider.AddSamples(buffer.Data, buffer.Index, buffer.Length);

}

public override void Destroy()

{

if (WasapiOut != null)

{

WasapiOut.Stop();

WasapiOut.Dispose();

}

if (WaveOut != null)

{

WaveOut.Dispose();

}

}

}

Create a VideoRenderProvider

implementation

Writing a VideoRenderProvider requires implementing three methods (presented in the order they are

invoked):

Initialize Initializes the provider. Arguments to this method include details about the output clock rate.

GetControl Should return the video control.

Render Should render a video frame to the video control.

Page 168: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Destroy Allows you to release unmanaged resources and tie up any loose ends.

A VideoRenderProvider implementation could use any control that supports the display of images, from

the PictureBox control in .NET to the GLKView in iOS to the NSImageView in Mac OS X. For this

example, we'll use a PictureBox control. Remember to perform UI updates on the main thread!

public class PictureBoxVideoRenderProvider : VideoRenderProvider

{

private PictureBox PictureBox;

public PictureBoxVideoRenderProvider()

{

PictureBox = new PictureBox();

PictureBox.BackColor = Color.Black;

PictureBox.SizeMode = PictureBoxSizeMode.Zoom;

}

public override void Initialize(VideoRenderInitializeArgs renderArgs)

{ }

public override void Render(VideoBuffer frame)

{

RenderBitmap(ImageUtility.BufferToBitmap(frame));

}

public override void Destroy()

{ }

Page 169: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

internal void RenderBitmap(Bitmap image)

{

if (image != null)

{

PictureBox.BeginInvoke(new Action(() =>

{

PictureBox.Image = image;

}));

}

}

public override object GetControl()

{

return PictureBox;

}

}

WebRTC Codec Registration

Out of the box, each WebRTC platform supports the following codecs:

Audio: PCMU and PCMA (G.711u and G.711a)

Video: Motion JPEG

Page 170: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Adding additional codec support is easy.

1. Implement AudioCodec or VideoCodec. 2. Call AudioStream.RegisterCodec or VideoStream.RegisterCodec to register the codec.

When registering a codec, you need to specify the encoding name and a callback that will create an

instance of the codec when required. Optionally, you can set the preferred flag so the codec is

preferred over built-in codecs. The RTP payload type can be specified as well if the codec is registered

with the IANA. (Otherwise the payload type will be dynamically assigned.)

// For true WebRTC compatibility, we have to use VP8 as

// the preferred video codec. Unfortunately for .NET,

// VP8 is only available as a native library, and so

// we have to use a Visual C++ wrapper if we want VP8

// support. We've already done the work of wrapping it

// in the Win.VP8 project, so all that's left for us to

// do is register it as the preferred video codec.

VideoStream.RegisterCodec("VP8", () =>

{

return new Win.VP8.Codec();

}, true);

The VP8 video codec is a requirement for WebRTC compatibility, and for performance reasons, the codec

must run using native code. To provide you with flexibility in building your application, the core

Messenger libraries do not contain a hard link to VP8. Instead, each WebRTC example in the Messenger

SDK includes the VP8 codec and demonstrates how to use it (using VideoStream.RegisterCodec).

Configuration

Configuring your Messenger server is easy! You can set configuration options programatically or in

app.config.

Page 171: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

To configure Messenger programatically, simply assign values to the properties found

on Config.Current.Server (Eyeball.Messenger.Server).

To configure Messenger in app.config, create a new <messenger> section in app.config with

a <server> element.

<configuration>

<configSections>

<section name="messenger" type="Eyeball.Messenger.Server.Config, Eyeball.Messenger.Server" />

</configSections>

<!-- xmlns is optional -->

<messenger xmlns="http://schemas.eyeball.com/messenger">

<server />

</messenger>

</configuration>

Firewall

Allow incoming UDP traffic on port 3478.

<server> Attributes

Attribute Default Description

ipAddress IPAddress.Any The IP address to use when listening for client

STUN/TURN requests. If nothing is specified, the server

will listen on all IP addresses bound to the machine.

Page 172: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

logProviderType Eyeball.NullLogProvider The fully-qualified type name of the log provider for

TheRest.

When applicable, a logProviderSettings sub-element

defines additional properties specific to a particular log

provider.

port 3478 The port to use when listening for client STUN/TURN

requests.

Minimum value is 1024. Maximum value is 65535.

targetedScan auto Determines the nature of the automatic assembly scan at

startup that finds and registers server-side event code.

When set to auto, a smart algorithm is used that only

scans assemblies not belonging to the .NET framework.

When set to true, a strict algorithm is used that only

scans assemblies with the EventContainer assembly-

level attribute. When set to false, all assemblies are

scanned.

For optimal startup time, it is recommended to set this

value to true and add the EventContainer attribute to

all assemblies with server-side event code.

Sample App.config

This sample configuration uses the log4net log provider found in Eyeball.Log4Net.dll.

<?xml version="1.0"?>

<configuration>

<configSections>

Page 173: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

<section name="messenger" type="Eyeball.Messenger.Server.Config, Eyeball.Messenger.Server" />

<!-- For the log4net log provider -->

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

</configSections>

<!-- xmlns is optional -->

<messenger xmlns="http://schemas.eyeball.com/messenger">

<server logProviderType="Eyeball.Log4Net.LogProvider" />

</messenger>

<!-- For the log4net log provider -->

<log4net debug="false">

<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">

<file value="C:\\Logs\\Eyeball.Messenger.txt" />

<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

<appendToFile value="true" />

<layout type="log4net.Layout.PatternLayout">

<conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" />

</layout>

</appender>

<root>

<level value="WARN" />

<appender-ref ref="LogFileAppender" />

</root>

</log4net>

Page 174: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

</configuration>

Debugging

Debugging asynchronous Messenger applications isn't hard, but you need the right tools. It can also be

helpful to increase the connection's Timeout property before stepping into client and server events to

prevent timeouts from getting in the way.

Free IDEs are available for all the other platforms that can help you debug your code (Visual Studio,

Xcode, Eclipse, and many others). To inspect network traffic, we recommend Wireshark.

Page 175: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

No Audio? No Video?

A common problem on .NET/Windows is to have a connection establish, but with no video and possibly

with no audio as well. The solution to this problem is to make sure that the correct Visual C++

redistributable is installed. Both the VP8 and Opus codecs dip into unmanaged code, and without the

Visual C++ redistributable, they can silently fail.

Make sure you install the right version! If you are building your project using Visual Studio 2013, install

the Visual C++ 2013 redistributable.

Licensing

Edition Commercial

Use

Description

Community N Free for non-commercial use. WAN links are terminated after 30 seconds.

Enterprise Y Licensed for commercial applications.

Enterprise

OEM

Y Licensed for commercial applications and server distribution.

Page 176: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

All Messenger products are licensed per developer. A developer is defined as anyone who contributes to

the source code of a project that uses Messenger. Basically, if they need an IDE to contribute to the

project, they need a license for Messenger.

Additional details on the pricing model and licensing agreement are available upon request.

Messenger includes a copy of the following third-party libraries:

Apache log4net, distributed under the Apache license, used by the log provider found in

Eyeball.Log4Net.dll for outputting log statements. NAudio, distributed under the Microsoft Public License (Ms-PL), used by the .NET WebRTC library to

control the device microphone and speakers. AForge.NET, distributed under the GNU Lesser GPL License (LGPL), used by the .NET WebRTC library

to control the device camera.

Notes

Server-Side API for Visual Studio 2005/2008.

The server-side API makes use of optional arguments. If you are using Visual Studio 2005/2008 and don't

need to specify any of these arguments, you will have to pass in default values (eg. null) where

applicable.

MessengerServer.Start(null, 0);

Page 177: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Converting Examples for Visual Studio 2005/2008

Our .NET examples make extensive use of the var keyword and lambda expressions for convenience.

You can easily convert to explicit typing and defined callbacks by simply changing var to the name of the

type and creating a new method with the contents of the lambda expression.

Consider this code snippet:

var conference = new Conference("serverAddress", videoStream);

conference.OnLinkInit += (e) =>

{

Console.WriteLine("Connecting to peer {0}...", e.PeerId);

};

Here is the equivalent code snippet using explicit typing and defined callbacks:

Conference conference = new Conference("serverAddress", videoStream);

conference.OnLinkInit += OnConferenceLinkInit;

...

private void OnConferenceLinkInit(LinkInitArgs e)

{

Console.WriteLine("Connecting to peer {0}...", e.PeerId);

}

Page 178: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Converting Examples to Visual Basic

Our .NET examples are all written in C#. Since C# and VB are functionally equivalent, any of our

examples can also be modified to run using VB. There are several excellent tools available for converting

C# to Visual Basic automatically (here's a free online converter from Telerik), but to give you an idea, this

is what a CreateOffer snippet might look like in VB:

Dim connection = New Connection("192.168.0.1", 3478)

connection.CreateOffer(New CreateArgs(New () {New StreamDescription(StreamType.Video, New StreamFormat(100, "vp8"))}) With { _

.OnFailure = Function(e) Do

Console.WriteLine("Could not create offer (" + e.Exception.Message + ").")

End Function _

})

Server Requirements

Messenger server can run on even the most basic hardware. We offer server support for a wide range of

platforms. Messenger servers perform both public IP address discovery for clients as well as packet

relaying.

There are only two requirements for Messenger servers:

Page 179: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

1. They must be publicly accessible for UDP traffic on port 3478. (Allow incoming UDP port 3478 in your

firewall.) 2. The must be edge devices, which means no routing or network address translation between

them and the public internet.

Java Applet

The Java applet creates multiple <applet> elements during normal use. To avoid unnecessary re-

downloading of the Java applet:

1. Make sure your webserver uses Content-Type: application/java-archive for the applet JAR file. Java will not cache applets if the MIME type is incorrect (i.e. Content-Type: application/octet-

stream). 2. Client-side caching should not be disabled on client machines. (It is enabled by default.)

Legal and Contact Information

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Confidential Information: This document contains confidential and proprietary information. The document has been provided to you in your capacity as a customer or evaluator of Eyeball Networks Inc.'s products. Unauthorized reproduction and distribution is prohibited unless specifically approved by Eyeball Networks Inc.

Page 180: Eyeball Messenger SDK WebRTC Developer Reference Guide

Copyright © 2002-2015 Eyeball Networks Inc. Patented and patents pending. All rights reserved.

Eyeball, Eyeball.com, its logos, AnyBandwidthTM and AnyFirewall™ are trademarks of Eyeball Networks Inc. All other referenced companies and product names may or may not be trademarks of their respective owners.

For more information visit Eyeball Networks Inc. at http://www.eyeball.com.

Department E-mail

Sales [email protected]

Technical Support [email protected]

Corporate Headquarters:

730 - 1201 West Pender Street

Vancouver, BC V6E 2V2

Canada

Tel. +1 604.921.5993

Fax +1 604.921.5909