From 2c01fde713dd432744f0e6d545f349a10046c5bb Mon Sep 17 00:00:00 2001 From: paweldomas Date: Wed, 21 Sep 2016 13:10:11 -0500 Subject: [PATCH 1/3] ref(SmallVideo): rename 'isMuted' to avoid confusion --- modules/UI/videolayout/RemoteVideo.js | 9 ++++----- modules/UI/videolayout/SmallVideo.js | 10 +++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js index 43e4ce872..6d577765a 100644 --- a/modules/UI/videolayout/RemoteVideo.js +++ b/modules/UI/videolayout/RemoteVideo.js @@ -19,7 +19,6 @@ function RemoteVideo(id, VideoLayout, emitter) { this.setDisplayName(); this.flipX = false; this.isLocal = false; - this.isMuted = false; } RemoteVideo.prototype = Object.create(SmallVideo.prototype); @@ -61,7 +60,7 @@ RemoteVideo.prototype._initPopupMenu = function (popupMenuElement) { this.popover.show = function () { // update content by forcing it, to finish even if popover // is not visible - this.updateRemoteVideoMenu(this.isMuted, true); + this.updateRemoteVideoMenu(this.isAudioMuted, true); // call the original show, passing its actual this origShowFunc.call(this.popover); }.bind(this); @@ -97,7 +96,7 @@ RemoteVideo.prototype._generatePopupContent = function () { muteLinkItem.id = "mutelink_" + this.id; - if (this.isMuted) { + if (this.isAudioMuted) { muteLinkItem.innerHTML = mutedHTML; muteLinkItem.className = 'mutelink disabled'; } @@ -109,7 +108,7 @@ RemoteVideo.prototype._generatePopupContent = function () { // Delegate event to the document. $(document).on("click", "#mutelink_" + this.id, function(){ - if (this.isMuted) + if (this.isAudioMuted) return; this.emitter.emit(UIEvents.REMOTE_AUDIO_MUTED, this.id); @@ -153,7 +152,7 @@ RemoteVideo.prototype._generatePopupContent = function () { */ RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted, force) { - this.isMuted = isMuted; + this.isAudioMuted = isMuted; // generate content, translate it and add it to document only if // popover is visible or we force to do so. diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index 911c3bc4f..bf3acfce4 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -7,7 +7,7 @@ import UIEvents from "../../../service/UI/UIEvents"; const RTCUIHelper = JitsiMeetJS.util.RTCUIHelper; function SmallVideo(VideoLayout) { - this.isMuted = false; + this.isAudioMuted = false; this.hasAvatar = false; this.isVideoMuted = false; this.videoStream = null; @@ -204,7 +204,7 @@ SmallVideo.prototype.showAudioIndicator = function(isMuted) { else { audioMutedIndicator.show(); } - this.isMuted = isMuted; + this.isAudioMuted = isMuted; }; /** @@ -222,7 +222,7 @@ SmallVideo.prototype.getAudioMutedIndicator = function () { audioMutedSpan = document.createElement('span'); audioMutedSpan.className = 'audioMuted toolbar-icon'; - + UIUtil.setTooltip(audioMutedSpan, "videothumbnail.mute", "top"); @@ -277,11 +277,11 @@ SmallVideo.prototype.getVideoMutedIndicator = function () { var mutedIndicator = document.createElement('i'); mutedIndicator.className = 'icon-camera-disabled'; - + UIUtil.setTooltip(mutedIndicator, "videothumbnail.videomute", "top"); - + videoMutedSpan.appendChild(mutedIndicator); return $('#' + this.videoSpanId + ' .videoMuted'); From e0a05c5908cd30b05e6ffcfe134038d91cbf5249 Mon Sep 17 00:00:00 2001 From: paweldomas Date: Wed, 21 Sep 2016 15:02:19 -0500 Subject: [PATCH 2/3] ref(LargeVideo): move VideoContainer to separate file VideoContainer is a separate being which implements the LargeContainer and it's confusing to have it in the same file. This was encouraging to access private parts of the VideoContainer directly(not through the interface). --- conference.js | 4 +- modules/UI/videolayout/LargeVideo.js | 382 +--------------------- modules/UI/videolayout/VideoContainer.js | 385 +++++++++++++++++++++++ modules/UI/videolayout/VideoLayout.js | 6 +- 4 files changed, 395 insertions(+), 382 deletions(-) create mode 100644 modules/UI/videolayout/VideoContainer.js diff --git a/conference.js b/conference.js index 0b8307c37..b0edba985 100644 --- a/conference.js +++ b/conference.js @@ -39,7 +39,7 @@ let connectionIsInterrupted = false; */ let DSExternalInstallationInProgress = false; -import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/LargeVideo"; +import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/VideoContainer"; /** * Known custom conference commands. @@ -1424,6 +1424,8 @@ export default { APP.UI.addListener(UIEvents.PINNED_ENDPOINT, (smallVideo, isPinned) => { var smallVideoId = smallVideo.getId(); + // FIXME why VIDEO_CONTAINER_TYPE instead of checking if + // the participant is on the large video ? if (smallVideo.getVideoType() === VIDEO_CONTAINER_TYPE && !APP.conference.isLocalId(smallVideoId)) { diff --git a/modules/UI/videolayout/LargeVideo.js b/modules/UI/videolayout/LargeVideo.js index e5449dc02..8c145e77e 100644 --- a/modules/UI/videolayout/LargeVideo.js +++ b/modules/UI/videolayout/LargeVideo.js @@ -1,388 +1,10 @@ /* global $, APP, interfaceConfig */ /* jshint -W101 */ -import UIUtil from "../util/UIUtil"; -import UIEvents from "../../../service/UI/UIEvents"; -import LargeContainer from './LargeContainer'; -import FilmStrip from './FilmStrip'; import Avatar from "../avatar/Avatar"; import {createDeferred} from '../../util/helpers'; - -const FADE_DURATION_MS = 300; - -export const VIDEO_CONTAINER_TYPE = "camera"; - -/** - * Get stream id. - * @param {JitsiTrack?} stream - */ -function getStreamOwnerId(stream) { - if (!stream) { - return; - } - if (stream.isLocal()) { // local stream doesn't have method "getParticipantId" - return APP.conference.getMyUserId(); - } else { - return stream.getParticipantId(); - } -} - -/** - * Returns an array of the video dimensions, so that it keeps it's aspect - * ratio and fits available area with it's larger dimension. This method - * ensures that whole video will be visible and can leave empty areas. - * - * @return an array with 2 elements, the video width and the video height - */ -function getDesktopVideoSize(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight) { - - let aspectRatio = videoWidth / videoHeight; - - let availableWidth = Math.max(videoWidth, videoSpaceWidth); - let availableHeight = Math.max(videoHeight, videoSpaceHeight); - - videoSpaceHeight -= FilmStrip.getFilmStripHeight(); - - if (availableWidth / aspectRatio >= videoSpaceHeight) { - availableHeight = videoSpaceHeight; - availableWidth = availableHeight * aspectRatio; - } - - if (availableHeight * aspectRatio >= videoSpaceWidth) { - availableWidth = videoSpaceWidth; - availableHeight = availableWidth / aspectRatio; - } - - return [ availableWidth, availableHeight ]; -} - - -/** - * Returns an array of the video dimensions. It respects the - * VIDEO_LAYOUT_FIT config, to fit the video to the screen, by hiding some parts - * of it, or to fit it to the height or width. - * - * @param videoWidth the original video width - * @param videoHeight the original video height - * @param videoSpaceWidth the width of the video space - * @param videoSpaceHeight the height of the video space - * @return an array with 2 elements, the video width and the video height - */ -function getCameraVideoSize(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight) { - - let aspectRatio = videoWidth / videoHeight; - - let availableWidth = videoWidth; - let availableHeight = videoHeight; - - if (interfaceConfig.VIDEO_LAYOUT_FIT == 'height') { - availableHeight = videoSpaceHeight; - availableWidth = availableHeight*aspectRatio; - } - else if (interfaceConfig.VIDEO_LAYOUT_FIT == 'width') { - availableWidth = videoSpaceWidth; - availableHeight = availableWidth/aspectRatio; - } - else if (interfaceConfig.VIDEO_LAYOUT_FIT == 'both') { - availableWidth = Math.max(videoWidth, videoSpaceWidth); - availableHeight = Math.max(videoHeight, videoSpaceHeight); - - if (availableWidth / aspectRatio < videoSpaceHeight) { - availableHeight = videoSpaceHeight; - availableWidth = availableHeight * aspectRatio; - } - - if (availableHeight * aspectRatio < videoSpaceWidth) { - availableWidth = videoSpaceWidth; - availableHeight = availableWidth / aspectRatio; - } - } - - - return [ availableWidth, availableHeight ]; -} - -/** - * Returns an array of the video horizontal and vertical indents, - * so that if fits its parent. - * - * @return an array with 2 elements, the horizontal indent and the vertical - * indent - */ -function getCameraVideoPosition(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight) { - // Parent height isn't completely calculated when we position the video in - // full screen mode and this is why we use the screen height in this case. - // Need to think it further at some point and implement it properly. - if (UIUtil.isFullScreen()) { - videoSpaceHeight = window.innerHeight; - } - - let horizontalIndent = (videoSpaceWidth - videoWidth) / 2; - let verticalIndent = (videoSpaceHeight - videoHeight) / 2; - - return { horizontalIndent, verticalIndent }; -} - -/** - * Returns an array of the video horizontal and vertical indents. - * Centers horizontally and top aligns vertically. - * - * @return an array with 2 elements, the horizontal indent and the vertical - * indent - */ -function getDesktopVideoPosition(videoWidth, - videoHeight, - videoSpaceWidth, - videoSpaceHeight) { - - let horizontalIndent = (videoSpaceWidth - videoWidth) / 2; - - let verticalIndent = 0;// Top aligned - - return { horizontalIndent, verticalIndent }; -} - -/** - * Container for user video. - */ -class VideoContainer extends LargeContainer { - // FIXME: With Temasys we have to re-select everytime - get $video () { - return $('#largeVideo'); - } - - get id () { - return getStreamOwnerId(this.stream); - } - - constructor (onPlay, emitter) { - super(); - this.stream = null; - this.videoType = null; - this.localFlipX = true; - this.emitter = emitter; - - this.isVisible = false; - - this.$avatar = $('#dominantSpeaker'); - this.$wrapper = $('#largeVideoWrapper'); - - this.avatarHeight = $("#dominantSpeakerAvatar").height(); - - // This does not work with Temasys plugin - has to be a property to be - // copied between new elements - //this.$video.on('play', onPlay); - this.$video[0].onplay = onPlay; - } - - /** - * Get size of video element. - * @returns {{width, height}} - */ - getStreamSize () { - let video = this.$video[0]; - return { - width: video.videoWidth, - height: video.videoHeight - }; - } - - /** - * Calculate optimal video size for specified container size. - * @param {number} containerWidth container width - * @param {number} containerHeight container height - * @returns {{availableWidth, availableHeight}} - */ - getVideoSize (containerWidth, containerHeight) { - let { width, height } = this.getStreamSize(); - if (this.stream && this.isScreenSharing()) { - return getDesktopVideoSize( width, - height, - containerWidth, - containerHeight); - } else { - return getCameraVideoSize( width, - height, - containerWidth, - containerHeight); - } - } - - /** - * Calculate optimal video position (offset for top left corner) - * for specified video size and container size. - * @param {number} width video width - * @param {number} height video height - * @param {number} containerWidth container width - * @param {number} containerHeight container height - * @returns {{horizontalIndent, verticalIndent}} - */ - getVideoPosition (width, height, containerWidth, containerHeight) { - if (this.stream && this.isScreenSharing()) { - return getDesktopVideoPosition( width, - height, - containerWidth, - containerHeight); - } else { - return getCameraVideoPosition( width, - height, - containerWidth, - containerHeight); - } - } - - resize (containerWidth, containerHeight, animate = false) { - let [width, height] - = this.getVideoSize(containerWidth, containerHeight); - let { horizontalIndent, verticalIndent } - = this.getVideoPosition(width, height, - containerWidth, containerHeight); - - // update avatar position - let top = containerHeight / 2 - this.avatarHeight / 4 * 3; - - this.$avatar.css('top', top); - - this.$wrapper.animate({ - width: width, - height: height, - - top: verticalIndent, - bottom: verticalIndent, - - left: horizontalIndent, - right: horizontalIndent - }, { - queue: false, - duration: animate ? 500 : 0 - }); - } - - /** - * Update video stream. - * @param {JitsiTrack?} stream new stream - * @param {string} videoType video type - */ - setStream (stream, videoType) { - // detach old stream - if (this.stream) { - this.stream.detach(this.$video[0]); - } - - this.stream = stream; - this.videoType = videoType; - - if (!stream) { - return; - } - - stream.attach(this.$video[0]); - let flipX = stream.isLocal() && this.localFlipX; - this.$video.css({ - transform: flipX ? 'scaleX(-1)' : 'none' - }); - } - - /** - * Changes the flipX state of the local video. - * @param val {boolean} true if flipped. - */ - setLocalFlipX(val) { - this.localFlipX = val; - if(!this.$video || !this.stream || !this.stream.isLocal()) - return; - this.$video.css({ - transform: this.localFlipX ? 'scaleX(-1)' : 'none' - }); - } - - /** - * Check if current video stream is screen sharing. - * @returns {boolean} - */ - isScreenSharing () { - return this.videoType === 'desktop'; - } - - /** - * Show or hide user avatar. - * @param {boolean} show - */ - showAvatar (show) { - // TO FIX: Video background need to be black, so that we don't have a - // flickering effect when scrolling between videos and have the screen - // move to grey before going back to video. Avatars though can have the - // default background set. - // In order to fix this code we need to introduce video background or - // find a workaround for the video flickering. - $("#largeVideoContainer").css("background", - (show) ? interfaceConfig.DEFAULT_BACKGROUND : "#000"); - - this.$avatar.css("visibility", show ? "visible" : "hidden"); - - this.emitter.emit(UIEvents.LARGE_VIDEO_AVATAR_DISPLAYED, show); - } - - // We are doing fadeOut/fadeIn animations on parent div which wraps - // largeVideo, because when Temasys plugin is in use it replaces - //