Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
toby cabot committed Jul 22, 2013
0 parents commit 09117f4
Show file tree
Hide file tree
Showing 6 changed files with 337 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules
83 changes: 83 additions & 0 deletions PeerConnection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* MIT License: https://webrtc-experiment.appspot.com/licence/
2013, Muaz Khan<muazkh>--[github.com/muaz-khan]
Demo & Documentation: http://bit.ly/RTCPeerConnection-Documentation */
window.moz = !! navigator.mozGetUserMedia;
var PeerConnection = function (options) {
var PeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection,
SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription,
IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;

// See https://gist.github.com/zziuni/3741933 for a list of public STUN servers
var iceServers = {
iceServers: [{ url: 'stun:stunserver.org' }]
};

var optional = {
optional: []
};
if (!moz) {
// See http://www.webrtc.org/interop under "Constraints / configurations issues."
optional.optional = [{
DtlsSrtpKeyAgreement: true
}
];
}

var peerConnection = new PeerConnection(iceServers, optional);
peerConnection.onicecandidate = function(event) {
if (!event.candidate) return;
options.onicecandidate(event.candidate);
}
peerConnection.onaddstream = function(event) {
console.log('------------onaddstream');
options.onaddstream(event.stream);
}

var constraints = options.constraints || {
optional: [],
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}
};
if (moz) constraints.mandatory.MozDontOfferDataChannel = true;

return {
createOffer: function (callback) {
peerConnection.createOffer(function (sessionDescription) {
peerConnection.setLocalDescription(sessionDescription);
callback(sessionDescription);
}, null, constraints);
},

createAnswer: function (offerSDP, callback) {
peerConnection.setRemoteDescription(new SessionDescription(offerSDP));
peerConnection.createAnswer(function (sessionDescription) {
peerConnection.setLocalDescription(sessionDescription);
callback(sessionDescription);
}, null, constraints);
},

setRemoteDescription: function (sdp) {
console.log('--------adding answer sdp:');
console.log(sdp.sdp);

sdp = new SessionDescription(sdp);
peerConnection.setRemoteDescription(sdp);
},

addICECandidate: function (candidate) {
console.log("addICE: got candidate: " + candidate.candidate);
peerConnection.addIceCandidate(new IceCandidate({
sdpMLineIndex: candidate.sdpMLineIndex,
candidate: candidate.candidate
}));
},

addStream: function(stream) {
console.log("stream provided, attaching...");
peerConnection.addStream(stream);
}
};
};
55 changes: 55 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
This is a *minimal* demo of WebRTC video calling between two browsers.
Because the signalling layer isn't standardized, you'll need to run a
small node.js server to pass signalling messages between the two
browsers. The media connections are point-to-point, though, once the
signalling has happened no server is required.

This demo is based on Silvia Pfeiffer's WebRTC via Web Sockets demo,
and Muaz Khan's WebRTC-Experiment websocket-over-nodejs demo.
Silvia's demo became obsolete (it uses ROAP signalling while JSEP is
now the standard) and Muaz's demo was more complex than I liked which
made it difficult to figure out what the WebRTC API's were doing.
Both of their code was very helpful to me, though!

Silvia's Blog post:
http://blog.gingertech.net/2012/06/04/video-conferencing-in-html5-webrtc-via-web-sockets/

Muaz's WebRTC Experiments web site:
https://www.webrtc-experiment.com/

Muaz's WebSocket over Node.js demo:
https://github.com/muaz-khan/WebRTC-Experiment/tree/master/websocket-over-nodejs

Installation:

Install node.js from http://nodejs.org

Install Node's websocket package:
$ npm install websocket

Install the node-static package to serve static files:
$ npm install node-static

Usage:

Run the Node server:
$ node websocket-server.js

Point two browsers at http://your-server-address:1337/. You'll be
prompted to allow the use of your camera and microphone.

One of the browsers clicks "Call" and the call should be set up.

To close the call just reload the page. Like I said: this is a
minimal demo.

Debugging the Node Server:
install https://github.com/node-inspector/node-inspector
run the node app in debug mode (will stop at the first line)
$ node --debug-brk websocket-server.js
then in another terminal
$ node node_modules/node-inspector/bin/inspector.js
- or -
$ node_modules/.bin/node-inspector
open chrome to http://127.0.0.1:8080/debug?port=5858
step once to go to the first line of the program
78 changes: 78 additions & 0 deletions call.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* MIT License: https://webrtc-experiment.appspot.com/licence/ */

var call = function (config) {
var
peerConnection = PeerConnection(makePeerConfig()),
webSocket = new WebSocket('ws://' + document.location.host + '/');

// configure the signalling WebSocket
webSocket.onmessage = function (event) {
console.log("received a message: " + event.data);
onIncomingMessage(JSON.parse(event.data));
};
webSocket.push = webSocket.send;
webSocket.send = function (data) {
webSocket.push(JSON.stringify(data));
};

function onIncomingMessage(response) {
// the other client has sent me an offer SDP
if (response.offerSDP) {
console.log("received offerSDP " + response.offerSDP + ", will answer");
peerConnection.addStream(config.localStream);
peerConnection.createAnswer(response.offerSDP, function (sdp) {
console.log("sending answer SDP");
webSocket.send({
answerSDP: sdp
});
});
}

// the other client has sent me an answer SDP
if (response.answerSDP) {
peerConnection.setRemoteDescription(response.answerSDP);
}

// the other client has sent me an ICE candidate
if (response.candidate) {
console.log("got a candidate message, passing to RTCPeerConnection");
peerConnection.addICECandidate({
sdpMLineIndex: response.candidate.sdpMLineIndex,
candidate: response.candidate.candidate
});
}
}

// PeerConnection.js's options structure
function makePeerConfig() {
return {
onicecandidate: function (candidate) {
console.log("onICE");
webSocket.send({
candidate: {
sdpMLineIndex: candidate.sdpMLineIndex,
candidate: candidate.candidate
}
});
},
onaddstream: function (stream) {
console.log("onRemoteStream");
config.video['src'] = URL.createObjectURL(stream);
}
};
}

return {
initiateCall: function(localStream) {
// attach the stream to the peer connection
peerConnection.addStream(localStream);
// create the offer SDP and send it when it's ready
peerConnection.createOffer(function (sdp) {
console.log("sending offer SDP");
webSocket.send({
offerSDP: sdp
})
});
}
};
};
51 changes: 51 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title>Example WebRTC Point-to-point Video</title>
<style>
#video {
position: relative;
}
#local-video {
left: 0;
position: absolute;
top: 0;
z-index: 1;
}
</style>
</head>
<body>
<h1>Example WebRTC Point-to-point Video</h1>
<table class="visible">
<tr><td><button id="call" onClick="callPeer.initiateCall(config.localStream)">Call</button></td></tr>
</table>
<div id="video">
<video id="remote-video" autoplay="true" controls="true" width="480" height="360"></video>
<video id="local-video" autoplay="true" controls="true" muted="true" width="160" height="120"></video>
</div>
<script src="PeerConnection.js" type="text/javascript"></script>
<script src="call.js" type="text/javascript"></script>
<script type="text/javascript">
// temporary kludge to paper over browser differences
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

var config = {
video: document.getElementById('remote-video'),
};

navigator.getUserMedia({
audio: true,
video: true
},
function (localStream) {
video = document.getElementById('local-video');
video['src'] = URL.createObjectURL(localStream);
config.localStream = localStream;
},
function (e) { console.error(e); }
);

var callPeer = call(config);
</script>
</body>
</html>
69 changes: 69 additions & 0 deletions websocket-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// adapted from:
// http://blog.gingertech.net/2012/06/04/video-conferencing-in-html5-webrtc-via-web-sockets/

var WebSocketServer = require('websocket').server;
var http = require('http');
var static = require('node-static');
var clients = [];

var staticServer = new static.Server('.');

// set up node-static to serve static files in this directory,
// i.e., http://localhost:1337/index.html
var server = http.createServer(function(request, response) {
request.addListener('end', function() {
staticServer.serve(request, response);
}).resume();
});
server.listen(1337, function() {
console.log((new Date()) + " Server is listening on port 1337");
});

// create the server
wsServer = new WebSocketServer({
httpServer: server
});

function sendCallback(err) {
if (err) console.error((new Date()) + "send() error: " + err);
}

// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
var connection = request.accept(null, request.origin);
console.log((new Date()) + ' Connection remoteAddress ' + connection.remoteAddress);
clients.push(connection);

// This is the most important callback for us, we'll handle
// all messages from users here.
connection.on('message', function(message) {
if (message.type === 'utf8') {
// process WebSocket message
console.log((new Date()) + ' Received Message ' + message.utf8Data);
// broadcast message to all connected clients
clients.forEach(function (outputConnection) {
if (outputConnection != connection) {
outputConnection.send(message.utf8Data, sendCallback);
}
});
}
});

connection.on('close', function(connection) {
// close user connection
console.log((new Date()) + " Peer disconnected.");
for (var i = 0; i < clients.length; i++) {
if (!clients[i].connected)
clients.remove(i);
}
});
});

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};

0 comments on commit 09117f4

Please sign in to comment.