Skip to content

Commit

Permalink
Merge pull request #483 from fippo/filetransfer-bitrate
Browse files Browse the repository at this point in the history
filetransfer: show bitrate stats
  • Loading branch information
samdutton committed Feb 27, 2015
2 parents 57230e8 + 056cc85 commit f53760f
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/content/datachannel/filetransfer/css/main.css
Expand Up @@ -5,7 +5,7 @@
* that can be found in the LICENSE file in the root of the source
* tree.
*/
div.progress {
div.progress, div#bitrate {
margin: 0 0 1em 0;
}

Expand Down
49 changes: 34 additions & 15 deletions src/content/datachannel/filetransfer/index.html
Expand Up @@ -29,28 +29,47 @@
<div id="container">

<h1><a href="https://webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> <span>Transfer a file</span></h1>
<section>

<form id="fileInfo">
<input type="file" id="fileInput" name="files"/>
</form>
<p>This page shows how to transfer a file via WebRTC datachannels.</p>

<div class="progress">
<div class="label">Send progress: </div>
<progress id="sendProgress" max="0" value="0"></progress>
</div>
<p>To accomplish this in an interoperable way, the file is split into chunks which are then transferred via the datachannel. The datachannel is reliable and ordered by default which is well-suited to filetransfers.</p>

<div class="progress">
<div class="label">Receive progress: </div>
<progress id="receiveProgress" max="0" value="0"></progress>
</div>
<p>Send and receive progress is monitored using HTML5 <i>progress</i> elements.</p>

<p>At the receiver, the file is reassembled using the Blob API and made available for download.</p>

<a id="received"></a>
<p>Note: real-world applications require a file transfer protocol to send metadata about the file (such as the filename, type, size, last modification date, hash, ...).This information can be conveyed either via the signaling channel or in-band. The demo elides this by assuming knowledge of the file size at the receiver and closes both the datachannel and the peerconnection when the correct amount of bytes has been received.</p>

<p>View the console to see logging.</p>
</section>

<p>The <code>RTCPeerConnection</code> objects <code>localConnection</code> and <code>remoteConnection</code> are in global scope, so you can inspect them in the console as well.</p>
<section>
<form id="fileInfo">
<input type="file" id="fileInput" name="files"/>
</form>

<p>For more information about RTCDataChannel, see <a href="http://www.html5rocks.com/en/tutorials/webrtc/basics/#toc-rtcdatachannel" title="RTCDataChannel section of HTML5 Rocks article about WebRTC">Getting Started With WebRTC</a>.</p>
<div class="progress">
<div class="label">Send progress: </div>
<progress id="sendProgress" max="0" value="0"></progress>
</div>

<div class="progress">
<div class="label">Receive progress: </div>
<progress id="receiveProgress" max="0" value="0"></progress>
</div>

<div id="bitrate"></div>

<a id="received"></a>
</section>

<section>
<p>View the console to see logging.</p>

<p>The <code>RTCPeerConnection</code> objects <code>localConnection</code> and <code>remoteConnection</code> are in global scope, so you can inspect them in the console as well.</p>

<p>For more information about RTCDataChannel, see <a href="http://www.html5rocks.com/en/tutorials/webrtc/basics/#toc-rtcdatachannel" title="RTCDataChannel section of HTML5 Rocks article about WebRTC">Getting Started With WebRTC</a>.</p>
</section>

<a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/datachannel/filetransfer" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a>
</div>
Expand Down
79 changes: 79 additions & 0 deletions src/content/datachannel/filetransfer/js/main.js
Expand Up @@ -13,6 +13,7 @@ var remoteConnection;
var sendChannel;
var receiveChannel;
var pcConstraint;
var bitrateDiv = document.querySelector('div#bitrate');
var fileInput = document.querySelector('input#fileInput');
fileInput.addEventListener('change', createConnection, false);
var sendProgress = document.querySelector('progress#sendProgress');
Expand All @@ -21,6 +22,12 @@ var receiveProgress = document.querySelector('progress#receiveProgress');
var receiveBuffer = [];
var receivedSize = 0;

var bytesPrev = 0;
var timestampPrev = 0;
var timestampStart;
var statsInterval = null;
var bitrateMax = 0;

function createConnection() {
var servers = null;
pcConstraint = null;
Expand Down Expand Up @@ -58,6 +65,9 @@ function sendData() {
var file = fileInput.files[0];
trace('file is ' + [file.name, file.size, file.type,
file.lastModifiedDate].join(' '));
if (file.size === 0) {
return;
}
sendProgress.max = file.size;
receiveProgress.max = file.size;
var chunkSize = 16384;
Expand Down Expand Up @@ -161,6 +171,17 @@ function onReceiveMessageCallback(event) {
' bytes)';
href.appendChild(document.createTextNode(text));
href.style.display = 'block';

var bitrate = Math.round(receivedSize * 8 /
((new Date()).getTime() - timestampStart));
bitrateDiv.innerHTML = '<strong>Average Bitrate:</strong> ' +
bitrate + ' kbits/sec (max: ' + bitrateMax + ' kbits/sec)';

if (statsInterval) {
window.clearInterval(statsInterval);
statsInterval = null;
}

closeDataChannels();
}
}
Expand All @@ -176,4 +197,62 @@ function onSendChannelStateChange() {
function onReceiveChannelStateChange() {
var readyState = receiveChannel.readyState;
trace('Receive channel state is: ' + readyState);
if (readyState === 'open') {
timestampStart = (new Date()).getTime();
timestampPrev = timestampStart;
statsInterval = window.setInterval(displayStats, 500);
window.setTimeout(displayStats, 100);
window.setTimeout(displayStats, 300);
}
}

// display bitrate statistics.
function displayStats() {
var display = function(bitrate) {
bitrateDiv.innerHTML = '<strong>Current Bitrate:</strong> ' +
bitrate + ' kbits/sec';
};

if (remoteConnection &&
remoteConnection.iceConnectionState === 'connected') {
if (webrtcDetectedBrowser === 'chrome') {
// TODO: once https://code.google.com/p/webrtc/issues/detail?id=4321
// lands those stats should be preferrred over the connection stats.
remoteConnection.getStats(function(stats) {
stats.result().forEach(function(res) {
if (timestampPrev === res.timestamp) {
return;
}
if (res.type === 'googCandidatePair' &&
res.stat('googActiveConnection') === 'true') {
// calculate current bitrate
var bytesNow = res.stat('bytesReceived');
var bitrate = Math.round((bytesNow - bytesPrev) * 8 /
(res.timestamp - timestampPrev));
display(bitrate);
timestampPrev = res.timestamp;
bytesPrev = bytesNow;
if (bitrate > bitrateMax) {
bitrateMax = bitrate;
}
}
});
});
} else {
// Firefox currently does not have data channel stats. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1136832
// Instead, the bitrate is calculated based on the number of
// bytes received.
var bytesNow = receivedSize;
var now = (new Date()).getTime();
var bitrate = Math.round((bytesNow - bytesPrev) * 8 /
(now - timestampPrev));
display(bitrate);
timestampPrev = now;
bytesPrev = bytesNow;
if (bitrate > bitrateMax) {
bitrateMax = bitrate;
}
}
}
}

0 comments on commit f53760f

Please sign in to comment.