From 47e86a5fa9ab7ddf73c0990b9498cdf5be7fe718 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Tue, 29 Dec 2015 16:25:07 -0600 Subject: [PATCH] Fixes minor Firefox issues. Adds methods for the desktop sharing. --- JitsiMeetJS.js | 7 +++ doc/API.md | 15 +++++-- doc/example/example.js | 24 ++++++++++ doc/example/index.html | 1 + lib-jitsi-meet.js | 92 +++++++++++++++++++++------------------ modules/RTC/JitsiTrack.js | 11 ++++- modules/RTC/RTC.js | 8 ++++ modules/RTC/RTCUtils.js | 9 +++- modules/xmpp/ChatRoom.js | 2 +- modules/xmpp/SDP.js | 5 +-- 10 files changed, 123 insertions(+), 51 deletions(-) diff --git a/JitsiMeetJS.js b/JitsiMeetJS.js index 9a756fd60..bd17600c1 100644 --- a/JitsiMeetJS.js +++ b/JitsiMeetJS.js @@ -29,6 +29,13 @@ var LibJitsiMeet = { init: function (options) { return RTC.init(options || {}); }, + /** + * Returns whether the desktop sharing is enabled or not. + * @returns {boolean} + */ + isDesktopSharingEnabled: function () { + return RTC.isDesktopSharingEnabled(); + }, setLogLevel: function (level) { Logger.setLogLevel(level); }, diff --git a/doc/API.md b/doc/API.md index 45f4140a6..98df9b27e 100644 --- a/doc/API.md +++ b/doc/API.md @@ -37,7 +37,14 @@ You can access the following methods and objects trough ```JitsiMeetJS``` object * ```JitsiMeetJS.init(options)``` - this method initialized Jitsi Meet API. The ```options``` parameter is JS object with the following properties: 1. useIPv6 - boolean property - + 2. desktopSharingChromeMethod - Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable. + 3. desktopSharingChromeExtId - The ID of the jidesha extension for Chrome or Firefox. Example: 'mbocklcggfhnbahlnepmldehdhpjfcjp' + desktopSharingChromeSources - Array of strings with the media sources to use when using screen sharing with the Chrome extension. Example: ['screen', 'window'] + 4. desktopSharingChromeMinExtVersion - Required version of Chrome extension. Example: '0.1' + 5. desktopSharingFirefoxExtId - The ID of the jidesha extension for Firefox. If null, we assume that no extension is required. + 6. desktopSharingFirefoxDisabled - Boolean. Whether desktop sharing should be disabled on Firefox. Example: false. + 7. desktopSharingFirefoxMaxVersionExtRequired - 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. + 8. desktopSharingFirefoxExtensionURL - The URL to the Firefox extension for desktop sharing. "null" if no extension is required. * ```JitsiMeetJS.JitsiConnection``` - the ```JitsiConnection``` constructor. You can use that to create new server connection. @@ -48,7 +55,7 @@ JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR); * ```JitsiMeetJS.createLocalTracks(options)``` - Creates the media tracks and returns them trough ```Promise``` object. - options - JS object with configuration options for the local media tracks. You can change the following properties there: - 1. devices - array with the devices - "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices. + 1. devices - array with the devices - "desktop", "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices. 2. resolution - the prefered resolution for the local video. 3. cameraDeviceId - the deviceID for the video device that is going to be used 4. micDeviceId - the deviceID for the audio device that is going to be used @@ -60,6 +67,8 @@ JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR); * ```JitsiMeetJS.isDeviceListAvailable()```- returns true if retrieving the device list is support and false - otherwise. +* ```JitsiMeetJS.isDesktopSharingEnabled()``` - returns true if desktop sharing is supported and false otherwise. NOTE: that method can be used after ```JitsiMeetJS.init(options)``` is completed otherwise the result will be always null. + * ```JitsiMeetJS.events``` - JS object that contains all events used by the API. You will need that JS object when you try to subscribe for connection or conference events. We have two event types - connection and conference. You can access the events with the following code ```JitsiMeetJS.events..```. For example if you want to use the conference event that is fired when somebody leave conference you can use the following code - ```JitsiMeetJS.events.conference.USER_LEFT```. @@ -316,7 +325,7 @@ room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined); 5. You also may want to get your local tracks from the camera and microphone: ```javascript -room.createLocalTracks().then(onLocalTracks); +JitsiMeetJS.createLocalTracks().then(onLocalTracks); ``` NOTE: Adding listeners and creating local streams are not mandatory steps. diff --git a/doc/example/example.js b/doc/example/example.js index 181fc5910..52bc874ba 100644 --- a/doc/example/example.js +++ b/doc/example/example.js @@ -157,6 +157,30 @@ function unload() { room.leave(); connection.disconnect(); } +var isVideo = true; +function switchVideo() { + isVideo = !isVideo; + if(localTracks[1]) { + localTracks[1].stop(); + localTracks.pop(); + } + JitsiMeetJS.createLocalTracks({devices: isVideo? ["video"] : ["desktop"]}). + then(function (tracks) { + localTracks.push(tracks[0]); + localTracks[1].addEventListener(JitsiMeetJS.events.track.TRACK_MUTE_CHANGED, + function () { + console.log("local track muted"); + }); + localTracks[1].addEventListener(JitsiMeetJS.events.track.TRACK_STOPPED, + function () { + console.log("local track stoped"); + }); + localTracks[1].attach($("#localVideo1")); + room.addTrack(localTracks[1]); + }).catch(function (error) { + console.log(error); + }); +} $(window).bind('beforeunload', unload); $(window).bind('unload', unload); diff --git a/doc/example/index.html b/doc/example/index.html index 896ba7313..a97c91639 100644 --- a/doc/example/index.html +++ b/doc/example/index.html @@ -12,6 +12,7 @@ Unload + switchVideo diff --git a/lib-jitsi-meet.js b/lib-jitsi-meet.js index 4d25a609b..251e21076 100644 --- a/lib-jitsi-meet.js +++ b/lib-jitsi-meet.js @@ -54,7 +54,7 @@ function JitsiConference(options) { */ JitsiConference.prototype.join = function (password) { if(this.room) - this.room.join(password, this.connection.tokenPassword); + this.room.join(password); }; /** @@ -903,33 +903,18 @@ module.exports = JitsiConferenceEvents; },{}],4:[function(require,module,exports){ var JitsiConference = require("./JitsiConference"); var XMPP = require("./modules/xmpp/xmpp"); -var RandomUtil = require("./modules/util/RandomUtil"); - -/** - * Utility method that generates user name based on random hex values. - * Eg. 12345678-1234-1234-12345678 - * @returns {string} - */ -function generateUserName() { - return RandomUtil.random8digitsHex() + "-" + RandomUtil.random4digitsHex() + "-" + - RandomUtil.random4digitsHex() + "-" + RandomUtil.random8digitsHex(); -} /** * Creates new connection object for the Jitsi Meet server side video conferencing service. Provides access to the * JitsiConference interface. * @param appID identification for the provider of Jitsi Meet video conferencing services. - * @param tokenPassword secret generated by the provider of Jitsi Meet video conferencing services. - * The token will be send to the provider from the Jitsi Meet server deployment for authorization of the current client. - * The format is: - * passwordToken = token + "_" + roomName + "_" + ts - * See doc/tokens.md for more info on how tokens are generated. + * @param token the JWT token used to authenticate with the server(optional) * @param options Object with properties / settings related to connection with the server. * @constructor */ -function JitsiConnection(appID, tokenPassword, options) { +function JitsiConnection(appID, token, options) { this.appID = appID; - this.tokenPassword = tokenPassword; + this.token = token; this.options = options; this.xmpp = new XMPP(options); this.conferences = {}; @@ -943,14 +928,6 @@ JitsiConnection.prototype.connect = function (options) { if(!options) options = {}; - // If we have token provided use it as a password and generate random username - if (this.tokenPassword) { - options.password = this.tokenPassword; - if (!options.id) { - options.id = generateUserName() + "@" + this.options.hosts.domain; - } - } - this.xmpp.connect(options.id, options.password); } @@ -1000,7 +977,7 @@ JitsiConnection.prototype.removeEventListener = function (event, listener) { module.exports = JitsiConnection; -},{"./JitsiConference":1,"./modules/util/RandomUtil":25,"./modules/xmpp/xmpp":42}],5:[function(require,module,exports){ +},{"./JitsiConference":1,"./modules/xmpp/xmpp":42}],5:[function(require,module,exports){ /** * Enumeration with the errors for the connection. * @type {{string: string}} @@ -1082,6 +1059,13 @@ var LibJitsiMeet = { init: function (options) { return RTC.init(options || {}); }, + /** + * Returns whether the desktop sharing is enabled or not. + * @returns {boolean} + */ + isDesktopSharingEnabled: function () { + return RTC.isDesktopSharingEnabled(); + }, setLogLevel: function (level) { Logger.setLogLevel(level); }, @@ -1822,6 +1806,7 @@ module.exports = JitsiRemoteTrack; var RTCBrowserType = require("./RTCBrowserType"); var JitsiTrackEvents = require("../../JitsiTrackEvents"); var EventEmitter = require("events"); +var RTC = require("./RTCUtils"); /** * This implements 'onended' callback normally fired by WebRTC after the stream @@ -2012,13 +1997,21 @@ JitsiTrack.prototype.isScreenSharing = function(){ * Returns id of the track. * @returns {string} id of the track or null if this is fake track. */ -JitsiTrack.prototype.getId = function () { +JitsiTrack.prototype._getId = function () { var tracks = this.stream.getTracks(); if(!tracks || tracks.length === 0) return null; return tracks[0].id; }; +/** + * Returns id of the track. + * @returns {string} id of the track or null if this is fake track. + */ +JitsiTrack.prototype.getId = function () { + return RTC.getStreamID(this.stream); +}; + /** * Checks whether the MediaStream is avtive/not ended. * When there is no check for active we don't have information and so @@ -2270,6 +2263,14 @@ RTC.stopMediaStream = function (mediaStream) { RTCUtils.stopMediaStream(mediaStream); }; +/** + * Returns whether the desktop sharing is enabled or not. + * @returns {boolean} + */ +RTC.isDesktopSharingEnabled = function () { + return RTCUtils.isDesktopSharingEnabled(); +} + RTC.prototype.getVideoElementName = function () { return RTCBrowserType.isTemasysPluginUsed() ? 'object' : 'video'; }; @@ -3128,7 +3129,7 @@ var RTCUtils = { var deviceGUM = { "audio": GUM.bind(self, ["audio"]), "video": GUM.bind(self, ["video"]), - "desktop": screenObtainer.obtainStream + "desktop": screenObtainer.obtainStream.bind(screenObtainer) }; // With FF/IE we can't split the stream into audio and video because FF // doesn't support media stream constructors. So, we need to get the @@ -3234,6 +3235,13 @@ var RTCUtils = { if (mediaStream.stop) { mediaStream.stop(); } + }, + /** + * Returns whether the desktop sharing is enabled or not. + * @returns {boolean} + */ + isDesktopSharingEnabled: function () { + return screenObtainer.isSupported(); } }; @@ -6151,17 +6159,17 @@ ChatRoom.prototype.updateDeviceAvailability = function (devices) { }); }; -ChatRoom.prototype.join = function (password, tokenPassword) { +ChatRoom.prototype.join = function (password) { if(password) this.password = password; var self = this; this.moderator.allocateConferenceFocus(function() { - self.sendPresence(tokenPassword); + self.sendPresence(); }.bind(this)); }; -ChatRoom.prototype.sendPresence = function (tokenPassword) { +ChatRoom.prototype.sendPresence = function () { if (!this.presMap['to']) { // Too early to send presence - not initialized return; @@ -6181,11 +6189,6 @@ ChatRoom.prototype.sendPresence = function (tokenPassword) { pres.c('c', this.connection.caps.generateCapsAttrs()).up(); } - if (tokenPassword) { - pres.c('token', { xmlns: 'http://jitsi.org/jitmeet/auth-token'}) - .t(tokenPassword).up(); - } - parser.JSON2packet(this.presMap.nodes, pres); this.connection.send(pres); }; @@ -6372,7 +6375,7 @@ ChatRoom.prototype.onPresence = function (pres) { ChatRoom.prototype.processNode = function (node, from) { if(this.presHandlers[node.tagName]) - this.presHandlers[node.tagName](node, from); + this.presHandlers[node.tagName](node, Strophe.getResourceFromJid(from)); }; ChatRoom.prototype.sendMessage = function (body, nickname) { @@ -9116,11 +9119,11 @@ SDP.prototype.toJingle = function (elem, thecreator) { var msid = null; if(mline.media == "audio") { - msid = APP.RTC.localAudio.getId(); + msid = APP.RTC.localAudio._getId(); } else { - msid = APP.RTC.localVideo.getId(); + msid = APP.RTC.localVideo._getId(); } if(msid != null) { @@ -9516,7 +9519,6 @@ SDP.prototype.jingle2media = function (content) { module.exports = SDP; - }).call(this,"/modules/xmpp/SDP.js") },{"./SDPUtil":32,"jitsi-meet-logger":48}],31:[function(require,module,exports){ var SDPUtil = require("./SDPUtil"); @@ -11801,6 +11803,12 @@ var authenticatedUser = false; function createConnection(bosh) { bosh = bosh || '/http-bind'; + // Append token as URL param + if (this.token) { + bosh += bosh.indexOf('?') == -1 ? + '?token=' + this.token : '&token=' + this.token; + } + return new Strophe.Connection(bosh); }; diff --git a/modules/RTC/JitsiTrack.js b/modules/RTC/JitsiTrack.js index 79ab5bb4c..4e541b282 100644 --- a/modules/RTC/JitsiTrack.js +++ b/modules/RTC/JitsiTrack.js @@ -1,6 +1,7 @@ var RTCBrowserType = require("./RTCBrowserType"); var JitsiTrackEvents = require("../../JitsiTrackEvents"); var EventEmitter = require("events"); +var RTC = require("./RTCUtils"); /** * This implements 'onended' callback normally fired by WebRTC after the stream @@ -191,13 +192,21 @@ JitsiTrack.prototype.isScreenSharing = function(){ * Returns id of the track. * @returns {string} id of the track or null if this is fake track. */ -JitsiTrack.prototype.getId = function () { +JitsiTrack.prototype._getId = function () { var tracks = this.stream.getTracks(); if(!tracks || tracks.length === 0) return null; return tracks[0].id; }; +/** + * Returns id of the track. + * @returns {string} id of the track or null if this is fake track. + */ +JitsiTrack.prototype.getId = function () { + return RTC.getStreamID(this.stream); +}; + /** * Checks whether the MediaStream is avtive/not ended. * When there is no check for active we don't have information and so diff --git a/modules/RTC/RTC.js b/modules/RTC/RTC.js index 92ce662ce..5feab7d15 100644 --- a/modules/RTC/RTC.js +++ b/modules/RTC/RTC.js @@ -195,6 +195,14 @@ RTC.stopMediaStream = function (mediaStream) { RTCUtils.stopMediaStream(mediaStream); }; +/** + * Returns whether the desktop sharing is enabled or not. + * @returns {boolean} + */ +RTC.isDesktopSharingEnabled = function () { + return RTCUtils.isDesktopSharingEnabled(); +} + RTC.prototype.getVideoElementName = function () { return RTCBrowserType.isTemasysPluginUsed() ? 'object' : 'video'; }; diff --git a/modules/RTC/RTCUtils.js b/modules/RTC/RTCUtils.js index 1d3f9fa8b..df946c48a 100644 --- a/modules/RTC/RTCUtils.js +++ b/modules/RTC/RTCUtils.js @@ -657,7 +657,7 @@ var RTCUtils = { var deviceGUM = { "audio": GUM.bind(self, ["audio"]), "video": GUM.bind(self, ["video"]), - "desktop": screenObtainer.obtainStream + "desktop": screenObtainer.obtainStream.bind(screenObtainer) }; // With FF/IE we can't split the stream into audio and video because FF // doesn't support media stream constructors. So, we need to get the @@ -763,6 +763,13 @@ var RTCUtils = { if (mediaStream.stop) { mediaStream.stop(); } + }, + /** + * Returns whether the desktop sharing is enabled or not. + * @returns {boolean} + */ + isDesktopSharingEnabled: function () { + return screenObtainer.isSupported(); } }; diff --git a/modules/xmpp/ChatRoom.js b/modules/xmpp/ChatRoom.js index 672eb8326..918a58faa 100644 --- a/modules/xmpp/ChatRoom.js +++ b/modules/xmpp/ChatRoom.js @@ -328,7 +328,7 @@ ChatRoom.prototype.onPresence = function (pres) { ChatRoom.prototype.processNode = function (node, from) { if(this.presHandlers[node.tagName]) - this.presHandlers[node.tagName](node, from); + this.presHandlers[node.tagName](node, Strophe.getResourceFromJid(from)); }; ChatRoom.prototype.sendMessage = function (body, nickname) { diff --git a/modules/xmpp/SDP.js b/modules/xmpp/SDP.js index b9c61e212..20f5cd1f0 100644 --- a/modules/xmpp/SDP.js +++ b/modules/xmpp/SDP.js @@ -246,11 +246,11 @@ SDP.prototype.toJingle = function (elem, thecreator) { var msid = null; if(mline.media == "audio") { - msid = APP.RTC.localAudio.getId(); + msid = APP.RTC.localAudio._getId(); } else { - msid = APP.RTC.localVideo.getId(); + msid = APP.RTC.localVideo._getId(); } if(msid != null) { @@ -645,4 +645,3 @@ SDP.prototype.jingle2media = function (content) { module.exports = SDP; -