Skip to content

Commit 5919dcd

Browse files
Philippe Sultanmarkandrus
authored andcommitted
New example datachannel buffer limits (#5)
1 parent 727ac14 commit 5919dcd

File tree

3 files changed

+237
-0
lines changed

3 files changed

+237
-0
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
'use strict';
2+
3+
const createExample = require('../../lib/browser/example');
4+
5+
const description = 'This example sends a given amount of data from the client \
6+
over an RTCDataChannel. Upon receipt, node-webrtc responds by sending the data \
7+
back to the client. \
8+
Data is chunked into pieces, you can adjust both the chunk size and global \
9+
size to test the outbound buffer limits of the RTCDataChannel.';
10+
11+
const dataSize = document.createElement('input');
12+
dataSize.type = 'number';
13+
dataSize.value = 10;
14+
dataSize.min = 1;
15+
dataSize.max = 1024;
16+
17+
const chunkSize = document.createElement('input');
18+
chunkSize.type = 'number';
19+
chunkSize.value = 64;
20+
chunkSize.step = 16;
21+
chunkSize.min = 16;
22+
chunkSize.max = 512;
23+
24+
function beforeAnswer(peerConnection) {
25+
let dataChannel = null;
26+
let downloadStartTime = 0;
27+
let downLoadDuration = 0;
28+
let downloadedBytes = 0;
29+
const uploadedBytes = (dataSize.value)*1024*1024;
30+
31+
function closeDatachannel() {
32+
if (dataChannel) {
33+
dataChannel.removeEventListener('message', onMessage);
34+
dataChannel.close();
35+
dataChannel = null;
36+
}
37+
}
38+
39+
function resetButtons() {
40+
document.querySelectorAll('button').forEach((button) => {
41+
if (button.innerText === 'Start') {
42+
button.disabled = false;
43+
}
44+
45+
if (button.innerText === 'Stop') {
46+
button.disabled = true;
47+
}
48+
});
49+
}
50+
51+
function onMessage({ data }) {
52+
if (/^#START/.test(data)) {
53+
downloadStartTime = Date.now();
54+
const uploadDuration = data.split(' ')[1];
55+
const uploadBitRate = uploadedBytes*8/(uploadDuration/1000)/1000000;
56+
const text = `Upload   -- total : ${uploadedBytes}, duration : ${uploadDuration} ms, bitrate : ~${uploadBitRate.toFixed(2)} Mbits/s`;
57+
uploadLabel.innerHTML = text;
58+
console.log(text);
59+
60+
return;
61+
}
62+
63+
if (/^#STOP/.test(data)) {
64+
downLoadDuration = Date.now() - downloadStartTime;
65+
const downloadBitRate = downloadedBytes*8/(downLoadDuration/1000)/1000000;
66+
const text = `Download -- total : ${downloadedBytes}, duration : ${downLoadDuration} ms, bitrate : ~${downloadBitRate.toFixed(2)} Mbits/s`;
67+
downloadLabel.innerHTML = text;
68+
console.log(text);
69+
70+
peerConnection.close();
71+
closeDatachannel();
72+
resetButtons();
73+
74+
return;
75+
}
76+
77+
downloadedBytes += data.length;
78+
}
79+
80+
function onDataChannel({ channel }) {
81+
if (channel.label !== 'datachannel-buffer-limits') {
82+
return;
83+
}
84+
85+
uploadLabel.innerHTML = 'Upload   -- ...';
86+
downloadLabel.innerHTML = 'Download -- ...';
87+
88+
// Slightly delaying everything because Firefox needs it
89+
setTimeout(() => {
90+
dataChannel = channel;
91+
dataChannel.addEventListener('message', onMessage);
92+
93+
const queueStartTime = Date.now();
94+
const chunkSizeInBytes = (chunkSize.value)*1024;
95+
const loops = uploadedBytes / chunkSizeInBytes;
96+
const rem = uploadedBytes % chunkSizeInBytes;
97+
98+
try {
99+
dataChannel.send(`#START ${chunkSize.value}`);
100+
101+
var data = new Array(chunkSizeInBytes + 1).join('.');
102+
for (let i = 0; i < loops; i++) {
103+
dataChannel.send(data);
104+
}
105+
106+
if (rem) {
107+
dataChannel.send(data);
108+
}
109+
110+
dataChannel.send('#STOP');
111+
const queueDuration = Date.now() - queueStartTime;
112+
console.log(`Queued ${uploadedBytes} bytes in ${queueDuration} ms`);
113+
} catch(e) {
114+
console.log('Failed to send data over dataChannel :', e);
115+
peerConnection.close();
116+
closeDatachannel();
117+
resetButtons();
118+
alert(e);
119+
}
120+
}, 200);
121+
}
122+
123+
function onConnectionStateChange(event) {
124+
switch(peerConnection.connectionState) {
125+
case "disconnected":
126+
case "failed":
127+
case "closed":
128+
console.log('Received close event');
129+
closeDatachannel();
130+
break;
131+
}
132+
}
133+
134+
peerConnection.addEventListener('connectionstatechange', onConnectionStateChange);
135+
peerConnection.addEventListener('datachannel', onDataChannel);
136+
}
137+
138+
createExample('datachannel-buffer-limits', description, { beforeAnswer, RTCPeerConnection: window.RTCPeerConnection });
139+
140+
const dataSizeLabel = document.createElement('label');
141+
dataSizeLabel.innerText = 'Data size to send (MBytes):';
142+
dataSizeLabel.appendChild(dataSize);
143+
144+
const chunkSizeLabel = document.createElement('label');
145+
chunkSizeLabel.innerText = 'Chunk size (Kbytes):';
146+
chunkSizeLabel.appendChild(chunkSize);
147+
148+
const uploadLabel = document.createElement('label');
149+
uploadLabel.innerHTML = 'Upload &emsp;&emsp;-- ';
150+
151+
const downloadLabel = document.createElement('label');
152+
downloadLabel.innerHTML = 'Download -- ';
153+
154+
document.body.appendChild(dataSizeLabel);
155+
document.body.appendChild(chunkSizeLabel);
156+
document.body.appendChild(uploadLabel);
157+
document.body.appendChild(downloadLabel);
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
'use strict';
2+
3+
function beforeOffer(peerConnection) {
4+
const dataChannel = peerConnection.createDataChannel('datachannel-buffer-limits');
5+
let uploadStartTime = 0;
6+
let uploadedBytesTotal = 0;
7+
let chunkSize = 64; // Default value, updated from the client
8+
9+
function onMessage({ data }) {
10+
if (/^#START/.test(data)) {
11+
uploadStartTime = Date.now();
12+
const value = parseInt(data.split(' ')[1]);
13+
14+
if (!isNaN(value)) {
15+
chunkSize = value;
16+
}
17+
18+
return;
19+
}
20+
21+
if (data === '#STOP') {
22+
const uploadDuration = Date.now() - uploadStartTime;
23+
24+
console.log('Client upload duration :', uploadDuration, 'ms');
25+
console.log(`uploadedBytesTotal : ${uploadedBytesTotal}`);
26+
27+
const queueStartTime = Date.now();
28+
const chunkSizeInBytes = chunkSize*1024;
29+
30+
const loops = uploadedBytesTotal / chunkSizeInBytes;
31+
const rem = uploadedBytesTotal % chunkSizeInBytes;
32+
const obuf = new Array(chunkSizeInBytes + 1).join('.');
33+
34+
try {
35+
dataChannel.send('#START ' + uploadDuration);
36+
37+
for (let i = 0; i < loops; i++) {
38+
dataChannel.send(obuf);
39+
}
40+
41+
if (rem) {
42+
dataChannel.send(obuf);
43+
}
44+
45+
const queueDuration = Date.now() - queueStartTime;
46+
47+
dataChannel.send('#STOP ' + queueDuration);
48+
console.log(`Data sent back to client, queueDuration : ${queueDuration} ms`)
49+
50+
} catch(e) {
51+
console.log('Failed to send data :', e);
52+
dataChannel.removeEventListener('message', onMessage);
53+
dataChannel.close();
54+
peerConnection.close();
55+
}
56+
57+
return;
58+
}
59+
60+
uploadedBytesTotal += Buffer.byteLength(data);
61+
}
62+
63+
function onConnectionStateChange(event) {
64+
switch(peerConnection.connectionState) {
65+
case "disconnected":
66+
case "failed":
67+
case "closed":
68+
console.log('Received close event');
69+
dataChannel.removeEventListener('message', onMessage);
70+
dataChannel.close();
71+
break;
72+
}
73+
}
74+
75+
dataChannel.addEventListener('message', onMessage);
76+
peerConnection.addEventListener('connectionstatechange', onConnectionStateChange);
77+
}
78+
79+
module.exports = { beforeOffer };

html/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ <h1>node-webrtc examples</h1>
4343
<li><a href="/audio-video-loopback/index.html">audio-video-loopback
4444
<li><a href="/ping-pong/index.html">ping-pong
4545
<li><a href="/pitch-detector/index.html">pitch-detector
46+
<li><a href="/datachannel-buffer-limits/index.html">datachannel-buffer-limits
4647
<li><a href="/sine-wave/index.html">sine-wave
4748
<li><a href="/sine-wave-stereo/index.html">sine-wave-stereo
4849
<li><a href="/video-compositing/index.html">video-compositing

0 commit comments

Comments
 (0)