Skip to content

Instantly share code, notes, and snippets.

@luser
Created October 27, 2012 15:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luser/3965049 to your computer and use it in GitHub Desktop.
Save luser/3965049 to your computer and use it in GitHub Desktop.
webrtc datachannel demo
<html>
<head>
<title>Simple WebRTC Data Channel Test</title>
</head>
<body>
<table width=100% height=100%>
<tr><td><h1>Simple WebRTC Data Channel Test</h1></td></tr>
<tr><td>(Note: this JS code is REALLY UGLY)</td></tr>
<tr><td><div><button id="thebutton" onClick="start();">Start!</button></div><br/></td></tr>
<tr><td><form id="pc1_form" action="javascript:sendit(1)">
<div>pc1 says: <input id="pc1_input" type="text" value="type here" onKeyPress="return submitenter(this,event)"/>
<input type="submit"/></div></form></td>
<td><form id="pc1_blob" action="javascript:sendblob(1)">
<div>pc1 sends a blob: <input id="pc1_browse" type="file"/>
<input type="submit"/></div></form></td></tr>
<tr><td><form id="pc2_form" action="javascript:sendit(2)">
<div>pc2 says: <input id="pc2_input" type="text" value="type here" onKeyPress="return submitenter(this,event)"/>
<input type="submit"/></div></form></td>
<td><form id="pc2_blob" action="javascript:sendblob(2)">
<div>pc2 sends a blob: <input id="pc2_browse" type="file"/>
<input type="submit"/></div></form></td></tr>
<tr><td><div id="datawindow" style="
width: 100%;
height: 500px;
overflow: auto;
border: 1px solid red;"></div></td></tr>
</table>
<script type="application/javascript;version=1.8">
let button = document.getElementById("thebutton");
let text_pc1 = document.getElementById("pc1_input");
let text_pc2 = document.getElementById("pc2_input");
let blob_pc1 = document.getElementById("pc1_browse");
let blob_pc2 = document.getElementById("pc2_browse");
let datawindow = document.getElementById("datawindow");
let pc1;
let pc2;
let dc1;
let dc2;
let channel1;
let channel2;
let num_channels;
num_channels = 0;
var datachannels = new Array(0);
let pc1_offer;
let pc2_answer;
let iter = 0;
let iter2 = 0;
function log(msg) {
console.log(msg);
let div = document.getElementById("datawindow");
div.innerHTML = div.innerHTML + "<p>" + msg + "</p>";
}
var fancy_log = function(msg,color) {
console.log(msg);
var pre = document.createElement("p");
var message = '<span style="color: ' + color + ';">' + msg + '</span>';
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
datawindow.appendChild(pre); // (window).* here doesn't work right
pre.scrollIntoView(false);
};
function submitenter(myfield,e)
{
var keycode;
if (window.event) keycode = window.event.keyCode;
else if (e) keycode = e.which;
else return true;
if (keycode == 13)
{
myfield.form.submit();
return false;
}
else
return true;
}
var sendit = function (which) {
iter = iter + 1;
//log("Sending message #" + iter + " this = " + this);
if (which == 1) {
dc1.send(text_pc1.value);
text_pc1.value = "";
} else if (which == 2) {
dc2.send(text_pc2.value);
text_pc2.value = "";
}
else log("Unknown send " + which);
};
var sendblob = function (which) {
iter = iter + 1;
//log("Sending blob #" + iter + " this = " + this);
if (which == 1) {
dc1.send(blob_pc1.files[0]);
blob_pc1.value = "";
} else if (which == 2) {
dc2.send(blob_pc2.files[0]);
blob_pc2.value = "";
}
else log("Unknown sendblob " + which);
};
function failed(code) {
log("Failure callback: " + code);
}
// pc1.createOffer finished, call pc1.setLocal
function step1(offer) {
log("pc1.createOffer success callback");
pc1_offer = offer;
pc1.setLocalDescription(offer, step1_5, failed);
}
function step1_5() {
log("pc1 setLocalDescription callback");
setTimeout(step2,0);
}
// pc1.setLocal finished, call pc2.setRemote
function step2() {
log("pc1 createOffer/setLocalDescription finished");
pc2 = new mozRTCPeerConnection();
log("pc2 created");
pc2.ondatachannel = function(channel) {
log("pc2 onDataChannel [" +num_channels + "] = " + channel +
", label='" + channel.label + "'");
dc2 = channel;
datachannels[num_channels] = channel;
num_channels++;
log("pc2 created channel " + dc2 + " binarytype = " + dc2.binaryType);
channel.binaryType = "blob";
log("pc2 new binarytype = " + dc2.binaryType);
channel.onmessage = function(evt) {
iter2 = iter2 + 1;
if (evt.data instanceof Blob) {
fancy_log("*** pc1 sent Blob: " + evt.data + ", length=" + evt.data.size,"red");
} else {
fancy_log("*** pc1 said: " + evt.data + ", length=" + evt.data.length,"red");
}
};
/*
channel.addEventListener("message",function(evt) {
fancy_log('*** pc1 said: ' + evt.data,"red");
}, false);
*/
channel.onopen = function() {
log("*** pc2 onopen fired, sending to " + channel);
channel.send("pc2 says Hi there!");
};
channel.onclose = function() {
log("*** pc2 onclose fired");
};
log("*** pc2 state:" + channel.readyState);
// There's a race condition with onopen; if the channel is already
// open it should fire after onDataChannel -- state should normally be 0 here
if (channel.readyState != 0) {
log("*** pc2 no onopen??! possible race");
}
};
log("set pc2.ondatachannel");
pc2.onconnection = function() {
log("pc2 onconnection ");
//dc2 = pc2.createDataChannel();
//log("pc2 created channel " + dc2);
};
log("set pc2.onconnection");
pc2.onclosedconnection = function() {
log("pc2 onClosedConnection ");
};
log("set pc2.onclosedconnection");
function gotMediaStream(stream) {
log("pc2 mozGetUserMedia callback");
pc2.addStream(stream);
pc2.setRemoteDescription(pc1_offer, step3, failed);
log("pc2.setRemoteDescription finished");
}
navigator.mozGetUserMedia({audio: true, fake: true},
gotMediaStream, failed);
pc2.onaddstream = function(obj) {
log("pc2 got remote stream from pc1 " + obj.type);
}
};
// pc2.setRemote finished, call pc2.createAnswer
function step3() {
log("pc2.setRemoteDescription success callback");
pc2.createAnswer(step4, failed, {mandatory: {}, optional: []}, false);
log("pc2.createAnswer finished");
}
// pc2.createAnswer finished, call pc2.setLocal
function step4(answer) {
log("pc2.createAnswer success callback");
pc2_answer = answer;
pc2.setLocalDescription(answer, step5, failed);
log("pc2.setLocalDescription finished");
}
// pc2.setLocal finished, call pc1.setRemote
function step5() {
log("pc2.setLocalDescription success callback");
pc1.setRemoteDescription(pc2_answer, step6, failed);
log("pc1.setRemoteDescription finished");
}
// pc1.setRemote finished, make a data channel
function step6() {
log("pc1.setRemoteDescription success callback");
log("HIP HIP HOORAY");
setTimeout(step7,2000);
}
function step7() {
log("about to connect data connections");
pc1.connectDataConnection(5000,5001);
log("called pc1.connectDataConnection");
pc2.connectDataConnection(5001,5000);
log("called pc2.connectDataConnection");
}
function start() {
button.innerHTML = "Stop!";
button.onclick = stop;
pc1 = new mozRTCPeerConnection();
log("pc1 created");
pc1.onaddstream = function(obj) {
log("pc1 got remote stream from pc2 " + obj.type);
}
log("set pc1.onaddstream");
pc1.ondatachannel = function(channel) {
// In case pc2 opens a channel
log("pc1 ondatachannel [" +num_channels + "] = " + channel +
", label='" + channel.label + "'");
datachannels[num_channels] = channel;
num_channels++;
channel.onmessage = function(evt) {
if (evt.data instanceof Blob) {
fancy_log("*** pc2 sent Blob: " + evt.data + ", length=" + evt.data.size,"blue");
} else {
fancy_log('pc2 said: ' + evt.data + ", length=" + evt.data.length,"blue");
}
}
/*
channel.addEventListener("message",function(evt) {
fancy_log('pc2 said: ' + evt.data,"blue");
}, false);
*/
channel.onopen = function() {
log("pc1 onopen fired for " + channel);
channel.send("pc1 says Hello out there...");
log("pc1 state: " + channel.state);
}
channel.onclose = function() {
log("pc1 onclose fired");
};
log("pc1 state:" + channel.readyState);
// There's a race condition with onopen; if the channel is already
// open it should fire after ondatachannel -- state should normally be 0 here
if (channel.readyState != 0) {
log("*** pc1 no onopen??! possible race");
}
};
log("set pc1.ondatachannel");
pc1.onconnection = function() {
log("pc1 onconnection ");
dc1 = pc1.createDataChannel("This is pc1",{}); // reliable (TCP-like)
// dc1 = pc1.createDataChannel("This is pc1",{outOfOrderAllowed: true, maxRetransmitNum: 0}); // unreliable (UDP-like)
log("pc1 created channel " + dc1 + " binarytype = " + dc1.binaryType);
channel = dc1;
channel.binaryType = "blob";
log("pc1 new binarytype = " + dc1.binaryType);
// Since we create the datachannel, don't wait for ondatachannel!
channel.onmessage = function(evt) {
if (evt.data instanceof Blob) {
fancy_log("*** pc2 sent Blob: " + evt.data + ", length=" + evt.data.size,"blue");
} else {
fancy_log('pc2 said: ' + evt.data,"blue");
}
}
/*
// This is generally preferred to onxxx =
channel.addEventListener("message",function(evt) {
fancy_log('pc2 said: ' + evt.data,"blue");
}, false);
*/
channel.onopen = function() {
log("pc1 onopen fired for " + channel);
channel.send("pc1 says Hello...");
log("pc1 state: " + channel.state);
}
channel.onclose = function() {
log("pc1 onclose fired");
};
log("pc1 state:" + channel.readyState);
};
log("set pc1.onconnection");
pc1.onclosedconnection = function() {
log("pc1 onclosedconnection ");
};
log("set pc1.onclosedconnection");
function gotMediaStream(stream) {
log("pc1 mozGetUserMedia callback");
pc1.addStream(stream);
pc1.createOffer(step1, failed, {mandatory: {}, optional: []});
log("pc1.createOffer");
}
navigator.mozGetUserMedia({audio: true, fake: true},
gotMediaStream, failed);
}
function stop() {
pc1.close();
pc2.close();
button.innerHTML = "Start!";
button.onclick = start;
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment