diff --git a/bigbluebutton-client/resources/prod/lib/kurento-extension.js b/bigbluebutton-client/resources/prod/lib/kurento-extension.js index b7aafb39360ca65500dcb67a4b6d9f4eabda5b34..ad7f6cdff2d5cd768f64f2ee5ede6bf4b98a6fdc 100644 --- a/bigbluebutton-client/resources/prod/lib/kurento-extension.js +++ b/bigbluebutton-client/resources/prod/lib/kurento-extension.js @@ -9,6 +9,7 @@ const SFU_APP = "screenshare"; const ON_ICE_CANDIDATE_MSG = "onIceCandidate"; const START_MSG = "start"; const START_RESPONSE_MSG = "startResponse"; +const PING_INTERVAL = 15000; Kurento = function ( tag, @@ -44,6 +45,7 @@ Kurento = function ( this.kurentoPort = 'bbb-webrtc-sfu'; this.hostName = window.location.hostname; this.socketUrl = `wss://${this.hostName}/${this.kurentoPort}`; + this.pingInterval = null; this.iceServers = null; @@ -60,6 +62,7 @@ Kurento = function ( _this.logError('Default error handler'); }; } + }; this.KurentoManager = function () { @@ -75,11 +78,11 @@ KurentoManager.prototype.exitScreenShare = function () { this.kurentoScreenshare.ws.close(); } - this.kurentoScreenshare.disposeScreenShare(); - this.kurentoScreenshare = null; - } + if (this.kurentoScreenshare.pingInterval) { + clearInterval(this.kurentoScreenshare.pingInterval); + } - if (this.kurentoScreenshare) { + this.kurentoScreenshare.disposeScreenShare(); this.kurentoScreenshare = null; } @@ -96,11 +99,11 @@ KurentoManager.prototype.exitVideo = function () { this.kurentoVideo.ws.close(); } - this.kurentoVideo.disposeScreenShare(); - this.kurentoVideo = null; - } + if (this.kurentoVideo.pingInterval) { + clearInterval(this.kurentoVideo.pingInterval); + } - if (this.kurentoVideo) { + this.kurentoVideo.disposeScreenShare(); this.kurentoVideo = null; } }; @@ -149,6 +152,7 @@ Kurento.prototype.init = function () { self.onFail('Websocket connection error'); }; this.ws.onopen = function () { + self.pingInterval = setInterval(self.ping.bind(self), PING_INTERVAL); self.mediaCallback(); }; } else { console.log('this browser does not support websockets'); } @@ -166,6 +170,8 @@ Kurento.prototype.onWSMessage = function (message) { case 'iceCandidate': this.webRtcPeer.addIceCandidate(parsedMessage.candidate); break; + case 'pong': + break; default: console.error('Unrecognized message', parsedMessage); } @@ -364,6 +370,13 @@ Kurento.prototype.disposeScreenShare = function () { } }; +Kurento.prototype.ping = function () { + const message = { + id: 'ping' + }; + this.sendMessage(message); +} + Kurento.prototype.sendMessage = function (message) { const jsonMessage = JSON.stringify(message); console.log(`Sending message: ${jsonMessage}`); diff --git a/bigbluebutton-html5/client/compatibility/kurento-extension.js b/bigbluebutton-html5/client/compatibility/kurento-extension.js index f376a9c19da82902eea1800c0b2d9f973365965f..ad7f6cdff2d5cd768f64f2ee5ede6bf4b98a6fdc 100644 --- a/bigbluebutton-html5/client/compatibility/kurento-extension.js +++ b/bigbluebutton-html5/client/compatibility/kurento-extension.js @@ -9,6 +9,7 @@ const SFU_APP = "screenshare"; const ON_ICE_CANDIDATE_MSG = "onIceCandidate"; const START_MSG = "start"; const START_RESPONSE_MSG = "startResponse"; +const PING_INTERVAL = 15000; Kurento = function ( tag, @@ -44,6 +45,7 @@ Kurento = function ( this.kurentoPort = 'bbb-webrtc-sfu'; this.hostName = window.location.hostname; this.socketUrl = `wss://${this.hostName}/${this.kurentoPort}`; + this.pingInterval = null; this.iceServers = null; @@ -60,6 +62,7 @@ Kurento = function ( _this.logError('Default error handler'); }; } + }; this.KurentoManager = function () { @@ -75,11 +78,11 @@ KurentoManager.prototype.exitScreenShare = function () { this.kurentoScreenshare.ws.close(); } - this.kurentoScreenshare.disposeScreenShare(); - this.kurentoScreenshare = null; - } + if (this.kurentoScreenshare.pingInterval) { + clearInterval(this.kurentoScreenshare.pingInterval); + } - if (this.kurentoScreenshare) { + this.kurentoScreenshare.disposeScreenShare(); this.kurentoScreenshare = null; } @@ -96,11 +99,11 @@ KurentoManager.prototype.exitVideo = function () { this.kurentoVideo.ws.close(); } - this.kurentoVideo.disposeScreenShare(); - this.kurentoVideo = null; - } + if (this.kurentoVideo.pingInterval) { + clearInterval(this.kurentoVideo.pingInterval); + } - if (this.kurentoVideo) { + this.kurentoVideo.disposeScreenShare(); this.kurentoVideo = null; } }; @@ -149,6 +152,7 @@ Kurento.prototype.init = function () { self.onFail('Websocket connection error'); }; this.ws.onopen = function () { + self.pingInterval = setInterval(self.ping.bind(self), PING_INTERVAL); self.mediaCallback(); }; } else { console.log('this browser does not support websockets'); } @@ -166,6 +170,8 @@ Kurento.prototype.onWSMessage = function (message) { case 'iceCandidate': this.webRtcPeer.addIceCandidate(parsedMessage.candidate); break; + case 'pong': + break; default: console.error('Unrecognized message', parsedMessage); } @@ -364,6 +370,13 @@ Kurento.prototype.disposeScreenShare = function () { } }; +Kurento.prototype.ping = function () { + const message = { + id: 'ping' + }; + this.sendMessage(message); +} + Kurento.prototype.sendMessage = function (message) { const jsonMessage = JSON.stringify(message); console.log(`Sending message: ${jsonMessage}`); @@ -488,3 +501,41 @@ window.getChromeScreenConstraints = function (callback, extensionId) { }, ); }; + +// a function to check whether the browser (Chrome only) is in an isIncognito +// session. Requires 1 mandatory callback that only gets called if the browser +// session is incognito. The callback for not being incognito is optional. +// Attempts to retrieve the chrome filesystem API. +window.checkIfIncognito = function(isIncognito, isNotIncognito = function () {}) { + isIncognito = Kurento.normalizeCallback(isIncognito); + isNotIncognito = Kurento.normalizeCallback(isNotIncognito); + + var fs = window.RequestFileSystem || window.webkitRequestFileSystem; + if (!fs) { + isNotIncognito(); + return; + } + fs(window.TEMPORARY, 100, function(){isNotIncognito()}, function(){isIncognito()}); +}; + +window.checkChromeExtInstalled = function (callback, chromeExtensionId) { + callback = Kurento.normalizeCallback(callback); + + if (typeof chrome === "undefined" || !chrome || !chrome.runtime) { + // No API, so no extension for sure + callback(false); + return; + } + chrome.runtime.sendMessage( + chromeExtensionId, + { getVersion: true }, + function (response) { + if (!response || !response.version) { + // Communication failure - assume that no endpoint exists + callback(false); + return; + } + callback(true); + } + ); +} diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx index 48732d7c67bcca5a5df951c0dd0e188134f5e011..dddf331f326cc247077cd1d5104fd1f0273d9837 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx @@ -33,8 +33,8 @@ const intlMessages = defineMessages({ }, }); -const RECONNECT_WAIT_TIME = 5000; const CAMERA_SHARE_FAILED_WAIT_TIME = 10000; +const PING_INTERVAL = 15000; class VideoProvider extends Component { constructor(props) { @@ -128,6 +128,8 @@ class VideoProvider extends Component { this.sendMessage(this.wsQueue.pop()); } + this.pingInterval = setInterval(this.ping.bind(this), PING_INTERVAL); + this.setState({ socketOpen: true }); } @@ -135,10 +137,18 @@ class VideoProvider extends Component { log('debug', '------ Websocket connection closed.'); this.stopWebRTCPeer(this.props.userId); + clearInterval(this.pingInterval); this.setState({ socketOpen: false }); } + ping() { + const message = { + id: 'ping' + }; + this.sendMessage(message); + } + disconnected(id) { this.reconnectList.push(id); @@ -169,6 +179,10 @@ class VideoProvider extends Component { this.handleIceCandidate(parsedMessage); break; + case 'pong': + console.debug("Received pong from server"); + break; + case 'error': default: this.handleError(parsedMessage); diff --git a/labs/bbb-webrtc-sfu/lib/connection-manager/WebsocketConnectionManager.js b/labs/bbb-webrtc-sfu/lib/connection-manager/WebsocketConnectionManager.js index 0dc0a6d37cd5ac920fa053967a161b3bd1dfe419..22df53957ad6fc278641c08b9d14b702750c098a 100644 --- a/labs/bbb-webrtc-sfu/lib/connection-manager/WebsocketConnectionManager.js +++ b/labs/bbb-webrtc-sfu/lib/connection-manager/WebsocketConnectionManager.js @@ -50,6 +50,12 @@ module.exports = class WebsocketConnectionManager { try { message = JSON.parse(data); + + if (message.id === 'ping') { + ws.sendMessage({id: 'pong'}); + return; + } + message.connectionId = ws.id; if (!ws.sessionId) { diff --git a/labs/bbb-webrtc-sfu/package-lock.json b/labs/bbb-webrtc-sfu/package-lock.json index c2cab4e85ec27fd894aa519fc30604b52e6da702..2230bf4bcbc75ad0e3e4c14e8fdee218a4c832c4 100644 --- a/labs/bbb-webrtc-sfu/package-lock.json +++ b/labs/bbb-webrtc-sfu/package-lock.json @@ -1,6 +1,6 @@ { "name": "bbb-webrtc-sfu", - "version": "0.0.3", + "version": "0.0.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -171,39 +171,26 @@ "promise": "7.1.1", "promisecallback": "0.0.4", "reconnect-ws": "github:KurentoForks/reconnect-ws#f287385d75861654528c352e60221f95c9209f8a" + } + }, + "kurento-client-core": { + "version": "github:Kurento/kurento-client-core-js#2160f8e6938f138b52b72a5c5c354d1e5fce1ca0" + }, + "kurento-client-elements": { + "version": "github:Kurento/kurento-client-elements-js#cbd1ff67fbf0faddc9f6f266bb33e449bc9e1f81" + }, + "kurento-client-filters": { + "version": "github:Kurento/kurento-client-filters-js#51308da53e432a2db9559dcdb308d87951417bf0" + }, + "kurento-jsonrpc": { + "version": "github:Kurento/kurento-jsonrpc-js#827827bbeb557e1c1901f5a562c4c700b9a51401", + "requires": { + "bufferutil": "1.2.1", + "inherits": "2.0.3", + "utf-8-validate": "1.2.2", + "ws": "1.1.5" }, "dependencies": { - "kurento-client-core": { - "version": "github:Kurento/kurento-client-core-js#2160f8e6938f138b52b72a5c5c354d1e5fce1ca0" - }, - "kurento-client-elements": { - "version": "github:Kurento/kurento-client-elements-js#cbd1ff67fbf0faddc9f6f266bb33e449bc9e1f81" - }, - "kurento-client-filters": { - "version": "github:Kurento/kurento-client-filters-js#51308da53e432a2db9559dcdb308d87951417bf0" - }, - "kurento-jsonrpc": { - "version": "github:Kurento/kurento-jsonrpc-js#827827bbeb557e1c1901f5a562c4c700b9a51401", - "requires": { - "bufferutil": "1.2.1", - "inherits": "2.0.3", - "utf-8-validate": "1.2.2", - "ws": "1.1.5" - } - }, - "reconnect-core": { - "version": "github:KurentoForks/reconnect-core#921d43e91578abb2fb2613f585c010c1939cf734", - "requires": { - "backoff": "2.3.0" - } - }, - "reconnect-ws": { - "version": "github:KurentoForks/reconnect-ws#f287385d75861654528c352e60221f95c9209f8a", - "requires": { - "reconnect-core": "github:KurentoForks/reconnect-core#921d43e91578abb2fb2613f585c010c1939cf734", - "websocket-stream": "0.5.1" - } - }, "ws": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", @@ -291,6 +278,19 @@ "nanoid": "1.0.1" } }, + "reconnect-core": { + "version": "github:KurentoForks/reconnect-core#921d43e91578abb2fb2613f585c010c1939cf734", + "requires": { + "backoff": "2.3.0" + } + }, + "reconnect-ws": { + "version": "github:KurentoForks/reconnect-ws#f287385d75861654528c352e60221f95c9209f8a", + "requires": { + "reconnect-core": "github:KurentoForks/reconnect-core#921d43e91578abb2fb2613f585c010c1939cf734", + "websocket-stream": "0.5.1" + } + }, "redis": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", diff --git a/labs/bbb-webrtc-sfu/package.json b/labs/bbb-webrtc-sfu/package.json index 0c380aa82af781c39a673d8359b2350fd78b5206..10a253b70b088c642fc94701d52a46129572e661 100644 --- a/labs/bbb-webrtc-sfu/package.json +++ b/labs/bbb-webrtc-sfu/package.json @@ -1,6 +1,6 @@ { "name": "bbb-webrtc-sfu", - "version": "0.0.3", + "version": "0.0.5", "private": true, "scripts": { "start": "node server.js"