Skip to content

Commit

Permalink
Merge pull request #182 from guymguym/develop
Browse files Browse the repository at this point in the history
fix #184, and bandwidth test to reproduce issue #171
  • Loading branch information
Alan K committed Apr 4, 2015
2 parents fb7cf51 + 67c7aef commit 412dc2e
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 1 deletion.
5 changes: 5 additions & 0 deletions lib/datachannel.js
Expand Up @@ -30,6 +30,11 @@ function RTCDataChannel(internalDC) {
};

Object.defineProperties(this, {
'bufferedAmount': {
get: function getBufferedAmount() {
return internalDC.bufferedAmount;
}
},
'label': {
get: function getLabel() {
return internalDC.label;
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -41,6 +41,7 @@
"grunt": "~0.4.2",
"grunt-contrib-jshint": "~0.8.0",
"grunt-tape": "~0.0.2",
"simple-peer": "^4.0.4",
"tape": "~2.4.2",
"ws": "~0.4.31",
"node-static": "^0.7.3",
Expand Down
15 changes: 14 additions & 1 deletion src/datachannel.cc
Expand Up @@ -192,7 +192,7 @@ void DataChannel::Run(uv_async_t* handle, int status)
data->message, v8::kExternalByteArray, data->size);
array->ForceSet(NanNew("byteLength"), NanNew<v8::Integer>(static_cast<uint32_t>(data->size)));
#endif
NanMakeWeakPersistent(array, data, &MessageWeakCallback);
NanMakeWeakPersistent(callback, data, &MessageWeakCallback);

argv[0] = array;
NanMakeCallback(dc, callback, 1, argv);
Expand Down Expand Up @@ -282,6 +282,18 @@ NAN_METHOD(DataChannel::Shutdown) {
NanReturnUndefined();
}

NAN_GETTER(DataChannel::GetBufferedAmount) {
TRACE_CALL;
NanScope();

DataChannel* self = node::ObjectWrap::Unwrap<DataChannel>( args.Holder() );

uint64_t buffered_amount = self->_jingleDataChannel->buffered_amount();

TRACE_END;
NanReturnValue(NanNew<v8::Number>(buffered_amount));
}

NAN_GETTER(DataChannel::GetLabel) {
TRACE_CALL;
NanScope();
Expand Down Expand Up @@ -341,6 +353,7 @@ void DataChannel::Init( v8::Handle<v8::Object> exports ) {
tpl->PrototypeTemplate()->Set( NanNew( "send" ),
NanNew<v8::FunctionTemplate>( Send )->GetFunction() );

tpl->InstanceTemplate()->SetAccessor(NanNew("bufferedAmount"), GetBufferedAmount, ReadOnly);
tpl->InstanceTemplate()->SetAccessor(NanNew("label"), GetLabel, ReadOnly);
tpl->InstanceTemplate()->SetAccessor(NanNew("binaryType"), GetBinaryType, SetBinaryType);
tpl->InstanceTemplate()->SetAccessor(NanNew("readyState"), GetReadyState, ReadOnly);
Expand Down
1 change: 1 addition & 0 deletions src/datachannel.h
Expand Up @@ -91,6 +91,7 @@ class DataChannel
static NAN_METHOD(Close);
static NAN_METHOD(Shutdown);

static NAN_GETTER(GetBufferedAmount);
static NAN_GETTER(GetLabel);
static NAN_GETTER(GetBinaryType);
static NAN_GETTER(GetReadyState);
Expand Down
11 changes: 11 additions & 0 deletions test/bwtest.html
@@ -0,0 +1,11 @@
<!--
PREPARING THE BROWSERIFY BUNDLE:
$ npm install browserify
$ browserify -e test/bwtest.js -o build/bwtest-browserify.js
open browser - file:///.../node-webrtc/test/bwtest.html
-->
<script src="../build/bwtest-browserify.js"></script>
143 changes: 143 additions & 0 deletions test/bwtest.js
@@ -0,0 +1,143 @@
'use strict';

/**
* define window with webrtc functions for simple-peer
*/
if (typeof(window) === 'undefined') {
var wrtc = require('..');
global.window = {
RTCPeerConnection: wrtc.RTCPeerConnection,
RTCSessionDescription: wrtc.RTCSessionDescription,
RTCIceCandidate: wrtc.RTCIceCandidate,
// Firefox does not trigger "negotiationneeded"
// this is a workaround to make simple-peer trigger the negotiation
mozRTCPeerConnection: wrtc.RTCPeerConnection,
};
}

var SimplePeer = require('simple-peer');


function bwtest(peer1, peer2) {
var START_TIME = Date.now();
var BUFFERED_DELAY_MS = 5;
var NPACKETS = 5000;
var PACKET_SIZE = 16 * 1024;
var CONGEST_HIGH_THRESHOLD = 1 * 1024 * 1024;
var CONGEST_LOW_THRESHOLD = 256 * 1024;
var buffer = new ArrayBuffer(PACKET_SIZE);
var n = 0;
var congested = 0;
var stats = {
count: 0,
bytes: 0,
congestCount: 0,
congestTime: 0
};

function info() {
var now = Date.now();
if (congested) {
stats.congestTime += Date.now() - congested;
congested = now;
}
var took = (now - START_TIME) / 1000;
var bufferedAmount = peer1._channel && peer1._channel.bufferedAmount;
return 'sent ' + n + ' received ' + stats.count + '. ' +
'congestion #' + stats.congestCount + ' ' +
(stats.congestTime / 1024).toFixed(3) + ' seconds. ' +
(bufferedAmount ? 'bufferedAmount ' + bufferedAmount + '. ' : '') +
'took ' + took.toFixed(3) + ' seconds. ' +
'bandwidth ' + (stats.bytes / took / 1024).toFixed(0) + ' KB/s. ';
}

peer2.on('data', function(data) {
stats.count += 1;
stats.bytes += data.length;
if (stats.count >= NPACKETS) {
console.log('RECEIVE DONE!', info());
peer1.destroy();
peer2.destroy();
}
});

function congestion() {
var bufferedAmount = peer1._channel && peer1._channel.bufferedAmount || 0;
if ((bufferedAmount > CONGEST_HIGH_THRESHOLD) ||
(congested && bufferedAmount > CONGEST_LOW_THRESHOLD)) {
if (!congested) {
congested = Date.now();
}
stats.congestCount += 1;
} else {
if (congested) {
stats.congestTime += Date.now() - congested;
}
congested = 0;
}
return congested;
}

function send() {
if (n >= NPACKETS) {
console.log('SEND DONE!', info());
return;
}
if (n % 100 === 0) {
console.log('SENDING:', info());
}
if (congestion()) {
setTimeout(send, BUFFERED_DELAY_MS);
return;
}
peer1.send(buffer, function(err) {
if (err) {
console.error('ERROR!', info(), err.stack || err);
return;
}
n += 1;
if (global.setImmediate) {
global.setImmediate(send);
} else {
setTimeout(send, 0);
}
});
}

send();
}

function init(callback) {
var INITIATOR_CONFIG = {
initiator: true,
config: {
iceServers: [{
url: 'stun:23.21.150.121'
}],

/*
* data channels are ordered by default - using unordered channel improves
* performance but will likely require ordering in another app layer
*/
ordered: false,

/*
* data channels are reliable by default - using either maxRetransmits
* or maxPacketLifeTime will change to unreliable mode
*/
// maxRetransmits: 5,
// maxPacketLifeTime: 3000,
}
};
var peer1 = new SimplePeer(INITIATOR_CONFIG);
var peer2 = new SimplePeer();

// when peer1 has signaling data, give it to peer2, and vice versa
peer1.on('signal', peer2.signal.bind(peer2));
peer2.on('signal', peer1.signal.bind(peer1));

// wait for 'connect' event before using the data channel
peer1.on('connect', callback.bind(null, peer1, peer2));
}

init(bwtest);

0 comments on commit 412dc2e

Please sign in to comment.