You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2018/11/09 06:54:52 UTC

[openmeetings] branch master updated: [OPENMEETINGS-1352] screen-sharing seems to work in Chrome

This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git


The following commit(s) were added to refs/heads/master by this push:
     new 616672c  [OPENMEETINGS-1352] screen-sharing seems to work in Chrome
616672c is described below

commit 616672cbcc14fe907a394ba7422b93ecf7fcf6f1
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Fri Nov 9 13:54:40 2018 +0700

    [OPENMEETINGS-1352] screen-sharing seems to work in Chrome
---
 .../openmeetings/core/remote/KurentoHandler.java   |   2 +-
 openmeetings-web/pom.xml                           |   1 -
 .../apache/openmeetings/web/room/RoomPanel.html    |   1 +
 .../apache/openmeetings/web/room/RoomPanel.java    |   4 +-
 .../apache/openmeetings/web/room/getScreenId.js    | 209 ---------------------
 .../org/apache/openmeetings/web/room/raw-room.js   |   2 +-
 .../org/apache/openmeetings/web/room/raw-sharer.js |  95 +++++++++-
 .../org/apache/openmeetings/web/room/raw-video.js  |  47 +++--
 pom.xml                                            |   2 +-
 9 files changed, 120 insertions(+), 243 deletions(-)

diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
index 6191a7f..bf2fdde 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
@@ -264,7 +264,7 @@ public class KurentoHandler {
 					break;
 				case "wannaShare":
 					if (screenShareAllowed(c)) {
-						startSharing(c, msg);
+						startSharing(c, msg, Activity.SCREEN);
 					}
 					break;
 				case "wannaRecord":
diff --git a/openmeetings-web/pom.xml b/openmeetings-web/pom.xml
index cdffadf..6185131 100644
--- a/openmeetings-web/pom.xml
+++ b/openmeetings-web/pom.xml
@@ -212,7 +212,6 @@
 								<jsSourceFile>jquery.dialogextend.js</jsSourceFile>
 								<jsSourceFile>raw-video.js</jsSourceFile>
 								<jsSourceFile>raw-video-manager.js</jsSourceFile>
-								<jsSourceFile>getScreenId.js</jsSourceFile>
 								<jsSourceFile>raw-sharer.js</jsSourceFile>
 								<jsSourceFile>raw-room.js</jsSourceFile>
 							</jsSourceFiles>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
index 15c86df..e09e5da 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
@@ -93,6 +93,7 @@
 					<option value="screen">Screen</option>
 					<option value="window">Window</option>
 					<option value="application">Application</option>
+					<option value="tab">Tab</option>
 				</select>
 			</div>
 			<div>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
index e8d6ae0..4e287fc 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
@@ -138,12 +138,12 @@ public class RoomPanel extends BasePanel {
 					.put("interview", interview)
 					.put("audioOnly", r.isAudioOnly())
 					.put("showMicStatus", !r.getHiddenElements().contains(RoomElement.MicrophoneStatus))
-					.put("exclusiveTitle", getString("1386"));
+					.put("exclusiveTitle", getString("1386"))
+					.put("chromeExtUrl", getChromeExtensionUrl());
 			if (!Strings.isEmpty(r.getRedirectURL()) && (ws.getSoapLogin() != null || ws.getInvitation() != null)) {
 				options.put("reloadUrl", r.getRedirectURL());
 			}
 			StringBuilder sb = new StringBuilder()
-					.append("MuazKhan.init('").append(getChromeExtensionUrl()).append("');")
 					.append("Room.init(").append(options.toString(new NullStringer())).append(");")
 					.append(wb.getInitScript())
 					.append("Room.setSize();")
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/getScreenId.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/getScreenId.js
deleted file mode 100644
index ea96a98..0000000
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/getScreenId.js
+++ /dev/null
@@ -1,209 +0,0 @@
-// Licensed MIT
-// Last time updated on June 08, 2018
-
-// Latest file can be found here: https://cdn.webrtc-experiment.com/getScreenId.js
-
-// Muaz Khan         - www.MuazKhan.com
-// MIT License       - www.WebRTC-Experiment.com/licence
-// Documentation     - https://github.com/muaz-khan/getScreenId.
-
-// ______________
-// getScreenId.js
-
-/*
-getScreenId(function (error, sourceId, screen_constraints) {
-    // error    == null || 'permission-denied' || 'not-installed' || 'installed-disabled' || 'not-chrome'
-    // sourceId == null || 'string' || 'firefox'
-    
-    if(microsoftEdge) {
-        navigator.getDisplayMedia(screen_constraints).then(onSuccess, onFailure);
-    }
-    else {
-        navigator.mediaDevices.getUserMedia(screen_constraints).then(onSuccess)catch(onFailure);
-    }
-
-}, 'pass second parameter only if you want system audio');
-*/
-
-var MuazKhan = (function() {
-	const self = {};
-	let frameUrl = 'https://www.webrtc-experiment.com/getSourceId/';
-
-	self.init = function(url) {
-		frameUrl = url;
-	}
-	self.getScreenId = function(callback, custom_parameter) {
-        window.addEventListener('message', onIFrameCallback);
-
-        function onIFrameCallback(event) {
-            if (!event.data) return;
-
-            if (event.data.chromeMediaSourceId) {
-                if (event.data.chromeMediaSourceId === 'PermissionDeniedError') {
-                    callback('permission-denied');
-                } else {
-                    callback(null, event.data.chromeMediaSourceId, getScreenConstraints(null, event.data.chromeMediaSourceId, event.data.canRequestAudioTrack));
-                }
-
-                // this event listener is no more needed
-                window.removeEventListener('message', onIFrameCallback);
-            }
-
-            if (event.data.chromeExtensionStatus) {
-                callback(event.data.chromeExtensionStatus, null, getScreenConstraints(event.data.chromeExtensionStatus));
-
-                // this event listener is no more needed
-                window.removeEventListener('message', onIFrameCallback);
-            }
-        }
-
-        if(!custom_parameter) {
-            setTimeout(postGetSourceIdMessage, 100);
-        }
-        else {
-            setTimeout(function() {
-                postGetSourceIdMessage(custom_parameter);
-            }, 100);
-        }
-    };
-
-    function getScreenConstraints(error, sourceId, canRequestAudioTrack) {
-        var screen_constraints = {
-            audio: false,
-            video: {
-                mandatory: {
-                    chromeMediaSource: error ? 'screen' : 'desktop',
-                    maxWidth: window.screen.width > 1920 ? window.screen.width : 1920,
-                    maxHeight: window.screen.height > 1080 ? window.screen.height : 1080
-                },
-                optional: []
-            }
-        };
-
-        if(!!canRequestAudioTrack) {
-            screen_constraints.audio = {
-                mandatory: {
-                    chromeMediaSource: error ? 'screen' : 'desktop',
-                    // echoCancellation: true
-                },
-                optional: []
-            };
-        }
-
-        if (sourceId) {
-            screen_constraints.video.mandatory.chromeMediaSourceId = sourceId;
-
-            if(screen_constraints.audio && screen_constraints.audio.mandatory) {
-                screen_constraints.audio.mandatory.chromeMediaSourceId = sourceId;
-            }
-        }
-
-        return screen_constraints;
-    }
-
-    function postGetSourceIdMessage(custom_parameter) {
-        if (!iframe) {
-            loadIFrame(function() {
-                postGetSourceIdMessage(custom_parameter);
-            });
-            return;
-        }
-
-        if (!iframe.isLoaded) {
-            setTimeout(function() {
-                postGetSourceIdMessage(custom_parameter);
-            }, 100);
-            return;
-        }
-
-        if(!custom_parameter) {
-            iframe.contentWindow.postMessage({
-                captureSourceId: true
-            }, '*');
-        }
-        else if(!!custom_parameter.forEach) {
-            iframe.contentWindow.postMessage({
-                captureCustomSourceId: custom_parameter
-            }, '*');
-        }
-        else {
-            iframe.contentWindow.postMessage({
-                captureSourceIdWithAudio: true
-            }, '*');
-        }
-    }
-
-    var iframe;
-
-    // this function is used in RTCMultiConnection v3
-    self.getScreenConstraints = function(callback) {
-        loadIFrame(function() {
-            self.getScreenId(function(error, sourceId, screen_constraints) {
-                if(!screen_constraints) {
-                    screen_constraints = {
-                        video: true
-                    };
-                }
-
-                callback(error, screen_constraints.video);
-            });
-        });
-    };
-
-    function loadIFrame(loadCallback) {
-        if (iframe) {
-            loadCallback();
-            return;
-        }
-
-        iframe = document.createElement('iframe');
-        iframe.onload = function() {
-            iframe.isLoaded = true;
-
-            loadCallback();
-        };
-        iframe.src = frameUrl;
-        iframe.style.display = 'none';
-        (document.body || document.documentElement).appendChild(iframe);
-    }
-
-    self.getChromeExtensionStatus = function(callback) {
-        // for Firefox:
-        if (!!navigator.mozGetUserMedia) {
-            callback('installed-enabled');
-            return;
-        }
-
-        window.addEventListener('message', onIFrameCallback);
-
-        function onIFrameCallback(event) {
-            if (!event.data) return;
-
-            if (event.data.chromeExtensionStatus) {
-                callback(event.data.chromeExtensionStatus);
-
-                // this event listener is no more needed
-                window.removeEventListener('message', onIFrameCallback);
-            }
-        }
-
-        setTimeout(postGetChromeExtensionStatusMessage, 100);
-    };
-
-    function postGetChromeExtensionStatusMessage() {
-        if (!iframe) {
-            loadIFrame(postGetChromeExtensionStatusMessage);
-            return;
-        }
-
-        if (!iframe.isLoaded) {
-            setTimeout(postGetChromeExtensionStatusMessage, 100);
-            return;
-        }
-
-        iframe.contentWindow.postMessage({
-            getChromeExtensionStatus: true
-        }, '*');
-    }
-    return self;
-})();
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js
index 992e0f3..286ef12 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js
@@ -43,7 +43,7 @@ var Room = (function() {
 		if (typeof(Activities) !== 'undefined') {
 			Activities.init();
 		}
-		Sharer.init();
+		Sharer.init(options.chromeExtUrl);
 	}
 	function _getSelfAudioClient() {
 		const vw = $('#video' + Room.getOptions().uid);
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-sharer.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-sharer.js
index 63160b8..aec324e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-sharer.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-sharer.js
@@ -5,14 +5,19 @@ var SHARE_STOPED = 'stoped';
 var Sharer = (function() {
 	const self = {};
 	let sharer, type, fps, sbtn, rbtn, width, height
-		, shareState = SHARE_STOPED, recState = SHARE_STOPED;
+		, shareState = SHARE_STOPED, recState = SHARE_STOPED
+		, iframe, frameUrl = 'https://www.webrtc-experiment.com/getSourceId/';
 
-	function _init() {
+	function _init(url) {
+		frameUrl = url;
 		sharer = $('#sharer').dialog({
 			width: 450
 			, autoOpen: false
 		});
-		type = sharer.find('select.type').selectmenu({
+		type = sharer.find('select.type');
+		const b = kurentoUtils.WebRtcPeer.browser;
+		type.find('option[value="' + (b.name === 'Chrome' ? 'application' : 'tab') + '"]').remove();
+		type.selectmenu({
 			width: 150
 			, disabled: VideoUtil.isEdge()
 		});
@@ -105,6 +110,73 @@ var Sharer = (function() {
 			rbtn.button('enable');
 		}
 	}
+	// Following methods are based on
+	// Licensed MIT
+	// Last time updated on June 08, 2018
+	// Latest file can be found here: https://cdn.webrtc-experiment.com/getScreenId.js
+	// Muaz Khan         - www.MuazKhan.com
+	function _getChromeConstraints(sd) {
+		return new Promise((resolve) => {
+			if (iframe) {
+				iframe.remove();
+			}
+			iframe = $('<iframe>')
+				.on('load', function() {
+					resolve();
+				})
+				.attr('src', frameUrl)
+				.hide();
+			$(document.body || document.documentElement).append(iframe);
+		}).then(() => {
+			return new Promise((resolve, reject) => {
+				window.addEventListener('message', _onIFrameCallback);
+
+				function _onIFrameCallback(event) {
+					if (!event.data) {
+						return;
+					}
+					if (event.data.chromeMediaSourceId) {
+						if (event.data.chromeMediaSourceId === 'PermissionDeniedError') {
+							reject('permission-denied');
+						} else {
+							resolve(_getScreenConstraints(sd, event.data.chromeMediaSourceId));
+						}
+						// this event listener is no more needed
+						window.removeEventListener('message', _onIFrameCallback);
+					}
+					if (event.data.chromeExtensionStatus) {
+						reject(event.data.chromeExtensionStatus);
+						// this event listener is no more needed
+						window.removeEventListener('message', _onIFrameCallback);
+					}
+				}
+
+				iframe[0].contentWindow.postMessage({
+					captureCustomSourceId: [sd.shareType]
+				}, '*');
+			});
+		});
+	};
+	function _getScreenConstraints(sd, sourceId) {
+		//Chrom screen constraints requires old school definition
+		const cnts = {
+			audio: false
+			, video: {
+				mandatory: {
+					maxWidth: sd.width
+					, maxHeight: sd.height
+				}
+				, optional: []
+			}
+		};
+		if (sourceId) {
+			cnts.video.mandatory = {
+				chromeMediaSourceId: sourceId
+				, chromeMediaSource: 'desktop'
+			};
+		}
+		return cnts;
+	}
 
 	self.init = _init;
 	self.open = function() {
@@ -119,5 +191,22 @@ var Sharer = (function() {
 	};
 	self.setShareState = _setShareState;
 	self.setRecState = _setRecState;
+	self.baseConstraints = function(sd) {
+		return {
+			video: {
+				frameRate: {
+					ideal: sd.fps
+				}
+				, width: {
+					ideal: sd.width
+				}
+				, height: {
+					ideal: sd.height
+				}
+			}
+			, audio: false
+		};
+	};
+	self.getChromeConstraints = _getChromeConstraints;
 	return self;
 })();
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video.js
index 8b41b3f..4fb34cc 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-video.js
@@ -45,40 +45,37 @@ var Video = (function() {
 		}
 	}
 	function _getScreenStream(msg, callback) {
+		function __handleScreenError(err) {
+			Sharer.setShareState(SHARE_STOPED);
+			Sharer.setRecState(SHARE_STOPED);
+			OmUtil.error(err);
+		}
 		const b = kurentoUtils.WebRtcPeer.browser;
+		let promise, cnts;
 		if (VideoUtil.isEdge() && b.major > 16) {
-			const cnts = {
+			cnts = {
 				video: true
 			};
-			navigator.getDisplayMedia(cnts).then(function(stream) {
-				callback(msg, cnts, stream);
-			}).catch(function(err) {
-				Sharer.setShareState(SHARE_STOPED);
-				Sharer.setRecState(SHARE_STOPED);
-				OmUtil.error(err);
-			});
+			promise = navigator.getDisplayMedia(cnts);
 		} else if (b.name === 'Firefox') {
 			// https://mozilla.github.io/webrtc-landing/gum_test.html
-			const cnts = {
-				video: {
-					mediaSource: sd.shareType
-					, frameRate: sd.fps //TODO ideal
-					 //TODO ideal width
-					 //TODO ideal height
-				}};
-			navigator.mediaDevices.getUserMedia(cnts).then(function(stream) {
-				callback(msg, cnts, stream);
-			}).catch(function(err) {
-				Sharer.setShareState(SHARE_STOPED);
-				Sharer.setRecState(SHARE_STOPED);
-				OmUtil.error(err);
+			cnts = Sharer.baseConstraints(sd);
+			cnts.video.mediaSource = sd.shareType;
+			promise = navigator.mediaDevices.getUserMedia(cnts);
+		} else if (b.name === 'Chrome') {
+			promise = Sharer.getChromeConstraints(sd).then((_cnts) => {
+				cnts = _cnts;
+				return navigator.mediaDevices.getUserMedia(_cnts);
 			});
 		} else {
-			Sharer.setShareState(SHARE_STOPED);
-			Sharer.setRecState(SHARE_STOPED);
-			Sharer.close();
-			OmUtil.error('Screen-sharing is not supported in ' + b.name + '[' + b.major + ']');
+			promise = new Promise(() => {
+				Sharer.close();
+				throw 'Screen-sharing is not supported in ' + b.name + '[' + b.major + ']';
+			});
 		}
+		promise.then(function(stream) {
+			callback(msg, cnts, stream);
+		}).catch(__handleScreenError);
 	}
 	function _getVideoStream(msg, callback) {
 		VideoSettings.constraints(sd, function(cnts) {
diff --git a/pom.xml b/pom.xml
index 62e0fc5..82621c1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -114,7 +114,7 @@
 		<!--  URL of the ASF SonarQube server  -->
 		<sonar.host.url>https://builds.apache.org/analysis</sonar.host.url>
 		<!--  Exclude all generated code  -->
-		<sonar.exclusions>file:**/generated-sources/**, file:**/fabric.js, file:**/cssemoticons.js, file:**/kurento-utils.js, file:**/getScreenId.js, file:**/fileinput*.js, file:**/MathJax.js, file:**/network.js, file:**/jquery.dialogextend.js</sonar.exclusions>
+		<sonar.exclusions>file:**/generated-sources/**, file:**/fabric.js, file:**/cssemoticons.js, file:**/kurento-utils.js, file:**/fileinput*.js, file:**/MathJax.js, file:**/network.js, file:**/jquery.dialogextend.js</sonar.exclusions>
 		<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
 		<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
 		<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>