diff --git a/modules/UI/videolayout/LargeContainer.js b/modules/UI/videolayout/LargeContainer.js
index 319ccef62..cc80f3f42 100644
--- a/modules/UI/videolayout/LargeContainer.js
+++ b/modules/UI/videolayout/LargeContainer.js
@@ -38,4 +38,20 @@ export default class LargeContainer {
*/
onHoverOut (e) {
}
+
+ /**
+ * Update video stream.
+ * @param {JitsiTrack?} stream new stream
+ * @param {string} videoType video type
+ */
+ setStream (stream, videoType) {
+ }
+
+ /**
+ * Show or hide user avatar.
+ * @param {boolean} show
+ */
+ showAvatar (show) {
+ }
+
}
diff --git a/modules/UI/videolayout/LargeVideo.js b/modules/UI/videolayout/LargeVideo.js
index 9f27bb8b2..88d74cd65 100644
--- a/modules/UI/videolayout/LargeVideo.js
+++ b/modules/UI/videolayout/LargeVideo.js
@@ -150,7 +150,7 @@ function getDesktopVideoPosition(videoWidth,
return { horizontalIndent, verticalIndent };
}
-export const VideoContainerType = "video";
+export const VideoContainerType = "camera";
/**
* Container for user video.
@@ -332,6 +332,10 @@ class VideoContainer extends LargeContainer {
}
hide () {
+ // as the container is hidden/replaced by another container
+ // hide its avatar
+ this.showAvatar(false);
+
// its already hidden
if (!this.isVisible) {
return Promise.resolve();
@@ -357,6 +361,8 @@ export default class LargeVideoManager {
this.state = VideoContainerType;
this.videoContainer = new VideoContainer(() => this.resizeContainer(VideoContainerType));
this.addContainer(VideoContainerType, this.videoContainer);
+ // use the same video container to handle and desktop tracks
+ this.addContainer("desktop", this.videoContainer);
this.width = 0;
this.height = 0;
@@ -413,7 +419,8 @@ export default class LargeVideoManager {
}
get id () {
- return this.videoContainer.id;
+ let container = this.getContainer(this.state);
+ return container.id;
}
scheduleLargeVideoUpdate () {
@@ -430,8 +437,9 @@ export default class LargeVideoManager {
this.newStreamData = null;
console.info("hover in %s", id);
- this.state = VideoContainerType;
- this.videoContainer.setStream(stream, videoType);
+ this.state = videoType;
+ let container = this.getContainer(this.state);
+ container.setStream(stream, videoType);
// change the avatar url on large
this.updateAvatar(Avatar.getAvatarUrl(id));
@@ -439,7 +447,7 @@ export default class LargeVideoManager {
let isVideoMuted = stream ? stream.isMuted() : true;
// show the avatar on large if needed
- this.videoContainer.showAvatar(isVideoMuted);
+ container.showAvatar(isVideoMuted);
let promise;
@@ -449,7 +457,7 @@ export default class LargeVideoManager {
this.showWatermark(true);
promise = Promise.resolve();
} else {
- promise = this.videoContainer.show();
+ promise = container.show();
}
// resolve updateLargeVideo promise after everything is done
@@ -529,7 +537,8 @@ export default class LargeVideoManager {
* @param enable true to enable, false to disable
*/
enableVideoProblemFilter (enable) {
- this.videoContainer.$video.toggleClass("videoProblemFilter", enable);
+ let container = this.getContainer(this.state);
+ container.$video.toggleClass("videoProblemFilter", enable);
}
/**
diff --git a/modules/UI/videolayout/LocalVideo.js b/modules/UI/videolayout/LocalVideo.js
index c108e3252..380e9d7cc 100644
--- a/modules/UI/videolayout/LocalVideo.js
+++ b/modules/UI/videolayout/LocalVideo.js
@@ -13,7 +13,6 @@ function LocalVideo(VideoLayout, emitter) {
this.videoSpanId = "localVideoContainer";
this.container = $("#localVideoContainer").get(0);
this.bindHoverHandler();
- this.VideoLayout = VideoLayout;
this.flipX = true;
this.isLocal = true;
this.emitter = emitter;
@@ -22,7 +21,7 @@ function LocalVideo(VideoLayout, emitter) {
return APP.conference.localId;
}
});
- SmallVideo.call(this);
+ SmallVideo.call(this, VideoLayout);
}
LocalVideo.prototype = Object.create(SmallVideo.prototype);
diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js
index d9f4dae10..60c9fbcf9 100644
--- a/modules/UI/videolayout/RemoteVideo.js
+++ b/modules/UI/videolayout/RemoteVideo.js
@@ -11,14 +11,13 @@ function RemoteVideo(id, VideoLayout, emitter) {
this.id = id;
this.emitter = emitter;
this.videoSpanId = `participant_${id}`;
- this.VideoLayout = VideoLayout;
+ SmallVideo.call(this, VideoLayout);
this.addRemoteVideoContainer();
this.connectionIndicator = new ConnectionIndicator(this, id);
this.setDisplayName();
this.bindHoverHandler();
this.flipX = false;
this.isLocal = false;
- SmallVideo.call(this);
}
RemoteVideo.prototype = Object.create(SmallVideo.prototype);
diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js
index e55eafec6..fa5bac0bf 100644
--- a/modules/UI/videolayout/SmallVideo.js
+++ b/modules/UI/videolayout/SmallVideo.js
@@ -5,12 +5,13 @@ import UIUtil from "../util/UIUtil";
const RTCUIHelper = JitsiMeetJS.util.RTCUIHelper;
-function SmallVideo() {
+function SmallVideo(VideoLayout) {
this.isMuted = false;
this.hasAvatar = false;
this.isVideoMuted = false;
this.videoStream = null;
this.audioStream = null;
+ this.VideoLayout = VideoLayout;
}
function setVisibility(selector, show) {
diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js
index 1dd96d20e..31adc8ae1 100644
--- a/modules/UI/videolayout/VideoLayout.js
+++ b/modules/UI/videolayout/VideoLayout.js
@@ -16,7 +16,6 @@ import PanelToggler from "../side_pannels/SidePanelToggler";
const RTCUIUtil = JitsiMeetJS.util.RTCUIHelper;
var remoteVideos = {};
-var remoteVideoTypes = {};
var localVideoThumbnail = null;
var currentDominantSpeaker = null;
@@ -277,10 +276,11 @@ var VideoLayout = {
/**
* Return the type of the remote video.
* @param id the id for the remote video
- * @returns the video type video or screen.
+ * @returns {String} the video type video or screen.
*/
getRemoteVideoType (id) {
- return remoteVideoTypes[id];
+ let smallVideo = VideoLayout.getSmallVideo(id);
+ return smallVideo ? smallVideo.getVideoType() : null;
},
handleVideoThumbClicked (noPinnedEndpointChangedEvent,
@@ -326,22 +326,26 @@ var VideoLayout = {
this.updateLargeVideo(resourceJid);
},
-
/**
- * Checks if container for participant identified by given id exists
- * in the document and creates it eventually.
- *
- * @return Returns true if the peer container exists,
- * false - otherwise
+ * Creates a remote video for participant for the given id.
+ * @param id the id of the participant to add
+ * @param {SmallVideo} smallVideo optional small video instance to add as a
+ * remote video, if undefined RemoteVideo will be created
*/
- addParticipantContainer (id) {
- let remoteVideo = new RemoteVideo(id, VideoLayout, eventEmitter);
+ addParticipantContainer (id, smallVideo) {
+ let remoteVideo;
+ if(smallVideo)
+ remoteVideo = smallVideo;
+ else
+ remoteVideo = new RemoteVideo(id, VideoLayout, eventEmitter);
remoteVideos[id] = remoteVideo;
- let videoType = remoteVideoTypes[id];
- if (videoType) {
- remoteVideo.setVideoType(videoType);
+ let videoType = VideoLayout.getRemoteVideoType(id);
+ if (!videoType) {
+ // make video type the default one (camera)
+ videoType = VideoContainerType;
}
+ remoteVideo.setVideoType(videoType);
// In case this is not currently in the last n we don't show it.
if (localLastNCount && localLastNCount > 0 &&
@@ -752,12 +756,11 @@ var VideoLayout = {
},
onVideoTypeChanged (id, newVideoType) {
- if (remoteVideoTypes[id] === newVideoType) {
+ if (VideoLayout.getRemoteVideoType(id) === newVideoType) {
return;
}
console.info("Peer video type changed: ", id, newVideoType);
- remoteVideoTypes[id] = newVideoType;
var smallVideo;
if (APP.conference.isLocalId(id)) {
@@ -771,8 +774,8 @@ var VideoLayout = {
} else {
return;
}
-
smallVideo.setVideoType(newVideoType);
+
if (this.isCurrentlyOnLarge(id)) {
this.updateLargeVideo(id, true);
}