do not use RTC/xmpp in UI module

This commit is contained in:
isymchych 2015-12-14 14:26:50 +02:00
parent cb522eadd8
commit 6ded050b51
13 changed files with 1467 additions and 1120 deletions

78
app.js
View File

@ -13,6 +13,7 @@ import "jQuery-Impromptu";
import "autosize"; import "autosize";
window.toastr = require("toastr"); window.toastr = require("toastr");
import URLProcessor from "./modules/config/URLProcessor";
import RoomnameGenerator from './modules/util/RoomnameGenerator'; import RoomnameGenerator from './modules/util/RoomnameGenerator';
import CQEvents from './service/connectionquality/CQEvents'; import CQEvents from './service/connectionquality/CQEvents';
import UIEvents from './service/UI/UIEvents'; import UIEvents from './service/UI/UIEvents';
@ -101,23 +102,23 @@ const APP = {
}; };
var ConnectionEvents = JitsiMeetJS.events.connection; const ConnectionEvents = JitsiMeetJS.events.connection;
var ConnectionErrors = JitsiMeetJS.errors.connection; const ConnectionErrors = JitsiMeetJS.errors.connection;
function connect() { function connect() {
var connection = new JitsiMeetJS.JitsiConnection(null, null, { let connection = new JitsiMeetJS.JitsiConnection(null, null, {
hosts: config.hosts, hosts: config.hosts,
bosh: config.bosh, bosh: config.bosh,
clientNode: config.clientNode clientNode: config.clientNode
}); });
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var handlers = {}; let handlers = {};
var unsubscribe = function () { function unsubscribe () {
Object.keys(handlers).forEach(function (event) { Object.keys(handlers).forEach(function (event) {
connection.removeEventListener(event, handlers[event]); connection.removeEventListener(event, handlers[event]);
}); });
}; }
handlers[ConnectionEvents.CONNECTION_ESTABLISHED] = function () { handlers[ConnectionEvents.CONNECTION_ESTABLISHED] = function () {
console.log('CONNECTED'); console.log('CONNECTED');
@ -125,14 +126,14 @@ function connect() {
resolve(connection); resolve(connection);
}; };
var listenForFailure = function (event) { function listenForFailure (event) {
handlers[event] = function (...args) { handlers[event] = function (...args) {
console.error(`CONNECTION FAILED: ${event}`, ...args); console.error(`CONNECTION FAILED: ${event}`, ...args);
unsubscribe(); unsubscribe();
reject([event, ...args]); reject([event, ...args]);
}; };
}; }
listenForFailure(ConnectionEvents.CONNECTION_FAILED); listenForFailure(ConnectionEvents.CONNECTION_FAILED);
listenForFailure(ConnectionErrors.PASSWORD_REQUIRED); listenForFailure(ConnectionErrors.PASSWORD_REQUIRED);
@ -172,6 +173,13 @@ function initConference(localTracks, connection) {
} }
}); });
APP.conference.listMembers = function () {
return room.getParticipants();
};
APP.conference.listMembersIds = function () {
return room.getParticipants().map(p => p.getId());
};
function getDisplayName(id) { function getDisplayName(id) {
if (APP.conference.isLocalId(id)) { if (APP.conference.isLocalId(id)) {
return APP.settings.getDisplayName(); return APP.settings.getDisplayName();
@ -187,17 +195,22 @@ function initConference(localTracks, connection) {
room.on(ConferenceEvents.CONFERENCE_JOINED, function () { room.on(ConferenceEvents.CONFERENCE_JOINED, function () {
localTracks.forEach(function (track) { localTracks.forEach(function (track) {
room.addTrack(track); room.addTrack(track);
//APP.UI.addLocalStream(track); APP.UI.addLocalStream(track);
}); });
}); });
room.on(ConferenceEvents.USER_JOINED, function (id) { room.on(ConferenceEvents.USER_JOINED, function (id, user) {
if (APP.conference.isLocalId(id)) {
return;
}
console.error('USER %s connnected', id);
// FIXME email??? // FIXME email???
//APP.UI.addUser(id); APP.UI.addUser(id, user.getDisplayName());
}); });
room.on(ConferenceEvents.USER_LEFT, function (id) { room.on(ConferenceEvents.USER_LEFT, function (id, user) {
APP.UI.removeUser(id); console.error('USER LEFT', id);
APP.UI.removeUser(id, user.getDisplayName());
}); });
@ -230,6 +243,26 @@ function initConference(localTracks, connection) {
}); });
room.on(ConferenceEvents.TRACK_ADDED, function (track) {
if (!track.getParticipantId) { // skip local tracks
return;
}
console.error(
'REMOTE %s TRACK', track.getType(), track.getParticipantId()
);
APP.UI.addRemoteStream(track);
});
room.on(ConferenceEvents.TRACK_REMOVED, function (track) {
if (!track.getParticipantId) { // skip local tracks
return;
}
console.error(
'REMOTE %s TRACK REMOVED', track.getType(), track.getParticipantId()
);
// FIXME handle
});
room.on(ConferenceEvents.TRACK_MUTE_CHANGED, function (track) { room.on(ConferenceEvents.TRACK_MUTE_CHANGED, function (track) {
// FIXME handle mute // FIXME handle mute
}); });
@ -421,10 +454,23 @@ function initConference(localTracks, connection) {
// on SUBJECT_CHANGED UI.setSubject(topic); // on SUBJECT_CHANGED UI.setSubject(topic);
}); });
APP.UI.addListener(UIEvents.USER_KICKED, function (id) {
// FIXME handle
// APP.xmpp.eject(self.id);
});
APP.UI.addListener(UIEvents.SELECTED_ENDPOINT, function (id) {
room.selectParticipant(id);
});
room.on(ConferenceEvents.DTMF_SUPPORT_CHANGED, function (isDTMFSupported) { room.on(ConferenceEvents.DTMF_SUPPORT_CHANGED, function (isDTMFSupported) {
APP.UI.updateDTMFSupport(isDTMFSupported); APP.UI.updateDTMFSupport(isDTMFSupported);
}); });
$(window).bind('beforeunload', function () {
room.leave();
});
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
room.on(ConferenceEvents.CONFERENCE_JOINED, resolve); room.on(ConferenceEvents.CONFERENCE_JOINED, resolve);
@ -456,6 +502,7 @@ function createLocalTracks () {
} }
function init() { function init() {
APP.UI.start();
JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.TRACE); JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.TRACE);
JitsiMeetJS.init().then(function () { JitsiMeetJS.init().then(function () {
return Promise.all([createLocalTracks(), connect()]); return Promise.all([createLocalTracks(), connect()]);
@ -463,8 +510,6 @@ function init() {
console.log('initialized with %s local tracks', tracks.length); console.log('initialized with %s local tracks', tracks.length);
return initConference(tracks, connection); return initConference(tracks, connection);
}).then(function () { }).then(function () {
APP.UI.start();
APP.UI.initConference(); APP.UI.initConference();
APP.UI.addListener(UIEvents.LANG_CHANGED, function (language) { APP.UI.addListener(UIEvents.LANG_CHANGED, function (language) {
@ -518,7 +563,6 @@ function obtainConfigAndInit() {
$(document).ready(function () { $(document).ready(function () {
console.log("(TIME) document ready:\t", window.performance.now()); console.log("(TIME) document ready:\t", window.performance.now());
var URLProcessor = require("./modules/config/URLProcessor");
URLProcessor.setConfigParametersFromUrl(); URLProcessor.setConfigParametersFromUrl();
APP.init(); APP.init();
@ -537,4 +581,4 @@ $(window).bind('beforeunload', function () {
} }
}); });
export default APP; module.exports = APP;

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,33 @@
/* global Strophe, APP, $, config, interfaceConfig, toastr */ /* global APP, $, config, interfaceConfig, toastr */
/* jshint -W101 */ /* jshint -W101 */
var UI = {}; var UI = {};
var VideoLayout = require("./videolayout/VideoLayout"); import AudioLevels from './audio_levels/AudioLevels';
var AudioLevels = require("./audio_levels/AudioLevels"); import Chat from "./side_pannels/chat/Chat";
import Toolbar from "./toolbars/Toolbar";
import ToolbarToggler from "./toolbars/ToolbarToggler";
import BottomToolbar from "./toolbars/BottomToolbar";
import ContactList from "./side_pannels/contactlist/ContactList";
import Avatar from "./avatar/Avatar";
import PanelToggler from "./side_pannels/SidePanelToggler";
import UIUtil from "./util/UIUtil";
import UIEvents from "../../service/UI/UIEvents";
import VideoLayout from "./videolayout/VideoLayout";
var Prezi = require("./prezi/Prezi"); var Prezi = require("./prezi/Prezi");
var Etherpad = require("./etherpad/Etherpad"); var Etherpad = require("./etherpad/Etherpad");
var Chat = require("./side_pannels/chat/Chat");
var Toolbar = require("./toolbars/Toolbar");
var ToolbarToggler = require("./toolbars/ToolbarToggler");
var BottomToolbar = require("./toolbars/BottomToolbar");
var ContactList = require("./side_pannels/contactlist/ContactList");
var Avatar = require("./avatar/Avatar");
var EventEmitter = require("events"); var EventEmitter = require("events");
var SettingsMenu = require("./side_pannels/settings/SettingsMenu"); var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
var Settings = require("./../settings/Settings"); var Settings = require("./../settings/Settings");
var PanelToggler = require("./side_pannels/SidePanelToggler");
UI.messageHandler = require("./util/MessageHandler"); UI.messageHandler = require("./util/MessageHandler");
var messageHandler = UI.messageHandler; var messageHandler = UI.messageHandler;
var Authentication = require("./authentication/Authentication"); var Authentication = require("./authentication/Authentication");
var UIUtil = require("./util/UIUtil");
var JitsiPopover = require("./util/JitsiPopover"); var JitsiPopover = require("./util/JitsiPopover");
var CQEvents = require("../../service/connectionquality/CQEvents"); var CQEvents = require("../../service/connectionquality/CQEvents");
var DesktopSharingEventTypes var DesktopSharingEventTypes
= require("../../service/desktopsharing/DesktopSharingEventTypes"); = require("../../service/desktopsharing/DesktopSharingEventTypes");
var StatisticsEvents = require("../../service/statistics/Events"); var StatisticsEvents = require("../../service/statistics/Events");
var UIEvents = require("../../service/UI/UIEvents");
var Feedback = require("./Feedback"); var Feedback = require("./Feedback");
var eventEmitter = new EventEmitter(); var eventEmitter = new EventEmitter();
@ -352,7 +354,7 @@ function initEtherpad(name) {
Etherpad.init(name); Etherpad.init(name);
} }
UI.addUser = function (jid, id, displayName) { UI.addUser = function (id, displayName) {
messageHandler.notify( messageHandler.notify(
displayName,'notify.somebody', 'connected', 'notify.connected' displayName,'notify.somebody', 'connected', 'notify.connected'
); );
@ -362,16 +364,14 @@ UI.addUser = function (jid, id, displayName) {
UIUtil.playSoundNotification('userJoined'); UIUtil.playSoundNotification('userJoined');
// Configure avatar // Configure avatar
UI.setUserAvatar(jid, id); UI.setUserAvatar(id, displayName);
// Add Peer's container // Add Peer's container
VideoLayout.ensurePeerContainerExists(jid); VideoLayout.ensurePeerContainerExists(id);
}; };
UI.removeUser = function (jid) { UI.removeUser = function (id, displayName) {
console.log('left.muc', jid); console.log('left.muc', id);
var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
'>.displayname').html();
messageHandler.notify(displayName,'notify.somebody', messageHandler.notify(displayName,'notify.somebody',
'disconnected', 'disconnected',
'notify.disconnected'); 'notify.disconnected');
@ -380,9 +380,9 @@ UI.removeUser = function (jid) {
UIUtil.playSoundNotification('userLeft'); UIUtil.playSoundNotification('userLeft');
} }
ContactList.removeContact(jid); ContactList.removeContact(id);
VideoLayout.participantLeft(jid); VideoLayout.participantLeft(id);
}; };
function onMucPresenceStatus(jid, info) { function onMucPresenceStatus(jid, info) {
@ -601,7 +601,7 @@ UI.handleLastNEndpoints = function (ids) {
UI.setAudioLevel = function (id, lvl) { UI.setAudioLevel = function (id, lvl) {
AudioLevels.updateAudioLevel( AudioLevels.updateAudioLevel(
id, lvl, VideoLayout.getLargeVideoResource() id, lvl, VideoLayout.getLargeVideoId()
); );
}; };

View File

@ -248,8 +248,7 @@ const AudioLevels = {
// Fill the shape. // Fill the shape.
ASDrawContext.fill(); ASDrawContext.fill();
}, }
}; };
export default AudioLevels; export default AudioLevels;

View File

@ -1,5 +1,8 @@
var UIUtil = require("../util/UIUtil"); /* global $, APP */
var VideoLayout = require("../videolayout/VideoLayout"); /* jshint -W101 */
import UIUtil from "../util/UIUtil";
import VideoLayout from "../videolayout/VideoLayout";
var messageHandler = require("../util/MessageHandler"); var messageHandler = require("../util/MessageHandler");
var PreziPlayer = require("./PreziPlayer"); var PreziPlayer = require("./PreziPlayer");

View File

@ -1,13 +1,15 @@
/* global $, config, interfaceConfig */ /* global $, config, interfaceConfig */
import PanelToggler from "../side_pannels/SidePanelToggler";
/** /**
* Created by hristo on 12/22/14. * Created by hristo on 12/22/14.
*/ */
var UIUtil = module.exports = { var UIUtil = {
/** /**
* Returns the available video width. * Returns the available video width.
*/ */
getAvailableVideoWidth: function (isVisible) { getAvailableVideoWidth: function (isVisible) {
var PanelToggler = require("../side_pannels/SidePanelToggler");
if(typeof isVisible === "undefined" || isVisible === null) if(typeof isVisible === "undefined" || isVisible === null)
isVisible = PanelToggler.isVisible(); isVisible = PanelToggler.isVisible();
var rightPanelWidth var rightPanelWidth
@ -114,3 +116,5 @@ var UIUtil = module.exports = {
$(selector).hide(); $(selector).hide();
} }
}; };
export default UIUtil;

View File

@ -1,13 +1,13 @@
/* global APP, $ */ /* global APP, $ */
/* jshint -W101 */ /* jshint -W101 */
var JitsiPopover = require("../util/JitsiPopover"); import JitsiPopover from "../util/JitsiPopover";
/** /**
* Constructs new connection indicator. * Constructs new connection indicator.
* @param videoContainer the video container associated with the indicator. * @param videoContainer the video container associated with the indicator.
* @constructor * @constructor
*/ */
function ConnectionIndicator(videoContainer, jid) { function ConnectionIndicator(videoContainer, id) {
this.videoContainer = videoContainer; this.videoContainer = videoContainer;
this.bandwidth = null; this.bandwidth = null;
this.packetLoss = null; this.packetLoss = null;
@ -16,7 +16,7 @@ function ConnectionIndicator(videoContainer, jid) {
this.resolution = null; this.resolution = null;
this.transport = []; this.transport = [];
this.popover = null; this.popover = null;
this.jid = jid; this.id = id;
this.create(); this.create();
} }
@ -87,7 +87,7 @@ ConnectionIndicator.prototype.generateText = function () {
} }
var resolutionValue = null; var resolutionValue = null;
if(this.resolution && this.jid) { if(this.resolution && this.id) {
var keys = Object.keys(this.resolution); var keys = Object.keys(this.resolution);
for(var ssrc in this.resolution) { for(var ssrc in this.resolution) {
// skip resolutions for ssrc that don't have this info // skip resolutions for ssrc that don't have this info
@ -99,7 +99,7 @@ ConnectionIndicator.prototype.generateText = function () {
} }
} }
if(this.jid === null) { if(this.id === null) {
resolution = ""; resolution = "";
if(this.resolution === null || !Object.keys(this.resolution) || if(this.resolution === null || !Object.keys(this.resolution) ||
Object.keys(this.resolution).length === 0) { Object.keys(this.resolution).length === 0) {
@ -144,8 +144,8 @@ ConnectionIndicator.prototype.generateText = function () {
if(this.videoContainer.videoSpanId == "localVideoContainer") { if(this.videoContainer.videoSpanId == "localVideoContainer") {
result += "<div class=\"jitsipopover_showmore\" " + result += "<div class=\"jitsipopover_showmore\" " +
"onclick = \"APP.UI.connectionIndicatorShowMore('" + "onclick = \"APP.UI.connectionIndicatorShowMore('" +
// FIXME: we do not know local jid when this text is generated // FIXME: we do not know local id when this text is generated
//this.jid + "')\" data-i18n='connectionindicator." + //this.id + "')\" data-i18n='connectionindicator." +
"local')\" data-i18n='connectionindicator." + "local')\" data-i18n='connectionindicator." +
(this.showMoreValue ? "less" : "more") + "'>" + (this.showMoreValue ? "less" : "more") + "'>" +
translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) + translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
@ -385,4 +385,4 @@ ConnectionIndicator.prototype.hideIndicator = function () {
this.popover.forceHide(); this.popover.forceHide();
}; };
module.exports = ConnectionIndicator; export default ConnectionIndicator;

View File

@ -1,11 +1,11 @@
/* global $, APP, Strophe, interfaceConfig */ /* global $, APP, interfaceConfig */
/* jshint -W101 */ /* jshint -W101 */
var Avatar = require("../avatar/Avatar"); import Avatar from "../avatar/Avatar";
import ToolbarToggler from "../toolbars/ToolbarToggler";
import UIUtil from "../util/UIUtil";
import UIEvents from "../../../service/UI/UIEvents";
var RTCBrowserType = require("../../RTC/RTCBrowserType"); var RTCBrowserType = require("../../RTC/RTCBrowserType");
var UIUtil = require("../util/UIUtil");
var UIEvents = require("../../../service/UI/UIEvents");
var xmpp = require("../../xmpp/xmpp");
var ToolbarToggler = require("../toolbars/ToolbarToggler");
// FIXME: With Temasys we have to re-select everytime // FIXME: With Temasys we have to re-select everytime
//var video = $('#largeVideo'); //var video = $('#largeVideo');
@ -37,22 +37,22 @@ var state = "video";
* @param state the state. * @param state the state.
* @returns {JQuery|*|jQuery|HTMLElement} the container. * @returns {JQuery|*|jQuery|HTMLElement} the container.
*/ */
function getContainerByState(state) function getContainerByState(state) {
{
var selector = null; var selector = null;
switch (state) switch (state) {
{ case "video":
case "video": selector = "#largeVideoWrapper";
selector = "#largeVideoWrapper"; break;
break; case "etherpad":
case "etherpad": selector = "#etherpad>iframe";
selector = "#etherpad>iframe"; break;
break; case "prezi":
case "prezi": selector = "#presentation>iframe";
selector = "#presentation>iframe"; break;
break; default:
return null;
} }
return (selector !== null)? $(selector) : null; return $(selector);
} }
/** /**
@ -72,24 +72,25 @@ function positionVideo(video,
animate) { animate) {
if (animate) { if (animate) {
video.animate({ video.animate({
width: width, width: width,
height: height, height: height,
top: verticalIndent, top: verticalIndent,
bottom: verticalIndent, bottom: verticalIndent,
left: horizontalIndent, left: horizontalIndent,
right: horizontalIndent right: horizontalIndent
}, }, {
{ queue: false,
queue: false, duration: 500
duration: 500 });
});
} else { } else {
video.width(width); video.width(width);
video.height(height); video.height(height);
video.css({ top: verticalIndent + 'px', video.css({
bottom: verticalIndent + 'px', top: verticalIndent,
left: horizontalIndent + 'px', bottom: verticalIndent,
right: horizontalIndent + 'px'}); left: horizontalIndent,
right: horizontalIndent
});
} }
} }
@ -237,16 +238,13 @@ function getCameraVideoSize(videoWidth,
/** /**
* Updates the src of the active speaker avatar * Updates the src of the active speaker avatar
* @param jid of the current active speaker
*/ */
function updateActiveSpeakerAvatarSrc() { function updateActiveSpeakerAvatarSrc() {
var avatar = $("#activeSpeakerAvatar")[0]; let avatar = $("#activeSpeakerAvatar");
var jid = currentSmallVideo.peerJid; let id = currentSmallVideo.id;
var url = Avatar.getActiveSpeakerUrl(jid); let url = Avatar.getActiveSpeakerUrl(id);
if (avatar.src === url) if (id && avatar.attr('src') !== url) {
return; avatar.attr('src', url);
if (jid) {
avatar.src = url;
currentSmallVideo.showAvatar(); currentSmallVideo.showAvatar();
} }
} }
@ -263,13 +261,15 @@ function changeVideo(isVisible) {
} }
updateActiveSpeakerAvatarSrc(); updateActiveSpeakerAvatarSrc();
var largeVideoElement = $('#largeVideo')[0]; let largeVideoElement = $('#largeVideo');
APP.RTC.setVideoSrc(largeVideoElement, currentSmallVideo.getSrc()); currentSmallVideo.stream.attach(largeVideoElement);
var flipX = currentSmallVideo.flipX; let flipX = currentSmallVideo.flipX;
largeVideoElement.style.transform = flipX ? "scaleX(-1)" : "none"; largeVideoElement.css({
transform: flipX ? "scaleX(-1)" : "none"
});
LargeVideo.updateVideoSizeAndPosition(currentSmallVideo.getVideoType()); LargeVideo.updateVideoSizeAndPosition(currentSmallVideo.getVideoType());
@ -369,40 +369,35 @@ var LargeVideo = {
/** /**
* Returns <tt>true</tt> if the user is currently displayed on large video. * Returns <tt>true</tt> if the user is currently displayed on large video.
*/ */
isCurrentlyOnLarge: function (resourceJid) { isCurrentlyOnLarge: function (id) {
return currentSmallVideo && resourceJid && return id && id === this.getId();
currentSmallVideo.getResourceJid() === resourceJid;
}, },
/** /**
* Updates the large video with the given new video source. * Updates the large video with the given new video source.
*/ */
updateLargeVideo: function (resourceJid, forceUpdate) { updateLargeVideo: function (id, forceUpdate) {
if(!isEnabled) if(!isEnabled) {
return; return;
var newSmallVideo = this.VideoLayout.getSmallVideo(resourceJid); }
console.info('hover in ' + resourceJid + ', video: ', newSmallVideo); let newSmallVideo = this.VideoLayout.getSmallVideo(id);
console.info(`hover in ${id} , video: `, newSmallVideo);
if (!newSmallVideo) { if (!newSmallVideo) {
console.error("Small video not found for: " + resourceJid); console.error("Small video not found for: " + id);
return; return;
} }
if (!LargeVideo.isCurrentlyOnLarge(resourceJid) || forceUpdate) { if (!LargeVideo.isCurrentlyOnLarge(id) || forceUpdate) {
$('#activeSpeaker').css('visibility', 'hidden'); $('#activeSpeaker').css('visibility', 'hidden');
var oldSmallVideo = null; let oldId = this.getId();
if (currentSmallVideo) {
oldSmallVideo = currentSmallVideo;
}
currentSmallVideo = newSmallVideo; currentSmallVideo = newSmallVideo;
var oldJid = null; if (oldId !== id) {
if (oldSmallVideo) // we want the notification to trigger even if id is undefined,
oldJid = oldSmallVideo.peerJid;
if (oldJid !== resourceJid) {
// we want the notification to trigger even if userJid is undefined,
// or null. // or null.
this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, resourceJid); this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, id);
} }
// We are doing fadeOut/fadeIn animations on parent div which wraps // We are doing fadeOut/fadeIn animations on parent div which wraps
// largeVideo, because when Temasys plugin is in use it replaces // largeVideo, because when Temasys plugin is in use it replaces
@ -443,11 +438,10 @@ var LargeVideo = {
currentSmallVideo.enableDominantSpeaker(false); currentSmallVideo.enableDominantSpeaker(false);
} }
}, },
onVideoTypeChanged: function (resourceJid, newVideoType) { onVideoTypeChanged: function (id, newVideoType) {
if (!isEnabled) if (!isEnabled)
return; return;
if (LargeVideo.isCurrentlyOnLarge(resourceJid)) if (LargeVideo.isCurrentlyOnLarge(id)) {
{
LargeVideo.updateVideoSizeAndPosition(newVideoType); LargeVideo.updateVideoSizeAndPosition(newVideoType);
this.position(null, null, null, null, true); this.position(null, null, null, null, true);
@ -562,22 +556,23 @@ var LargeVideo = {
getVideoPosition = isDesktop ? getDesktopVideoPosition : getVideoPosition = isDesktop ? getDesktopVideoPosition :
getCameraVideoPosition; getCameraVideoPosition;
}, },
getResourceJid: function () { getId: function () {
return currentSmallVideo ? currentSmallVideo.getResourceJid() : null; return currentSmallVideo ? currentSmallVideo.id : null;
}, },
updateAvatar: function (resourceJid) { updateAvatar: function (id) {
if(!isEnabled) if (!isEnabled) {
return; return;
if (resourceJid === this.getResourceJid()) { }
if (id === this.getId()) {
updateActiveSpeakerAvatarSrc(); updateActiveSpeakerAvatarSrc();
} }
}, },
showAvatar: function (resourceJid, show) { showAvatar: function (id, show) {
if (!isEnabled) if (!isEnabled) {
return; return;
if (this.getResourceJid() === resourceJid && state === "video") { }
$("#largeVideoWrapper") if (this.getId() === id && state === "video") {
.css("visibility", show ? "hidden" : "visible"); $("#largeVideoWrapper").css("visibility", show ? "hidden" : "visible");
$('#activeSpeaker').css("visibility", show ? "visible" : "hidden"); $('#activeSpeaker').css("visibility", show ? "visible" : "hidden");
return true; return true;
} }
@ -721,4 +716,4 @@ var LargeVideo = {
} }
}; };
module.exports = LargeVideo; export default LargeVideo;

View File

@ -1,8 +1,9 @@
/* global $, interfaceConfig, APP */ /* global $, interfaceConfig, APP */
var SmallVideo = require("./SmallVideo"); import ConnectionIndicator from "./ConnectionIndicator";
var ConnectionIndicator = require("./ConnectionIndicator"); import UIUtil from "../util/UIUtil";
var UIUtil = require("../util/UIUtil"); import UIEvents from "../../../service/UI/UIEvents";
var UIEvents = require("../../../service/UI/UIEvents"); import SmallVideo from "./SmallVideo";
var LargeVideo = require("./LargeVideo"); var LargeVideo = require("./LargeVideo");
var RTCBrowserType = require("../../RTC/RTCBrowserType"); var RTCBrowserType = require("../../RTC/RTCBrowserType");
@ -13,7 +14,6 @@ function LocalVideo(VideoLayout, emitter) {
this.VideoLayout = VideoLayout; this.VideoLayout = VideoLayout;
this.flipX = true; this.flipX = true;
this.isLocal = true; this.isLocal = true;
this.peerJid = null;
this.emitter = emitter; this.emitter = emitter;
} }
@ -143,32 +143,25 @@ LocalVideo.prototype.createConnectionIndicator = function() {
this.connectionIndicator = new ConnectionIndicator(this, null); this.connectionIndicator = new ConnectionIndicator(this, null);
}; };
LocalVideo.prototype.changeVideo = function (stream, isMuted) { LocalVideo.prototype.changeVideo = function (stream) {
var self = this; this.stream = stream;
function localVideoClick(event) { let localVideoClick = (event) => {
// FIXME: with Temasys plugin event arg is not an event, but // FIXME: with Temasys plugin event arg is not an event, but
// the clicked object itself, so we have to skip this call // the clicked object itself, so we have to skip this call
if (event.stopPropagation) { if (event.stopPropagation) {
event.stopPropagation(); event.stopPropagation();
} }
self.VideoLayout.handleVideoThumbClicked( this.VideoLayout.handleVideoThumbClicked(true, this.id);
true, };
APP.xmpp.myResource());
}
var localVideoContainerSelector = $('#localVideoContainer'); let localVideoContainerSelector = $('#localVideoContainer');
localVideoContainerSelector.off('click'); localVideoContainerSelector.off('click');
localVideoContainerSelector.on('click', localVideoClick); localVideoContainerSelector.on('click', localVideoClick);
if(isMuted) {
APP.UI.setVideoMute(true);
return;
}
this.flipX = stream.videoType != "screen"; this.flipX = stream.videoType != "screen";
var localVideo = document.createElement('video'); let localVideo = document.createElement('video');
localVideo.id = 'localVideo_' + localVideo.id = 'localVideo_' + stream.getId();
APP.RTC.getStreamID(stream.getOriginalStream());
if (!RTCBrowserType.isIExplorer()) { if (!RTCBrowserType.isIExplorer()) {
localVideo.autoplay = true; localVideo.autoplay = true;
localVideo.volume = 0; // is it required if audio is separated ? localVideo.volume = 0; // is it required if audio is separated ?
@ -192,7 +185,10 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
} }
// Attach WebRTC stream // Attach WebRTC stream
APP.RTC.attachMediaStream(localVideoSelector, stream.getOriginalStream()); stream.attach(localVideoSelector);
// FIXME handle
return;
// Add stream ended handler // Add stream ended handler
APP.RTC.addMediaStreamInactiveHandler( APP.RTC.addMediaStreamInactiveHandler(
@ -201,20 +197,12 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
// because <video> element is replaced with <object> // because <video> element is replaced with <object>
localVideo = $('#' + localVideo.id)[0]; localVideo = $('#' + localVideo.id)[0];
localVideoContainer.removeChild(localVideo); localVideoContainer.removeChild(localVideo);
self.VideoLayout.updateRemovedVideo(APP.xmpp.myResource()); self.VideoLayout.updateRemovedVideo(self.id);
}); });
}; };
LocalVideo.prototype.joined = function (jid) { LocalVideo.prototype.joined = function (id) {
this.peerJid = jid; this.id = id;
}; };
LocalVideo.prototype.getResourceJid = function () { export default LocalVideo;
var myResource = APP.xmpp.myResource();
if (!myResource) {
console.error("Requested local resource before we're in the MUC");
}
return myResource;
};
module.exports = LocalVideo;

View File

@ -1,24 +1,25 @@
/* global $, APP, require, Strophe, interfaceConfig */ /* global $, APP, interfaceConfig */
var ConnectionIndicator = require("./ConnectionIndicator");
var SmallVideo = require("./SmallVideo");
var AudioLevels = require("../audio_levels/AudioLevels");
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
var RTCBrowserType = require("../../RTC/RTCBrowserType");
var UIUtils = require("../util/UIUtil");
var XMPPEvents = require("../../../service/xmpp/XMPPEvents");
function RemoteVideo(peerJid, VideoLayout) { import ConnectionIndicator from './ConnectionIndicator';
this.peerJid = peerJid;
this.resourceJid = Strophe.getResourceFromJid(peerJid); import SmallVideo from "./SmallVideo";
this.videoSpanId = 'participant_' + this.resourceJid; import AudioLevels from "../audio_levels/AudioLevels";
import UIUtils from "../util/UIUtil";
import UIEvents from '../../../service/UI/UIEvents';
var RTCBrowserType = require("../../RTC/RTCBrowserType");
function RemoteVideo(id, VideoLayout, emitter) {
this.id = id;
this.emitter = emitter;
this.videoSpanId = `participant_${id}`;
this.VideoLayout = VideoLayout; this.VideoLayout = VideoLayout;
this.addRemoteVideoContainer(); this.addRemoteVideoContainer();
this.connectionIndicator = new ConnectionIndicator( this.connectionIndicator = new ConnectionIndicator(this, id);
this, this.peerJid);
this.setDisplayName(); this.setDisplayName();
var nickfield = document.createElement('span'); var nickfield = document.createElement('span');
nickfield.className = "nick"; nickfield.className = "nick";
nickfield.appendChild(document.createTextNode(this.resourceJid)); nickfield.appendChild(document.createTextNode(id));
this.container.appendChild(nickfield); this.container.appendChild(nickfield);
this.bindHoverHandler(); this.bindHoverHandler();
this.flipX = false; this.flipX = false;
@ -30,18 +31,19 @@ RemoteVideo.prototype.constructor = RemoteVideo;
RemoteVideo.prototype.addRemoteVideoContainer = function() { RemoteVideo.prototype.addRemoteVideoContainer = function() {
this.container = RemoteVideo.createContainer(this.videoSpanId); this.container = RemoteVideo.createContainer(this.videoSpanId);
if (APP.xmpp.isModerator()) if (APP.conference.isModerator) {
this.addRemoteVideoMenu(); this.addRemoteVideoMenu();
AudioLevels.updateAudioLevelCanvas(this.peerJid, this.VideoLayout); }
AudioLevels.updateAudioLevelCanvas(this.id, this.VideoLayout);
return this.container; return this.container;
}; };
/** /**
* Adds the remote video menu element for the given <tt>jid</tt> in the * Adds the remote video menu element for the given <tt>id</tt> in the
* given <tt>parentElement</tt>. * given <tt>parentElement</tt>.
* *
* @param jid the jid indicating the video for which we're adding a menu. * @param id the id indicating the video for which we're adding a menu.
* @param parentElement the parent element where this menu will be added * @param parentElement the parent element where this menu will be added
*/ */
@ -60,7 +62,7 @@ if (!interfaceConfig.filmStripOnly) {
var popupmenuElement = document.createElement('ul'); var popupmenuElement = document.createElement('ul');
popupmenuElement.className = 'popupmenu'; popupmenuElement.className = 'popupmenu';
popupmenuElement.id = 'remote_popupmenu_' + this.getResourceJid(); popupmenuElement.id = `remote_popupmenu_${this.id}`;
spanElement.appendChild(popupmenuElement); spanElement.appendChild(popupmenuElement);
var muteMenuItem = document.createElement('li'); var muteMenuItem = document.createElement('li');
@ -88,7 +90,7 @@ if (!interfaceConfig.filmStripOnly) {
event.preventDefault(); event.preventDefault();
} }
var isMute = !!self.isMuted; var isMute = !!self.isMuted;
APP.xmpp.setMute(self.peerJid, !isMute); self.emitter.emit(UIEvents.AUDIO_MUTED, !isMute);
popupmenuElement.setAttribute('style', 'display:none;'); popupmenuElement.setAttribute('style', 'display:none;');
@ -117,7 +119,7 @@ if (!interfaceConfig.filmStripOnly) {
"data-i18n='videothumbnail.kick'>&nbsp;</div>"; "data-i18n='videothumbnail.kick'>&nbsp;</div>";
ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText; ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
ejectLinkItem.onclick = function(){ ejectLinkItem.onclick = function(){
APP.xmpp.eject(self.peerJid); self.emitter.emit(UIEvents.USER_KICKED, self.id);
popupmenuElement.setAttribute('style', 'display:none;'); popupmenuElement.setAttribute('style', 'display:none;');
}; };
@ -157,36 +159,36 @@ RemoteVideo.prototype.removeRemoteStreamElement =
select.remove(); select.remove();
console.info((isVideo ? "Video" : "Audio") + console.info((isVideo ? "Video" : "Audio") +
" removed " + this.getResourceJid(), select); " removed " + this.id, select);
if (isVideo) if (isVideo)
this.VideoLayout.updateRemovedVideo(this.getResourceJid()); this.VideoLayout.updateRemovedVideo(this.id);
}; };
/** /**
* Removes RemoteVideo from the page. * Removes RemoteVideo from the page.
*/ */
RemoteVideo.prototype.remove = function () { RemoteVideo.prototype.remove = function () {
console.log("Remove thumbnail", this.peerJid); console.log("Remove thumbnail", this.id);
this.removeConnectionIndicator(); this.removeConnectionIndicator();
// Make sure that the large video is updated if are removing its // Make sure that the large video is updated if are removing its
// corresponding small video. // corresponding small video.
this.VideoLayout.updateRemovedVideo(this.getResourceJid()); this.VideoLayout.updateRemovedVideo(this.id);
// Remove whole container // Remove whole container
if (this.container.parentNode) if (this.container.parentNode) {
this.container.parentNode.removeChild(this.container); this.container.parentNode.removeChild(this.container);
}
}; };
RemoteVideo.prototype.waitForPlayback = function (sel, stream) { RemoteVideo.prototype.waitForPlayback = function (sel, stream) {
var webRtcStream = stream.getOriginalStream(); var webRtcStream = stream.getOriginalStream();
var isVideo = stream.isVideoStream(); var isVideo = stream.isVideoTrack();
if (!isVideo || webRtcStream.id === 'mixedmslabel') { if (!isVideo || webRtcStream.id === 'mixedmslabel') {
return; return;
} }
var self = this; var self = this;
var resourceJid = this.getResourceJid();
// Register 'onplaying' listener to trigger 'videoactive' on VideoLayout // Register 'onplaying' listener to trigger 'videoactive' on VideoLayout
// when video playback starts // when video playback starts
@ -198,7 +200,7 @@ RemoteVideo.prototype.waitForPlayback = function (sel, stream) {
if (RTCBrowserType.isTemasysPluginUsed()) { if (RTCBrowserType.isTemasysPluginUsed()) {
sel = self.selectVideoElement(); sel = self.selectVideoElement();
} }
self.VideoLayout.videoactive(sel, resourceJid); self.VideoLayout.videoactive(sel, self.id);
sel[0].onplaying = null; sel[0].onplaying = null;
if (RTCBrowserType.isTemasysPluginUsed()) { if (RTCBrowserType.isTemasysPluginUsed()) {
// 'currentTime' is used to check if the video has started // 'currentTime' is used to check if the video has started
@ -210,39 +212,33 @@ RemoteVideo.prototype.waitForPlayback = function (sel, stream) {
}; };
RemoteVideo.prototype.addRemoteStreamElement = function (stream) { RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
if (!this.container) if (!this.container) {
return; return;
}
var self = this; this.stream = stream;
var webRtcStream = stream.getOriginalStream();
var isVideo = stream.isVideoStream(); let isVideo = stream.isVideoTrack();
var streamElement = SmallVideo.createStreamElement(stream); let streamElement = SmallVideo.createStreamElement(stream);
var newElementId = streamElement.id; let newElementId = streamElement.id;
// Put new stream element always in front // Put new stream element always in front
UIUtils.prependChild(this.container, streamElement); UIUtils.prependChild(this.container, streamElement);
var sel = $('#' + newElementId); let sel = $(`#${newElementId}`);
sel.hide(); sel.hide();
// If the container is currently visible we attach the stream. // If the container is currently visible we attach the stream.
if (!isVideo || (this.container.offsetParent !== null && isVideo)) { if (!isVideo || (this.container.offsetParent !== null && isVideo)) {
this.waitForPlayback(sel, stream); this.waitForPlayback(sel, stream);
APP.RTC.attachMediaStream(sel, webRtcStream); stream.attach(sel);
} }
APP.RTC.addMediaStreamInactiveHandler(
webRtcStream, function () {
console.log('stream ended', this);
self.removeRemoteStreamElement(webRtcStream, isVideo, newElementId);
});
// Add click handler. // Add click handler.
var onClickHandler = function (event) { let onClickHandler = (event) => {
self.VideoLayout.handleVideoThumbClicked(false, self.getResourceJid()); this.VideoLayout.handleVideoThumbClicked(false, this.id);
// On IE we need to populate this handler on video <object> // On IE we need to populate this handler on video <object>
// and it does not give event instance as an argument, // and it does not give event instance as an argument,
@ -255,13 +251,14 @@ RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
}; };
this.container.onclick = onClickHandler; this.container.onclick = onClickHandler;
// reselect // reselect
if (RTCBrowserType.isTemasysPluginUsed()) if (RTCBrowserType.isTemasysPluginUsed()) {
sel = $('#' + newElementId); sel = $(`#${newElementId}`);
sel[0].onclick = onClickHandler; }
sel.click(onClickHandler);
}, },
/** /**
* Show/hide peer container for the given resourceJid. * Show/hide peer container for the given id.
*/ */
RemoteVideo.prototype.showPeerContainer = function (state) { RemoteVideo.prototype.showPeerContainer = function (state) {
if (!this.container) if (!this.container)
@ -294,7 +291,7 @@ RemoteVideo.prototype.showPeerContainer = function (state) {
// We want to be able to pin a participant from the contact list, even // We want to be able to pin a participant from the contact list, even
// if he's not in the lastN set! // if he's not in the lastN set!
// ContactList.setClickable(resourceJid, !isHide); // ContactList.setClickable(id, !isHide);
}; };
@ -311,12 +308,11 @@ RemoteVideo.prototype.hideConnectionIndicator = function () {
/** /**
* Updates the remote video menu. * Updates the remote video menu.
* *
* @param jid the jid indicating the video for which we're adding a menu. * @param id the id indicating the video for which we're adding a menu.
* @param isMuted indicates the current mute state * @param isMuted indicates the current mute state
*/ */
RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted) { RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted) {
var muteMenuItem var muteMenuItem = $(`#remote_popupmenu_${this.id}>li>a.mutelink`);
= $('#remote_popupmenu_' + this.getResourceJid() + '>li>a.mutelink');
var mutedIndicator = "<i class='icon-mic-disabled'></i>"; var mutedIndicator = "<i class='icon-mic-disabled'></i>";
@ -423,13 +419,6 @@ RemoteVideo.prototype.removeRemoteVideoMenu = function() {
} }
}; };
RemoteVideo.prototype.getResourceJid = function () {
if (!this.resourceJid) {
console.error("Undefined resource jid");
}
return this.resourceJid;
};
RemoteVideo.createContainer = function (spanId) { RemoteVideo.createContainer = function (spanId) {
var container = document.createElement('span'); var container = document.createElement('span');
container.id = spanId; container.id = spanId;
@ -439,4 +428,4 @@ RemoteVideo.createContainer = function (spanId) {
}; };
module.exports = RemoteVideo; export default RemoteVideo;

View File

@ -1,14 +1,16 @@
/* global $, APP, require */ /* global $, APP, require */
/* jshint -W101 */ /* jshint -W101 */
var Avatar = require("../avatar/Avatar"); import Avatar from "../avatar/Avatar";
var UIUtil = require("../util/UIUtil"); import UIUtil from "../util/UIUtil";
var LargeVideo = require("./LargeVideo"); import LargeVideo from "./LargeVideo";
var RTCBrowserType = require("../../RTC/RTCBrowserType"); var RTCBrowserType = require("../../RTC/RTCBrowserType");
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes"); var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
function SmallVideo() { function SmallVideo() {
this.isMuted = false; this.isMuted = false;
this.hasAvatar = false; this.hasAvatar = false;
this.stream = null;
} }
function setVisibility(selector, show) { function setVisibility(selector, show) {
@ -106,9 +108,10 @@ SmallVideo.prototype.setPresenceStatus = function (statusMsg) {
* Creates an audio or video element for a particular MediaStream. * Creates an audio or video element for a particular MediaStream.
*/ */
SmallVideo.createStreamElement = function (stream) { SmallVideo.createStreamElement = function (stream) {
var isVideo = stream.isVideoStream(); let isVideo = stream.isVideoTrack();
var element = isVideo ? document.createElement('video') let element = isVideo
? document.createElement('video')
: document.createElement('audio'); : document.createElement('audio');
if (isVideo) { if (isVideo) {
element.setAttribute("muted", "true"); element.setAttribute("muted", "true");
@ -118,8 +121,7 @@ SmallVideo.createStreamElement = function (stream) {
element.autoplay = true; element.autoplay = true;
} }
element.id = (isVideo ? 'remoteVideo_' : 'remoteAudio_') + element.id = (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
APP.RTC.getStreamID(stream.getOriginalStream());
element.onplay = function () { element.onplay = function () {
console.log("(TIME) Render " + (isVideo ? 'video' : 'audio') + ":\t", console.log("(TIME) Render " + (isVideo ? 'video' : 'audio') + ":\t",
@ -145,7 +147,7 @@ SmallVideo.prototype.bindHoverHandler = function () {
// If the video has been "pinned" by the user we want to // If the video has been "pinned" by the user we want to
// keep the display name on place. // keep the display name on place.
if (!LargeVideo.isLargeVideoVisible() || if (!LargeVideo.isLargeVideoVisible() ||
!LargeVideo.isCurrentlyOnLarge(self.getResourceJid())) !LargeVideo.isCurrentlyOnLarge(self.id))
self.showDisplayName(false); self.showDisplayName(false);
} }
); );
@ -237,15 +239,14 @@ SmallVideo.prototype.showVideoIndicator = function(isMuted) {
}; };
SmallVideo.prototype.enableDominantSpeaker = function (isEnable) { SmallVideo.prototype.enableDominantSpeaker = function (isEnable) {
var resourceJid = this.getResourceJid(); var displayName = this.id;
var displayName = resourceJid;
var nameSpan = $('#' + this.videoSpanId + '>span.displayname'); var nameSpan = $('#' + this.videoSpanId + '>span.displayname');
if (nameSpan.length > 0) if (nameSpan.length > 0)
displayName = nameSpan.html(); displayName = nameSpan.html();
console.log("UI enable dominant speaker", console.log("UI enable dominant speaker",
displayName, displayName,
resourceJid, this.id,
isEnable); isEnable);
@ -316,6 +317,8 @@ SmallVideo.prototype.createModeratorIndicatorElement = function () {
}; };
SmallVideo.prototype.selectVideoElement = function () { SmallVideo.prototype.selectVideoElement = function () {
return $('#' + this.videoSpanId).find(videoElem);
// FIXME maybe move this to the library?
var videoElem = APP.RTC.getVideoElementName(); var videoElem = APP.RTC.getVideoElementName();
if (!RTCBrowserType.isTemasysPluginUsed()) { if (!RTCBrowserType.isTemasysPluginUsed()) {
return $('#' + this.videoSpanId).find(videoElem); return $('#' + this.videoSpanId).find(videoElem);
@ -367,32 +370,31 @@ SmallVideo.prototype.hasVideo = function () {
*/ */
SmallVideo.prototype.showAvatar = function (show) { SmallVideo.prototype.showAvatar = function (show) {
if (!this.hasAvatar) { if (!this.hasAvatar) {
if (this.peerJid) { if (this.id) {
// Init avatar // Init avatar
this.avatarChanged(Avatar.getThumbUrl(this.peerJid)); this.avatarChanged(Avatar.getThumbUrl(this.id));
} else { } else {
console.error("Unable to init avatar - no peerjid", this); console.error("Unable to init avatar - no id", this);
return; return;
} }
} }
var resourceJid = this.getResourceJid(); let video = this.selectVideoElement();
var video = this.selectVideoElement();
var avatar = $('#avatar_' + resourceJid); let avatar = $(`#avatar_${this.id}`);
if (show === undefined || show === null) { if (show === undefined || show === null) {
if (!this.isLocal && if (!this.isLocal &&
!this.VideoLayout.isInLastN(resourceJid)) { !this.VideoLayout.isInLastN(this.id)) {
show = true; show = true;
} else { } else {
// We want to show the avatar when the video is muted or not exists // We want to show the avatar when the video is muted or not exists
// that is when 'true' or 'null' is returned // that is when 'true' or 'null' is returned
show = APP.RTC.isVideoMuted(this.peerJid) !== false; show = !this.stream || this.stream.isMuted();
} }
} }
if (LargeVideo.showAvatar(resourceJid, show)) { if (LargeVideo.showAvatar(this.id, show)) {
setVisibility(avatar, false); setVisibility(avatar, false);
setVisibility(video, false); setVisibility(video, false);
} else { } else {
@ -405,8 +407,7 @@ SmallVideo.prototype.showAvatar = function (show) {
SmallVideo.prototype.avatarChanged = function (thumbUrl) { SmallVideo.prototype.avatarChanged = function (thumbUrl) {
var thumbnail = $('#' + this.videoSpanId); var thumbnail = $('#' + this.videoSpanId);
var resourceJid = this.getResourceJid(); var avatar = $('#avatar_' + this.id);
var avatar = $('#avatar_' + resourceJid);
this.hasAvatar = true; this.hasAvatar = true;
// set the avatar in the thumbnail // set the avatar in the thumbnail
@ -415,7 +416,7 @@ SmallVideo.prototype.avatarChanged = function (thumbUrl) {
} else { } else {
if (thumbnail && thumbnail.length > 0) { if (thumbnail && thumbnail.length > 0) {
avatar = document.createElement('img'); avatar = document.createElement('img');
avatar.id = 'avatar_' + resourceJid; avatar.id = 'avatar_' + this.id;
avatar.className = 'userAvatar'; avatar.className = 'userAvatar';
avatar.src = thumbUrl; avatar.src = thumbUrl;
thumbnail.append(avatar); thumbnail.append(avatar);
@ -423,4 +424,4 @@ SmallVideo.prototype.avatarChanged = function (thumbUrl) {
} }
}; };
module.exports = SmallVideo; export default SmallVideo;

View File

@ -1,19 +1,19 @@
/* global config, APP, $, Strophe, require, interfaceConfig */ /* global config, APP, $, interfaceConfig */
/* jshint -W101 */ /* jshint -W101 */
var AudioLevels = require("../audio_levels/AudioLevels");
var ContactList = require("../side_pannels/contactlist/ContactList"); import AudioLevels from "../audio_levels/AudioLevels";
import ContactList from "../side_pannels/contactlist/ContactList";
import UIEvents from "../../../service/UI/UIEvents";
import UIUtil from "../util/UIUtil";
import RemoteVideo from "./RemoteVideo";
import LargeVideo from "./LargeVideo";
import LocalVideo from "./LocalVideo";
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes"); var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
var UIEvents = require("../../../service/UI/UIEvents");
var UIUtil = require("../util/UIUtil");
var RTC = require("../../RTC/RTC");
var RTCBrowserType = require('../../RTC/RTCBrowserType'); var RTCBrowserType = require('../../RTC/RTCBrowserType');
var RemoteVideo = require("./RemoteVideo");
var LargeVideo = require("./LargeVideo");
var LocalVideo = require("./LocalVideo");
var remoteVideos = {}; var remoteVideos = {};
var remoteVideoTypes = {}; var remoteVideoTypes = {};
var localVideoThumbnail = null; var localVideoThumbnail = null;
@ -23,7 +23,7 @@ var lastNCount = config.channelLastN;
var localLastNCount = config.channelLastN; var localLastNCount = config.channelLastN;
var localLastNSet = []; var localLastNSet = [];
var lastNEndpointsCache = []; var lastNEndpointsCache = [];
var lastNPickupJid = null; var lastNPickupId = null;
var eventEmitter = null; var eventEmitter = null;
@ -33,8 +33,50 @@ var eventEmitter = null;
*/ */
var focusedVideoResourceJid = null; var focusedVideoResourceJid = null;
var VideoLayout = (function (my) { /**
my.init = function (emitter) { * On contact list item clicked.
*/
$(ContactList).bind('contactclicked', function(event, id) {
if (!id) {
return;
}
if (APP.conference.isLocalId(id)) {
$("#localVideoContainer").click();
return;
}
var remoteVideo = remoteVideos[id];
if (remoteVideo && remoteVideo.selectVideoElement().length) {
var videoThumb = remoteVideo.selectVideoElement()[0];
// It is not always the case that a videoThumb exists (if there is
// no actual video).
if (RTC.getVideoSrc(videoThumb)) {
// We have a video src, great! Let's update the large video
// now.
VideoLayout.handleVideoThumbClicked(false, id);
} else {
// If we don't have a video src for jid, there's absolutely
// no point in calling handleVideoThumbClicked; Quite
// simply, it won't work because it needs an src to attach
// to the large video.
//
// Instead, we trigger the pinned endpoint changed event to
// let the bridge adjust its lastN set for myjid and store
// the pinned user in the lastNPickupId variable to be
// picked up later by the lastN changed event handler.
lastNPickupId = id;
eventEmitter.emit(UIEvents.PINNED_ENDPOINT, id);
}
}
});
var VideoLayout = {
init (emitter) {
eventEmitter = emitter; eventEmitter = emitter;
localVideoThumbnail = new LocalVideo(VideoLayout, emitter); localVideoThumbnail = new LocalVideo(VideoLayout, emitter);
if (interfaceConfig.filmStripOnly) { if (interfaceConfig.filmStripOnly) {
@ -45,19 +87,21 @@ var VideoLayout = (function (my) {
VideoLayout.resizeLargeVideoContainer(); VideoLayout.resizeLargeVideoContainer();
}; },
my.isInLastN = function(resource) { isInLastN (resource) {
return lastNCount < 0 || // lastN is disabled return lastNCount < 0 || // lastN is disabled
// lastNEndpoints cache not built yet // lastNEndpoints cache not built yet
(lastNCount > 0 && !lastNEndpointsCache.length) || (lastNCount > 0 && !lastNEndpointsCache.length) ||
(lastNEndpointsCache && (lastNEndpointsCache &&
lastNEndpointsCache.indexOf(resource) !== -1); lastNEndpointsCache.indexOf(resource) !== -1);
}; },
my.changeLocalAudio = function(stream, isMuted) { changeLocalAudio (stream) {
APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream()); let localAudio = document.getElementById('localAudio');
var localAudio = document.getElementById('localAudio'); stream.attach($(localAudio));
return; // FIXME maybe move this into the library?
// Writing volume not allowed in IE // Writing volume not allowed in IE
if (!RTCBrowserType.isIExplorer()) { if (!RTCBrowserType.isIExplorer()) {
localAudio.autoplay = true; localAudio.autoplay = true;
@ -73,39 +117,41 @@ var VideoLayout = (function (my) {
// which will result in audio mute issues // which will result in audio mute issues
$('#localAudio').hide(); $('#localAudio').hide();
} }
}; },
my.changeLocalVideo = function(stream, isMuted) { changeLocalVideo (stream) {
// Set default display name. // Set default display name.
localVideoThumbnail.setDisplayName(); localVideoThumbnail.setDisplayName();
localVideoThumbnail.createConnectionIndicator(); localVideoThumbnail.createConnectionIndicator();
this.onVideoTypeChanged(APP.xmpp.myResource(), stream.videoType); let localId = APP.conference.localId;
this.onVideoTypeChanged(localId, stream.getType());
AudioLevels.updateAudioLevelCanvas(null, VideoLayout); AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
localVideoThumbnail.changeVideo(stream, isMuted); localVideoThumbnail.changeVideo(stream);
/* force update if we're currently being displayed */ /* force update if we're currently being displayed */
if (LargeVideo.isCurrentlyOnLarge(APP.xmpp.myResource())) { if (LargeVideo.isCurrentlyOnLarge(localId)) {
LargeVideo.updateLargeVideo(APP.xmpp.myResource(), true); LargeVideo.updateLargeVideo(localId, true);
} }
}; },
my.mucJoined = function () { mucJoined () {
var myResourceJid = APP.xmpp.myResource(); let id = APP.conference.localId;
localVideoThumbnail.joined(APP.xmpp.myJid()); localVideoThumbnail.joined(id);
if (!LargeVideo.getResourceJid()) if (!LargeVideo.id) {
LargeVideo.updateLargeVideo(myResourceJid, true); LargeVideo.updateLargeVideo(id, true);
}; }
},
/** /**
* Adds or removes icons for not available camera and microphone. * Adds or removes icons for not available camera and microphone.
* @param resourceJid the jid of user * @param resourceJid the jid of user
* @param devices available devices * @param devices available devices
*/ */
my.setDeviceAvailabilityIcons = function (resourceJid, devices) { setDeviceAvailabilityIcons (resourceJid, devices) {
if(!devices) if(!devices)
return; return;
@ -115,31 +161,31 @@ var VideoLayout = (function (my) {
if(remoteVideos[resourceJid]) if(remoteVideos[resourceJid])
remoteVideos[resourceJid].setDeviceAvailabilityIcons(devices); remoteVideos[resourceJid].setDeviceAvailabilityIcons(devices);
} }
}; },
/** /**
* Checks if removed video is currently displayed and tries to display * Checks if removed video is currently displayed and tries to display
* another one instead. * another one instead.
*/ */
my.updateRemovedVideo = function(resourceJid) { updateRemovedVideo (id) {
var newResourceJid; let newId;
if (resourceJid === LargeVideo.getResourceJid()) { if (id === LargeVideo.getId()) {
// We'll show user's avatar if he is the dominant speaker or if // We'll show user's avatar if he is the dominant speaker or if
// his video thumbnail is pinned // his video thumbnail is pinned
if (remoteVideos[resourceJid] && if (remoteVideos[id] &&
resourceJid === focusedVideoResourceJid || id === focusedVideoResourceJid ||
resourceJid === currentDominantSpeaker) { id === currentDominantSpeaker) {
newResourceJid = resourceJid; newId = id;
} else { } else {
// Otherwise select last visible video // Otherwise select last visible video
newResourceJid = this.electLastVisibleVideo(); newId = this.electLastVisibleVideo();
} }
LargeVideo.updateLargeVideo(newResourceJid); LargeVideo.updateLargeVideo(id);
} }
}; },
my.electLastVisibleVideo = function () { electLastVisibleVideo () {
// pick the last visible video in the row // pick the last visible video in the row
// if nobody else is left, this picks the local video // if nobody else is left, this picks the local video
var jid; var jid;
@ -174,39 +220,36 @@ var VideoLayout = (function (my) {
console.info("electLastVisibleVideo: " + jid); console.info("electLastVisibleVideo: " + jid);
return jid; return jid;
}; },
my.onRemoteStreamAdded = function (stream) { onRemoteStreamAdded (stream) {
if (stream.peerjid) { let id = stream.getParticipantId();
VideoLayout.ensurePeerContainerExists(stream.peerjid); VideoLayout.ensurePeerContainerExists(id);
var resourceJid = Strophe.getResourceFromJid(stream.peerjid); remoteVideos[id].addRemoteStreamElement(stream);
remoteVideos[resourceJid].addRemoteStreamElement(stream); },
}
};
my.getLargeVideoResource = function () { getLargeVideoId () {
return LargeVideo.getResourceJid(); return LargeVideo.getId();
}; },
/** /**
* Return the type of the remote video. * Return the type of the remote video.
* @param jid the jid for the remote video * @param id the id for the remote video
* @returns the video type video or screen. * @returns the video type video or screen.
*/ */
my.getRemoteVideoType = function (jid) { getRemoteVideoType (id) {
return remoteVideoTypes[jid]; return remoteVideoTypes[id];
}; },
/** /**
* Called when large video update is finished * Called when large video update is finished
* @param currentSmallVideo small video currently displayed on large video * @param currentSmallVideo small video currently displayed on large video
*/ */
my.largeVideoUpdated = function (currentSmallVideo) { largeVideoUpdated (currentSmallVideo) {
// Makes sure that dominant speaker UI // Makes sure that dominant speaker UI
// is enabled only on current small video // is enabled only on current small video
localVideoThumbnail.enableDominantSpeaker( localVideoThumbnail.enableDominantSpeaker(localVideoThumbnail === currentSmallVideo);
localVideoThumbnail === currentSmallVideo);
Object.keys(remoteVideos).forEach( Object.keys(remoteVideos).forEach(
function (resourceJid) { function (resourceJid) {
var remoteVideo = remoteVideos[resourceJid]; var remoteVideo = remoteVideos[resourceJid];
@ -216,9 +259,9 @@ var VideoLayout = (function (my) {
} }
} }
); );
}; },
my.handleVideoThumbClicked = function(noPinnedEndpointChangedEvent, handleVideoThumbClicked (noPinnedEndpointChangedEvent,
resourceJid) { resourceJid) {
if(focusedVideoResourceJid) { if(focusedVideoResourceJid) {
var oldSmallVideo var oldSmallVideo
@ -269,50 +312,46 @@ var VideoLayout = (function (my) {
el.volume = 1; el.volume = 1;
}); });
} }
}; },
/** /**
* Checks if container for participant identified by given peerJid exists * Checks if container for participant identified by given id exists
* in the document and creates it eventually. * in the document and creates it eventually.
* *
* @param peerJid peer Jid to check.
*
* @return Returns <tt>true</tt> if the peer container exists, * @return Returns <tt>true</tt> if the peer container exists,
* <tt>false</tt> - otherwise * <tt>false</tt> - otherwise
*/ */
my.ensurePeerContainerExists = function(peerJid) { ensurePeerContainerExists (id) {
ContactList.ensureAddContact(peerJid); ContactList.ensureAddContact(id);
var resourceJid = Strophe.getResourceFromJid(peerJid); if (remoteVideos[id]) {
return;
if (!remoteVideos[resourceJid]) {
var remoteVideo = new RemoteVideo(peerJid, VideoLayout);
remoteVideos[resourceJid] = remoteVideo;
var videoType = remoteVideoTypes[resourceJid];
if (videoType) {
remoteVideo.setVideoType(videoType);
}
// In case this is not currently in the last n we don't show it.
if (localLastNCount &&
localLastNCount > 0 &&
$('#remoteVideos>span').length >= localLastNCount + 2) {
remoteVideo.showPeerContainer('hide');
}
else
VideoLayout.resizeThumbnails();
} }
};
let remoteVideo = new RemoteVideo(id, VideoLayout, eventEmitter);
remoteVideos[id] = remoteVideo;
let videoType = remoteVideoTypes[id];
if (videoType) {
remoteVideo.setVideoType(videoType);
}
// In case this is not currently in the last n we don't show it.
if (localLastNCount && localLastNCount > 0 &&
$('#remoteVideos>span').length >= localLastNCount + 2) {
remoteVideo.showPeerContainer('hide');
} else {
VideoLayout.resizeThumbnails();
}
},
my.inputDisplayNameHandler = function (name) { inputDisplayNameHandler (name) {
localVideoThumbnail.inputDisplayNameHandler(name); localVideoThumbnail.inputDisplayNameHandler(name);
}; },
my.videoactive = function (videoelem, resourceJid) { videoactive (videoelem, resourceJid) {
console.info(resourceJid + " video is now active"); console.info(resourceJid + " video is now active");
@ -330,61 +369,50 @@ var VideoLayout = (function (my) {
currentDominantSpeaker === resourceJid)) { currentDominantSpeaker === resourceJid)) {
LargeVideo.updateLargeVideo(resourceJid, true); LargeVideo.updateLargeVideo(resourceJid, true);
} }
}; },
/** /**
* Shows the presence status message for the given video. * Shows the presence status message for the given video.
*/ */
my.setPresenceStatus = function (resourceJid, statusMsg) { setPresenceStatus (resourceJid, statusMsg) {
remoteVideos[resourceJid].setPresenceStatus(statusMsg); remoteVideos[resourceJid].setPresenceStatus(statusMsg);
}; },
/** /**
* Shows a visual indicator for the moderator of the conference. * Shows a visual indicator for the moderator of the conference.
*/ */
my.showModeratorIndicator = function () { showModeratorIndicator () {
let isModerator = APP.conference.isModerator;
var isModerator = APP.xmpp.isModerator();
if (isModerator) { if (isModerator) {
localVideoThumbnail.createModeratorIndicatorElement(); localVideoThumbnail.createModeratorIndicatorElement();
} }
var members = APP.xmpp.getMembers(); APP.conference.listMembers().forEach(function (member) {
let id = member.getId();
Object.keys(members).forEach(function (jid) { if (member.isModerator()) {
remoteVideos[id].removeRemoteVideoMenu();
var resourceJid = Strophe.getResourceFromJid(jid); remoteVideos[id].createModeratorIndicatorElement();
var member = members[jid];
if (member.isFocus) {
// Skip server side focus
return;
}
if (member.role === 'moderator') {
remoteVideos[resourceJid].removeRemoteVideoMenu();
remoteVideos[resourceJid].createModeratorIndicatorElement();
} else if (isModerator) { } else if (isModerator) {
// We are moderator, but user is not - add menu // We are moderator, but user is not - add menu
if ($('#remote_popupmenu_' + resourceJid).length <= 0) { if ($(`#remote_popupmenu_${id}`).length <= 0) {
remoteVideos[resourceJid].addRemoteVideoMenu(); remoteVideos[id].addRemoteVideoMenu();
} }
} }
}); });
}; },
/* /*
* Shows or hides the audio muted indicator over the local thumbnail video. * Shows or hides the audio muted indicator over the local thumbnail video.
* @param {boolean} isMuted * @param {boolean} isMuted
*/ */
my.showLocalAudioIndicator = function(isMuted) { showLocalAudioIndicator (isMuted) {
localVideoThumbnail.showAudioIndicator(isMuted); localVideoThumbnail.showAudioIndicator(isMuted);
}; },
/** /**
* Resizes the large video container. * Resizes the large video container.
*/ */
my.resizeLargeVideoContainer = function () { resizeLargeVideoContainer () {
if(LargeVideo.isEnabled()) { if(LargeVideo.isEnabled()) {
LargeVideo.resize(); LargeVideo.resize();
} else { } else {
@ -392,12 +420,12 @@ var VideoLayout = (function (my) {
} }
VideoLayout.resizeThumbnails(); VideoLayout.resizeThumbnails();
LargeVideo.position(); LargeVideo.position();
}; },
/** /**
* Resizes thumbnails. * Resizes thumbnails.
*/ */
my.resizeThumbnails = function(animate) { resizeThumbnails (animate) {
var videoSpaceWidth = $('#remoteVideos').width(); var videoSpaceWidth = $('#remoteVideos').width();
var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth); var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
@ -441,14 +469,14 @@ var VideoLayout = (function (my) {
$(document).trigger("remotevideo.resized", [width, height]); $(document).trigger("remotevideo.resized", [width, height]);
} }
}; },
/** /**
* Calculates the thumbnail size. * Calculates the thumbnail size.
* *
* @param videoSpaceWidth the width of the video space * @param videoSpaceWidth the width of the video space
*/ */
my.calculateThumbnailSize = function (videoSpaceWidth) { calculateThumbnailSize (videoSpaceWidth) {
// Calculate the available height, which is the inner window height // Calculate the available height, which is the inner window height
// minus 39px for the header minus 2px for the delimiter lines on the // minus 39px for the header minus 2px for the delimiter lines on the
// top and bottom of the large video, minus the 36px space inside the // top and bottom of the large video, minus the 36px space inside the
@ -478,7 +506,7 @@ var VideoLayout = (function (my) {
} }
return [availableWidth, availableHeight]; return [availableWidth, availableHeight];
}; },
/** /**
* Returns the corresponding resource jid to the given peer container * Returns the corresponding resource jid to the given peer container
@ -487,66 +515,21 @@ var VideoLayout = (function (my) {
* @return the corresponding resource jid to the given peer container * @return the corresponding resource jid to the given peer container
* DOM element * DOM element
*/ */
my.getPeerContainerResourceJid = function (containerElement) { getPeerContainerResourceJid (containerElement) {
if (localVideoThumbnail.container === containerElement) { if (localVideoThumbnail.container === containerElement) {
return localVideoThumbnail.getResourceJid(); return localVideoThumbnail.getId();
} }
var i = containerElement.id.indexOf('participant_'); var i = containerElement.id.indexOf('participant_');
if (i >= 0) if (i >= 0)
return containerElement.id.substring(i + 12); return containerElement.id.substring(i + 12);
}; },
/**
* On contact list item clicked.
*/
$(ContactList).bind('contactclicked', function(event, jid) {
if (!jid) {
return;
}
if (jid === APP.xmpp.myJid()) {
$("#localVideoContainer").click();
return;
}
var resource = Strophe.getResourceFromJid(jid);
var remoteVideo = remoteVideos[resource];
if (remoteVideo && remoteVideo.selectVideoElement().length) {
var videoThumb = remoteVideo.selectVideoElement()[0];
// It is not always the case that a videoThumb exists (if there is
// no actual video).
if (RTC.getVideoSrc(videoThumb)) {
// We have a video src, great! Let's update the large video
// now.
VideoLayout.handleVideoThumbClicked(
false,
Strophe.getResourceFromJid(jid));
} else {
// If we don't have a video src for jid, there's absolutely
// no point in calling handleVideoThumbClicked; Quite
// simply, it won't work because it needs an src to attach
// to the large video.
//
// Instead, we trigger the pinned endpoint changed event to
// let the bridge adjust its lastN set for myjid and store
// the pinned user in the lastNPickupJid variable to be
// picked up later by the lastN changed event handler.
lastNPickupJid = jid;
eventEmitter.emit(UIEvents.PINNED_ENDPOINT,
Strophe.getResourceFromJid(jid));
}
}
});
/** /**
* On audio muted event. * On audio muted event.
*/ */
my.onAudioMute = function (jid, isMuted) { onAudioMute (jid, isMuted) {
var resourceJid = Strophe.getResourceFromJid(jid); var resourceJid = Strophe.getResourceFromJid(jid);
if (resourceJid === APP.xmpp.myResource()) { if (resourceJid === APP.xmpp.myResource()) {
localVideoThumbnail.showAudioIndicator(isMuted); localVideoThumbnail.showAudioIndicator(isMuted);
@ -557,12 +540,12 @@ var VideoLayout = (function (my) {
remoteVideos[resourceJid].updateRemoteVideoMenu(isMuted); remoteVideos[resourceJid].updateRemoteVideoMenu(isMuted);
} }
} }
}; },
/** /**
* On video muted event. * On video muted event.
*/ */
my.onVideoMute = function (jid, value) { onVideoMute (jid, value) {
if (jid !== APP.xmpp.myJid() && if (jid !== APP.xmpp.myJid() &&
!APP.RTC.muteRemoteVideoStream(jid, value)) !APP.RTC.muteRemoteVideoStream(jid, value))
return; return;
@ -582,12 +565,12 @@ var VideoLayout = (function (my) {
else else
el.hide(); el.hide();
} }
}; },
/** /**
* Display name changed. * Display name changed.
*/ */
my.onDisplayNameChanged = function (id, displayName, status) { onDisplayNameChanged (id, displayName, status) {
if (id === 'localVideoContainer' || if (id === 'localVideoContainer' ||
APP.conference.isLocalId(id)) { APP.conference.isLocalId(id)) {
localVideoThumbnail.setDisplayName(displayName); localVideoThumbnail.setDisplayName(displayName);
@ -595,39 +578,39 @@ var VideoLayout = (function (my) {
VideoLayout.ensurePeerContainerExists(id); VideoLayout.ensurePeerContainerExists(id);
remoteVideos[id].setDisplayName(displayName, status); remoteVideos[id].setDisplayName(displayName, status);
} }
}; },
/** /**
* On dominant speaker changed event. * On dominant speaker changed event.
*/ */
my.onDominantSpeakerChanged = function (resourceJid) { onDominantSpeakerChanged (id) {
// We ignore local user events. // We ignore local user events.
if (resourceJid === APP.xmpp.myResource()) if (APP.conference.isLocalId(id)) {
return;
var remoteVideo = remoteVideos[resourceJid];
var members = APP.xmpp.getMembers();
// Update the current dominant speaker.
if (resourceJid !== currentDominantSpeaker) {
if (remoteVideo) {
remoteVideo.updateDominantSpeakerIndicator(true);
// let's remove the indications from the remote video if any
var oldSpeakerRemoteVideo
= remoteVideos[currentDominantSpeaker];
if (oldSpeakerRemoteVideo) {
oldSpeakerRemoteVideo.updateDominantSpeakerIndicator(false);
}
}
currentDominantSpeaker = resourceJid;
} else {
return; return;
} }
if (!remoteVideo) if (id === currentDominantSpeaker) {
return; return;
}
let remoteVideo = remoteVideos[id];
if (!remoteVideo) {
return;
}
// Update the current dominant speaker.
remoteVideo.updateDominantSpeakerIndicator(true);
// let's remove the indications from the remote video if any
let oldSpeakerRemoteVideo = remoteVideos[currentDominantSpeaker];
if (oldSpeakerRemoteVideo) {
oldSpeakerRemoteVideo.updateDominantSpeakerIndicator(false);
}
currentDominantSpeaker = id;
// Obtain container for new dominant speaker. // Obtain container for new dominant speaker.
var videoSel = remoteVideo.selectVideoElement(); let videoSel = remoteVideo.selectVideoElement();
// Local video will not have container found, but that's ok // Local video will not have container found, but that's ok
// since we don't want to switch to local video. // since we don't want to switch to local video.
@ -635,10 +618,10 @@ var VideoLayout = (function (my) {
// Update the large video if the video source is already available, // Update the large video if the video source is already available,
// otherwise wait for the "videoactive.jingle" event. // otherwise wait for the "videoactive.jingle" event.
if (videoSel[0].currentTime > 0) { if (videoSel[0].currentTime > 0) {
LargeVideo.updateLargeVideo(resourceJid); LargeVideo.updateLargeVideo(id);
} }
} }
}; },
/** /**
* On last N change event. * On last N change event.
@ -647,7 +630,7 @@ var VideoLayout = (function (my) {
* @param endpointsEnteringLastN the list currently entering last N * @param endpointsEnteringLastN the list currently entering last N
* endpoints * endpoints
*/ */
my.onLastNEndpointsChanged = function (lastNEndpoints, endpointsEnteringLastN) { onLastNEndpointsChanged (lastNEndpoints, endpointsEnteringLastN) {
if (lastNCount !== lastNEndpoints.length) if (lastNCount !== lastNEndpoints.length)
lastNCount = lastNEndpoints.length; lastNCount = lastNEndpoints.length;
@ -727,7 +710,7 @@ var VideoLayout = (function (my) {
// displayed in the large video we have to switch to another // displayed in the large video we have to switch to another
// user. // user.
if (!updateLargeVideo && if (!updateLargeVideo &&
resourceJid === LargeVideo.getResourceJid()) { resourceJid === LargeVideo.getId()) {
updateLargeVideo = true; updateLargeVideo = true;
} }
} }
@ -751,9 +734,9 @@ var VideoLayout = (function (my) {
var sel = remoteVideo.selectVideoElement(); var sel = remoteVideo.selectVideoElement();
APP.RTC.attachMediaStream(sel, mediaStream.stream); APP.RTC.attachMediaStream(sel, mediaStream.stream);
if (lastNPickupJid == mediaStream.peerjid) { if (lastNPickupId == mediaStream.peerjid) {
// Clean up the lastN pickup jid. // Clean up the lastN pickup id.
lastNPickupJid = null; lastNPickupId = null;
// Don't fire the events again, they've already // Don't fire the events again, they've already
// been fired in the contact list click handler. // been fired in the contact list click handler.
@ -789,14 +772,14 @@ var VideoLayout = (function (my) {
break; break;
} }
} }
}; },
/** /**
* Updates local stats * Updates local stats
* @param percent * @param percent
* @param object * @param object
*/ */
my.updateLocalConnectionStats = function (percent, object) { updateLocalConnectionStats (percent, object) {
var resolution = null; var resolution = null;
if (object.resolution !== null) { if (object.resolution !== null) {
resolution = object.resolution; resolution = object.resolution;
@ -814,7 +797,7 @@ var VideoLayout = (function (my) {
updateResolution(resolution[jid]); updateResolution(resolution[jid]);
} }
} }
}; },
/** /**
* Updates remote stats. * Updates remote stats.
@ -822,92 +805,90 @@ var VideoLayout = (function (my) {
* @param percent the connection quality percent * @param percent the connection quality percent
* @param object the stats data * @param object the stats data
*/ */
my.updateConnectionStats = function (jid, percent, object) { updateConnectionStats (jid, percent, object) {
var resourceJid = Strophe.getResourceFromJid(jid); var resourceJid = Strophe.getResourceFromJid(jid);
if (remoteVideos[resourceJid]) if (remoteVideos[resourceJid])
remoteVideos[resourceJid].updateStatsIndicator(percent, object); remoteVideos[resourceJid].updateStatsIndicator(percent, object);
}; },
/** /**
* Hides the connection indicator * Hides the connection indicator
* @param jid * @param jid
*/ */
my.hideConnectionIndicator = function (jid) { hideConnectionIndicator (jid) {
remoteVideos[Strophe.getResourceFromJid(jid)].hideConnectionIndicator(); remoteVideos[Strophe.getResourceFromJid(jid)].hideConnectionIndicator();
}; },
/** /**
* Hides all the indicators * Hides all the indicators
*/ */
my.hideStats = function () { hideStats () {
for(var video in remoteVideos) { for(var video in remoteVideos) {
remoteVideos[video].hideIndicator(); remoteVideos[video].hideIndicator();
} }
localVideoThumbnail.hideIndicator(); localVideoThumbnail.hideIndicator();
}; },
my.participantLeft = function (jid) { participantLeft (id) {
// Unlock large video // Unlock large video
var resourceJid = Strophe.getResourceFromJid(jid); if (focusedVideoResourceJid === id) {
if (focusedVideoResourceJid === resourceJid) {
console.info("Focused video owner has left the conference"); console.info("Focused video owner has left the conference");
focusedVideoResourceJid = null; focusedVideoResourceJid = null;
} }
if (currentDominantSpeaker === resourceJid) { if (currentDominantSpeaker === id) {
console.info("Dominant speaker has left the conference"); console.info("Dominant speaker has left the conference");
currentDominantSpeaker = null; currentDominantSpeaker = null;
} }
var remoteVideo = remoteVideos[resourceJid]; var remoteVideo = remoteVideos[id];
if (remoteVideo) { if (remoteVideo) {
// Remove remote video // Remove remote video
console.info("Removing remote video: " + resourceJid); console.info("Removing remote video: " + id);
delete remoteVideos[resourceJid]; delete remoteVideos[id];
remoteVideo.remove(); remoteVideo.remove();
} else { } else {
console.warn("No remote video for " + resourceJid); console.warn("No remote video for " + id);
} }
VideoLayout.resizeThumbnails(); VideoLayout.resizeThumbnails();
}; },
my.onVideoTypeChanged = function (resourceJid, newVideoType) { onVideoTypeChanged (id, newVideoType) {
if (remoteVideoTypes[resourceJid] === newVideoType) { if (remoteVideoTypes[id] === newVideoType) {
return; return;
} }
console.info("Peer video type changed: ", resourceJid, newVideoType); console.info("Peer video type changed: ", id, newVideoType);
remoteVideoTypes[resourceJid] = newVideoType; remoteVideoTypes[id] = newVideoType;
var smallVideo; var smallVideo;
if (resourceJid === APP.xmpp.myResource()) { if (APP.conference.isLocalId(id)) {
if (!localVideoThumbnail) { if (!localVideoThumbnail) {
console.warn("Local video not ready yet"); console.warn("Local video not ready yet");
return; return;
} }
smallVideo = localVideoThumbnail; smallVideo = localVideoThumbnail;
} else if (remoteVideos[resourceJid]) { } else if (remoteVideos[id]) {
smallVideo = remoteVideos[resourceJid]; smallVideo = remoteVideos[id];
} else { } else {
return; return;
} }
smallVideo.setVideoType(newVideoType); smallVideo.setVideoType(newVideoType);
LargeVideo.onVideoTypeChanged(resourceJid, newVideoType); LargeVideo.onVideoTypeChanged(id, newVideoType);
},
};
/** /**
* Updates the video size and position. * Updates the video size and position.
*/ */
my.updateLargeVideoSize = function () { updateLargeVideoSize () {
LargeVideo.updateVideoSizeAndPosition(); LargeVideo.updateVideoSizeAndPosition();
LargeVideo.position(null, null, null, null, true); LargeVideo.position(null, null, null, null, true);
}; },
my.showMore = function (jid) { showMore (jid) {
if (jid === 'local') { if (jid === 'local') {
localVideoThumbnail.connectionIndicator.showMore(); localVideoThumbnail.connectionIndicator.showMore();
} else { } else {
@ -918,15 +899,15 @@ var VideoLayout = (function (my) {
console.info("Error - no remote video for jid: " + jid); console.info("Error - no remote video for jid: " + jid);
} }
} }
}; },
my.addPreziContainer = function (id) { addPreziContainer (id) {
var container = RemoteVideo.createContainer(id); var container = RemoteVideo.createContainer(id);
VideoLayout.resizeThumbnails(); VideoLayout.resizeThumbnails();
return container; return container;
}; },
my.setLargeVideoVisible = function (isVisible) { setLargeVideoVisible (isVisible) {
LargeVideo.setLargeVideoVisible(isVisible); LargeVideo.setLargeVideoVisible(isVisible);
if(!isVisible && focusedVideoResourceJid) { if(!isVisible && focusedVideoResourceJid) {
var smallVideo = VideoLayout.getSmallVideo(focusedVideoResourceJid); var smallVideo = VideoLayout.getSmallVideo(focusedVideoResourceJid);
@ -936,7 +917,7 @@ var VideoLayout = (function (my) {
} }
focusedVideoResourceJid = null; focusedVideoResourceJid = null;
} }
}; },
/** /**
* Resizes the video area. * Resizes the video area.
@ -945,10 +926,10 @@ var VideoLayout = (function (my) {
* @param callback a function to be called when the video space is * @param callback a function to be called when the video space is
* resized. * resized.
*/ */
my.resizeVideoArea = function(isSideBarVisible, callback) { resizeVideoArea (isSideBarVisible, callback) {
LargeVideo.resizeVideoAreaAnimated(isSideBarVisible, callback); LargeVideo.resizeVideoAreaAnimated(isSideBarVisible, callback);
VideoLayout.resizeThumbnails(true); VideoLayout.resizeThumbnails(true);
}; },
/** /**
* Resizes the #videospace html element * Resizes the #videospace html element
@ -961,7 +942,7 @@ var VideoLayout = (function (my) {
* @param completeFunction a function to be called when the video space * @param completeFunction a function to be called when the video space
* is resized. * is resized.
*/ */
my.resizeVideoSpace = function (animate, isChatVisible, completeFunction) { resizeVideoSpace (animate, isChatVisible, completeFunction) {
var availableHeight = window.innerHeight; var availableHeight = window.innerHeight;
var availableWidth = UIUtil.getAvailableVideoWidth(isChatVisible); var availableWidth = UIUtil.getAvailableVideoWidth(isChatVisible);
@ -983,19 +964,17 @@ var VideoLayout = (function (my) {
$('#videospace').height(availableHeight); $('#videospace').height(availableHeight);
} }
}; },
my.getSmallVideo = function (resourceJid) { getSmallVideo (id) {
if(resourceJid == APP.xmpp.myResource()) { if (APP.conference.isLocalId(id)) {
return localVideoThumbnail; return localVideoThumbnail;
} else { } else {
if(!remoteVideos[resourceJid]) return remoteVideos[id];
return null;
return remoteVideos[resourceJid];
} }
}; },
my.changeUserAvatar = function(id, thumbUrl) { changeUserAvatar (id, thumbUrl) {
var smallVideo = VideoLayout.getSmallVideo(id); var smallVideo = VideoLayout.getSmallVideo(id);
if (smallVideo) { if (smallVideo) {
smallVideo.avatarChanged(thumbUrl); smallVideo.avatarChanged(thumbUrl);
@ -1005,46 +984,43 @@ var VideoLayout = (function (my) {
); );
} }
LargeVideo.updateAvatar(id, thumbUrl); LargeVideo.updateAvatar(id, thumbUrl);
}; },
my.createEtherpadIframe = function(src, onloadHandler) createEtherpadIframe (src, onloadHandler) {
{
return LargeVideo.createEtherpadIframe(src, onloadHandler); return LargeVideo.createEtherpadIframe(src, onloadHandler);
}; },
my.setLargeVideoState = function (state) { setLargeVideoState (state) {
LargeVideo.setState(state); LargeVideo.setState(state);
}; },
my.getLargeVideoState = function () { getLargeVideoState () {
return LargeVideo.getState(); return LargeVideo.getState();
}; },
my.setLargeVideoHover = function (inHandler, outHandler) { setLargeVideoHover (inHandler, outHandler) {
LargeVideo.setHover(inHandler, outHandler); LargeVideo.setHover(inHandler, outHandler);
}; },
/** /**
* Indicates that the video has been interrupted. * Indicates that the video has been interrupted.
*/ */
my.onVideoInterrupted = function () { onVideoInterrupted () {
LargeVideo.enableVideoProblemFilter(true); LargeVideo.enableVideoProblemFilter(true);
var reconnectingKey = "connection.RECONNECTING"; var reconnectingKey = "connection.RECONNECTING";
$('#videoConnectionMessage').attr("data-i18n", reconnectingKey); $('#videoConnectionMessage').attr("data-i18n", reconnectingKey);
$('#videoConnectionMessage') $('#videoConnectionMessage')
.text(APP.translation.translateString(reconnectingKey)); .text(APP.translation.translateString(reconnectingKey));
$('#videoConnectionMessage').css({display: "block"}); $('#videoConnectionMessage').css({display: "block"});
}; },
/** /**
* Indicates that the video has been restored. * Indicates that the video has been restored.
*/ */
my.onVideoRestored = function () { onVideoRestored () {
LargeVideo.enableVideoProblemFilter(false); LargeVideo.enableVideoProblemFilter(false);
$('#videoConnectionMessage').css({display: "none"}); $('#videoConnectionMessage').css({display: "none"});
}; }
};
return my; export default VideoLayout;
}(VideoLayout || {}));
module.exports = VideoLayout;

View File

@ -25,6 +25,7 @@ export default {
ETHERPAD_CLICKED: "UI.etherpad_clicked", ETHERPAD_CLICKED: "UI.etherpad_clicked",
ROOM_LOCK_CLICKED: "UI.room_lock_clicked", ROOM_LOCK_CLICKED: "UI.room_lock_clicked",
USER_INVITED: "UI.user_invited", USER_INVITED: "UI.user_invited",
USER_KICKED: "UI.user_kicked",
FULLSCREEN_TOGGLE: "UI.fullscreen_toggle", FULLSCREEN_TOGGLE: "UI.fullscreen_toggle",
AUTH_CLICKED: "UI.auth_clicked", AUTH_CLICKED: "UI.auth_clicked",
TOGGLE_CHAT: "UI.toggle_chat", TOGGLE_CHAT: "UI.toggle_chat",