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

[WIP] Add screensharing support. #227

Merged
merged 14 commits into from
Mar 14, 2017
Merged
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
43 changes: 40 additions & 3 deletions css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@
background-position-y: 8px !important;
}

/**
* Video styles
*/

#videos {
position: absolute;
Expand Down Expand Up @@ -248,6 +251,14 @@ video {
display: block !important;
}

.participants-1 #video-fullscreen {
display: none;
}

.participants-1 #toggleScreensharing {
display: none;
}

/* big speaker video */
.participants-1 .videoContainer,
.participants-2 .videoContainer,
Expand Down Expand Up @@ -297,10 +308,23 @@ video {
#app-content.participants-7,
#app-content.participants-8,
#app-content.participants-9,
#app-content.participants-10 {
#app-content.participants-10,
#app-content.screensharing {
background-color: #000;
}

#app-content.screensharing .videoContainer video {
max-height: 200px;
background-color: transparent;
box-shadow: 0;
}

#app-content.screensharing #localScreenContainer {
height: calc(100% - 200px);
overflow: scroll;
background-color: transparent;
}

.nameIndicator {
position: absolute;
bottom: 0;
Expand All @@ -311,7 +335,7 @@ video {
text-align: center;
font-size: 20px;
white-space: nowrap;
overflow: hidden;
overflow: visible;
text-overflow: ellipsis;
}
.videoView .nameIndicator {
Expand All @@ -323,15 +347,28 @@ video {
padding: 12px 35%;
}

#video-fullscreen {
position: absolute;
right: 0px;
z-index: 90;
}

#video-fullscreen.public {
top: 45px;
}

#video-fullscreen,
.nameIndicator button {
background-color: transparent;
border: none;
width: 44px;
height: 44px;
background-size: 25px;
}

.nameIndicator button.audio-disabled,
.nameIndicator button.video-disabled {
.nameIndicator button.video-disabled,
.nameIndicator button.screensharing-disabled {
opacity: .7;
}

Expand Down
70 changes: 66 additions & 4 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@
});
});

// Initialize button tooltips
$('[data-toggle="tooltip"]').tooltip({trigger: 'hover'}).click(function() {
$(this).tooltip('hide');
});

$('#hideVideo').click(function() {
if(!OCA.SpreedMe.app.videoWasEnabledAtLeastOnce) {
// don't allow clicking the video toggle
Expand All @@ -173,6 +178,7 @@
localStorage.setItem("videoDisabled", true);
}
});

$('#mute').click(function() {
if (OCA.SpreedMe.webrtc.webrtc.isAudioEnabled()) {
OCA.SpreedMe.app.disableAudio();
Expand All @@ -197,6 +203,7 @@
} else if (fullscreenElem.msRequestFullscreen) {
fullscreenElem.msRequestFullscreen();
}
$(this).attr('data-original-title', 'Exit fullscreen');
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
Expand All @@ -207,6 +214,60 @@
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
$(this).attr('data-original-title', 'Fullscreen');
}
});

var screensharingStopped = function() {
console.log("Screensharing now stopped");
$('#toggleScreensharing').attr('data-original-title', 'Enable screensharing')
.addClass('screensharing-disabled icon-screen-off-white')
.removeClass('icon-screen-white');
};

OCA.SpreedMe.webrtc.on('localScreenStopped', function() {
screensharingStopped();
});

$('#toggleScreensharing').click(function() {
var webrtc = OCA.SpreedMe.webrtc;
if (!webrtc.capabilities.supportScreenSharing) {
OC.Notification.showTemporary(t('spreed', 'Screensharing is not supported by your browser.'));
return;
}

if (webrtc.getLocalScreen()) {
webrtc.stopScreenShare();
screensharingStopped();
} else {
webrtc.shareScreen(function(err) {
if (!err) {
OC.Notification.showTemporary(t('spreed', 'Screensharing is about to start…'));
$('#toggleScreensharing').attr('data-original-title', 'Stop screensharing')
.removeClass('screensharing-disabled icon-screen-off-white')
.addClass('icon-screen-white');
return;
}

switch (err.name) {
case "HTTPS_REQUIRED":
OC.Notification.showTemporary(t('spreed', 'Screensharing requires the page to be loaded through HTTPS.'));
break;
case "PERMISSION_DENIED":
case "NotAllowedError":
case "CEF_GETSCREENMEDIA_CANCELED": // Experimental, may go away in the future.
OC.Notification.showTemporary(t('spreed', 'The screensharing request has been cancelled.'));
break;
case "EXTENSION_UNAVAILABLE":
// TODO(fancycode): Show popup with links to Chrome/Firefox extensions.
OC.Notification.showTemporary(t('spreed', 'An extension is required to start screensharing.'));
break;
default:
OC.Notification.showTemporary(t('spreed', 'An error occurred while starting screensharing.'));
console.log("Could not start screensharing", err);
break;
}
});
}
});

