Skip to content

Instantly share code, notes, and snippets.

@markandrus
Created July 9, 2014 01:01
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markandrus/c1dad8607de5b7713214 to your computer and use it in GitHub Desktop.
Save markandrus/c1dad8607de5b7713214 to your computer and use it in GitHub Desktop.
WebRTC Test Client
// This is the signaling server for relaying messages between Node.js and
// Chrome. Run it with
//
// $ node server.js
//
function SignalingServer() {
var clients = {};
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({
'port': 8080
});
wss.on('connection', function(ws) {
ws.on('message', function(data) {
var message = JSON.parse(data);
if (message['register']) {
// Register the client's WebSocket if they aren't already registered.
var name = message['register'];
clients[name] = clients[name] || {};
var client = clients[name];
client['ws'] = ws;
console.log('Registering WebSocket for ' + name);
// Empty their queue of messages.
if (client['queue']) {
client['queue'].forEach(function(message) {
console.log('Send queued message to ' + name, message);
ws.send(message);
});
delete client['queue'];
}
} else {
// Get the recipient.
var name = message['to'];
clients[name] = clients[name] || {};
var to = clients[name];
var from = message['from'];
console.log('Sending message to ' + name + ' for ' + from, message);
// Enqueue the message if their WebSocket isn't already registered.
if (!('ws' in to)) {
to['queue'] = to['queue'] || [];
to['queue'].push(data);
} else {
to['ws'].send(data);
}
}
});
});
}
new SignalingServer();
<html>
<head>
<title>node-webrtc getUserMedia test</title>
</head>
<body>
<video id="localVideo"></video>
<video id="remoteVideo"></video>
<script>
var initiator = false;
</script>
<script src="./test.js"></script>
</body>
</html>
// WebRTC Test Client
// ------------------
// This is a WebRTC test client that can run in both Node.js and
// Chrome. Node.js relies on ws for WebSocket functionality and
// wrtc for WebRTC functionality.
//
// First, start the signaling server (see server.js).
//
// Then, run the Chrome client by navigating to test.html.
//
// Finally, run the Node.js client with
//
// $ node test.js
//
var NODE = 'Node.js';
var CHROME = 'Chrome';
var detected = typeof process !== 'undefined' ? NODE : CHROME;
console.log('Detected ' + detected);
// Signaling Channel
// -----------------
function SignalingChannel(to, from) {
var self = this instanceof SignalingChannel
? this
: Object.create(SignalingChannel.prototype);
// Setup the WebSocket.
var queue = [];
var open = false;
if (detected === NODE) {
WebSocket = require('ws');
}
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
open = true;
ws.send(JSON.stringify({
'register': from
}));
// Send any queued messages.
queue.forEach(function(blob) {
ws.send(blob);
});
};
self.send = function send(message) {
var blob = JSON.stringify({
'to': to,
'from': from,
'message': message
})
// Send or enqueue the message.
if (open) {
ws.send(blob);
} else {
queue.push(blob);
}
};
ws.onmessage = function(evt) {
var json = JSON.parse(evt['data']);
var message = JSON.parse(json['message']);
if (message['sdp']) {
pc.setRemoteDescription(new RTCSessionDescription(message['sdp']),
function() {
console.log('setRemoteDescription() succeeded');
if (pc.remoteDescription.type === 'offer') {
pc.createAnswer(createSucceeded('Answer'), createFailed('Answer'));
}
},
function(error) {
console.log('setRemoteDescription() failed: ', error.message);
});
} else if (message['candidate']) {
console.info(message['candidate']);
console.info(message['candidate']['candidate']);
pc.addIceCandidate(new RTCIceCandidate(message['candidate']));
}
};
return self;
}
var to = detected === NODE ? CHROME : NODE;
var from = detected;
var signalingChannel = new SignalingChannel(to, from);
// WebRTC
// ------
var pc = null;
var initiator = typeof initiator === 'undefined' ? true : initiator;
var RTCPeerConnection = null;
var getUserMedia = null;
if (detected === NODE) {
var webrtc = require('./lib/index');
RTCPeerConnection = webrtc.RTCPeerConnection;
RTCSessionDescription = webrtc.RTCSessionDescription;
RTCIceCandidate = webrtc.RTCIceCandidate;
getUserMedia = webrtc.getUserMedia;
} else if (detected === CHROME) {
RTCPeerConnection = window.webkitRTCPeerConnection;
getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
}
pc = new RTCPeerConnection({
'iceServers': [
{'url': 'stun:stun.l.google.com:19302'}
]
}, {
'optional': [
{'DtlsSrtpKeyAgreement': true}
]
});
pc.onicecandidate = function(evt) {
console.log('onicecandidate() called: ', evt);
var candidate = evt.candidate;
if (candidate) {
signalingChannel.send(JSON.stringify({
'candidate': candidate
}));
}
};
/*pc.onnegotiationneeded = function() {
console.log('onnegotiationneeded() called');
pc.createOffer(createSucceeded('Offer'), createFailed('Offer'));
};*/
pc.onaddstream = function(evt) {
var stream = evt.stream;
console.log('onaddstream() called: ', evt);
if (detected === CHROME) {
var remoteVideo = document.getElementById('remoteVideo');
remoteVideo.src = URL.createObjectURL(stream);
}
};
getUserMedia({
'audio': true,
'video': false
}, function(stream) {
console.log('getUserMedia() succeeded: ', stream);
pc.addStream(stream);
if (detected === CHROME) {
var localVideo = document.getElementById('localVideo');
localVideo.src = URL.createObjectURL(stream);
}
}, function(error) {
console.error('getUserMedia() failed: ', error.message);
});
function createSucceeded(type) {
return function(offer) {
console.log('create' + type + '() succeeded: ', offer);
pc.setLocalDescription(offer, function() {
console.log('setLocalDescription() succeeded');
signalingChannel.send(JSON.stringify({
'sdp': pc.localDescription
}));
});
};
}
function createFailed(type) {
return function(type) {
console.error('create' + type + '() failed: ', error.message);
};
}
if (initiator) {
console.log('Initiating call...');
pc.createOffer(createSucceeded('Offer'), createFailed('Offer'), {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': false
}
});
} else {
console.log('Awaiting offer...');
console.log('HINT: Call signalingChannel.recvJSON() with SDPs or ICE candidates.');
}
@dh1tw
Copy link

dh1tw commented Sep 13, 2014

A few notes if you want to try out this code:

  1. Check out the markandrus:getStats branch of node-webrtc from Mark's repo as long as his pull request hasn't been merged into the main trunk of node-webrtc
    git clone --branch getStats https://github.com/markandrus/node-webrtc.git
  1. You need to build the project (with all the webrtc bindings) so that the added getUserMedia function get's correctly recognized.
    cd /bin
    npm install --build-from-source

This might take some time (20minutes)

  1. Copy the files in this Gist into /examples/getUserMedia
  2. Execute examples/getUserMedia/server.js (with node.js)
  3. Open Chrome and load /examples/getUserMedia/test.html
  4. Execute examples/getUserMedia/test.js (with node.js)

@eafzali
Copy link

eafzali commented Sep 30, 2014

I've done as you said on a an ubuntu server 14.04 server with node v0.10.32 but when I run wrtc = require('./lib/index') node process halts! without any response at all.
I cloned this gist and when I run test.js using node the same thing happens.
here is my build.log: http://pastebin.com/UPkGhxSi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment