Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-node capability #12

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ WebRTC offer/answer exchange is performed manually by the users, for example
via IM. This means that the app can run out of `file:///` directly, without
involving a web server. You can send text messages and files between peers.

This repository contains two different clients that can talk to each other:
This repository contains three different clients that can talk to each other:

1. `serverless-webrtc.js` runs under node.js
2. `serverless-webrtc.html` runs in Chrome or Firefox
3. `serverless-webrtc-multinode.html` runs in Chrome or Firefox

Chat is fully interoperable between all of the above (Node, Chrome, Firefox)
in any combination (tested with Chrome 35 and Firefox 29).
Expand Down Expand Up @@ -53,3 +54,25 @@ http://blog.printf.net/articles/2014/07/01/serverless-webrtc-continued
http://cjb.github.io/serverless-webrtc/serverless-webrtc.html

-- Chris Ball <chris@printf.net> (http://printf.net/)

#### Multi-node capability

serverless-webrtc-multinode.html adds on top of serverless-webrtc.html the functionality of many-to-many connections.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please line wrap to 80 cols to match the rest of the file


It just does so by making a new WebRTC peer connection for each new pair of users.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can drop "just"


Peer connections are either ''Guest'' connections (Bob the recipient), or ''Host'' connections (Alice the sender)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use real double quotes "

put a period at the end of the sentence

these issues come up below too


An unordered list (labeled ''Network'') at the bottom of the page shows all the connections made between you and other users.

You could send text to all connected users at once via the ''Send to all'' button, or to a particular user via the ''Send''

button near his/her nickname in the ''Network'' list.

Individual connections can also be closed, or queried for their Round Trip Duration (labeled RTD) via the ''Latency'' button.

RTD is queried by sending an ''echo request'' package, which automatically triggers an ''echo response'' from the other user.

One could optionally use different nicknames for different connections.

At the moment, sending a file would transmit it only to the last connection made
7 changes: 7 additions & 0 deletions js/FileSaver.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 84 additions & 0 deletions js/SWGuestConnection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// This is a moderatorless version of
// http://www.rtcmulticonnection.org/docs/

/* THIS IS BOB, THE ANSWERER/RECEIVER */

function SWGuestConnection() {
return {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these files/funcs have bad/inconsistent indentation in general

you could try fixing it with something like clang-format -i -style=file

username: null,
counterparty: null,
lastTimestamp: null,
latency: null,
pc2 : new RTCPeerConnection(cfg, con),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no spaces before the :

dc2 : null,
guestConnections: null,
p1: null,
init: function(un,pc2a2,p11) {
var self=this;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing spaces around the =

this func has inconsistent indentation

self.username=un;
self.guestConnections=pc2a2;
self.p1=p11;

self.pc2.ondatachannel = function (e) {
var fileReceiver2 = new FileReceiver();
var datachannel = e.channel || e; // Chrome sends event, FF sends raw channel
console.log("Received datachannel (pc2)", arguments);
self.dc2 = datachannel;
activedc = self.dc2;
self.dc2.onopen = function (e) {
console.log('data channel connect');
$('#waitForConnection').remove();
$('#showLocalAnswer').modal('hide');
setTimeout(function() { self.send('Initiated'); }, 500);
setTimeout(function() { self.send('','echo request'); }, 1500);
};
self.dc2.onmessage = function (e) { handleOnMessage(e,self); };
};

self.pc2.onsignalingstatechange = onsignalingstatechange;
self.pc2.oniceconnectionstatechange = function(e) { oniceconnectionstatechange(e,self) };
self.pc2.onicegatheringstatechange = onicegatheringstatechange;

self.pc2.onaddstream = function (e) {
console.log("Got remote stream", e);
var el = new Audio();
el.autoplay = true;
attachMediaStream(el, e.stream);
};

self.pc2.onconnection = handleOnconnection;

self.pc2.onicecandidate = function (e) {
console.log("ICE candidate (pc2)", e);
if (e.candidate == null)
$('#localAnswer').html(JSON.stringify(self.pc2.localDescription));
};

return self;
},
send: function(msg,type) {
var self=this;
self.dc2.send(JSON.stringify({
username: self.username,
message: msg,
timestamp: getTimestamp(),
type: type
}));
},
handleOfferFromPC1:function(offerDesc) {
var self=this;
self.pc2.setRemoteDescription(offerDesc);
self.pc2.createAnswer(function (answerDesc) {
self.pc2.setLocalDescription(answerDesc);
}, function () { console.warn("No create answer"); });
},
close: function() {
this.pc2.close();
if(this.echoId!=null) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing spaces in the right place

you should compare to null using !== instead. or just go with a truthy check like if (this.echoid) {.

clearTimeout(this.echoId);
this.echoId=null;
}
},
echoId:null,
};
}
68 changes: 68 additions & 0 deletions js/SWHostConnection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* THIS IS ALICE, THE CALLER/SENDER */

function SWHostConnection() {
return {
username: null,
counterparty: null,
lastTimestamp: null,
latency: null,
pc1 : new RTCPeerConnection(cfg, con),
dc1 : null,
setupDC1: function() {
try {
var self=this;
self.dc1 = self.pc1.createDataChannel('test', {reliable:true});
activedc = self.dc1;
console.log("Created datachannel (pc1)");
self.dc1.onopen = function (e) {
console.log('data channel connect');
$('#waitForConnection').modal('hide');
$('#waitForConnection').remove();
self.send('Initiated');
setTimeout(function() { self.send('','echo request'); }, 1000);
};
self.dc1.onmessage = function (e) { handleOnMessage(e,self); };
} catch (e) { console.warn("No data channel (pc1)", e); }
},
createLocalOffer: function() {
var self=this;
self.setupDC1();
self.pc1.createOffer(function (desc) {
self.pc1.setLocalDescription(desc, function () {});
console.log("created local offer", desc);
}, function () {console.warn("Couldn't create offer");});
},
init: function(un) {
var self=this;
self.username=un;
self.pc1.onconnection = handleOnconnection;
self.pc1.onsignalingstatechange = onsignalingstatechange;
self.pc1.oniceconnectionstatechange = function(e) { oniceconnectionstatechange(e,self) };
self.pc1.onicegatheringstatechange = onicegatheringstatechange;
self.pc1.onicecandidate = function (e) {
console.log("ICE candidate (pc1)", e);
if (e.candidate == null) {
$('#localOffer').html(JSON.stringify(self.pc1.localDescription));
}
};
return self;
},
send: function(msg,type) {
var self=this;
self.dc1.send(JSON.stringify({
username: self.username,
message: msg,
timestamp: getTimestamp(),
type: type
}));
},
close: function() {
this.pc1.close();
if(this.echoId!=null) {
clearTimeout(this.echoId);
this.echoId=null;
}
},
echoId:null,
};
}