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.
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.)
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: 'liveweb.itp.io', 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.