Updates the way we update large/small video, avatars and displayname. Fixes issue with not displying avatars in local or remote video when video muted. Fixes if pinned participant turns off video and when unpin we return to the correct dominant speaker.

This commit is contained in:
damencho 2016-01-14 10:28:24 -06:00
parent cb40ab5420
commit 0531daf541
7 changed files with 97 additions and 92 deletions

View File

@ -246,6 +246,7 @@ export default {
_createRoom () {
room = connection.initJitsiConference(APP.conference.roomName,
this._getConferenceOptions());
this.localId = room.myUserId();
localTracks.forEach((track) => {
if(track.isAudioTrack()) {
localAudio = track;
@ -258,7 +259,6 @@ export default {
});
roomLocker = createRoomLocker(room);
this._room = room; // FIXME do not use this
this.localId = room.myUserId();
let email = APP.settings.getEmail();
email && sendEmail(email);

View File

@ -258,20 +258,12 @@ JitsiConference.prototype.addTrack = function (track) {
if (track.startMuted) {
track.mute();
}
var muteHandler = this._fireMuteChangeEvent.bind(this, track);
var stopHandler = this.removeTrack.bind(this, track);
var audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
track.addEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
this.addEventListener(JitsiConferenceEvents.TRACK_REMOVED, function (someTrack) {
if (someTrack !== track) {
return;
}
track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
});
track.muteHandler = this._fireMuteChangeEvent.bind(this, track);
track.stopHandler = this.removeTrack.bind(this, track);
track.audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, track.muteHandler);
track.addEventListener(JitsiTrackEvents.TRACK_STOPPED, track.stopHandler);
track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, track.audioLevelHandler);
this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
}.bind(this));
};
@ -306,6 +298,9 @@ JitsiConference.prototype.removeTrack = function (track) {
}
this.room.removeStream(track.getOriginalStream(), function(){
this.rtc.removeLocalStream(track);
track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, track.muteHandler);
track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED, track.stopHandler);
track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, track.audioLevelHandler);
this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
}.bind(this));
};
@ -1303,7 +1298,6 @@ var LibJitsiMeet = {
}
};
require("es6-promise").polyfill()
//Setups the promise object.
window.Promise = window.Promise || require("es6-promise").Promise;
@ -1601,7 +1595,7 @@ DataChannels.prototype.onDataChannel = function (event) {
// selections so that it can do adaptive simulcast,
// we want the notification to trigger even if userJid is undefined,
// or null.
this.handleSelectedEndpointEvent(this.lastSelectedEndpoint);
self.handleSelectedEndpointEvent(self.lastSelectedEndpoint);
};
dataChannel.onerror = function (error) {
@ -1959,6 +1953,10 @@ JitsiRemoteTrack.prototype.constructor = JitsiRemoteTrack;
* @param value the muted status.
*/
JitsiRemoteTrack.prototype.setMute = function (value) {
if(this.muted === value)
return;
this.stream.muted = value;
this.muted = value;
this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
@ -5187,6 +5185,14 @@ var WEBAUDIO_ANALYZER_FFT_SIZE = 2048;
*/
var WEBAUDIO_ANALYZER_SMOOTING_TIME = 0.8;
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = null;
if(window.AudioContext) {
context = new AudioContext();
}
/**
* Converts time domain data array to audio level.
* @param samples the time domain data array.
@ -5238,7 +5244,6 @@ function animateLevel(newLevel, lastLevel) {
* @constructor
*/
function LocalStatsCollector(stream, interval, callback) {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
this.stream = stream;
this.intervalId = null;
this.intervalMilis = interval;
@ -5250,16 +5255,14 @@ function LocalStatsCollector(stream, interval, callback) {
* Starts the collecting the statistics.
*/
LocalStatsCollector.prototype.start = function () {
if (!window.AudioContext ||
if (!context ||
RTCBrowserType.isTemasysPluginUsed())
return;
var context = new AudioContext();
var analyser = context.createAnalyser();
analyser.smoothingTimeConstant = WEBAUDIO_ANALYZER_SMOOTING_TIME;
analyser.fftSize = WEBAUDIO_ANALYZER_FFT_SIZE;
var source = context.createMediaStreamSource(this.stream);
source.connect(analyser);

View File

@ -341,7 +341,7 @@ export default class LargeVideoManager {
return this.videoContainer.id;
}
updateLargeVideo (stream, videoType) {
updateLargeVideo (stream, videoType, largeVideoUpdatedCallBack) {
let id = getStreamId(stream);
let container = this.getContainer(this.state);
@ -351,6 +351,7 @@ export default class LargeVideoManager {
this.state = VideoContainerType;
this.videoContainer.setStream(stream, videoType);
this.videoContainer.show();
largeVideoUpdatedCallBack();
});
}

View File

@ -17,6 +17,7 @@ function LocalVideo(VideoLayout, emitter) {
this.flipX = true;
this.isLocal = true;
this.emitter = emitter;
SmallVideo.call(this);
}
LocalVideo.prototype = Object.create(SmallVideo.prototype);

View File

@ -24,6 +24,7 @@ function RemoteVideo(id, VideoLayout, emitter) {
this.bindHoverHandler();
this.flipX = false;
this.isLocal = false;
SmallVideo.call(this);
}
RemoteVideo.prototype = Object.create(SmallVideo.prototype);
@ -274,10 +275,10 @@ RemoteVideo.prototype.showPeerContainer = function (state) {
resizeThumbnails = true;
$(this.container).show();
}
// Call showAvatar with undefined, so that we'll figure out if avatar
// Call updateView, so that we'll figure out if avatar
// should be displayed based on video muted status and whether or not
// it's in the lastN set
this.showAvatar(undefined);
this.updateView();
}
else if ($(this.container).is(':visible') && isHide)
{

View File

@ -2,13 +2,13 @@
/* jshint -W101 */
import Avatar from "../avatar/Avatar";
import UIUtil from "../util/UIUtil";
import LargeVideo from "./LargeVideo";
var RTCBrowserType = require("../../RTC/RTCBrowserType");
function SmallVideo() {
this.isMuted = false;
this.hasAvatar = false;
this.isVideoMuted = false;
this.stream = null;
}
@ -203,10 +203,12 @@ SmallVideo.prototype.showAudioIndicator = function(isMuted) {
};
/**
* Shows video muted indicator over small videos.
* Shows video muted indicator over small videos and disables/enables avatar
* if video muted.
*/
SmallVideo.prototype.showVideoIndicator = function(isMuted) {
this.showAvatar(isMuted);
SmallVideo.prototype.setMutedView = function(isMuted) {
this.isVideoMuted = isMuted;
this.updateView();
var videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
@ -233,36 +235,9 @@ SmallVideo.prototype.showVideoIndicator = function(isMuted) {
}
this.updateIconPositions();
}
};
SmallVideo.prototype.enableDominantSpeaker = function (isEnable) {
var displayName = this.id;
var nameSpan = $('#' + this.videoSpanId + '>span.displayname');
if (nameSpan.length > 0)
displayName = nameSpan.html();
console.log("UI enable dominant speaker",
displayName,
this.id,
isEnable);
if (!this.container) {
return;
}
if (isEnable) {
this.showDisplayName(this.VideoLayout.isLargeVideoVisible());
}
else {
this.showDisplayName(false);
}
this.showAvatar();
};
SmallVideo.prototype.updateIconPositions = function () {
var audioMutedSpan = $('#' + this.videoSpanId + '>span.audioMuted');
var connectionIndicator = $('#' + this.videoSpanId + '>div.connectionindicator');
@ -310,15 +285,15 @@ SmallVideo.prototype.createModeratorIndicatorElement = function () {
};
SmallVideo.prototype.selectVideoElement = function () {
return $('#' + this.videoSpanId).find(videoElem);
// FIXME maybe move this to the library?
var videoElem = APP.RTC.getVideoElementName();
var videoElemName;
if (!RTCBrowserType.isTemasysPluginUsed()) {
return $('#' + this.videoSpanId).find(videoElem);
videoElemName = 'video';
return $('#' + this.videoSpanId).find(videoElemName);
} else {
videoElemName = 'object';
var matching = $('#' + this.videoSpanId +
(this.isLocal ? '>>' : '>') +
videoElem + '>param[value="video"]');
videoElemName + '>param[value="video"]');
if (matching.length < 2) {
return matching.parent();
}
@ -352,11 +327,12 @@ SmallVideo.prototype.hasVideo = function () {
};
/**
* Hides or shows the user's avatar
* Hides or shows the user's avatar.
*
* @param show whether we should show the avatar or not
* video because there is no dominant speaker and no focused speaker
*/
SmallVideo.prototype.showAvatar = function (show) {
SmallVideo.prototype.updateView = function () {
if (!this.hasAvatar) {
if (this.id) {
// Init avatar
@ -371,28 +347,31 @@ SmallVideo.prototype.showAvatar = function (show) {
let avatar = $(`#avatar_${this.id}`);
if (show === undefined || show === null) {
if (!this.isLocal &&
!this.VideoLayout.isInLastN(this.id)) {
show = true;
} else {
// We want to show the avatar when the video is muted or not exists
// that is when 'true' or 'null' is returned
show = !this.stream || this.stream.isMuted();
}
var showVideo = !this.isVideoMuted
&& !this.VideoLayout.isCurrentlyOnLarge(this.id);
var showAvatar;
if ((!this.isLocal &&
!this.VideoLayout.isInLastN(this.id)) ||
this.isVideoMuted) {
showAvatar = true;
} else {
// We want to show the avatar when the video is muted or not exists
// that is when 'true' or 'null' is returned
showAvatar = !this.stream || this.stream.isMuted();
}
if (this.VideoLayout.isCurrentlyOnLarge(this.id)
&& this.VideoLayout.isLargeVideoVisible()) {
if (video && video.length > 0) {
setVisibility(video, showVideo);
}
setVisibility(avatar, showAvatar);
this.VideoLayout.showLargeVideoAvatar(show);
setVisibility(avatar, false);
setVisibility(video, false);
} else {
if (video && video.length > 0) {
setVisibility(video, !show);
}
setVisibility(avatar, show);
var showDisplayName = !showVideo && !showAvatar;
if (showDisplayName) {
this.showDisplayName(this.VideoLayout.isLargeVideoVisible());
}
else {
this.showDisplayName(false);
}
};

View File

@ -2,6 +2,7 @@
/* jshint -W101 */
import AudioLevels from "../audio_levels/AudioLevels";
import Avatar from "../avatar/Avatar";
import BottomToolbar from "../toolbars/BottomToolbar";
import UIEvents from "../../../service/UI/UIEvents";
@ -262,6 +263,15 @@ var VideoLayout = {
onRemoteStreamAdded (stream) {
let id = stream.getParticipantId();
remoteVideos[id].addRemoteStreamElement(stream);
// if track is muted make sure we reflect that
if(stream.isMuted())
{
if(stream.getType() === "audio")
this.onAudioMute(stream.getParticipantId(), true);
else
this.onVideoMute(stream.getParticipantId(), true);
}
},
/**
@ -499,10 +509,10 @@ var VideoLayout = {
*/
onVideoMute (id, value) {
if (APP.conference.isLocalId(id)) {
localVideoThumbnail.showVideoIndicator(value);
localVideoThumbnail.setMutedView(value);
} else {
var remoteVideo = remoteVideos[id];
remoteVideo.showVideoIndicator(value);
remoteVideo.setMutedView(value);
var el = remoteVideo.selectVideoElement();
if (!value)
@ -510,6 +520,9 @@ var VideoLayout = {
else
el.hide();
}
if(this.isCurrentlyOnLarge(id))
largeVideo.showAvatar(value);
},
/**
@ -960,26 +973,33 @@ var VideoLayout = {
eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, id);
}
if (currentId) {
let currentSmallVideo = this.getSmallVideo(currentId);
currentSmallVideo && currentSmallVideo.enableDominantSpeaker(false);
var oldSmallVideo = this.getSmallVideo(currentId);
}
let smallVideo = this.getSmallVideo(id);
let videoType = this.getRemoteVideoType(id);
largeVideo.updateLargeVideo(smallVideo.stream, videoType);
largeVideo.updateLargeVideo(
smallVideo.stream,
videoType,
// LargeVideoUpdatedCallBack
function() {
// update current small video and the old one
smallVideo.updateView();
oldSmallVideo && oldSmallVideo.updateView();
// change the avatar url on large
largeVideo.updateAvatar(Avatar.getThumbUrl(smallVideo.id));
// show the avatar on large if needed
largeVideo.showAvatar(show);
});
smallVideo.enableDominantSpeaker(true);
} else if (currentId) {
let currentSmallVideo = this.getSmallVideo(currentId);
currentSmallVideo.showAvatar();
currentSmallVideo.updateView();
}
},
showLargeVideoAvatar (show) {
largeVideo && largeVideo.showAvatar(show);
},
addLargeVideoContainer (type, container) {
largeVideo && largeVideo.addContainer(type, container);
},