Merge pull request #487 from isymchych/video-mute-screensharing
Handle video mute/unmute during screensharing
This commit is contained in:
commit
e688a5cb9f
6
app.js
6
app.js
|
@ -62,8 +62,6 @@ const APP = {
|
|||
conference,
|
||||
API,
|
||||
init () {
|
||||
this.desktopsharing =
|
||||
require("./modules/desktopsharing/desktopsharing");
|
||||
this.keyboardshortcut =
|
||||
require("./modules/keyboardshortcut/keyboardshortcut");
|
||||
this.translation = require("./modules/translation/translation");
|
||||
|
@ -75,10 +73,6 @@ function init() {
|
|||
var isUIReady = APP.UI.start();
|
||||
if (isUIReady) {
|
||||
APP.conference.init({roomName: buildRoomName()}).then(function () {
|
||||
// init desktop before UI, in order to make sure
|
||||
// autoEnableDesktopSharing works
|
||||
APP.desktopsharing.init(JitsiMeetJS.isDesktopSharingEnabled());
|
||||
|
||||
APP.UI.initConference();
|
||||
|
||||
APP.UI.addListener(UIEvents.LANG_CHANGED, function (language) {
|
||||
|
|
250
conference.js
250
conference.js
|
@ -9,7 +9,6 @@ import ConnectionQuality from './modules/connectionquality/connectionquality';
|
|||
|
||||
import CQEvents from './service/connectionquality/CQEvents';
|
||||
import UIEvents from './service/UI/UIEvents';
|
||||
import DSEvents from './service/desktopsharing/DesktopSharingEventTypes';
|
||||
|
||||
const ConnectionEvents = JitsiMeetJS.events.connection;
|
||||
const ConnectionErrors = JitsiMeetJS.errors.connection;
|
||||
|
@ -18,6 +17,7 @@ const ConferenceEvents = JitsiMeetJS.events.conference;
|
|||
const ConferenceErrors = JitsiMeetJS.errors.conference;
|
||||
|
||||
const TrackEvents = JitsiMeetJS.events.track;
|
||||
const TrackErrors = JitsiMeetJS.errors.track;
|
||||
|
||||
let room, connection, localTracks, localAudio, localVideo, roomLocker;
|
||||
|
||||
|
@ -47,19 +47,6 @@ function connect() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add local track to the conference and shares
|
||||
* video type with other users if its video track.
|
||||
* @param {JitsiLocalTrack} track local track
|
||||
*/
|
||||
function addTrack (track) {
|
||||
room.addTrack(track);
|
||||
|
||||
if (track.isAudioTrack()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Share email with other users.
|
||||
* @param {string} email new email
|
||||
|
@ -89,6 +76,73 @@ function getDisplayName (id) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mute or unmute local audio stream if it exists.
|
||||
* @param {boolean} muted if audio stream should be muted or unmuted.
|
||||
*/
|
||||
function muteLocalAudio (muted) {
|
||||
if (!localAudio) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (muted) {
|
||||
localAudio.mute();
|
||||
} else {
|
||||
localAudio.unmute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mute or unmute local video stream if it exists.
|
||||
* @param {boolean} muted if video stream should be muted or unmuted.
|
||||
*/
|
||||
function muteLocalVideo (muted) {
|
||||
if (!localVideo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (muted) {
|
||||
localVideo.mute();
|
||||
} else {
|
||||
localVideo.unmute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create local tracks of specified types.
|
||||
* @param {string[]} devices required track types ('audio', 'video' etc.)
|
||||
* @returns {Promise<JitsiLocalTrack[]>}
|
||||
*/
|
||||
function createLocalTracks (...devices) {
|
||||
return JitsiMeetJS.createLocalTracks({
|
||||
// copy array to avoid mutations inside library
|
||||
devices: devices.slice(0),
|
||||
resolution: config.resolution,
|
||||
// adds any ff fake device settings if any
|
||||
firefox_fake_device: config.firefox_fake_device
|
||||
}).catch(function (err) {
|
||||
console.error('failed to create local tracks', ...devices, err);
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create local screen sharing track.
|
||||
* Shows UI notification if Firefox extension is required.
|
||||
* @returns {Promise<JitsiLocalTrack[]>}
|
||||
*/
|
||||
function createDesktopTrack () {
|
||||
return createLocalTracks('desktop').catch(function (err) {
|
||||
if (err === TrackErrors.FIREFOX_EXTENSION_NEEDED) {
|
||||
APP.UI.showExtensionRequiredDialog(
|
||||
config.desktopSharingFirefoxExtensionURL
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
class ConferenceConnector {
|
||||
constructor(resolve, reject) {
|
||||
this._resolve = resolve;
|
||||
|
@ -213,6 +267,8 @@ export default {
|
|||
isModerator: false,
|
||||
audioMuted: false,
|
||||
videoMuted: false,
|
||||
isSharingScreen: false,
|
||||
isDesktopSharingEnabled: false,
|
||||
/**
|
||||
* Open new connection and join to the conference.
|
||||
* @param {object} options
|
||||
|
@ -225,10 +281,12 @@ export default {
|
|||
|
||||
return JitsiMeetJS.init(config).then(() => {
|
||||
return Promise.all([
|
||||
this.createLocalTracks('audio', 'video').catch(()=>{
|
||||
return this.createLocalTracks('audio');
|
||||
}).catch(
|
||||
() => {return [];}),
|
||||
// try to retrieve audio and video
|
||||
createLocalTracks('audio', 'video')
|
||||
// if failed then try to retrieve only audio
|
||||
.catch(() => createLocalTracks('audio'))
|
||||
// if audio also failed then just return empty array
|
||||
.catch(() => []),
|
||||
connect()
|
||||
]);
|
||||
}).then(([tracks, con]) => {
|
||||
|
@ -236,6 +294,8 @@ export default {
|
|||
localTracks = tracks;
|
||||
connection = con;
|
||||
this._createRoom();
|
||||
this.isDesktopSharingEnabled =
|
||||
JitsiMeetJS.isDesktopSharingEnabled();
|
||||
// XXX The API will take care of disconnecting from the XMPP server
|
||||
// (and, thus, leaving the room) on unload.
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -243,24 +303,6 @@ export default {
|
|||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Create local tracks of specified types.
|
||||
* If we cannot obtain required tracks it will return empty array.
|
||||
* @param {string[]} devices required track types ('audio', 'video' etc.)
|
||||
* @returns {Promise<JitsiLocalTrack[]>}
|
||||
*/
|
||||
createLocalTracks (...devices) {
|
||||
return JitsiMeetJS.createLocalTracks({
|
||||
// copy array to avoid mutations inside library
|
||||
devices: devices.slice(0),
|
||||
resolution: config.resolution,
|
||||
// adds any ff fake device settings if any
|
||||
firefox_fake_device: config.firefox_fake_device
|
||||
}).catch(function (err) {
|
||||
console.error('failed to create local tracks', ...devices, err);
|
||||
return Promise.reject(err);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Check if id is id of the local user.
|
||||
* @param {string} id id to check
|
||||
|
@ -274,9 +316,7 @@ export default {
|
|||
* @param mute true for mute and false for unmute.
|
||||
*/
|
||||
muteAudio (mute) {
|
||||
//FIXME: Maybe we should create method for that in the UI instead of
|
||||
//accessing directly eventEmitter????
|
||||
APP.UI.eventEmitter.emit(UIEvents.AUDIO_MUTED, mute);
|
||||
muteLocalAudio(mute);
|
||||
},
|
||||
/**
|
||||
* Returns whether local audio is muted or not.
|
||||
|
@ -296,9 +336,7 @@ export default {
|
|||
* @param mute true for mute and false for unmute.
|
||||
*/
|
||||
muteVideo (mute) {
|
||||
//FIXME: Maybe we should create method for that in the UI instead of
|
||||
//accessing directly eventEmitter????
|
||||
APP.UI.eventEmitter.emit(UIEvents.VIDEO_MUTED, mute);
|
||||
muteLocalVideo(mute);
|
||||
},
|
||||
/**
|
||||
* Simulates toolbar button click for video mute. Used by shortcuts and API.
|
||||
|
@ -420,7 +458,7 @@ export default {
|
|||
else if (track.isVideoTrack()) {
|
||||
localVideo = track;
|
||||
}
|
||||
addTrack(track);
|
||||
room.addTrack(track);
|
||||
APP.UI.addLocalStream(track);
|
||||
});
|
||||
roomLocker = createRoomLocker(room);
|
||||
|
@ -448,6 +486,79 @@ export default {
|
|||
}
|
||||
return options;
|
||||
},
|
||||
|
||||
videoSwitchInProgress: false,
|
||||
toggleScreenSharing () {
|
||||
if (this.videoSwitchInProgress) {
|
||||
console.warn("Switch in progress.");
|
||||
return;
|
||||
}
|
||||
if (!this.isDesktopSharingEnabled) {
|
||||
console.warn("Cannot toggle screen sharing: not supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.videoSwitchInProgress = true;
|
||||
|
||||
if (this.isSharingScreen) {
|
||||
// stop sharing desktop and share video
|
||||
createLocalTracks('video').then(function ([stream]) {
|
||||
return room.addTrack(stream);
|
||||
}).then((stream) => {
|
||||
if (localVideo) {
|
||||
localVideo.stop();
|
||||
}
|
||||
localVideo = stream;
|
||||
this.videoMuted = stream.isMuted();
|
||||
APP.UI.setVideoMuted(this.localId, this.videoMuted);
|
||||
|
||||
APP.UI.addLocalStream(stream);
|
||||
console.log('sharing local video');
|
||||
}).catch((err) => {
|
||||
localVideo = null;
|
||||
console.error('failed to share local video', err);
|
||||
}).then(() => {
|
||||
this.videoSwitchInProgress = false;
|
||||
this.isSharingScreen = false;
|
||||
APP.UI.updateDesktopSharingButtons();
|
||||
});
|
||||
} else {
|
||||
// stop sharing video and share desktop
|
||||
createDesktopTrack().then(([stream]) => {
|
||||
stream.on(
|
||||
TrackEvents.TRACK_STOPPED,
|
||||
() => {
|
||||
// if stream was stopped during screensharing session
|
||||
// then we should switch to video
|
||||
// otherwise we stopped it because we already switched
|
||||
// to video, so nothing to do here
|
||||
if (this.isSharingScreen) {
|
||||
this.toggleScreenSharing();
|
||||
}
|
||||
}
|
||||
);
|
||||
return room.addTrack(stream);
|
||||
}).then((stream) => {
|
||||
if (localVideo) {
|
||||
localVideo.stop();
|
||||
}
|
||||
localVideo = stream;
|
||||
|
||||
this.videoMuted = stream.isMuted();
|
||||
APP.UI.setVideoMuted(this.localId, this.videoMuted);
|
||||
|
||||
APP.UI.addLocalStream(stream);
|
||||
|
||||
this.videoSwitchInProgress = false;
|
||||
this.isSharingScreen = true;
|
||||
APP.UI.updateDesktopSharingButtons();
|
||||
console.log('sharing local desktop');
|
||||
}).catch((err) => {
|
||||
this.videoSwitchInProgress = false;
|
||||
console.error('failed to share local desktop', err);
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Setup interaction between conference and UI.
|
||||
*/
|
||||
|
@ -607,16 +718,8 @@ export default {
|
|||
}
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.AUDIO_MUTED, (muted) => {
|
||||
if(!localAudio)
|
||||
return;
|
||||
(muted)? localAudio.mute() : localAudio.unmute();
|
||||
});
|
||||
APP.UI.addListener(UIEvents.VIDEO_MUTED, (muted) => {
|
||||
if(!localVideo)
|
||||
return;
|
||||
(muted)? localVideo.mute() : localVideo.unmute();
|
||||
});
|
||||
APP.UI.addListener(UIEvents.AUDIO_MUTED, muteLocalAudio);
|
||||
APP.UI.addListener(UIEvents.VIDEO_MUTED, muteLocalVideo);
|
||||
|
||||
if (!interfaceConfig.filmStripOnly) {
|
||||
APP.UI.addListener(UIEvents.MESSAGE_CREATED, (message) => {
|
||||
|
@ -799,45 +902,8 @@ export default {
|
|||
room.pinParticipant(id);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.TOGGLE_SCREENSHARING, () => {
|
||||
APP.desktopsharing.toggleScreenSharing();
|
||||
});
|
||||
|
||||
APP.desktopsharing.addListener(DSEvents.SWITCHING_DONE,
|
||||
(isSharingScreen) => {
|
||||
APP.UI.updateDesktopSharingButtons(isSharingScreen);
|
||||
});
|
||||
|
||||
APP.desktopsharing.addListener(DSEvents.FIREFOX_EXTENSION_NEEDED,
|
||||
(url) => {
|
||||
APP.UI.showExtensionRequiredDialog(url);
|
||||
});
|
||||
|
||||
APP.desktopsharing.addListener(DSEvents.NEW_STREAM_CREATED,
|
||||
(track, callback) => {
|
||||
const localCallback = (newTrack) => {
|
||||
if(!newTrack || !localVideo || !newTrack.isLocal() ||
|
||||
newTrack !== localVideo)
|
||||
return;
|
||||
if(localVideo.isMuted() &&
|
||||
localVideo.videoType !== track.videoType) {
|
||||
localVideo.mute();
|
||||
}
|
||||
callback();
|
||||
if(room)
|
||||
room.off(ConferenceEvents.TRACK_ADDED, localCallback);
|
||||
};
|
||||
if(room) {
|
||||
room.on(ConferenceEvents.TRACK_ADDED, localCallback);
|
||||
}
|
||||
if(localVideo)
|
||||
localVideo.stop();
|
||||
localVideo = track;
|
||||
addTrack(track);
|
||||
if(!room)
|
||||
localCallback();
|
||||
APP.UI.addLocalStream(track);
|
||||
}
|
||||
APP.UI.addListener(
|
||||
UIEvents.TOGGLE_SCREENSHARING, this.toggleScreenSharing.bind(this)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -782,10 +782,9 @@ UI.setAudioLevel = function (id, lvl) {
|
|||
|
||||
/**
|
||||
* Update state of desktop sharing buttons.
|
||||
* @param {boolean} isSharingScreen if user is currently sharing his screen
|
||||
*/
|
||||
UI.updateDesktopSharingButtons = function (isSharingScreen) {
|
||||
Toolbar.changeDesktopSharingButtonState(isSharingScreen);
|
||||
UI.updateDesktopSharingButtons = function () {
|
||||
Toolbar.updateDesktopSharingButtonState();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -131,7 +131,7 @@ const buttonHandlers = {
|
|||
emitter.emit(UIEvents.ETHERPAD_CLICKED);
|
||||
},
|
||||
"toolbar_button_desktopsharing": function () {
|
||||
if (APP.desktopsharing.isUsingScreenStream) {
|
||||
if (APP.conference.isSharingScreen) {
|
||||
AnalyticsAdapter.sendEvent('toolbar.screen.disabled');
|
||||
} else {
|
||||
AnalyticsAdapter.sendEvent('toolbar.screen.enabled');
|
||||
|
@ -371,13 +371,12 @@ const Toolbar = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Sets the state of the button. The button has blue glow if desktop
|
||||
* Update the state of the button. The button has blue glow if desktop
|
||||
* streaming is active.
|
||||
* @param active the state of the desktop streaming.
|
||||
*/
|
||||
changeDesktopSharingButtonState (active) {
|
||||
updateDesktopSharingButtonState () {
|
||||
let button = $("#toolbar_button_desktopsharing");
|
||||
if (active) {
|
||||
if (APP.conference.isSharingScreen) {
|
||||
button.addClass("glow");
|
||||
} else {
|
||||
button.removeClass("glow");
|
||||
|
|
|
@ -7,7 +7,7 @@ let toolbarTimeoutObject;
|
|||
let toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
|
||||
|
||||
function showDesktopSharingButton() {
|
||||
if (APP.desktopsharing.isDesktopSharingEnabled() &&
|
||||
if (APP.conference.isDesktopSharingEnabled &&
|
||||
UIUtil.isButtonEnabled('desktop')) {
|
||||
$('#toolbar_button_desktopsharing').css({display: "inline-block"});
|
||||
} else {
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
/* global APP, JitsiMeetJS, config */
|
||||
var EventEmitter = require("events");
|
||||
import DSEvents from '../../service/desktopsharing/DesktopSharingEventTypes';
|
||||
|
||||
const TrackEvents = JitsiMeetJS.events.track;
|
||||
|
||||
/**
|
||||
* Indicates that desktop stream is currently in use (for toggle purpose).
|
||||
* @type {boolean}
|
||||
*/
|
||||
var isUsingScreenStream = false;
|
||||
|
||||
/**
|
||||
* Indicates that switch stream operation is in progress and prevent from
|
||||
* triggering new events.
|
||||
* @type {boolean}
|
||||
*/
|
||||
var switchInProgress = false;
|
||||
|
||||
/**
|
||||
* true if desktop sharing is enabled and false otherwise.
|
||||
*/
|
||||
var isEnabled = false;
|
||||
|
||||
var eventEmitter = new EventEmitter();
|
||||
|
||||
function streamSwitchDone() {
|
||||
switchInProgress = false;
|
||||
eventEmitter.emit(DSEvents.SWITCHING_DONE, isUsingScreenStream);
|
||||
}
|
||||
|
||||
function newStreamCreated(track) {
|
||||
eventEmitter.emit(DSEvents.NEW_STREAM_CREATED, track, streamSwitchDone);
|
||||
}
|
||||
|
||||
function getVideoStreamFailed(error) {
|
||||
console.error("Failed to obtain the stream to switch to", error);
|
||||
switchInProgress = false;
|
||||
isUsingScreenStream = false;
|
||||
newStreamCreated(null);
|
||||
}
|
||||
|
||||
function getDesktopStreamFailed(error) {
|
||||
console.error("Failed to obtain the stream to switch to", error);
|
||||
switchInProgress = false;
|
||||
}
|
||||
|
||||
function onEndedHandler() {
|
||||
if (!switchInProgress && isUsingScreenStream) {
|
||||
APP.desktopsharing.toggleScreenSharing();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isUsingScreenStream: function () {
|
||||
return isUsingScreenStream;
|
||||
},
|
||||
/**
|
||||
* Initializes the desktop sharing module.
|
||||
* @param {boolean} <tt>true</tt> if desktop sharing feature is available
|
||||
* and enabled.
|
||||
*/
|
||||
init: function (enabled) {
|
||||
isEnabled = enabled;
|
||||
},
|
||||
/**
|
||||
* @returns {boolean} <tt>true</tt> if desktop sharing feature is available
|
||||
* and enabled.
|
||||
*/
|
||||
isDesktopSharingEnabled: function () {
|
||||
return isEnabled;
|
||||
},
|
||||
addListener: function (type, listener) {
|
||||
eventEmitter.on(type, listener);
|
||||
},
|
||||
|
||||
removeListener: function (type, listener) {
|
||||
eventEmitter.removeListener(type, listener);
|
||||
},
|
||||
|
||||
/*
|
||||
* Toggles screen sharing.
|
||||
*/
|
||||
toggleScreenSharing: function () {
|
||||
if (switchInProgress) {
|
||||
console.warn("Switch in progress.");
|
||||
return;
|
||||
} else if (!this.isDesktopSharingEnabled()) {
|
||||
console.warn("Cannot toggle screen sharing: not supported.");
|
||||
return;
|
||||
}
|
||||
switchInProgress = true;
|
||||
let type;
|
||||
if (!isUsingScreenStream) {
|
||||
// Switch to desktop stream
|
||||
type = "desktop";
|
||||
} else {
|
||||
type = "video";
|
||||
}
|
||||
var fail = (error) => {
|
||||
if (type === 'desktop') {
|
||||
getDesktopStreamFailed(error);
|
||||
} else {
|
||||
getVideoStreamFailed(error);
|
||||
}
|
||||
};
|
||||
APP.conference.createLocalTracks(type).then((tracks) => {
|
||||
// FIXME does it mean that 'not track.length' == GUM failed ?
|
||||
// And will this ever happen if promise is supposed to fail in GUM
|
||||
// failed case ?
|
||||
if (!tracks.length) {
|
||||
fail();
|
||||
return;
|
||||
}
|
||||
let stream = tracks[0];
|
||||
|
||||
// We now use screen stream
|
||||
isUsingScreenStream = type === "desktop";
|
||||
if (isUsingScreenStream) {
|
||||
stream.on(TrackEvents.TRACK_STOPPED, onEndedHandler);
|
||||
}
|
||||
newStreamCreated(stream);
|
||||
}).catch((error) => {
|
||||
if(error === JitsiMeetJS.errors.track.FIREFOX_EXTENSION_NEEDED)
|
||||
{
|
||||
eventEmitter.emit(
|
||||
DSEvents.FIREFOX_EXTENSION_NEEDED,
|
||||
config.desktopSharingFirefoxExtensionURL);
|
||||
return;
|
||||
}
|
||||
fail(error);
|
||||
});
|
||||
}
|
||||
};
|
|
@ -13,8 +13,8 @@ function initShortcutHandlers() {
|
|||
68: {
|
||||
character: "D",
|
||||
id: "toggleDesktopSharingPopover",
|
||||
function: function() {
|
||||
APP.desktopsharing.toggleScreenSharing();
|
||||
function: function () {
|
||||
APP.conference.toggleScreenSharing();
|
||||
}
|
||||
},
|
||||
70: {
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
export default {
|
||||
SWITCHING_DONE: "ds.switching_done",
|
||||
|
||||
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"
|
||||
};
|
Loading…
Reference in New Issue