Skip to content

Instantly share code, notes, and snippets.

@mvenkatesh431
Forked from xeoncross/Webrtc.html
Last active August 31, 2015 11:00
Show Gist options
  • Select an option

  • Save mvenkatesh431/23eea38a8f356aaf9e02 to your computer and use it in GitHub Desktop.

Select an option

Save mvenkatesh431/23eea38a8f356aaf9e02 to your computer and use it in GitHub Desktop.
Simple webrtc demo script
<h1>WebRTC</h1>
<script>
// This is only needed for browser testing
window.RTCPeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
window.RTCSessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
window.RTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
// window.URL = window.webkitURL || window.URL;
</script>
<script>
// Globals that will be object properties once we wrap this up as a module
var localStream;
var localStreamView;
var clients;
var remoteVideoViews = [];
var ourClientId = '' + randomInt(1,1000);
console.log('ourClientId', ourClientId);
// Actual RTCPeerConnections based on clients
var peers = {};
var mediaConstraints = {
optional: [],
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}
};
// http://www.w3.org/TR/webrtc/#idl-def-RTCOfferOptions
var RTC_Offer_Options = {
offerToReceiveVideo: true,
offerToReceiveAudio: true
};
var peerconnectionOptions = {
'optional': [
{'DtlsSrtpKeyAgreement': true},
{'RtpDataChannels': true }
]
};
// http://w3c.github.io/webrtc-pc/#idl-def-RTCConfiguration
var RTC_Configuration = {
// more options here
// ...
iceServers: [
// {url: 'stun:stun.services.mozilla.com'},
{url: 'stun:stun.l.google.com:19302'}
]
};
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
</script>
<!-- Sample signaling server using socket.io -->
<script src="socket.io.js"></script>
<script>
var signaling = io.connect('http://localhost:8000/');
signaling.on('clients', function(clients) {
console.log('clients', clients);
});
signaling.on('call list', function(room, usernames) {
clients = usernames;
startCalling();
});
signaling.emit('username', ourClientId, function(error) {
console.log('username', error);
signaling.emit('join', 'testing', function(error) {
console.log('join', error);
});
});
function send(name, message) {
console.log('send', name, message);
signaling.emit('sendMessage', name, message);
}
</script>
<script>
// And and remove videos as needed
var remoteVideoViews = [];
function addStream(stream, me) {
var videoView = document.createElement('video');
videoView.autoplay = true;
videoView.setAttribute('muted', true);
videoView.setAttribute('autoplay', true);
videoView.setAttribute('controls', true);
videoView.style.width = '300px';
// videoView.id = me || +new Date();
videoView.className = me ? 'me' : 'them';
videoView.src = URL.createObjectURL(stream);
videoView.load();
remoteVideoViews.push(videoView);
document.body.appendChild(videoView);
return videoView;
}
function removeStream(videoView) {
document.body.removeChild(videoView);
remoteVideoViews.splice(videoView, 1);
}
var startCalling = function() {
console.log('startCalling', clients, !!localStream);
// Wait to recive a client list and access to the local video view
if(! clients || !localStream) {
return;
}
signaling.on('messageReceived', function(name, message) {
console.log('messageReceived from', name, message);
if(message.type === 'offer') {
var peer = peerConnectionTo(name);
var state = peer.signalingState;
var offerSDP = new RTCSessionDescription(message.data);
peer.setRemoteDescription(offerSDP);
// We have been called so we need to send the SDP and ICE Candidate
if(state === 'stable') {
console.log('state', state);
peer.createAnswer(function (answerSDP) {
// Upgrade bandwidth from 30k to 5000k
// console.log('answerSDP', answerSDP.sdp);
// var Bandwidth = 5000;
// answerSDP.sdp = answerSDP.sdp.replace(/b=AS:([0-9]+)/g, 'b=AS:'+Bandwidth);
// console.log('answerSDP', answerSDP.sdp);
peer.setLocalDescription(answerSDP);
// use XHR/WebSocket/etc. to exchange answer-sdp with "offerer"
signaling.emit('sendMessage', name, {
type: 'offer',
data: answerSDP
});
}, console.log, mediaConstraints);
peer.onicecandidate = function (event) {
if (!event || !event.candidate) return;
// answerer.addIceCandidate(event.candidate);
signaling.emit('sendMessage', client, {
type: 'candidate',
data: event.candidate
});
// We only need the first candidate...?
peer.onicecandidate = null;
};
}
return;
}
if(message.type === 'candidate') {
var peer = peerConnectionTo(name);
peer.addIceCandidate(new RTCIceCandidate(message.data));
}
});
for (var i = 0; i < clients.length; i++) {
var client = clients[i];
// Skip ourselves
if(client === ourClientId) continue;
if(peers[client]) {
console.log('already have a peer with', client);
continue;
}
call(client);
};
}
// We are calling something
function call(name) {
if(peers[name]) {
console.log('already have a peer with', name);
return;
}
console.log('call', name);
var peer = peerConnectionTo(name);
// let the "negotiationneeded" event trigger offer generation
peer.onnegotiationneeded = function () {
console.log('peer.negotiationneeded for ', name);
peer.createOffer(function (offer) {
console.log('createOffer', name, offer);
peer.setLocalDescription(offer);
signaling.emit('sendMessage', name, {
type: 'offer',
data: offer // peer.localDescription
});
}, console.log, RTC_Offer_Options);
};
peer.onicecandidate = function (event) {
console.log('onicecandidate for', name, event.candidate);
if (!event || !event.candidate) return;
signaling.emit('sendMessage', name, {
type: 'candidate',
data: event.candidate
});
// We only need the first candidate...?
// peer.onicecandidate = null;
};
// Caller creates the datachannel
var dc = peer.createDataChannel("chats");
peer.dc = dc; // save for later
console.log("created DataChannel", dc.id, name);
dc.onmessage = function (event) {
console.log("dc.received: " + event.data, name);
};
dc.onopen = function () {
console.log("dc.open", name);
var readyState = dc.readyState;
console.log('dc.readyState', dc.readyState);
if (readyState == "open") {
dc.send('dc.send to', name, 'from', ourClientId);
} else {
console.log('channel not open yet, dc.send fail');
}
// setTimeout(function() {
// dc.send('dc.send to', name, 'from', ourClientId);
// }, 3000);
};
dc.onclose = function () {
console.log("dc.close", name);
};
}
function peerConnectionTo(name) {
if( ! peers[name]) {
console.log('creating peerConnectionTo', name);
// http://www.w3.org/TR/webrtc/#rtcpeerconnection-interface
peers[name] = new RTCPeerConnection(RTC_Configuration, peerconnectionOptions);
// Add our video stream
peers[name].addStream(localStream);
// When we get access to their stream show it
peers[name].onaddstream = function (event) {
console.log('adding stream', name);
addStream(event.stream);
};
// When we get access to their stream show it
peers[name].onremovestream = function (event) {
console.log('removing stream', name);
removeStream(event.stream);
};
// Both caller and callee get this but only callee uses it
// since the caller creates the channel in call
peers[name].ondatachannel = function (evt) {
console.log('ondatachannel', evt);
peers[name].dc = evt.channel;
peers[name].dc.send('First Message');
};
}
return peers[name];
}
function getUserMedia(callback) {
navigator.getUserMedia({
audio: true,
video: true
}, callback, function(e) {
console.log(e);
});
}
getUserMedia(function (stream) {
localStreamView = addStream(stream);
localStream = stream;
startCalling();
});
function waitUntilRemoteStreamStartsFlowing(remote_video, callback)
{
if (!(remote_video.readyState <= HTMLMediaElement.HAVE_CURRENT_DATA
|| remote_video.paused || remote_video.currentTime <= 0))
{
// remote stream started flowing!
callback();
return;
}
setTimeout(function() {
waitUntilRemoteStreamStartsFlowing(remote_video, callback)
}, 50);
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment