Skip to content

Commit

Permalink
Merge pull request #315 from Sing-Li/webrtc-inband-signaling
Browse files Browse the repository at this point in the history
Add web-rtc in-band signaling stack as an optional (not installed by default) package
  • Loading branch information
engelgabriel committed Jul 18, 2015
2 parents f12ce2c + def0d69 commit 2ffb7f9
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ rocketchat:markdown
rocketchat:me
rocketchat:mentions
rocketchat:oembed
rocketchat:webrtc
tap:i18n
tmeasday:crypto-md5
tmeasday:errors
Expand All @@ -60,3 +59,4 @@ yasaricli:slugify
meteorhacks:kadira
meteorhacks:flow-router
meteorhacks:flow-layout
rocketchat:webrtc
1 change: 1 addition & 0 deletions client/views/app/message.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Template.message.helpers
when 'nu' then t('User_added', { user_added: this.u.username })
when 'uj' then tr('User_joined_channel', { context: this.u.gender }, { user: this.u.username })
when 'wm' then t('Welcome', { user: this.u.username })
when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', this
else
this.html = this.msg
if _.trim(this.html) isnt ''
Expand Down
1 change: 1 addition & 0 deletions client/views/app/room.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ Template.room.events

'click .start-video': (event) ->
webrtc.to = FlowRouter.getParam('_id').replace(Meteor.userId(), '')
webrtc.room = FlowRouter.getParam('_id')
webrtc.start(true)

'click .stop-video': (event) ->
Expand Down
5 changes: 5 additions & 0 deletions packages/rocketchat-webrtc-ib/adapter.js

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

1 change: 1 addition & 0 deletions packages/rocketchat-webrtc-ib/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
stream = new Meteor.Stream('webrtc');
27 changes: 27 additions & 0 deletions packages/rocketchat-webrtc-ib/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Package.describe({
name: 'rocketchat:webrtc-ib',
version: '0.0.1',
summary: 'Package WebRTC In-band Signaling for Meteor server',
git: ''
});

Package.onUse(function(api) {
api.versionsFrom('1.0');

api.use([
'coffeescript',
'rocketchat:[email protected]',
'arunoda:[email protected]'
]);

api.addFiles('common.js');
api.addFiles('adapter.js', ['client']);
api.addFiles('webrtc.js', ['client']);
api.addFiles('webrtcmsg.coffee', ['client']);
api.addFiles('server.js', ['server']);

api.export('webrtc')
});


Package.onTest(function(api) {});
18 changes: 18 additions & 0 deletions packages/rocketchat-webrtc-ib/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
webrtc = {
stream: stream
}

stream.permissions.write(function(eventName) {
console.log('stream.permissions.write', this.userId);
return eventName == 'send' && this.userId;
});

stream.permissions.read(function(eventName) {
console.log('stream.permissions.read', this.userId, eventName);
return this.userId == eventName;
});

stream.on('send', function(data) {
console.log('send', data);
stream.emit(data.to, data);
});
168 changes: 168 additions & 0 deletions packages/rocketchat-webrtc-ib/webrtc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@

webrtc = {
// cid: Random.id(),
pc: undefined,
to: undefined,
room: undefined,
lastSeenTimestamp: new Date(),
debug: false,
config: {
iceServers: [
{url: "stun:23.21.150.121"},
{url: "stun:stun.l.google.com:19302"}
]
},
stream: stream,
send: function(data) {
console.log
data.to = webrtc.to;
data.from = Meteor.user().username;
Meteor.call('sendMessage', {
t: 'rtc',
u: {username: data.from},
to: webrtc.to,
msg: JSON.stringify(data),
rid: webrtc.room
});
// stream.emit('send', data);

},
stop: function(sendEvent) {
if (webrtc.pc) {
if (webrtc.pc.signalingState != 'closed') {
webrtc.pc.close();
}
if (sendEvent != false) {
webrtc.send( {to: webrtc.to, close: true});
}
}
},
log: function() {
if (webrtc.debug === true) {
console.log.apply(console, arguments);
}
},
onRemoteUrl: function() {},
onSelfUrl: function() {}
}

function onError() {
console.log(arguments);
}

// run start(true) to initiate a call
webrtc.start = function (isCaller, fromUsername) {
webrtc.pc = new RTCPeerConnection(webrtc.config);

webrtc.pc.ondatachannel = function() {webrtc.log('ondatachannel', arguments)}
webrtc.pc.onidentityresult = function() {webrtc.log('onidentityresult', arguments)}
webrtc.pc.onidpassertionerror = function() {webrtc.log('onidpassertionerror', arguments)}
webrtc.pc.onidpvalidationerror = function() {webrtc.log('onidpvalidationerror', arguments)}
webrtc.pc.onnegotiationneeded = function() {webrtc.log('onnegotiationneeded', arguments)}
webrtc.pc.onpeeridentity = function() {webrtc.log('onpeeridentity', arguments)}
webrtc.pc.onremovestream = function() {webrtc.log('onremovestream', arguments)}
webrtc.pc.onsignalingstatechange = function() {webrtc.log('onsignalingstatechange', arguments)}

// send any ice candidates to the other peer
webrtc.pc.onicecandidate = function (evt) {
webrtc.log('onicecandidate', arguments)
if (evt.candidate) {
webrtc.send({ "candidate": evt.candidate.toJSON(), cid: webrtc.cid });
}
};

// once remote stream arrives, show it in the remote video element
webrtc.pc.onaddstream = function (evt) {
webrtc.log('onaddstream', arguments)
webrtc.onRemoteUrl(URL.createObjectURL(evt.stream));
};

webrtc.pc.oniceconnectionstatechange = function(evt) {
webrtc.log('oniceconnectionstatechange', arguments)
var srcElement = evt.srcElement || evt.target;
if (srcElement.iceConnectionState == 'disconnected' || srcElement.iceConnectionState == 'closed') {
webrtc.pc.getLocalStreams().forEach(function(stream) {
stream.stop();
webrtc.onSelfUrl();
});
webrtc.pc.getRemoteStreams().forEach(function(stream) {
if (stream.stop) {
stream.stop();
}
webrtc.onRemoteUrl();
});
webrtc.pc = undefined;
}
}

var LocalGetUserMedia = function() {
// get the local stream, show it in the local video element and send it
navigator.getUserMedia({ "audio": true, "video": {mandatory: {minWidth:1280, minHeight:720}} }, function (stream) {
webrtc.log('getUserMedia got stream');
webrtc.onSelfUrl(URL.createObjectURL(stream));

webrtc.pc.addStream(stream);

if (isCaller) {
webrtc.pc.createOffer(gotDescription, onError);
} else {
webrtc.pc.createAnswer(gotDescription, onError);
}

function gotDescription(desc) {
webrtc.pc.setLocalDescription(desc, function() {}, onError);
webrtc.send({ "sdp": desc.toJSON(), cid: webrtc.cid });
}
}, function(e) { webrtc.log('getUserMedia faield' + e); });
}

if (isCaller) {
webrtc.log('isCaller LocalGetUserMedia');
LocalGetUserMedia();
} else {
swal({
title: "Video call from "+fromUsername,
text: "Do you want to accept?",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "Yes",
cancelButtonText: "No"
}, function(isConfirm){
if (isConfirm) {
LocalGetUserMedia();
} else {
webrtc.stop();
}
});
}
}


webrtc.processIncomingRtcMessage = function(data, from, room) {
webrtc.log('processIncomingRtcMessage()', Meteor.userId(), data)
if (!webrtc.to) {
webrtc.to = from;
}

if (!webrtc.room) {
webrtc.room = room;
}

if (data.close == true) {
webrtc.stop(false);
return
}

if (!webrtc.pc) {
webrtc.start(false, data.from);
}

if (data.sdp != undefined) {
webrtc.pc.setRemoteDescription(new RTCSessionDescription(data.sdp));
} else {
if( ["closed", "failed", "disconnected", "completed"].indexOf(webrtc.pc.iceConnectionState) === -1) {
webrtc.pc.addIceCandidate(new RTCIceCandidate(data.candidate));
}
}
}
31 changes: 31 additions & 0 deletions packages/rocketchat-webrtc-ib/webrtcmsg.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class IncomingRtcMessageProcessor
constructor: (message) ->
if (message.to == Meteor.userId())
if (message.ts > webrtc.lastSeenTimestamp)
webrtc.lastSeenTimestamp = message.ts
# console.log('RTC ' + JSON.stringify(message))
webrtc.processIncomingRtcMessage(JSON.parse(message.msg), message.rid.replace(message.to, ''), message.rid)



# stream.on(Meteor.userId(), function(data) {
# webrtc.log('stream.on', Meteor.userId(), data)
# if (data.close == true) {
# webrtc.stop(false);
# }

# if (!webrtc.pc)
# webrtc.start(false, data.from);
#
# if (data.sdp) {
# webrtc.pc.setRemoteDescription(new RTCSessionDescription(data.sdp));
# } else {
# if( ["closed", "failed", "disconnected", "completed"].indexOf(webrtc.pc.iceConnectionState) === -1) {
# webrtc.pc.addIceCandidate(new RTCIceCandidate(data.candidate));
# }
# }
#});



RocketChat.callbacks.add 'renderRtcMessage', IncomingRtcMessageProcessor, RocketChat.callbacks.priority.LOW

0 comments on commit 2ffb7f9

Please sign in to comment.