WebRTC

WebRTC is a new standard being put forth by the W3C to create an API to deliver realtime data, audio, and video between browsers in a peer to peer fashion.

PeerJS

Unfortunately, there is a fair amount of complexity involved in sending descriptions of the data, audio and video channels from peer to peer.

Fortunately, a few JavaScript libraries have popped up to aide in this. One, in particular that we'll go over is PeerJS. (Unfortunately, PeerJS itself seems to be in a bit of flux as well but for now, we'll stick with it.)

Simple Video Conferencing Example

The first step is to do our normal getUserMedia, gaining access to a stream from the user's camera and microphone:

/* Get User Media */
var my_stream = null;

window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (navigator.getUserMedia) {
	navigator.getUserMedia({video: true, audio: true}, function(stream) {
				my_stream = stream;
				var videoElement = document.getElementById('myvideo');
				videoElement.src = window.URL.createObjectURL(stream) || stream;
				videoElement.play();
			}, function(err) {
				console.log('Failed to get local stream' ,err);
	});
}		
		
This requires that a video element be present on the page with the id of "myvideo":
<video id="myvideo" width="320" height="240"></video>
		
Also, it should be run inside an onload event as the video element isn't available until it is rendered.

The next step is to include the PeerJS JavaScript library. (Download it from here: peer.min.js)

<script src="peer.min.js">/script>		
		
and to create an instance of a "peer" and connect to the PeerJS server
// We'll use a global variable to hold on to our id from PeerJS
var peer_id = null;

// Register for an API Key:	http://peerjs.com/peerserver
//var peer = new Peer({key: 'YOUR API KEY'});
// The Peer Cloud Server doesn't seem to be operational, I setup a server on a Digital Ocean instance for our use, you can use that with the following constructor:
var peer = new Peer({host: '104.131.82.13', port: 9000, path: '/'});

// Get an ID from the PeerJS server		
peer.on('open', function(id) {
  console.log('My peer ID is: ' + id);
  peer_id = id;
});		
		

This should be enough for us to receive a "call"

peer.on('call', function(incoming_call) {
	console.log("Got a call!");
	incoming_call.answer(my_stream); // Answer the call with our stream from getUserMedia
	incoming_call.on('stream', function(remoteStream) {  // we receive a getUserMedia stream from the remote caller
		// And attach it to a video object
		var ovideoElement = document.getElementById('othervideo');
		ovideoElement.src = window.URL.createObjectURL(remoteStream) || remoteStream;
		ovideoElement.setAttribute("autoplay", "true");		
		ovideoElement.play();
	});
});		
		

PeerJS runs a server which aides in the transmission of audio/video/data channel information but we'll still need to run a server to introduce the users to each-other. We can use a normal WebSocket server as we have been doing and use it to share the PeerJS ID value between users.

Here is a basic server that relays the peer_id's:

// HTTP Portion
var http = require('http');
var fs = require('fs'); // Using the filesystem module
var httpServer = http.createServer(requestHandler);
httpServer.listen(8080);

function requestHandler(req, res) {
	// Read index.html
	fs.readFile(__dirname + '/webrtc.html', 
		// Callback function for reading
		function (err, data) {
			// if there is an error
			if (err) {
				res.writeHead(500);
				return res.end('Error loading index.html');
			}
			// Otherwise, send the data, the contents of the file
			res.writeHead(200);
			res.end(data);
  		}
  	);
}


// WebSocket Portion
// WebSockets work with the HTTP server
var io = require('socket.io').listen(httpServer);

var connectedSockets = [];  // Since io.sockets.clients() no longer works

// Register a callback function to run when we have an individual connection
// This is run for each individual user that connects
io.sockets.on('connection', 
	// We are given a websocket object in our function
	function (socket) {
	
		console.log("We have a new client: " + socket.id);

		// Add to the connectedSockets Array
		connectedSockets.push(socket);
		
		socket.on('peer_id', function(data) {
			console.log("Received: 'peer_id' " + data);

			// We can save this in the socket object if we like
			socket.peer_id = data;
			console.log("Saved: " + socket.peer_id);

			// We can loop through these if we like
			for (var i  = 0; i < connectedSockets.length; i++) {
				console.log("loop: " + i + " " + connectedSockets[i].peer_id);
			}
			
			// Tell everyone my peer_id
			socket.broadcast.emit('peer_id',data);
		});
		
		
		socket.on('disconnect', function() {
			console.log("Client has disconnected");
			var indexToRemove = connectedSockets.indexOf(socket);
			connectedSockets.splice(indexToRemove, 1); // Remove 1 from position, indexToRemove
		});
	}
);
		

To use the server, we'll use our normal Socket.io code:

/* Socket Server - Socket.io */
var socket = io.connect('YOUR SOCKET.IO SERVER URL PORT');
					
socket.on('connect', function() {
	console.log("Connected");

	// Our socket is connected, send out our peer id here
	console.log("sending out our peer id");
	socket.emit("peer_id",peer_id);				
});

// Receive other folks peer ids
socket.on('peer_id', function (data) {
	console.log("Got a new peer: " + data);

	// Call them with our stream
	console.log("Calling peer: " + data);						
	var call = peer.call(data, my_stream);

	call.on('stream', function(remoteStream) {
		console.log("Got remote stream");
		var ovideoElement = document.createElement('video');
		ovideoElement.src = window.URL.createObjectURL(remoteStream) || remoteStream;
		ovideoElement.setAttribute("autoplay", "true");
		ovideoElement.play();
	});
});
		

Putting these pieces all together, we get something like this: webrtc_new.zip.
And an example that doesn't use a socket server, instead you have to get the peer id of the person you want to call by some other means: videochat.html.