Skip to content
Snippets Groups Projects
Commit 13031a70 authored by Sing Li's avatar Sing Li
Browse files

initial implementation of scalable remote video monitoring feature

parent f6b58f7d
No related merge requests found
...@@ -541,6 +541,13 @@ label.required:after { ...@@ -541,6 +541,13 @@ label.required:after {
min-width: 120px; min-width: 120px;
background-color: #bc2031; background-color: #bc2031;
} }
&.short {
min-width: 100px;
}
&.lightblue {
min-width: 100px;
background-color: #02acec;
}
&.clean { &.clean {
background-color: rgba(0, 0, 0, 0.025); background-color: rgba(0, 0, 0, 0.025);
font-size: 14px; font-size: 14px;
......
...@@ -235,11 +235,18 @@ Template.room.helpers ...@@ -235,11 +235,18 @@ Template.room.helpers
selfVideoUrl: -> selfVideoUrl: ->
return Session.get('selfVideoUrl') return Session.get('selfVideoUrl')
videoActive: ->
return (Session.get('remoteVideoUrl') || Session.get('selfVideoUrl'))
remoteMonitoring: ->
return (webrtc?.stackid? && (webrtc.stackid == 'webrtc-ib'))
flexOpenedRTC1: -> flexOpenedRTC1: ->
return 'layout1' if Session.equals('flexOpenedRTC1', true) return 'layout1' if Session.equals('flexOpenedRTC1', true)
flexOpenedRTC2: -> flexOpenedRTC2: ->
return 'layout2' if Session.equals('flexOpenedRTC2', true) return 'layout2' if Session.equals('flexOpenedRTC2', true)
rtcLayout1: -> rtcLayout1: ->
return (Session.get('rtcLayoutmode') == 1 ? true: false); return (Session.get('rtcLayoutmode') == 1 ? true: false);
...@@ -468,11 +475,25 @@ Template.room.events ...@@ -468,11 +475,25 @@ Template.room.events
_id = Template.instance().data._id _id = Template.instance().data._id
webrtc.to = _id.replace(Meteor.userId(), '') webrtc.to = _id.replace(Meteor.userId(), '')
webrtc.room = _id webrtc.room = _id
webrtc.mode = 1
webrtc.start(true) webrtc.start(true)
'click .stop-video': (event) -> 'click .stop-video': (event) ->
webrtc.stop() 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) -> 'dragenter .dropzone': (e) ->
e.currentTarget.classList.add 'over' e.currentTarget.classList.add 'over'
......
...@@ -166,7 +166,7 @@ ...@@ -166,7 +166,7 @@
{{#with userData}} {{#with userData}}
<div class="about clearfix"> <div class="about clearfix">
{{#if selfVideoUrl}} {{#if videoActive}}
{{#if rtcLayout3}} {{#if rtcLayout3}}
<div id='fullscreendiv' style="width: 100%"> <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> <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>
...@@ -212,8 +212,12 @@ ...@@ -212,8 +212,12 @@
</div> </div>
</div> </div>
<nav> <nav>
{{#unless selfVideoUrl}} {{#unless videoActive}}
<button class='button start-video'><span><i class='icon-videocam'></i> {{_ "Video"}}</span></button> <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}} {{else}}
<button class='button red stop-video'><span><i class='icon-videocam'></i> {{_ "StopVideo"}}</span></button> <button class='button red stop-video'><span><i class='icon-videocam'></i> {{_ "StopVideo"}}</span></button>
{{/unless}} {{/unless}}
......
webrtc = { webrtc = {
// cid: Random.id(), // cid: Random.id(),
stackid: 'webrtc-ib',
pc: undefined, pc: undefined,
to: undefined, to: undefined,
room: undefined, room: undefined,
activeMediastream: undefined,
remoteDataSDP: undefined,
mode: undefined,
lastSeenTimestamp: new Date(), lastSeenTimestamp: new Date(),
debug: false, debug: false,
config: { config: {
...@@ -21,19 +25,30 @@ webrtc = { ...@@ -21,19 +25,30 @@ webrtc = {
u: {username: data.from}, u: {username: data.from},
to: webrtc.to, to: webrtc.to,
msg: JSON.stringify(data), msg: JSON.stringify(data),
rid: webrtc.room rid: webrtc.room,
mode: (webrtc.mode ? webrtc.mode : 0)
}); });
}, },
stop: function(sendEvent) { stop: function(sendEvent) {
if (webrtc.activeMediastream) {
webrtc.activeMediastream = undefined;
}
if (webrtc.pc) { if (webrtc.pc) {
if (webrtc.pc.signalingState != 'closed') { if (webrtc.pc.signalingState != 'closed') {
webrtc.pc.close(); webrtc.pc.close();
} webrtc.pc = undefined;
if (sendEvent != false) { webrtc.mode = 0;
webrtc.send( {to: webrtc.to, close: true});
} }
} }
this.onRemoteUrl();
this.onSelfUrl();
if (sendEvent != false) {
webrtc.send( {to: webrtc.to, close: true});
}
}, },
log: function() { log: function() {
if (webrtc.debug === true) { if (webrtc.debug === true) {
...@@ -48,6 +63,18 @@ function onError() { ...@@ -48,6 +63,18 @@ function onError() {
console.log(arguments); 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 // run start(true) to initiate a call
webrtc.start = function (isCaller, fromUsername) { webrtc.start = function (isCaller, fromUsername) {
webrtc.pc = new RTCPeerConnection(webrtc.config); webrtc.pc = new RTCPeerConnection(webrtc.config);
...@@ -71,7 +98,7 @@ webrtc.start = function (isCaller, fromUsername) { ...@@ -71,7 +98,7 @@ webrtc.start = function (isCaller, fromUsername) {
// once remote stream arrives, show it in the remote video element // once remote stream arrives, show it in the remote video element
webrtc.pc.onaddstream = function (evt) { webrtc.pc.onaddstream = function (evt) {
webrtc.log('onaddstream', arguments) webrtc.log('onaddstream', arguments);
webrtc.onRemoteUrl(URL.createObjectURL(evt.stream)); webrtc.onRemoteUrl(URL.createObjectURL(evt.stream));
}; };
...@@ -79,23 +106,52 @@ webrtc.start = function (isCaller, fromUsername) { ...@@ -79,23 +106,52 @@ webrtc.start = function (isCaller, fromUsername) {
webrtc.log('oniceconnectionstatechange', arguments) webrtc.log('oniceconnectionstatechange', arguments)
var srcElement = evt.srcElement || evt.target; var srcElement = evt.srcElement || evt.target;
if (srcElement.iceConnectionState == 'disconnected' || srcElement.iceConnectionState == 'closed') { if (srcElement.iceConnectionState == 'disconnected' || srcElement.iceConnectionState == 'closed') {
webrtc.pc.getLocalStreams().forEach(function(stream) { if (webrtc.pc) {
stream.stop(); webrtc.pc.getLocalStreams().forEach(function(stream) {
webrtc.onSelfUrl();
});
webrtc.pc.getRemoteStreams().forEach(function(stream) {
if (stream.stop) {
stream.stop(); stream.stop();
} webrtc.onSelfUrl();
webrtc.onRemoteUrl(); });
}); webrtc.pc.getRemoteStreams().forEach(function(stream) {
webrtc.pc = undefined; 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 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 // 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.log('getUserMedia got stream');
webrtc.onSelfUrl(URL.createObjectURL(stream)); webrtc.onSelfUrl(URL.createObjectURL(stream));
...@@ -107,32 +163,44 @@ webrtc.start = function (isCaller, fromUsername) { ...@@ -107,32 +163,44 @@ webrtc.start = function (isCaller, fromUsername) {
webrtc.pc.createAnswer(gotDescription, onError); webrtc.pc.createAnswer(gotDescription, onError);
} }
function gotDescription(desc) { }, function(e) { webrtc.log('getUserMedia failed' + e); });
webrtc.pc.setLocalDescription(desc, function() {}, onError);
webrtc.send({ "sdp": desc.toJSON(), cid: webrtc.cid });
}
}, function(e) { webrtc.log('getUserMedia faield' + e); });
} }
if (isCaller) { if (isCaller) {
webrtc.log('isCaller LocalGetUserMedia'); webrtc.log('isCaller LocalGetUserMedia');
LocalGetUserMedia(); if (webrtc.mode) {
} else { if (webrtc.mode === 2) {
swal({ CreateMonitoringOffer();
title: "Video call from "+fromUsername, } else { // node === 1
text: "Do you want to accept?",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "Yes",
cancelButtonText: "No"
}, function(isConfirm){
if (isConfirm) {
LocalGetUserMedia(); 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();
}
} }
} }
...@@ -147,12 +215,34 @@ webrtc.processIncomingRtcMessage = function(data, from, room) { ...@@ -147,12 +215,34 @@ webrtc.processIncomingRtcMessage = function(data, from, room) {
webrtc.room = 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); webrtc.stop(false);
return
}
return
} }
if (!webrtc.pc) { if (!webrtc.pc) {
if ((webrtc.activeMediastream) && (data.sdp != undefined)){
webrtc.remoteDataSDP = data.sdp;
}
webrtc.start(false, data.from); webrtc.start(false, data.from);
} }
...@@ -163,4 +253,7 @@ webrtc.processIncomingRtcMessage = function(data, from, room) { ...@@ -163,4 +253,7 @@ webrtc.processIncomingRtcMessage = function(data, from, room) {
webrtc.pc.addIceCandidate(new RTCIceCandidate(data.candidate)); webrtc.pc.addIceCandidate(new RTCIceCandidate(data.candidate));
} }
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment