Skip to content

Commit

Permalink
Merge pull request #386 from Sing-Li/webrtc-scalable-remote-monitoring
Browse files Browse the repository at this point in the history
Initial implementation of scalable remote video monitoring - closes #385
  • Loading branch information
engelgabriel committed Aug 3, 2015
2 parents f6b58f7 + 5d3befd commit 7a73654
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 41 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ It is a great solution for communities and companies wanting to privately host t
- LDAP Authentication - [LDAP Authentication on Rocket.Chat Wiki](https://github.com/RocketChat/Rocket.Chat/wiki/LDAP-Authentication)
- Face to Face Video Conferencing aka WebRTC (Alpha) - [How to video chat](https://github.com/RocketChat/Rocket.Chat/wiki/Using-Face-to-face-video-conference-%28aka-webrtc%29)
- REST-full APIs - [Ready for testing ...](https://github.com/RocketChat/Rocket.Chat/wiki/REST-full-APIs)
- Remote Locations Video Monitoring - [Early access ...](https://github.com/RocketChat/Rocket.Chat/wiki/Remote-Video-Monitoring)

### Roadmap for v1.0

Expand Down
7 changes: 7 additions & 0 deletions client/stylesheets/base.less
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,13 @@ label.required:after {
min-width: 120px;
background-color: #bc2031;
}
&.short {
min-width: 100px;
}
&.lightblue {
min-width: 100px;
background-color: #02acec;
}
&.clean {
background-color: rgba(0, 0, 0, 0.025);
font-size: 14px;
Expand Down
21 changes: 21 additions & 0 deletions client/views/app/room.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,18 @@ Template.room.helpers
selfVideoUrl: ->
return Session.get('selfVideoUrl')

videoActive: ->
return (Session.get('remoteVideoUrl') || Session.get('selfVideoUrl'))

remoteMonitoring: ->
return (webrtc?.stackid? && (webrtc.stackid == 'webrtc-ib'))

flexOpenedRTC1: ->
return 'layout1' if Session.equals('flexOpenedRTC1', true)

flexOpenedRTC2: ->
return 'layout2' if Session.equals('flexOpenedRTC2', true)

rtcLayout1: ->
return (Session.get('rtcLayoutmode') == 1 ? true: false);

Expand Down Expand Up @@ -468,11 +475,25 @@ Template.room.events
_id = Template.instance().data._id
webrtc.to = _id.replace(Meteor.userId(), '')
webrtc.room = _id
webrtc.mode = 1
webrtc.start(true)

'click .stop-video': (event) ->
webrtc.stop()

'click .monitor-video': (event) ->
_id = Template.instance().data._id
webrtc.to = _id.replace(Meteor.userId(), '')
webrtc.room = _id
webrtc.mode = 2
webrtc.start(true)


'click .setup-video': (event) ->
webrtc.mode = 2
webrtc.activateLocalStream()


'dragenter .dropzone': (e) ->
e.currentTarget.classList.add 'over'

Expand Down
10 changes: 7 additions & 3 deletions client/views/app/room.html
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ <h3>{{username}}</h3>
{{#with userData}}
<div class="about clearfix">

{{#if selfVideoUrl}}
{{#if videoActive}}
{{#if rtcLayout3}}
<div id='fullscreendiv' style="width: 100%">
<video id='videoremote' class="video-remote" src="{{remoteVideoUrl}}" style="width: 100%; align-items: center; margin-bottom: 10px; background-color: #000; transition: width 2s, height 2s, top 2s, left 2s, transform 2s;" autoplay></video>
Expand Down Expand Up @@ -212,8 +212,12 @@ <h3>{{username}}</h3>
</div>
</div>
<nav>
{{#unless selfVideoUrl}}
<button class='button start-video'><span><i class='icon-videocam'></i> {{_ "Video"}}</span></button>
{{#unless videoActive}}
<button class='button start-video'><span><i class='icon-videocam'></i> {{_ "Video Chat"}}</span></button>
{{#if remoteMonitoring}}
<button class='button short monitor-video'><span><i class='icon-videocam'></i> {{_ "Remote"}}</span></button>
<button class='button lightblue setup-video'><span><i class='icon-videocam'></i> {{_ "Setup"}}</span></button>
{{/if}}
{{else}}
<button class='button red stop-video'><span><i class='icon-videocam'></i> {{_ "StopVideo"}}</span></button>
{{/unless}}
Expand Down
169 changes: 131 additions & 38 deletions packages/rocketchat-webrtc-ib/webrtc.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@

webrtc = {
// cid: Random.id(),
stackid: 'webrtc-ib',
pc: undefined,
to: undefined,
room: undefined,
activeMediastream: undefined,
remoteDataSDP: undefined,
mode: undefined,
lastSeenTimestamp: new Date(),
debug: false,
config: {
Expand All @@ -21,19 +25,30 @@ webrtc = {
u: {username: data.from},
to: webrtc.to,
msg: JSON.stringify(data),
rid: webrtc.room
rid: webrtc.room,
mode: (webrtc.mode ? webrtc.mode : 0)
});

},
stop: function(sendEvent) {
if (webrtc.activeMediastream) {
webrtc.activeMediastream = undefined;
}

if (webrtc.pc) {
if (webrtc.pc.signalingState != 'closed') {
webrtc.pc.close();
}
if (sendEvent != false) {
webrtc.send( {to: webrtc.to, close: true});
webrtc.pc = undefined;
webrtc.mode = 0;
}
}


this.onRemoteUrl();
this.onSelfUrl();
if (sendEvent != false) {
webrtc.send( {to: webrtc.to, close: true});
}
},
log: function() {
if (webrtc.debug === true) {
Expand All @@ -48,6 +63,18 @@ function onError() {
console.log(arguments);
}

webrtc.activateLocalStream = function() {
var media ={ "audio": true, "video": {mandatory: {minWidth:1280, minHeight:720}}} ;

// get the local stream, show it in the local video element and send it
navigator.getUserMedia(media, function (stream) {
webrtc.log('getUserMedia got stream');
webrtc.onSelfUrl(URL.createObjectURL(stream));
webrtc.activeMediastream = stream;

}, function(e) { webrtc.log('getUserMedia failed during activateLocalStream ' + e); });
}

// run start(true) to initiate a call
webrtc.start = function (isCaller, fromUsername) {
webrtc.pc = new RTCPeerConnection(webrtc.config);
Expand All @@ -71,31 +98,60 @@ webrtc.start = function (isCaller, fromUsername) {

// once remote stream arrives, show it in the remote video element
webrtc.pc.onaddstream = function (evt) {
webrtc.log('onaddstream', arguments)
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) {
if (webrtc.pc) {
webrtc.pc.getLocalStreams().forEach(function(stream) {
stream.stop();
}
webrtc.onRemoteUrl();
});
webrtc.pc = undefined;
webrtc.onSelfUrl();
});
webrtc.pc.getRemoteStreams().forEach(function(stream) {
if (stream.stop) {
stream.stop();
}
webrtc.onRemoteUrl();
});
webrtc.pc = undefined;
webrtc.mode = 0;
}

}
}


var gotDescription = function(desc) {
webrtc.pc.setLocalDescription(desc, function() {}, onError);
webrtc.send({ "sdp": desc.toJSON(), cid: webrtc.cid });

}

var CreateMonitoringOffer = function() {

webrtc.pc.createOffer(gotDescription, onError, { 'mandatory': { 'OfferToReceiveAudio': true, 'OfferToReceiveVideo': true } });

}

var AutoConnectStream = function() {
webrtc.pc.addStream(webrtc.activeMediastream);
webrtc.pc.setRemoteDescription(new RTCSessionDescription(webrtc.remoteDataSDP));
webrtc.pc.createAnswer(gotDescription, onError);

}
var LocalGetUserMedia = function() {



var media ={ "audio": true, "video": {mandatory: {minWidth:1280, minHeight:720}}} ;


// 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) {
navigator.getUserMedia(media, function (stream) {
webrtc.log('getUserMedia got stream');
webrtc.onSelfUrl(URL.createObjectURL(stream));

Expand All @@ -107,32 +163,44 @@ webrtc.start = function (isCaller, fromUsername) {
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); });
}, function(e) { webrtc.log('getUserMedia failed' + 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) {
if (webrtc.mode) {
if (webrtc.mode === 2) {
CreateMonitoringOffer();
} else { // node === 1

LocalGetUserMedia();
} else {
webrtc.stop();
}
});
} else {
// no mode
LocalGetUserMedia();
}

} else {
if (!webrtc.activeMediastream) {
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();
}
});
} else {
AutoConnectStream();
}
}
}

Expand All @@ -147,12 +215,34 @@ webrtc.processIncomingRtcMessage = function(data, from, room) {
webrtc.room = room;
}

if (data.close == true) {

// do not stop local video if in monitoring mode
if (data.close == true) {

if (webrtc.activeMediastream) {
if (webrtc.pc) {
webrtc.pc.getRemoteStreams().forEach(function(stream) {
if (!stream.stop) {
stream.stop();
}
});
webrtc.pc = undefined;
webrtc.mode = 0;
}

} else {

webrtc.stop(false);
return

}
return
}


if (!webrtc.pc) {
if ((webrtc.activeMediastream) && (data.sdp != undefined)){
webrtc.remoteDataSDP = data.sdp;
}
webrtc.start(false, data.from);
}

Expand All @@ -163,4 +253,7 @@ webrtc.processIncomingRtcMessage = function(data, from, room) {
webrtc.pc.addIceCandidate(new RTCIceCandidate(data.candidate));
}
}

}


0 comments on commit 7a73654

Please sign in to comment.