Expand Down Expand Up @@ -417,15 +478,15 @@
},
enableAudio: function() {
OCA.SpreedMe.webrtc.unmute();
$('#mute').data('title', 'Mute audio')
$('#mute').attr('data-original-title', 'Mute audio')
.removeClass('audio-disabled icon-audio-off-white')
.addClass('icon-audio-white');

OCA.SpreedMe.app.audioDisabled = false;
},
disableAudio: function() {
OCA.SpreedMe.webrtc.mute();
$('#mute').data('title', 'Enable audio')
$('#mute').attr('data-original-title', 'Enable audio')
.addClass('audio-disabled icon-audio-off-white')
.removeClass('icon-audio-white');

Expand All @@ -437,9 +498,10 @@
var localVideo = $hideVideoButton.closest('.videoView').find('#localVideo');

OCA.SpreedMe.webrtc.resumeVideo();
$hideVideoButton.data('title', 'Disable video')
$hideVideoButton.attr('data-original-title', 'Disable video')
.removeClass('video-disabled icon-video-off-white')
.addClass('icon-video-white');

avatarContainer.hide();
localVideo.show();

Expand All @@ -450,7 +512,7 @@
var avatarContainer = $hideVideoButton.closest('.videoView').find('.avatar-container');
var localVideo = $hideVideoButton.closest('.videoView').find('#localVideo');

$hideVideoButton.data('title', 'Enable video')
$hideVideoButton.attr('data-original-title', 'Enable video')
.addClass('video-disabled icon-video-off-white')
.removeClass('icon-video-white');

Expand Down
81 changes: 59 additions & 22 deletions js/simplewebrtc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3971,28 +3971,20 @@
var ffver = parseInt(window.navigator.userAgent.match(/Firefox\/(.*)/)[1], 10);
if (ffver >= 33) {
constraints = (hasConstraints && constraints) || {
video: {
mozMediaSource: 'window',
mediaSource: 'window'
}
};
getUserMedia(constraints, function (err, stream) {
callback(err, stream);
// workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1045810
if (!err) {
var lastTime = stream.currentTime;
var polly = window.setInterval(function () {
if (!stream) window.clearInterval(polly);
if (stream.currentTime == lastTime) {
window.clearInterval(polly);
if (stream.onended) {
stream.onended();
}
}
lastTime = stream.currentTime;
}, 500);
video: {
mozMediaSource: 'window',
mediaSource: 'window'
}
});
};
// Notify extension to add domain to whitelist and defer actual
// getUserMedia call until extension finished adding the domain.
var pending = window.setTimeout(function () {
error = new Error('NavigatorUserMediaError');
error.name = 'EXTENSION_UNAVAILABLE';
return callback(error);
}, 1000);
cache[pending] = [callback, constraints];
window.postMessage({ type: 'webrtcStartScreensharing', id: pending }, '*');
} else {
error = new Error('NavigatorUserMediaError');
error.name = 'EXTENSION_UNAVAILABLE'; // does not make much sense but...
Expand All @@ -4001,7 +3993,7 @@
};

typeof window !== 'undefined' && window.addEventListener('message', function (event) {
if (event.origin != window.location.origin) {
if (event.origin != window.location.origin && !event.isTrusted) {
return;
}
if (event.data.type == 'gotScreen' && cache[event.data.id]) {
Expand Down Expand Up @@ -4032,6 +4024,33 @@
}
} else if (event.data.type == 'getScreenPending') {
window.clearTimeout(event.data.id);
} else if (event.data.type == 'webrtcScreensharingWhitelisted' && cache[event.data.id]) {
var data = cache[event.data.id];
window.clearTimeout(event.data.id);
var constraints = data[1];
var callback = data[0];
delete cache[event.data.id];

getUserMedia(constraints, function (err, stream) {
// Notify extension to remove domain from whitelist.
window.postMessage({ type: 'webrtcStopScreensharing' }, '*');
callback(err, stream);
if (err) {
return;
}
// workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1045810
var lastTime = stream.currentTime;
var polly = window.setInterval(function () {
if (!stream) window.clearInterval(polly);
if (stream.currentTime == lastTime) {
window.clearInterval(polly);
if (stream.onended) {
stream.onended();
}
}
lastTime = stream.currentTime;
}, 500);
});
}
});

Expand Down Expand Up @@ -17739,6 +17758,9 @@
mLine.iceTransport.addRemoteCandidate({});
}
});
} else if (message.type === 'unshareScreen') {
this.parent.emit('unshareScreen', {id: message.from});
this.end();
}
};

Expand Down Expand Up @@ -18317,7 +18339,11 @@
if (this.getLocalScreen()) {
this.webrtc.stopScreenShare();
}
// Notify peers were sending to.
this.webrtc.peers.forEach(function (peer) {
if (peer.type === 'screen' && peer.sharemyscreen) {
peer.send('unshareScreen');
}
if (peer.broadcaster) {
peer.end();
}
Expand Down Expand Up @@ -18478,6 +18504,17 @@
}
});

this.on('unshareScreen', function(message) {
// End peers we were receiving the screensharing stream from.
var peers = self.getPeers(message.from, 'screen');
peers.forEach(function(peer) {
if (!peer.sharemyscreen) {
peer.end();
}
});
});


// log events in debug mode
if (this.config.debug) {
this.on('*', function (event, val1, val2) {
Expand Down