<!DOCTYPE html>
|
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
<title>SCTP - PNG image transfer test</title>
|
<style>
|
button {
|
font: 18px sans-serif;
|
padding: 8px;
|
}
|
textarea {
|
font-family: monospace;
|
}
|
</style>
|
</head>
|
<body>
|
<div>
|
<br>
|
<h2>Start an SCTP datachannel</h2>
|
<button id="startButton" onclick="createConnection()">Start</button>
|
<button id="closeButton" onclick="closeDataChannels()" >Stop</button>
|
<br>
|
<h2>Select a (small) PNG image file (large files fail)</h2>
|
<form id="form1" enctype="multipart/form-data" method="post" action="">
|
<label for="fileToUpload">Select a file to show</label><br>
|
<input type="file" name="fileToUpload" id="fileToUpload">
|
<br>
|
<input type="button" id="sendButton" onclick="uploadFile()" value="Show" disabled="">
|
</form>
|
</div>
|
<div>
|
<br>
|
<h2>PNG Image</h2>
|
<img id="dataChannelReceive"><br>
|
</div>
|
<script>
|
var pc1, pc2, sendChannel, receiveChannel;
|
window.onload = function () {
|
startButton.disabled = false;
|
sendButton.disabled = true;
|
closeButton.disabled = true;
|
sendChannel = null;
|
}
|
|
function uploadFile() {
|
var file = document.getElementById('fileToUpload').files[0];
|
if (file) {
|
trace('Uploading file ' + file);
|
var reader = new FileReader();
|
reader.onload = function(file) {
|
if (reader.readyState == FileReader.DONE) {
|
sendChannel.send(file.target.result);
|
}
|
};
|
reader.readAsArrayBuffer(file);
|
} else {
|
trace('Failed to get file for upload.');
|
}
|
}
|
|
function trace(text) {
|
// This function is used for logging.
|
if (text[text.length - 1] == '\n') {
|
text = text.substring(0, text.length - 1);
|
}
|
console.log((performance.now() / 1000).toFixed(3) + ": " + text);
|
}
|
|
function createConnection() {
|
var servers = null;
|
pc1 = new webkitRTCPeerConnection(servers,
|
{optional: [{DtlsSrtpKeyAgreement: true}]});
|
trace('Created local peer connection object pc1');
|
|
pc1.onicecandidate = iceCallback1;
|
|
pc2 = new webkitRTCPeerConnection(servers,
|
{optional: [{DtlsSrtpKeyAgreement: true}]});
|
trace('Created remote peer connection object pc2');
|
|
pc2.onicecandidate = iceCallback2;
|
pc2.ondatachannel = receiveChannelCallback;
|
|
pc1.createOffer(gotDescription1);
|
startButton.disabled = true;
|
closeButton.disabled = false;
|
}
|
|
function closeDataChannels() {
|
trace('Closing data Channels');
|
sendChannel.close();
|
trace('Closed data channel with label: ' + sendChannel.label);
|
receiveChannel.close();
|
trace('Closed data channel with label: ' + receiveChannel.label);
|
pc1.close();
|
pc2.close();
|
sendChannel = null;
|
pc1 = null;
|
pc2 = null;
|
trace('Closed peer connections');
|
startButton.disabled = false;
|
sendButton.disabled = true;
|
closeButton.disabled = true;
|
}
|
|
function gotDescription1(desc) {
|
trace('gotDescription1');
|
// trace('getDesc1[Entry]: Offer from pc1 \n' + desc.sdp);
|
pc1.setLocalDescription(desc);
|
// trace('getDesc1[setLocalDesc]: Offer from pc1 \n' + desc.sdp);
|
pc2.setRemoteDescription(desc);
|
// trace('getDesc1[setRemoteDesc]: Offer from pc1 \n' + desc.sdp);
|
pc2.createAnswer(gotDescription2);
|
// trace('getDesc1[createAnswer]: Offer from pc1 \n' + desc.sdp);
|
}
|
|
function gotDescription2(desc) {
|
trace('gotDescription2');
|
// trace('gotDesc2[Entry]: Answer from pc2 \n' + desc.sdp);
|
pc2.setLocalDescription(desc);
|
// trace('gotDesc2[setLocal]: Answer from pc2 \n' + desc.sdp);
|
pc1.setRemoteDescription(desc);
|
// trace('gotDesc2[setRemote]: Answer from pc2 \n' + desc.sdp);
|
}
|
|
function iceCallback1(event) {
|
trace('local ice callback');
|
if (event.candidate) {
|
pc2.addIceCandidate(event.candidate);
|
// trace('Local ICE candidate: \n' + event.candidate.candidate);
|
}
|
}
|
|
function iceCallback2(event) {
|
trace('remote ice callback, sendChannel is ' + sendChannel);
|
if (event.candidate) {
|
pc1.addIceCandidate(event.candidate);
|
// trace('Remote ICE candidate: \n ' + event.candidate.candidate);
|
}
|
trace('-- sendChannel is ' + sendChannel);
|
if (sendChannel == null) {
|
try {
|
// Reliable Data Channels not yet supported in Chrome
|
// Data Channel api supported from Chrome M25.
|
// You need to start chrome with --enable-data-channels flag.
|
sendChannel = pc1.createDataChannel("sendDataChannel",
|
{reliable: true});
|
trace('Created send data channel');
|
} catch (e) {
|
alert('Failed to create data channel. You need Chrome M30 or later ' +
|
'with flags: --enable-data-channels --enable-sctp-data-channels ');
|
trace('Create Data channel failed with exception: ' + e.message);
|
}
|
sendChannel.onopen = onSendChannelStateChange;
|
sendChannel.onclose = onSendChannelStateChange;
|
}
|
}
|
|
function receiveChannelCallback(event) {
|
trace('Receive Channel Callback');
|
receiveChannel = event.channel;
|
receiveChannel.onmessage = onReceiveMessageCallback;
|
receiveChannel.onopen = onReceiveChannelStateChange;
|
receiveChannel.onclose = onReceiveChannelStateChange;
|
}
|
|
function onReceiveMessageCallback(event) {
|
trace('Received Message: ' + event.data);
|
var blob = new Blob([event.data], {type:"image/png"});
|
var reader = new FileReader();
|
reader.onload = function(file) {
|
if (reader.readyState == FileReader.DONE) {
|
document.getElementById("dataChannelReceive").src = file.target.result;
|
}
|
}
|
reader.readAsDataURL(blob);
|
}
|
|
function onSendChannelStateChange() {
|
var readyState;
|
if (sendChannel != null) {
|
readyState = sendChannel.readyState;
|
} else {
|
readyState = "null";
|
}
|
trace('Send channel state is: ' + readyState);
|
if (readyState == "open") {
|
sendButton.disabled = false;
|
closeButton.disabled = false;
|
} else {
|
sendButton.disabled = true;
|
closeButton.disabled = true;
|
sendChannel = null;
|
}
|
}
|
|
function onReceiveChannelStateChange() {
|
var readyState = receiveChannel.readyState;
|
trace('Receive channel state is: ' + readyState);
|
}
|
|
</script>
|
</body></html>
|