Implements screen sharing for firefox, using a jidesha extension.

Renames some fields in config.js.
This commit is contained in:
Boris Grozev 2015-09-02 17:29:53 -05:00
parent e5184358c2
commit 995b3be6e7
8 changed files with 230 additions and 38 deletions

View File

@ -17,10 +17,31 @@ var config = {
clientNode: 'http://jitsi.org/jitsimeet', // The name of client node advertised in XEP-0115 'c' stanza
//focusUserJid: 'focus@auth.jitsi-meet.example.com', // The real JID of focus participant - can be overridden here
//defaultSipNumber: '', // Default SIP number
desktopSharing: 'ext', // Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable.
chromeExtensionId: 'diibjkoicjeejcmhdnailmkgecihlobk', // Id of desktop streamer Chrome extension
desktopSharingSources: ['screen', 'window'],
minChromeExtVersion: '0.1', // Required version of Chrome extension
// Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable.
desktopSharingChromeMethod: 'ext',
// The ID of the jidesha extension for Chrome.
desktopSharingChromeExtId: 'diibjkoicjeejcmhdnailmkgecihlobk',
// The media sources to use when using screen sharing with the Chrome
// extension.
desktopSharingChromeSources: ['screen', 'window'],
// Required version of Chrome extension
desktopSharingChromeMinExtVersion: '0.1',
// The ID of the jidesha extension for Firefox. If null, we assume that no
// extension is required.
desktopSharingFirefoxExtId: null,
// Whether desktop sharing should be disabled on Firefox.
desktopSharingFirefoxDisabled: true,
// The maximum version of Firefox which requires a jidesha extension.
// Example: if set to 41, we will require the extension for Firefox versions
// up to and including 41. On Firefox 42 and higher, we will run without the
// extension.
// If set to -1, an extension will be required for all versions of Firefox.
desktopSharingFirefoxMaxVersionExtRequired: -1,
// The URL to the Firefox extension for desktop sharing.
desktopSharingFirefoxExtensionURL: null,
openSctp: true, // Toggle to enable/disable SCTP channels
disableStats: false,
disableAudioLevels: false,

View File

@ -11,7 +11,7 @@
<meta itemprop="image" content="/images/jitsilogo.png"/>
<script src="https://api.callstats.io/static/callstats.min.js"></script>
<script src="libs/jquery-2.1.1.min.js"></script>
<script src="config.js?v=12"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="config.js?v=13"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="libs/strophe/strophe.min.js?v=2"></script>
<script src="libs/strophe/strophe.disco.min.js?v=1"></script>
<script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
@ -20,12 +20,12 @@
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
<script src="interface_config.js?v=5"></script>
<script src="libs/app.bundle.js?v=134"></script>
<script src="libs/app.bundle.js?v=131"></script>
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
<link rel="stylesheet" href="css/font.css?v=7"/>
<link rel="stylesheet" href="css/toastr.css?v=1">
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=31"/>
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=21" id="videolayout_default"/>
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=20" id="videolayout_default"/>
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
<link rel="stylesheet" href="css/modaldialog.css?v=3">

View File

@ -194,7 +194,9 @@
"password": "password",
"userPassword": "user password",
"token": "token",
"displayNameRequired": "Please enter your display name:"
"displayNameRequired": "Please enter your display name:",
"extensionRequired": "Extension required:",
"firefoxExtensionPrompt": "You need to install a Firefox extension in order to use screen sharing. Please try again after you <a href='__url__'>get it from here</a>!"
},
"email":
{

View File

@ -199,6 +199,16 @@ function registerListeners() {
APP.desktopsharing.addListener(
DesktopSharingEventTypes.SWITCHING_DONE,
Toolbar.changeDesktopSharingButtonState);
APP.desktopsharing.addListener(
DesktopSharingEventTypes.FIREFOX_EXTENSION_NEEDED,
function (url) {
APP.UI.messageHandler.openMessageDialog(
"dialog.extensionRequired",
null,
null,
APP.translation.generateTranslationHTML(
"dialog.firefoxExtensionPrompt", {url: url}));
});
APP.connectionquality.addListener(CQEvents.LOCALSTATS_UPDATED,
VideoLayout.updateLocalConnectionStats);
APP.connectionquality.addListener(CQEvents.REMOTESTATS_UPDATED,

View File

@ -11,15 +11,23 @@ var messageHandler = (function(my) {
/**
* Shows a message to the user.
*
* @param titleKey the title of the message
* @param messageKey the text of the message
* @param titleKey the key used to find the translation of the title of the
* message, if a message title is not provided.
* @param messageKey the key used to find the translation of the message,
* if a message is not provided.
* @param title the title of the message. If a falsy value is provided,
* titleKey will be used to get a title via the translation API.
* @param message the message to show. If a falsy value is provided,
* messageKey will be used to get a message via the translation API.
*/
my.openMessageDialog = function(titleKey, messageKey) {
var title = null;
if(titleKey) {
my.openMessageDialog = function(titleKey, messageKey, title, message) {
if (!title) {
title = APP.translation.generateTranslationHTML(titleKey);
}
var message = APP.translation.generateTranslationHTML(messageKey);
if (!message) {
message = APP.translation.generateTranslationHTML(messageKey);
}
$.prompt(message,
{title: title, persistent: false}
);

View File

@ -2,12 +2,15 @@
/* jshint -W003 */
var RTCBrowserType = require("../RTC/RTCBrowserType");
var AdapterJS = require("../RTC/adapter.screenshare");
var DesktopSharingEventTypes
= require("../../service/desktopsharing/DesktopSharingEventTypes");
/**
* Indicates whether the Chrome desktop sharing extension is installed.
* @type {boolean}
*/
var chromeExtInstalled = false;
/**
* Indicates whether an update of the Chrome desktop sharing extension is
* required.
@ -15,27 +18,54 @@ var chromeExtInstalled = false;
*/
var chromeExtUpdateRequired = false;
/**
* Whether the jidesha extension for firefox is installed for the domain on
* which we are running. Null designates an unknown value.
* @type {null}
*/
var firefoxExtInstalled = null;
/**
* If set to true, detection of an installed firefox extension will be started
* again the next time obtainScreenOnFirefox is called (e.g. next time the
* user tries to enable screen sharing).
*/
var reDetectFirefoxExtension = false;
/**
* Handles obtaining a stream from a screen capture on different browsers.
*/
function ScreenObtainer(){
}
/**
* The EventEmitter to use to emit events.
* @type {null}
*/
ScreenObtainer.prototype.eventEmitter = null;
/**
* Initializes the function used to obtain a screen capture (this.obtainStream).
*
* If the browser is Chrome, it uses the value of 'config.desktopSharing' to
* decide whether to use the a Chrome extension (if the value is 'ext'), use
* the "screen" media source (if the value is 'webrtc'), or disable screen
* capture (if the value is other).
* If the browser is Chrome, it uses the value of
* 'config.desktopSharingChromeMethod' (or 'config.desktopSharing') to * decide
* whether to use the a Chrome extension (if the value is 'ext'), use the
* "screen" media source (if the value is 'webrtc'), or disable screen capture
* (if the value is other).
* Note that for the "screen" media source to work the
* 'chrome://flags/#enable-usermedia-screen-capture' flag must be set.
*/
ScreenObtainer.prototype.init = function() {
ScreenObtainer.prototype.init = function(eventEmitter) {
this.eventEmitter = eventEmitter;
var obtainDesktopStream = null;
// When TemasysWebRTC plugin is used we always use getUserMedia, so we don't
// care about the value of config.desktopSharing.
if (RTCBrowserType.isFirefox())
initFirefoxExtensionDetection();
// TODO remove this, config.desktopSharing is deprecated.
var chromeMethod =
(config.desktopSharingChromeMethod || config.desktopSharing);
if (RTCBrowserType.isTemasysPluginUsed()) {
if (!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature) {
console.info("Screensharing not supported by this plugin version");
@ -47,7 +77,7 @@ ScreenObtainer.prototype.init = function() {
console.info("Using Temasys plugin for desktop sharing");
}
} else if (RTCBrowserType.isChrome()) {
if (config.desktopSharing == "ext") {
if (chromeMethod == "ext") {
if (RTCBrowserType.getChromeVersion() >= 34) {
obtainDesktopStream = obtainScreenFromExtension;
console.info("Using Chrome extension for desktop sharing");
@ -55,19 +85,28 @@ ScreenObtainer.prototype.init = function() {
} else {
console.info("Chrome extension not supported until ver 34");
}
} else if (config.desktopSharing == "webrtc") {
} else if (chromeMethod == "webrtc") {
obtainDesktopStream = obtainWebRTCScreen;
console.info("Using Chrome WebRTC for desktop sharing");
}
} else if (RTCBrowserType.isFirefox()) {
obtainDesktopStream = obtainWebRTCScreen;
if (config.desktopSharingFirefoxDisabled) {
obtainDesktopStream = null;
} else if (window.location.protocol === "http:"){
console.log("Screen sharing is not supported over HTTP. Use of " +
"HTTPS is required.");
obtainDesktopStream = null;
} else {
obtainDesktopStream = this.obtainScreenOnFirefox;
}
}
if (!obtainDesktopStream) {
console.info("Desktop sharing disabled");
}
ScreenObtainer.prototype.obtainStream = obtainDesktopStream.bind(this);
ScreenObtainer.prototype.obtainStream = obtainDesktopStream;
};
ScreenObtainer.prototype.obtainStream = null;
@ -105,8 +144,9 @@ function obtainWebRTCScreen(streamCallback, failCallback) {
*/
function getWebStoreInstallUrl()
{
//TODO remove chromeExtensionId (deprecated)
return "https://chrome.google.com/webstore/detail/" +
config.chromeExtensionId;
(config.desktopSharingChromeExtId || config.chromeExtensionId);
}
/**
@ -156,7 +196,8 @@ function checkChromeExtInstalled(callback) {
return;
}
chrome.runtime.sendMessage(
config.chromeExtensionId,
//TODO: remove chromeExtensionId (deprecated)
(config.desktopSharingChromeExtId || config.chromeExtensionId),
{ getVersion: true },
function (response) {
if (!response || !response.version) {
@ -169,8 +210,12 @@ function checkChromeExtInstalled(callback) {
// Check installed extension version
var extVersion = response.version;
console.log('Extension version is: ' + extVersion);
//TODO: remove minChromeExtVersion (deprecated)
var updateRequired
= isUpdateRequired(config.minChromeExtVersion, extVersion);
= isUpdateRequired(
(config.desktopSharingChromeMinExtVersion ||
config.minChromeExtVersion),
extVersion);
callback(!updateRequired, updateRequired);
}
);
@ -181,7 +226,12 @@ function doGetStreamFromExtension(streamCallback, failCallback) {
// Extension id must be defined in the config.
chrome.runtime.sendMessage(
config.chromeExtensionId,
{ getStream: true, sources: config.desktopSharingSources },
{
getStream: true,
//TODO: remove desktopSharingSources (deprecated).
sources: (config.desktopSharingChromeSources ||
config.desktopSharingSources)
},
function (response) {
if (!response) {
failCallback(chrome.runtime.lastError);
@ -261,5 +311,96 @@ function initChromeExtension() {
});
}
/**
* Obtains a screen capture stream on Firefox.
* @param callback
* @param errorCallback
*/
ScreenObtainer.prototype.obtainScreenOnFirefox =
function (callback, errorCallback) {
var self = this;
var extensionRequired = false;
if (config.desktopSharingFirefoxMaxVersionExtRequired === -1 ||
(config.desktopSharingFirefoxMaxVersionExtRequired >= 0 &&
RTCBrowserType.getFirefoxVersion() <=
config.desktopSharingFirefoxMaxVersionExtRequired)) {
extensionRequired = true;
console.log("Jidesha extension required on firefox version " +
RTCBrowserType.getFirefoxVersion());
}
if (!extensionRequired || firefoxExtInstalled === true) {
obtainWebRTCScreen(callback, errorCallback);
return;
}
if (reDetectFirefoxExtension) {
reDetectFirefoxExtension = false;
initFirefoxExtensionDetection();
}
// Give it some (more) time to initialize, and assume lack of extension if
// it hasn't.
if (firefoxExtInstalled === null) {
window.setTimeout(
function() {
if (firefoxExtInstalled === null)
firefoxExtInstalled = false;
self.obtainScreenOnFirefox(callback, errorCallback);
},
300
);
console.log("Waiting for detection of jidesha on firefox to finish.");
return;
}
// We need an extension and it isn't installed.
// Make sure we check for the extension when the user clicks again.
firefoxExtInstalled = null;
reDetectFirefoxExtension = true;
// Prompt the user to install the extension
this.eventEmitter.emit(DesktopSharingEventTypes.FIREFOX_EXTENSION_NEEDED,
config.desktopSharingFirefoxExtensionURL);
// Make sure desktopsharing knows that we failed, so that it doesn't get
// stuck in 'switching' mode.
errorCallback('Firefox extension required.');
};
/**
* Starts the detection of an installed jidesha extension for firefox.
*/
function initFirefoxExtensionDetection() {
if (config.desktopSharingFirefoxDisabled) {
return;
}
if (firefoxExtInstalled === false || firefoxExtInstalled === true)
return;
if (!config.desktopSharingFirefoxExtId) {
firefoxExtInstalled = false;
return;
}
var img = document.createElement('img');
img.onload = function(){
console.log("Detected firefox screen sharing extension.");
firefoxExtInstalled = true;
};
img.onerror = function(){
console.log("Detected lack of firefox screen sharing extension.");
firefoxExtInstalled = false;
};
// The jidesha extension exposes an empty image file under the url:
// "chrome://EXT_ID/content/DOMAIN.png"
// Where EXT_ID is the ID of the extension with "@" replaced by ".", and
// DOMAIN is a domain whitelisted by the extension.
var src = "chrome://" +
(config.desktopSharingFirefoxExtId.replace('@', '.')) +
"/content/" + document.location.hostname + ".png";
img.setAttribute('src', src);
}
module.exports = ScreenObtainer;

View File

@ -62,12 +62,6 @@ function onEndedHandler(stream) {
}
}
// Called when RTC finishes initialization
function onWebRtcReady() {
screenObtainer.init();
eventEmitter.emit(DesktopSharingEventTypes.INIT);
}
module.exports = {
isUsingScreenStream: function () {
return isUsingScreenStream;
@ -82,7 +76,12 @@ module.exports = {
},
init: function () {
APP.RTC.addListener(RTCEvents.RTC_READY, onWebRtcReady);
// Called when RTC finishes initialization
APP.RTC.addListener(RTCEvents.RTC_READY,
function() {
screenObtainer.init(eventEmitter);
eventEmitter.emit(DesktopSharingEventTypes.INIT);
});
},
addListener: function (type, listener) {
@ -139,6 +138,11 @@ module.exports = {
getVideoStreamFailed, config.resolution || '360'
);
}
}
},
/*
* Exports the event emitter to allow use by ScreenObtainer. Not for outside
* use.
*/
eventEmitter: eventEmitter
};

View File

@ -3,7 +3,13 @@ var DesktopSharingEventTypes = {
SWITCHING_DONE: "ds.switching_done",
NEW_STREAM_CREATED: "ds.new_stream_created"
NEW_STREAM_CREATED: "ds.new_stream_created",
/**
* An event which indicates that the jidesha extension for Firefox is
* needed to proceed with screen sharing, and that it is not installed.
*/
FIREFOX_EXTENSION_NEEDED: "ds.firefox_extension_needed"
};
module.exports = DesktopSharingEventTypes;