From 93a1c7b668116a169b1c772cd58f8493f5cc28bd Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Sat, 19 Jul 2014 17:10:47 +0200 Subject: [PATCH] Implemented extension bridge support. Implemented screen sharing for chrome using extension. --- static/js/directives/screenshare.js | 19 ++++- static/js/mediastream/peerscreenshare.js | 9 +- static/js/mediastream/webrtc.js | 2 +- static/js/services/chromeextension.js | 100 +++++++++++++++++++++++ static/js/services/screensharing.js | 55 ++++++++++++- static/js/services/services.js | 9 +- 6 files changed, 179 insertions(+), 15 deletions(-) create mode 100644 static/js/services/chromeextension.js diff --git a/static/js/directives/screenshare.js b/static/js/directives/screenshare.js index 1eeb57c6..0eb8ae12 100644 --- a/static/js/directives/screenshare.js +++ b/static/js/directives/screenshare.js @@ -20,7 +20,7 @@ */ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials/screensharepeer.html', 'bigscreen'], function($, _, template, templatePeer, BigScreen) { - return ["$window", "mediaStream", "$compile", "safeApply", "videoWaiter", "$timeout", "alertify", "translation", function($window, mediaStream, $compile, safeApply, videoWaiter, $timeout, alertify, translation) { + return ["$window", "mediaStream", "$compile", "safeApply", "videoWaiter", "$timeout", "alertify", "translation", "screensharing", function($window, mediaStream, $compile, safeApply, videoWaiter, $timeout, alertify, translation, screensharing) { var peerTemplate = $compile(templatePeer); @@ -168,9 +168,24 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials } $scope.layout.screenshare = true; + screensharing.getScreen().then(function(options) { + if (options) { + $scope.startScreenshare(options); + } else { + // No options received - assume cancel. + $scope.stopScreenshare(); + } + }, function(err) { + console.log("Screen sharing request returned error", err); + $scope.stopScreenshare(); + }); + + }; + + $scope.startScreenshare = function(options) { // Create userMedia with screen share type. - var usermedia = mediaStream.webrtc.doScreenshare(); + var usermedia = mediaStream.webrtc.doScreenshare(options); var handler; var peers = {}; var screenshares = []; diff --git a/static/js/mediastream/peerscreenshare.js b/static/js/mediastream/peerscreenshare.js index 6e6c3b20..824dc697 100644 --- a/static/js/mediastream/peerscreenshare.js +++ b/static/js/mediastream/peerscreenshare.js @@ -71,19 +71,16 @@ define(['jquery', 'underscore', 'mediastream/peercall', 'mediastream/tokens'], f var screenWidth = window.screen.width; var screenHeight = window.screen.height; - // NOTE(longsleep): This generates constrains for the experiental Screen sharing - // support in Chrome 31+. This needs to be enabled in flags: - // chrome://flags/#enable-usermedia-screen-capture + // Constains which define what actually gets shared need to + // be provided in options. var mandatoryVideoConstraints = $.extend({ - chromeMediaSource: 'screen', maxWidth: screenWidth, maxHeight: screenHeight }, options); var mediaConstraints = { audio: false, video: { - mandatory: mandatoryVideoConstraints, - optional: [] + mandatory: mandatoryVideoConstraints } } console.log("Setting screen sharing media constraints", mandatoryVideoConstraints); diff --git a/static/js/mediastream/webrtc.js b/static/js/mediastream/webrtc.js index 9ba200b1..bfe13ec8 100644 --- a/static/js/mediastream/webrtc.js +++ b/static/js/mediastream/webrtc.js @@ -481,7 +481,7 @@ function($, _, PeerCall, PeerConference, PeerXfer, PeerScreenshare, UserMedia, u var usermedia = new UserMedia({ noaudio: true }); - var ok = usermedia.doGetUserMedia(null, PeerScreenshare.getMediaContraints()); + var ok = usermedia.doGetUserMedia(null, PeerScreenshare.getMediaContraints(options)); if (ok) { this.e.one("done", function() { usermedia.stop(); diff --git a/static/js/services/chromeextension.js b/static/js/services/chromeextension.js new file mode 100644 index 00000000..532c8909 --- /dev/null +++ b/static/js/services/chromeextension.js @@ -0,0 +1,100 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 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 . + * + */ +define(["underscore"], function(_) { + + // chromeExtension + return ["$window", "$q", function($window, $q) { + + var available = false; + var marker = $window.document.getElementById("chromeextension-available"); + if (marker) { + available = true; + console.log("Chrome extension is available."); + } + + var ChromeExtension = function() { + this.registry = {}; + this.count = 0; + }; + + ChromeExtension.prototype.call = function(data) { + var deferred = $q.defer(); + var n = this.count++; + this.registry[n] = deferred; + var msg = { + Type: "Call", + Call: data, + n: n + } + $window.postMessage(msg, $window.document.URL); + return deferred.promise; + }; + + ChromeExtension.prototype.onMessage = function(event) { + var data = event.data; + switch (data.Type) { + case "Call": + var deferred = this.registry[data.n]; + if (deferred) { + delete this.registry[data.n]; + var call = data.Call; + if (call.Type === "Result") { + //console.log("Call complete with result", call); + deferred.resolve(call.Result); + } else { + //console.log("Call failed with error", call); + deferred.reject(call.Error); + } + } else { + console.warn("Unknown call reference received", data, this.registry, this); + } + break; + default: + console.log("Unknown message type", data.Type, data); + break; + } + }; + + var extension; + if (available) { + extension = new ChromeExtension(); + + $window.addEventListener("message", function(event) { + //console.log("message", event.origin, event.source === window, event); + if (event.source === window && event.data.answer) { + // Only let through our own messages marked as answer. + extension.onMessage(event); + } + }); + + } + + // public API. + return { + available: available, + call: function(data) { + return extension.call(data); + } + } + + }]; + +}); \ No newline at end of file diff --git a/static/js/services/screensharing.js b/static/js/services/screensharing.js index e5500677..1c0341b0 100644 --- a/static/js/services/screensharing.js +++ b/static/js/services/screensharing.js @@ -18,13 +18,14 @@ * along with this program. If not, see . * */ -define(['webrtc.adapter'], function() { +define(['underscore', 'webrtc.adapter'], function(_) { // screensharing - return ["$window", function($window) { + return ["$window", "$q", "chromeExtension", function($window, $q, chromeExtension) { // Check if we can do screensharing. var supported = false; + var prepare = null; if ($window.webrtcDetectedBrowser === "chrome") { if ($window.webrtcDetectedVersion >= 32 && $window.webrtcDetectedVersion < 37) { @@ -32,18 +33,66 @@ define(['webrtc.adapter'], function() { // It was removed in Chrome 37 in favour of chrome.chooseDesktopMedia // https://code.google.com/p/chromium/issues/detail?id=347641 supported = true; + prepare = function(options) { + // This generates constrains for the flag based screen screensharing + // support in Chrome 31+ to 36. Flag to be enabled is found at: + // chrome://flags/#enable-usermedia-screen-capture + var d = $q.defer() + var opts = _.extend({ + chromeMediaSource: "screen" + }, options); + d.resolve(opts); + return d.promise; + }; } else if ($window.webrtcDetectedVersion >= 37) { // We need a extension to support screen sharing. See // https://developer.chrome.com/extensions/desktopCapture#method-chooseDesktopMedia // for details. } + + if (chromeExtension.available) { + supported = true; + prepare = function(options) { + var select = chromeExtension.call({ + Type: "Action", + Action: "chooseDesktopMedia" + }); + var d = $q.defer(); + select.then(function(id) { + //console.log("Prepare screensharing success", id); + if (id) { + var opts = _.extend({ + chromeMediaSource: "desktop", + chromeMediaSourceId: id + }, options); + d.resolve(opts); + } else { + d.resolve(null); + } + }, function(err) { + console.log("Failed to prepare screensharing", err); + d.reject(err); + }); + return d.promise; + }; + } + } else { // Currently Chrome only. } // public API. return { - supported: supported + supported: supported, + getScreen: function(options) { + if (prepare) { + return prepare(options); + } else { + var d = $q.defer() + d.reject("No implementation to get screen."); + return d.promise; + } + } } }]; diff --git a/static/js/services/services.js b/static/js/services/services.js index f29f9e97..597a26cf 100644 --- a/static/js/services/services.js +++ b/static/js/services/services.js @@ -53,7 +53,8 @@ define([ 'services/dialogs', 'services/geolocation', 'services/screensharing', - 'services/continueconnector'], function(_, + 'services/continueconnector', + 'services/chromeextension'], function(_, desktopNotify, playSound, safeApply, @@ -86,7 +87,8 @@ animationFrame, dialogs, geolocation, screensharing, -continueConnector) { +continueConnector, +chromeExtension) { var services = { desktopNotify: desktopNotify, @@ -121,7 +123,8 @@ continueConnector) { dialogs: dialogs, geolocation: geolocation, screensharing: screensharing, - continueConnector: continueConnector + continueConnector: continueConnector, + chromeExtension: chromeExtension }; var initialize = function(angModule) {