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

Add support for auto install of Firefox screen sharing extension #238

Open
wants to merge 16 commits into
base: develop
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions static/js/directives/screenshare.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"use strict";
define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials/screensharepeer.html', 'bigscreen', 'webrtc.adapter'], function($, _, template, templatePeer, BigScreen) {

return ["$window", "mediaStream", "$compile", "safeApply", "videoWaiter", "$timeout", "alertify", "translation", "screensharing", function($window, mediaStream, $compile, safeApply, videoWaiter, $timeout, alertify, translation, screensharing) {
return ["$window", "mediaStream", "$compile", "safeApply", "videoWaiter", "$timeout", "alertify", "translation", "screensharing", "$location", function($window, mediaStream, $compile, safeApply, videoWaiter, $timeout, alertify, translation, screensharing, $location) {

var peerTemplate = $compile(templatePeer);

Expand Down Expand Up @@ -172,6 +172,7 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
}

$scope.layout.screenshare = true;
screensharing.globalNotify.screensharingStart();
screensharing.getScreen().then(function(options) {
if (options) {
$scope.startScreenshare(options);
Expand Down Expand Up @@ -278,9 +279,13 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
switch (error.name) {
case "PermissionDeniedError":
case "InvalidStateError":
if ($window.webrtcDetectedVersion >= 32 &&
if ($window.webrtcDetectedBrowser === "chrome" &&
$window.webrtcDetectedVersion >= 32 &&
$window.webrtcDetectedVersion < 37) {
alertify.dialog.alert(translation._("Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy chrome://flags/#enable-usermedia-screen-capture and open it with your browser and enable the flag on top. Then restart the browser and you are ready to go."));
} else if ($window.webrtcDetectedBrowser === "firefox" &&
$window.webrtcDetectedVersion >= 36) {
alertify.dialog.alert(translation._("Permission to start screen sharing was denied. Make sure to have enabled screen sharing access for your browser. Copy about:config?filter=screensharing.allowed_domains and open it with your browser, double click the option, and add the domain %s to the list (include a comma). Then you are ready to go. Otherwise install the Firefox screensharing extension.", $location.host()));
} else {
alertify.dialog.alert(translation._("Permission to start screen sharing was denied."));
}
Expand All @@ -307,6 +312,8 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
$scope.layout.screenshare = false;
}

screensharing.globalNotify.screensharingStop();

};

$scope.toggleFullscreen = function(elem) {
Expand Down
102 changes: 102 additions & 0 deletions static/js/services/firefoxextension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Spreed WebRTC.
* Copyright (C) 2013-2015 struktur AG
*
* This file is part of Spreed WebRTC.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

"use strict";
define(["underscore", "jquery", "webrtc.adapter"], function(_, $) {

// firefoxExtension
return ["$window", "$q", "alertify", "translation", "$interval", function($window, $q, alertify, translation, $interval) {

var EXTENSION_DOM_ID = 'firefoxextension-available';

var intervalSecs = 50;
var intervalCount = 1;
var isAvailable = function() {
return $window.document.getElementById(EXTENSION_DOM_ID);
};

var FirefoxExtension = function() {
this.available = false;
this.e = $({});
this.autoinstall = {};
this.initialize();
};

FirefoxExtension.prototype.initialize = function() {
if (isAvailable()) {
this.available = true;
console.log("Firefox extension is available.");
this.e.triggerHandler("available", true);
} else if (this.available) {
this.available = false;
console.log("Firefox extension is no longer available.");
this.e.triggerHandler("available", false);
}
};

FirefoxExtension.prototype.registerAutoInstall = function(installFunc, cancelInstallFunc, force) {
this.autoinstall.install = installFunc;
this.autoinstall.cancel = cancelInstallFunc;
this.autoinstall.force = !!force;
if (!this.available && installFunc) {
this.e.triggerHandler("available", true);
}
};

/**
* Checks for availability of the Firefox extension by looking for the id which the extension
* will append to the body of the document. Unfortunately there is no callback
* API implemented by Firefox which will allow other domains to see if an
* extension is installed using `InstallTrigger.install`. Only priviledged
* domains may use the callback.
*
* @param {int} How long of a timespan the function should check for the extension install at intervalSecs interval rate
* @return {promise}
*/
FirefoxExtension.prototype.detectInstalled = function(maxTimeout) {
var defer = $q.defer();
var that = this;

var intervalPromise = $interval(function() {
if (isAvailable()) {
console.log("Auto install success Firefox extension");
$interval.cancel(intervalPromise);
that.initialize();
defer.resolve("Auto install success Firefox extension");
} else if (intervalCount * intervalSecs >= maxTimeout) {
$interval.cancel(intervalPromise);
defer.reject("Timeout while waiting for extension to become available");
}
intervalCount++;
}, intervalSecs);

return defer.promise;
};

// Create extension api and wait for messages.
var extension = new FirefoxExtension();

// Expose.
return extension;

}];

});
115 changes: 89 additions & 26 deletions static/js/services/screensharing.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ define(['underscore', 'text!partials/screensharedialogff.html', 'webrtc.adapter'
};
}];

var GLOBAL_SCREENSHARING_START_EVENT = new Event('webrtcStartScreensharing');
var GLOBAL_SCREENSHARING_STOP_EVENT = new Event('webrtcStopScreensharing');

// screensharing
return ["$window", "$q", "$timeout", "chromeExtension", "dialogs", "$templateCache", function($window, $q, $timeout, chromeExtension, dialogs, $templateCache) {
return ["$window", "$q", "$timeout", "chromeExtension", "firefoxExtension", "dialogs", "$templateCache", function($window, $q, $timeout, chromeExtension, firefoxExtension, dialogs, $templateCache) {

$templateCache.put('/dialogs/screensharedialogff.html', screenshareDialogFF);

Expand All @@ -43,6 +46,18 @@ define(['underscore', 'text!partials/screensharedialogff.html', 'webrtc.adapter'
chromeExtension.e.on("available", _.bind(function() {
this.initialize();
}, this));
firefoxExtension.e.on("available", _.bind(function() {
this.initialize();
}, this));
};

Screensharing.prototype.globalNotify = {
screensharingStart: function() {
$window.dispatchEvent(GLOBAL_SCREENSHARING_START_EVENT);
},
screensharingStop: function() {
$window.dispatchEvent(GLOBAL_SCREENSHARING_STOP_EVENT);
}
};

Screensharing.prototype.initialize = function() {
Expand All @@ -53,6 +68,29 @@ define(['underscore', 'text!partials/screensharedialogff.html', 'webrtc.adapter'
// Define our helpers.
this.prepare = null;
this.cancel = null;
var that = this;

var selectFirefoxScreenToShare = function(options) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Only define this when Firefox.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that is used throughout the initialize function. See lines 213 and 220. The initialize function should really be broken up.

// To work, the current domain must be whitelisted in
// media.getusermedia.screensharing.allowed_domains (about:config).
// See https://wiki.mozilla.org/Screensharing for reference.
that.globalNotify.screensharingStart();
var d = $q.defer();
var dlg = dialogs.create('/dialogs/screensharedialogff.html', screenshareDialogFFController, {selection: "screen"}, {});
dlg.result.then(function(source) {
if (source) {
var opts = _.extend({
mediaSource: source
}, options);
d.resolve(opts);
} else {
d.resolve(null);
}
}, function(err) {
d.resolve(null);
});
return d.promise;
};

// Chrome support.
if ($window.webrtcDetectedBrowser === "chrome") {
Expand Down Expand Up @@ -133,44 +171,29 @@ define(['underscore', 'text!partials/screensharedialogff.html', 'webrtc.adapter'

}

} else if ($window.webrtcDetectedBrowser === "firefox") {
} else if ($window.webrtcDetectedBrowser === "firefox" && $window.webrtcDetectedVersion >= 36) {

// Firefox 36 got screen sharing support.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=923225
if ($window.webrtcDetectedVersion >= 36) {
this.prepare = function(options) {
return selectFirefoxScreenToShare(options);
};
if (firefoxExtension.available) {
this.supported = true;
} else if (!firefoxExtension.autoinstall.force) {
this.supported = true;
this.prepare = function(options) {
// To work, the current domain must be whitelisted in
// media.getusermedia.screensharing.allowed_domains (about:config).
// See https://wiki.mozilla.org/Screensharing for reference.
var d = $q.defer();
var dlg = dialogs.create('/dialogs/screensharedialogff.html', screenshareDialogFFController, {selection: "screen"}, {});
dlg.result.then(function(source) {
if (source) {
var opts = _.extend({
mediaSource: source
}, options);
d.resolve(opts);
} else {
d.resolve(null);
}
}, function(err) {
d.resolve(null);
});
return d.promise;
};
}

} else {
// No support for screen sharing.
}

var waiting = false;
var prepareAlternative = this.prepare;
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is not good about this? The variables are available in this scope level anyway. Declaring them here makes it more clear when used for Firefox as well.


// Auto install support.
if (!this.supported && chromeExtension.autoinstall.install) {
this.supported = this.autoinstall = true;
var that = this;
var waiting = false;
var prepareAlternative = this.prepare;
this.prepare = function(options) {
var d = $q.defer();
var install = chromeExtension.autoinstall.install();
Expand Down Expand Up @@ -230,6 +253,46 @@ define(['underscore', 'text!partials/screensharedialogff.html', 'webrtc.adapter'
}
waiting = false;
};
} else if (!this.supported && firefoxExtension.autoinstall.install) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Clean up the if else if !this.supported check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand what you want me to cleanup here.

this.supported = this.autoinstall = true;
this.prepare = function(options) {
var d = $q.defer();
var install = firefoxExtension.autoinstall.install();
install.then(function() {
var starter = function() {
var prepare = selectFirefoxScreenToShare(options);
prepare.then(function(id) {
d.resolve(id);
}, function(err) {
d.reject(err);
});
};
firefoxExtension.detectInstalled(30000).then(function() {
starter();
}, function(reason) {
d.reject(reason);
});
}, function(err) {
console.log("Auto install of extension failed.", err);
if (prepareAlternative) {
var alternative = prepareAlternative(options);
alternative.then(function(id) {
d.resolve(id);
}, function() {
d.reject(err);
});
} else {
d.reject(err);
}
});
return d.promise;
};
this.cancel = function() {
if (firefoxExtension.autoinstall.cancel) {
firefoxExtension.autoinstall.cancel();
}
waiting = false;
};
} else {
this.autoinstall = false;
}
Expand Down
9 changes: 6 additions & 3 deletions static/js/services/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ define([
'services/mediadevices',
'services/sandbox',
'services/dummystream',
'services/usermedia'], function(_,
'services/usermedia',
'services/firefoxextension'], function(_,
desktopNotify,
playSound,
safeApply,
Expand Down Expand Up @@ -118,7 +119,8 @@ modules,
mediaDevices,
sandbox,
dummyStream,
userMedia) {
userMedia,
firefoxExtension) {

var services = {
desktopNotify: desktopNotify,
Expand Down Expand Up @@ -168,7 +170,8 @@ userMedia) {
mediaDevices: mediaDevices,
sandbox: sandbox,
dummyStream: dummyStream,
userMedia: userMedia
userMedia: userMedia,
firefoxExtension: firefoxExtension
};

var initialize = function(angModule) {
Expand Down