| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 | 
							- /* global APP  */
 - 
 - import Logger from 'jitsi-meet-logger';
 - 
 - import { MEDIA_TYPE, VIDEO_TYPE } from '../../../react/features/base/media';
 - import {
 -     getPinnedParticipant,
 -     getParticipantById
 - } from '../../../react/features/base/participants';
 - import { getTrackByMediaTypeAndParticipant } from '../../../react/features/base/tracks';
 - 
 - import LargeVideoManager from './LargeVideoManager';
 - import { VIDEO_CONTAINER_TYPE } from './VideoContainer';
 - 
 - const logger = Logger.getLogger(__filename);
 - let largeVideo;
 - 
 - const VideoLayout = {
 -     /**
 -      * Handler for local flip X changed event.
 -      */
 -     onLocalFlipXChanged() {
 -         if (largeVideo) {
 -             const { store } = APP;
 -             const { localFlipX } = store.getState()['features/base/settings'];
 - 
 -             largeVideo.onLocalFlipXChange(localFlipX);
 -         }
 -     },
 - 
 -     /**
 -      * Cleans up state of this singleton {@code VideoLayout}.
 -      *
 -      * @returns {void}
 -      */
 -     reset() {
 -         this._resetLargeVideo();
 -     },
 - 
 -     initLargeVideo() {
 -         this._resetLargeVideo();
 - 
 -         largeVideo = new LargeVideoManager();
 - 
 -         const { store } = APP;
 -         const { localFlipX } = store.getState()['features/base/settings'];
 - 
 -         if (typeof localFlipX === 'boolean') {
 -             largeVideo.onLocalFlipXChange(localFlipX);
 -         }
 -         largeVideo.updateContainerSize();
 -     },
 - 
 -     /**
 -      * Sets the audio level of the video elements associated to the given id.
 -      *
 -      * @param id the video identifier in the form it comes from the library
 -      * @param lvl the new audio level to update to
 -      */
 -     setAudioLevel(id, lvl) {
 -         if (largeVideo && id === largeVideo.id) {
 -             largeVideo.updateLargeVideoAudioLevel(lvl);
 -         }
 -     },
 - 
 -     /**
 -      * FIXME get rid of this method once muted indicator are reactified (by
 -      * making sure that user with no tracks is displayed as muted )
 -      *
 -      * If participant has no tracks will make the UI display muted status.
 -      * @param {string} participantId
 -      */
 -     updateVideoMutedForNoTracks(participantId) {
 -         const participant = APP.conference.getParticipantById(participantId);
 - 
 -         if (participant && !participant.getTracksByMediaType('video').length) {
 -             VideoLayout._updateLargeVideoIfDisplayed(participantId, true);
 -         }
 -     },
 - 
 -     /**
 -      * Return the type of the remote video.
 -      * @param id the id for the remote video
 -      * @returns {String} the video type video or screen.
 -      */
 -     getRemoteVideoType(id) {
 -         const state = APP.store.getState();
 -         const participant = getParticipantById(state, id);
 - 
 -         if (participant?.isFakeParticipant) {
 -             return VIDEO_TYPE.CAMERA;
 -         }
 - 
 -         const videoTrack = getTrackByMediaTypeAndParticipant(state['features/base/tracks'], MEDIA_TYPE.VIDEO, id);
 - 
 -         return videoTrack?.videoType;
 -     },
 - 
 -     getPinnedId() {
 -         const { id } = getPinnedParticipant(APP.store.getState()) || {};
 - 
 -         return id || null;
 -     },
 - 
 -     /**
 -      * Shows/hides warning about a user's connectivity issues.
 -      *
 -      * @param {string} id - The ID of the remote participant(MUC nickname).
 -      * @returns {void}
 -      */
 -     onParticipantConnectionStatusChanged(id) {
 -         if (APP.conference.isLocalId(id)) {
 - 
 -             return;
 -         }
 - 
 -         // We have to trigger full large video update to transition from
 -         // avatar to video on connectivity restored.
 -         this._updateLargeVideoIfDisplayed(id, true);
 -     },
 - 
 -     /**
 -      * On last N change event.
 -      *
 -      * @param endpointsLeavingLastN the list currently leaving last N
 -      * endpoints
 -      * @param endpointsEnteringLastN the list currently entering last N
 -      * endpoints
 -      */
 -     onLastNEndpointsChanged(endpointsLeavingLastN, endpointsEnteringLastN) {
 -         if (endpointsLeavingLastN) {
 -             endpointsLeavingLastN.forEach(this._updateLargeVideoIfDisplayed, this);
 -         }
 - 
 -         if (endpointsEnteringLastN) {
 -             endpointsEnteringLastN.forEach(this._updateLargeVideoIfDisplayed, this);
 -         }
 -     },
 - 
 -     /**
 -      * Resizes the video area.
 -      */
 -     resizeVideoArea() {
 -         if (largeVideo) {
 -             largeVideo.updateContainerSize();
 -             largeVideo.resize(false);
 -         }
 -     },
 - 
 -     changeUserAvatar(id, avatarUrl) {
 -         if (this.isCurrentlyOnLarge(id)) {
 -             largeVideo.updateAvatar(avatarUrl);
 -         }
 -     },
 - 
 -     isLargeVideoVisible() {
 -         return this.isLargeContainerTypeVisible(VIDEO_CONTAINER_TYPE);
 -     },
 - 
 -     /**
 -      * @return {LargeContainer} the currently displayed container on large
 -      * video.
 -      */
 -     getCurrentlyOnLargeContainer() {
 -         return largeVideo.getCurrentContainer();
 -     },
 - 
 -     isCurrentlyOnLarge(id) {
 -         return largeVideo && largeVideo.id === id;
 -     },
 - 
 -     updateLargeVideo(id, forceUpdate) {
 -         if (!largeVideo) {
 -             return;
 -         }
 -         const currentContainer = largeVideo.getCurrentContainer();
 -         const currentContainerType = largeVideo.getCurrentContainerType();
 -         const isOnLarge = this.isCurrentlyOnLarge(id);
 -         const state = APP.store.getState();
 -         const videoTrack = getTrackByMediaTypeAndParticipant(state['features/base/tracks'], MEDIA_TYPE.VIDEO, id);
 -         const videoStream = videoTrack?.jitsiTrack;
 - 
 -         if (isOnLarge && !forceUpdate
 -                 && LargeVideoManager.isVideoContainer(currentContainerType)
 -                 && videoStream) {
 -             const currentStreamId = currentContainer.getStreamID();
 -             const newStreamId = videoStream?.getId() || null;
 - 
 -             // FIXME it might be possible to get rid of 'forceUpdate' argument
 -             if (currentStreamId !== newStreamId) {
 -                 logger.debug('Enforcing large video update for stream change');
 -                 forceUpdate = true; // eslint-disable-line no-param-reassign
 -             }
 -         }
 - 
 -         if (!isOnLarge || forceUpdate) {
 -             const videoType = this.getRemoteVideoType(id);
 - 
 - 
 -             largeVideo.updateLargeVideo(
 -                 id,
 -                 videoStream,
 -                 videoType || VIDEO_TYPE.CAMERA
 -             ).catch(() => {
 -                 // do nothing
 -             });
 -         }
 -     },
 - 
 -     addLargeVideoContainer(type, container) {
 -         largeVideo && largeVideo.addContainer(type, container);
 -     },
 - 
 -     removeLargeVideoContainer(type) {
 -         largeVideo && largeVideo.removeContainer(type);
 -     },
 - 
 -     /**
 -      * @returns Promise
 -      */
 -     showLargeVideoContainer(type, show) {
 -         if (!largeVideo) {
 -             return Promise.reject();
 -         }
 - 
 -         const isVisible = this.isLargeContainerTypeVisible(type);
 - 
 -         if (isVisible === show) {
 -             return Promise.resolve();
 -         }
 - 
 -         let containerTypeToShow = type;
 - 
 -         // if we are hiding a container and there is focusedVideo
 -         // (pinned remote video) use its video type,
 -         // if not then use default type - large video
 - 
 -         if (!show) {
 -             const pinnedId = this.getPinnedId();
 - 
 -             if (pinnedId) {
 -                 containerTypeToShow = this.getRemoteVideoType(pinnedId);
 -             } else {
 -                 containerTypeToShow = VIDEO_CONTAINER_TYPE;
 -             }
 -         }
 - 
 -         return largeVideo.showContainer(containerTypeToShow);
 -     },
 - 
 -     isLargeContainerTypeVisible(type) {
 -         return largeVideo && largeVideo.state === type;
 -     },
 - 
 -     /**
 -      * Returns the id of the current video shown on large.
 -      * Currently used by tests (torture).
 -      */
 -     getLargeVideoID() {
 -         return largeVideo && largeVideo.id;
 -     },
 - 
 -     /**
 -      * Returns the the current video shown on large.
 -      * Currently used by tests (torture).
 -      */
 -     getLargeVideo() {
 -         return largeVideo;
 -     },
 - 
 -     /**
 -      * Returns the wrapper jquery selector for the largeVideo
 -      * @returns {JQuerySelector} the wrapper jquery selector for the largeVideo
 -      */
 -     getLargeVideoWrapper() {
 -         return this.getCurrentlyOnLargeContainer().$wrapper;
 -     },
 - 
 -     /**
 -      * Helper method to invoke when the video layout has changed and elements
 -      * have to be re-arranged and resized.
 -      *
 -      * @returns {void}
 -      */
 -     refreshLayout() {
 -         VideoLayout.resizeVideoArea();
 -     },
 - 
 -     /**
 -      * Cleans up any existing largeVideo instance.
 -      *
 -      * @private
 -      * @returns {void}
 -      */
 -     _resetLargeVideo() {
 -         if (largeVideo) {
 -             largeVideo.destroy();
 -         }
 - 
 -         largeVideo = null;
 -     },
 - 
 -     /**
 -      * Triggers an update of large video if the passed in participant is
 -      * currently displayed on large video.
 -      *
 -      * @param {string} participantId - The participant ID that should trigger an
 -      * update of large video if displayed.
 -      * @param {boolean} force - Whether or not the large video update should
 -      * happen no matter what.
 -      * @returns {void}
 -      */
 -     _updateLargeVideoIfDisplayed(participantId, force = false) {
 -         if (this.isCurrentlyOnLarge(participantId)) {
 -             this.updateLargeVideo(participantId, force);
 -         }
 -     },
 - 
 -     /**
 -      * Handles window resizes.
 -      */
 -     onResize() {
 -         VideoLayout.resizeVideoArea();
 -     }
 - };
 - 
 - export default VideoLayout;
 
 
  |