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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,6 +2,7 @@
/* jshint -W101 */ /* jshint -W101 */
import AudioLevels from "../audio_levels/AudioLevels"; import AudioLevels from "../audio_levels/AudioLevels";
import Avatar from "../avatar/Avatar";
import BottomToolbar from "../toolbars/BottomToolbar"; import BottomToolbar from "../toolbars/BottomToolbar";
import UIEvents from "../../../service/UI/UIEvents"; import UIEvents from "../../../service/UI/UIEvents";
@ -262,6 +263,15 @@ var VideoLayout = {
onRemoteStreamAdded (stream) { onRemoteStreamAdded (stream) {
let id = stream.getParticipantId(); let id = stream.getParticipantId();
remoteVideos[id].addRemoteStreamElement(stream); 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) { onVideoMute (id, value) {
if (APP.conference.isLocalId(id)) { if (APP.conference.isLocalId(id)) {
localVideoThumbnail.showVideoIndicator(value); localVideoThumbnail.setMutedView(value);
} else { } else {
var remoteVideo = remoteVideos[id]; var remoteVideo = remoteVideos[id];
remoteVideo.showVideoIndicator(value); remoteVideo.setMutedView(value);
var el = remoteVideo.selectVideoElement(); var el = remoteVideo.selectVideoElement();
if (!value) if (!value)
@ -510,6 +520,9 @@ var VideoLayout = {
else else
el.hide(); el.hide();
} }
if(this.isCurrentlyOnLarge(id))
largeVideo.showAvatar(value);
}, },
/** /**
@ -960,26 +973,33 @@ var VideoLayout = {
eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, id); eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, id);
} }
if (currentId) { if (currentId) {
let currentSmallVideo = this.getSmallVideo(currentId); var oldSmallVideo = this.getSmallVideo(currentId);
currentSmallVideo && currentSmallVideo.enableDominantSpeaker(false);
} }
let smallVideo = this.getSmallVideo(id); let smallVideo = this.getSmallVideo(id);
let videoType = this.getRemoteVideoType(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) { } else if (currentId) {
let currentSmallVideo = this.getSmallVideo(currentId); let currentSmallVideo = this.getSmallVideo(currentId);
currentSmallVideo.showAvatar(); currentSmallVideo.updateView();
} }
}, },
showLargeVideoAvatar (show) {
largeVideo && largeVideo.showAvatar(show);
},
addLargeVideoContainer (type, container) { addLargeVideoContainer (type, container) {
largeVideo && largeVideo.addContainer(type, container); largeVideo && largeVideo.addContainer(type, container);
}, },