Node.js with socket.io and node-static. (Node.js hosting would also be an advantage -- see below for some options.)

The instructions in this codelab assume you are using Mac OS, Linux or Windows. Unless you know what you're doing, it's probably easier not to attempt this codelab from a Chromebook!

It would also be useful to have an Android device with Google Chrome installed in order to try out the examples on mobile. To run WebRTC APIs on Chrome for Android, you must enable WebRTC from the chrome://flags page.

Running The Examples

To run any of the examples provided in the complete directory of this repo simply cd into the specific step directory you'd like to see locally and run

Explanation

The constraints argument allows us to specify the media to get, in this case video only:

var constraints = {"video": true}

If successful, the video stream from the webcam is set as the source of the video element:

functionsuccessCallback(localMediaStream){window.stream=localMediaStream;// stream available to consolevarvideo=document.querySelector("video");video.src=window.URL.createObjectURL(localMediaStream);video.play();}

Bonus points

Inspect the stream object from the console.

Try calling stream.stop().

What does stream.getVideoTracks() return?

Look at the constraints object: what happens when you change it to {audio: true, video: true}?

What size is the video element? How can you get the video's natural size from JavaScript? Use the Chrome Dev Tools to check. Use CSS to make the video full width. How would you ensure the video is no higher than the viewport?

The syntax of RTCDataChannel is deliberately similar to WebSocket, with a send() method and a message event.

Notice the use of constraints.

Bonus points

Try out RTCDataChannel file sharing with Sharefest. When would RTCDataChannel need to provide reliable delivery of data, and when might performance be more important -- even if that means losing some data?

Use CSS to improve page layout, and add a placeholder attribute to the dataChannelReceive textarea.

Step 5: Set up a signaling server and exchange messages

RTCPeerConnection instances need to exchange metadata in order to set up and maintain a WebRTC 'call':

Candidate (network) information.

Offer and answer messages providing information about media such as resolution and codecs.

In other words, an exchange of metadata is required before peer-to-peer audio, video or data streaming can take place. This process is called signaling.

In the examples already completed, the 'sender' and 'receiver' RTCPeerConnection objects are on the same page, so signaling is simply a matter of passing objects between methods.

In a real world application, the sender and receiver RTCPeerConnections are not on the same page, and we need a way for them to communicate metadata.

For this, we use a signaling server: a server that can exchange messages between a WebRTC app (client) running in one browser and a client in another browser. The actual messages are stringified JavaScript objects.

To reiterate: metadata exchange between WebRTC clients (via a signaling server) is required for RTCPeerConnection to do audio, video and data streaming (peer to peer).

In this step we'll build a simple Node.js signaling server, using the socket.io Node module and JavaScript library for messaging. Experience of Node.js and socket.io will be useful, but not crucial -- the messaging components are very simple. In this example, the server (the Node app) is server.js and the client (the web app) is index.html.

Our simple WebRTC application will only permit a maximum of two peers to share a room.

Ensure you have Node, socket.io and node-static installed. Node can be downloaded from nodejs.org; installation is straightforward and quick. To install socket.io and node-static, run Node Package Manager from a terminal in your application directory:

npm install socket.io
npm install node-static

(You don't need to learn about node-static for this exercise: it just makes the server simpler.)

Using the code from the step 5 directory, run the server (server.js). To start the server, run the following command from a terminal in your application directory:

node server.js

From your browser, open localhost:2013. Open a new tab page or window in any browser and open localhost:2013 again, then repeat.

To see what's happening, check the Chrome DevTools console (Command-Option-J, or Ctrl-Shift-J).

Bonus points

Try deploying your messaging server so you can access it via a public URL. (Free trials and easy deployment options for Node are available on several hosting sites including nodejitsu, heroku and nodester.)

What alternative messaging mechanisms are available? (Take a look at apprtc.appspot.com.) What problems might we encounter using 'pure' WebSocket? (Take a look at Arnout Kazemier's presentation, WebSuckets.)

What issues might be involved with scaling this application? Can you develop a method for testing thousands or millions of simultaneous room requests.

Try out Remy Sharp's tool nodemon. This monitors any changes in your Node.js application and automatically restarts the server when changes are saved.

This app uses a JavaScript prompt to get a room name. Work out a way to get the room name from the URL, for example localhost:2013/foo would give the room name foo.

View logging from the Chrome DevTools console and WebRTC debug information from chrome://webrtc-internals.

Bonus points

This application only supports one-to-one video chat. How might you change the design to enable more than one person to share the same video chat room? (Look at talky.io for an example of this in action.)

The example has the room name foo hard coded. What would be the best way to enable other room names?

Does the app work on mobile? Try it out on a phone, on a 7" and a 10" tablet. What layout, UI and UX changes would be required to ensure a good mobile experience?

Deploy your app at a public URL (see above for hosting options). Try different network configurations, for example with one user on wifi and another on 3G. Any problems?

How would users share the room name? Try to build an alternative to sharing room names.

The receiving side converts data channel message bytes back to an image and displays this to the user:

varbuf,count;// dc is an RTCDataChannel initialized somewhere elsedc.onmessage=function(event){if(typeofevent.data==='string'){buf=newUint8ClampedArray(parseInt(event.data));count=0;console.log('Expecting a total of '+buf.byteLength+' bytes');return;}vardata=newUint8ClampedArray(event.data);buf.set(data,count);count+=data.byteLength;if(count==buf.byteLength){// we're done: all data chunks have been receivedrenderPhoto(buf);}}functionrenderPhoto(data){varphoto=document.createElement('canvas');trail.insertBefore(photo,trail.firstChild);varcanvas=photo.getContext('2d');varimg=canvas.createImageData(300,150);img.data.set(data);canvas.putImageData(img,0,0);}