npm install datachannel
# or
bower install datachannel
DataChannel.js is a JavaScript library useful to write many-to-many i.e. group file/data sharing or text chat applications. Its syntax is easier to use and understand. It highly simplifies complex tasks like any or all user rejection/ejection; direct messages delivery; and more.
If you want all DataChannel.js functionalities along with media streaming and runtime additions/deletions then RTCMultiConnection.js is a good chose with similar APIs/syntax.
user-id
user-id
leave
methodonleave
<script src="https://github.com/muaz-khan/DataChannel/raw/master//cdn.webrtc-experiment.com/DataChannel.js"> </script>
<button id="setup-datachannel" style="width:30%;">Open NEW DataChannel</button>
<input type="text" id="chat-input" disabled style="font-size: 2em; width: 65%;"><br />
<div id="chat-output"></div>
<script>
var chatOutput = document.getElementById('chat-output');
var chatInput = document.getElementById('chat-input');
chatInput.onkeypress = function (e) {
if (e.keyCode != 13) return;
channel.send(this.value);
chatOutput.innerHTML = 'Me: ' + this.value + '<hr />' + chatOutput.innerHTML;
this.value = '';
};
var channel = new DataChannel();
channel.onopen = function (userid) {
chatInput.disabled = false;
chatInput.value = 'Hi, ' + userid;
chatInput.focus();
};
channel.onmessage = function (message, userid) {
chatOutput.innerHTML = userid + ': ' + message + '<hr />' + chatOutput.innerHTML;
};
channel.onleave = function (userid) {
chatOutput.innerHTML = userid + ' Left.<hr />' + chatOutput.innerHTML;
};
// search for existing data channels
channel.connect();
document.querySelector('button#setup-datachannel').onclick = function () {
// setup new data channel
channel.open();
};
</script>
<script src="https://github.com/muaz-khan/DataChannel/raw/master//cdn.webrtc-experiment.com/DataChannel.js"></script>
var channel = new DataChannel('[optional] channel-name');
channel.send(file || data || 'text-message');
// to create/open a new channel
channel.open('channel-name');
// if someone already created a channel; to join it: use "connect" method
channel.connect('channel-name');
onopen
and onmessage
If you're familiar with WebSockets; these two methods works in the exact same way:
channel.onopen = function(userid) { }
channel.onmessage = function(message, userid, latency) { }
user-ids
can be used to send direct messages or to eject/leave any user:
ondatachannel
Allows you show list of all available data channels to the user; and let him choose which one to join:
channel.ondatachannel = function(data_channel) {
channel.join(data_channel);
// or
channel.join({
id: data_channel.id,
owner: data_channel.owner
});
// id: unique identifier for the session
// owner: unique identifier for the session initiator
};
channel.userid = 'predefined-userid';
Remember; custom defined user-id
must be unique username.
channel.channels[userid].send(file || data || 'text message');
user-ids
channel.eject(userid); // throw a user out of your room!
channel.leave(); // close your own entire data session
channel.onleave = function(userid) { };
When room initiator leaves; you can enforce auto-closing of the entire session. By default: it is false
:
channel.autoCloseEntireSession = true;
It means that session will be kept active all the time; even if initiator leaves the session.
You can set autoCloseEntireSession
before calling leave
method; which will enforce closing of the entire session:
channel.autoCloseEntireSession = true;
channel.leave(); // closing entire session
uuid
for filesYou can get uuid
for each file (being sent) like this:
channel.send(file);
var uuid = file.uuid; // "file"-Dot-uuid
var progressHelper = {};
// to make sure file-saver dialog is not invoked.
channel.autoSaveToDisk = false;
channel.onFileProgress = function (chunk, uuid) {
var helper = progressHelper[chunk.uuid];
helper.progress.value = chunk.currentPosition || chunk.maxChunks || helper.progress.max;
updateLabel(helper.progress, helper.label);
};
channel.onFileStart = function (file) {
var div = document.createElement('div');
div.title = file.name;
div.innerHTML = '<label>0%</label> <progress></progress>';
appendDIV(div, fileProgress);
progressHelper[file.uuid] = {
div: div,
progress: div.querySelector('progress'),
label: div.querySelector('label')
};
progressHelper[file.uuid].progress.max = file.maxChunks;
};
channel.onFileSent = function (file) {
progressHelper[file.uuid].div.innerHTML = '<a href="https://github.com/muaz-khan/DataChannel/blob/master/' + file.url + '" target="_blank" download="' + file.name + '">' + file.name + '</a>';
};
channel.onFileReceived = function (fileName, file) {
progressHelper[file.uuid].div.innerHTML = '<a href="https://github.com/muaz-khan/DataChannel/blob/master/' + file.url + '" target="_blank" download="' + file.name + '">' + file.name + '</a>';
};
function updateLabel(progress, label) {
if (progress.position == -1) return;
var position = +progress.position.toFixed(2).split('.')[1] || 100;
label.innerHTML = position + '%';
}
File Queue support added to make sure newly connected users gets all previously shared files.
You can see list of previously shared files:
console.log( channel.fileQueue );
By default; autoSaveToDisk
is set to true
. When it is true
; it will save file to disk as soon as it is received. To prevent auto-saving feature; just set it false
:
channel.autoSaveToDisk = false; // prevent auto-saving!
channel.onFileReceived = function (fileName, file) {
// file.url
// file.uuid
hyperlink.href = file.url;
};
channel.onmessage = function(message, userid, latency) {
console.log('latency:', latency, 'milliseconds');
};
You can send multiple files concurrently; or multiple longer text messages:
// individually
channel.send(fileNumber1);
channel.send(fileNumber2);
channel.send(fileNumber3);
// or as an array
channel.send([fileNumber1, fileNumber2, fileNumber3]);
channel.send('longer string-1');
channel.send('longer string-2');
channel.send('longer string-3');
// error to open data ports
channel.onerror = function(event) {}
// data ports suddenly dropped
channel.onclose = function(event) {}
Default direction is many-to-many
.
channel.direction = 'one-to-one';
channel.direction = 'one-to-many';
channel.direction = 'many-to-many';
=
For signaling; please check following page:
https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Signaling.md
Remember, you can use any signaling implementation that exists out there without modifying any single line! Just skip below code and open above link!
openSignalingChannel
: https://vimeo.com/91780227openSignalingChannel
: http://www.rtcmulticonnection.org/docs/openSignalingChannel/dataChannel.openSignalingChannel = function(config) {
var channel = config.channel || this.channel || 'default-channel';
var socket = io.connect('/?channel=' + channel);
socket.channel = channel;
socket.on('connect', function () {
if (config.callback) config.callback(socket);
});
socket.send = function (message) {
socket.emit('message', {
sender: dataChannel.userid,
data : message
});
};
socket.on('message', config.onmessage);
};
A demo & tutorial available here: http://pusher.com/tutorials/webrtc_chat
Another link: http://www.rtcmulticonnection.org/docs/openSignalingChannel/#pusher-signaling
transmitRoomOnce
transmitRoomOnce
is preferred when using Firebase for signaling. It saves bandwidth and asks DataChannel.js library to not repeatedly transmit room details.
channel.transmitRoomOnce = true;
DataChannel.js works fine on following browsers:
Browser | Support |
---|---|
Firefox | Stable / Aurora / Nightly |
Google Chrome | Stable / Canary / Beta / Dev |
Android | Chrome Beta |
DataChannel.js is released under MIT licence . Copyright (c) Muaz Khan.