Browse Source

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.

master
damencho 9 years ago
parent
commit
0531daf541

+ 1
- 1
conference.js View File

246
     _createRoom () {
246
     _createRoom () {
247
         room = connection.initJitsiConference(APP.conference.roomName,
247
         room = connection.initJitsiConference(APP.conference.roomName,
248
             this._getConferenceOptions());
248
             this._getConferenceOptions());
249
+        this.localId = room.myUserId();
249
         localTracks.forEach((track) => {
250
         localTracks.forEach((track) => {
250
             if(track.isAudioTrack()) {
251
             if(track.isAudioTrack()) {
251
                 localAudio = track;
252
                 localAudio = track;
258
         });
259
         });
259
         roomLocker = createRoomLocker(room);
260
         roomLocker = createRoomLocker(room);
260
         this._room = room; // FIXME do not use this
261
         this._room = room; // FIXME do not use this
261
-        this.localId = room.myUserId();
262
 
262
 
263
         let email = APP.settings.getEmail();
263
         let email = APP.settings.getEmail();
264
         email && sendEmail(email);
264
         email && sendEmail(email);

+ 23
- 20
libs/lib-jitsi-meet.js View File

258
         if (track.startMuted) {
258
         if (track.startMuted) {
259
             track.mute();
259
             track.mute();
260
         }
260
         }
261
-        var muteHandler = this._fireMuteChangeEvent.bind(this, track);
262
-        var stopHandler = this.removeTrack.bind(this, track);
263
-        var audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
264
-        track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
265
-        track.addEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
266
-        track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
267
-        this.addEventListener(JitsiConferenceEvents.TRACK_REMOVED, function (someTrack) {
268
-            if (someTrack !== track) {
269
-                return;
270
-            }
271
-            track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
272
-            track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
273
-            track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
274
-        });
261
+        track.muteHandler = this._fireMuteChangeEvent.bind(this, track);
262
+        track.stopHandler = this.removeTrack.bind(this, track);
263
+        track.audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
264
+        track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, track.muteHandler);
265
+        track.addEventListener(JitsiTrackEvents.TRACK_STOPPED, track.stopHandler);
266
+        track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, track.audioLevelHandler);
275
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
267
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
276
     }.bind(this));
268
     }.bind(this));
277
 };
269
 };
306
     }
298
     }
307
     this.room.removeStream(track.getOriginalStream(), function(){
299
     this.room.removeStream(track.getOriginalStream(), function(){
308
         this.rtc.removeLocalStream(track);
300
         this.rtc.removeLocalStream(track);
301
+        track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, track.muteHandler);
302
+        track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED, track.stopHandler);
303
+        track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, track.audioLevelHandler);
309
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
304
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
310
     }.bind(this));
305
     }.bind(this));
311
 };
306
 };
1303
     }
1298
     }
1304
 };
1299
 };
1305
 
1300
 
1306
-require("es6-promise").polyfill()
1307
 //Setups the promise object.
1301
 //Setups the promise object.
1308
 window.Promise = window.Promise || require("es6-promise").Promise;
1302
 window.Promise = window.Promise || require("es6-promise").Promise;
1309
 
1303
 
1601
         // selections so that it can do adaptive simulcast,
1595
         // selections so that it can do adaptive simulcast,
1602
         // we want the notification to trigger even if userJid is undefined,
1596
         // we want the notification to trigger even if userJid is undefined,
1603
         // or null.
1597
         // or null.
1604
-        this.handleSelectedEndpointEvent(this.lastSelectedEndpoint);
1598
+        self.handleSelectedEndpointEvent(self.lastSelectedEndpoint);
1605
     };
1599
     };
1606
 
1600
 
1607
     dataChannel.onerror = function (error) {
1601
     dataChannel.onerror = function (error) {
1959
  * @param value the muted status.
1953
  * @param value the muted status.
1960
  */
1954
  */
1961
 JitsiRemoteTrack.prototype.setMute = function (value) {
1955
 JitsiRemoteTrack.prototype.setMute = function (value) {
1956
+
1957
+    if(this.muted === value)
1958
+        return;
1959
+
1962
     this.stream.muted = value;
1960
     this.stream.muted = value;
1963
     this.muted = value;
1961
     this.muted = value;
1964
     this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
1962
     this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
5187
  */
5185
  */
5188
 var WEBAUDIO_ANALYZER_SMOOTING_TIME = 0.8;
5186
 var WEBAUDIO_ANALYZER_SMOOTING_TIME = 0.8;
5189
 
5187
 
5188
+window.AudioContext = window.AudioContext || window.webkitAudioContext;
5189
+
5190
+var context = null;
5191
+
5192
+if(window.AudioContext) {
5193
+    context = new AudioContext();
5194
+}
5195
+
5190
 /**
5196
 /**
5191
  * Converts time domain data array to audio level.
5197
  * Converts time domain data array to audio level.
5192
  * @param samples the time domain data array.
5198
  * @param samples the time domain data array.
5238
  * @constructor
5244
  * @constructor
5239
  */
5245
  */
5240
 function LocalStatsCollector(stream, interval, callback) {
5246
 function LocalStatsCollector(stream, interval, callback) {
5241
-    window.AudioContext = window.AudioContext || window.webkitAudioContext;
5242
     this.stream = stream;
5247
     this.stream = stream;
5243
     this.intervalId = null;
5248
     this.intervalId = null;
5244
     this.intervalMilis = interval;
5249
     this.intervalMilis = interval;
5250
  * Starts the collecting the statistics.
5255
  * Starts the collecting the statistics.
5251
  */
5256
  */
5252
 LocalStatsCollector.prototype.start = function () {
5257
 LocalStatsCollector.prototype.start = function () {
5253
-    if (!window.AudioContext ||
5258
+    if (!context ||
5254
         RTCBrowserType.isTemasysPluginUsed())
5259
         RTCBrowserType.isTemasysPluginUsed())
5255
         return;
5260
         return;
5256
 
5261
 
5257
-    var context = new AudioContext();
5258
     var analyser = context.createAnalyser();
5262
     var analyser = context.createAnalyser();
5259
     analyser.smoothingTimeConstant = WEBAUDIO_ANALYZER_SMOOTING_TIME;
5263
     analyser.smoothingTimeConstant = WEBAUDIO_ANALYZER_SMOOTING_TIME;
5260
     analyser.fftSize = WEBAUDIO_ANALYZER_FFT_SIZE;
5264
     analyser.fftSize = WEBAUDIO_ANALYZER_FFT_SIZE;
5261
 
5265
 
5262
-
5263
     var source = context.createMediaStreamSource(this.stream);
5266
     var source = context.createMediaStreamSource(this.stream);
5264
     source.connect(analyser);
5267
     source.connect(analyser);
5265
 
5268
 

+ 2
- 1
modules/UI/videolayout/LargeVideo.js View File

341
         return this.videoContainer.id;
341
         return this.videoContainer.id;
342
     }
342
     }
343
 
343
 
344
-    updateLargeVideo (stream, videoType) {
344
+    updateLargeVideo (stream, videoType, largeVideoUpdatedCallBack) {
345
         let id = getStreamId(stream);
345
         let id = getStreamId(stream);
346
 
346
 
347
         let container = this.getContainer(this.state);
347
         let container = this.getContainer(this.state);
351
             this.state = VideoContainerType;
351
             this.state = VideoContainerType;
352
             this.videoContainer.setStream(stream, videoType);
352
             this.videoContainer.setStream(stream, videoType);
353
             this.videoContainer.show();
353
             this.videoContainer.show();
354
+            largeVideoUpdatedCallBack();
354
         });
355
         });
355
     }
356
     }
356
 
357
 

+ 1
- 0
modules/UI/videolayout/LocalVideo.js View File

17
     this.flipX = true;
17
     this.flipX = true;
18
     this.isLocal = true;
18
     this.isLocal = true;
19
     this.emitter = emitter;
19
     this.emitter = emitter;
20
+    SmallVideo.call(this);
20
 }
21
 }
21
 
22
 
22
 LocalVideo.prototype = Object.create(SmallVideo.prototype);
23
 LocalVideo.prototype = Object.create(SmallVideo.prototype);

+ 3
- 2
modules/UI/videolayout/RemoteVideo.js View File

24
     this.bindHoverHandler();
24
     this.bindHoverHandler();
25
     this.flipX = false;
25
     this.flipX = false;
26
     this.isLocal = false;
26
     this.isLocal = false;
27
+    SmallVideo.call(this);
27
 }
28
 }
28
 
29
 
29
 RemoteVideo.prototype = Object.create(SmallVideo.prototype);
30
 RemoteVideo.prototype = Object.create(SmallVideo.prototype);
274
             resizeThumbnails = true;
275
             resizeThumbnails = true;
275
             $(this.container).show();
276
             $(this.container).show();
276
         }
277
         }
277
-        // Call showAvatar with undefined, so that we'll figure out if avatar
278
+        // Call updateView, so that we'll figure out if avatar
278
         // should be displayed based on video muted status and whether or not
279
         // should be displayed based on video muted status and whether or not
279
         // it's in the lastN set
280
         // it's in the lastN set
280
-        this.showAvatar(undefined);
281
+        this.updateView();
281
     }
282
     }
282
     else if ($(this.container).is(':visible') && isHide)
283
     else if ($(this.container).is(':visible') && isHide)
283
     {
284
     {

+ 36
- 57
modules/UI/videolayout/SmallVideo.js View File

2
 /* jshint -W101 */
2
 /* jshint -W101 */
3
 import Avatar from "../avatar/Avatar";
3
 import Avatar from "../avatar/Avatar";
4
 import UIUtil from "../util/UIUtil";
4
 import UIUtil from "../util/UIUtil";
5
-import LargeVideo from "./LargeVideo";
6
 
5
 
7
 var RTCBrowserType = require("../../RTC/RTCBrowserType");
6
 var RTCBrowserType = require("../../RTC/RTCBrowserType");
8
 
7
 
9
 function SmallVideo() {
8
 function SmallVideo() {
10
     this.isMuted = false;
9
     this.isMuted = false;
11
     this.hasAvatar = false;
10
     this.hasAvatar = false;
11
+    this.isVideoMuted = false;
12
     this.stream = null;
12
     this.stream = null;
13
 }
13
 }
14
 
14
 
203
 };
203
 };
204
 
204
 
205
 /**
205
 /**
206
- * Shows video muted indicator over small videos.
206
+ * Shows video muted indicator over small videos and disables/enables avatar
207
+ * if video muted.
207
  */
208
  */
208
-SmallVideo.prototype.showVideoIndicator = function(isMuted) {
209
-    this.showAvatar(isMuted);
209
+SmallVideo.prototype.setMutedView = function(isMuted) {
210
+    this.isVideoMuted = isMuted;
211
+    this.updateView();
210
 
212
 
211
     var videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
213
     var videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
212
 
214
 
233
         }
235
         }
234
 
236
 
235
         this.updateIconPositions();
237
         this.updateIconPositions();
236
-
237
-    }
238
-};
239
-
240
-SmallVideo.prototype.enableDominantSpeaker = function (isEnable) {
241
-    var displayName = this.id;
242
-    var nameSpan = $('#' + this.videoSpanId + '>span.displayname');
243
-    if (nameSpan.length > 0)
244
-        displayName = nameSpan.html();
245
-
246
-    console.log("UI enable dominant speaker",
247
-        displayName,
248
-        this.id,
249
-        isEnable);
250
-
251
-
252
-    if (!this.container) {
253
-        return;
254
-    }
255
-
256
-    if (isEnable) {
257
-        this.showDisplayName(this.VideoLayout.isLargeVideoVisible());
258
-    }
259
-    else {
260
-        this.showDisplayName(false);
261
     }
238
     }
262
-
263
-    this.showAvatar();
264
 };
239
 };
265
 
240
 
266
 SmallVideo.prototype.updateIconPositions = function () {
241
 SmallVideo.prototype.updateIconPositions = function () {
310
 };
285
 };
311
 
286
 
312
 SmallVideo.prototype.selectVideoElement = function () {
287
 SmallVideo.prototype.selectVideoElement = function () {
313
-    return $('#' + this.videoSpanId).find(videoElem);
314
-    // FIXME maybe move this to the library?
315
-    var videoElem = APP.RTC.getVideoElementName();
288
+    var videoElemName;
316
     if (!RTCBrowserType.isTemasysPluginUsed()) {
289
     if (!RTCBrowserType.isTemasysPluginUsed()) {
317
-        return $('#' + this.videoSpanId).find(videoElem);
290
+        videoElemName = 'video';
291
+        return $('#' + this.videoSpanId).find(videoElemName);
318
     } else {
292
     } else {
293
+        videoElemName = 'object';
319
         var matching = $('#' + this.videoSpanId +
294
         var matching = $('#' + this.videoSpanId +
320
                          (this.isLocal ? '>>' : '>') +
295
                          (this.isLocal ? '>>' : '>') +
321
-                         videoElem + '>param[value="video"]');
296
+                         videoElemName + '>param[value="video"]');
322
         if (matching.length < 2) {
297
         if (matching.length < 2) {
323
             return matching.parent();
298
             return matching.parent();
324
         }
299
         }
352
 };
327
 };
353
 
328
 
354
 /**
329
 /**
355
- * Hides or shows the user's avatar
330
+ * Hides or shows the user's avatar.
331
+ *
356
  * @param show whether we should show the avatar or not
332
  * @param show whether we should show the avatar or not
357
  * video because there is no dominant speaker and no focused speaker
333
  * video because there is no dominant speaker and no focused speaker
358
  */
334
  */
359
-SmallVideo.prototype.showAvatar = function (show) {
335
+SmallVideo.prototype.updateView = function () {
360
     if (!this.hasAvatar) {
336
     if (!this.hasAvatar) {
361
         if (this.id) {
337
         if (this.id) {
362
             // Init avatar
338
             // Init avatar
371
 
347
 
372
     let avatar = $(`#avatar_${this.id}`);
348
     let avatar = $(`#avatar_${this.id}`);
373
 
349
 
374
-    if (show === undefined || show === null) {
375
-        if (!this.isLocal &&
376
-            !this.VideoLayout.isInLastN(this.id)) {
377
-            show = true;
378
-        } else {
379
-            // We want to show the avatar when the video is muted or not exists
380
-            // that is when 'true' or 'null' is returned
381
-            show = !this.stream || this.stream.isMuted();
382
-        }
350
+    var showVideo = !this.isVideoMuted
351
+                        && !this.VideoLayout.isCurrentlyOnLarge(this.id);
352
+    var showAvatar;
353
+    if ((!this.isLocal &&
354
+        !this.VideoLayout.isInLastN(this.id)) ||
355
+        this.isVideoMuted) {
356
+        showAvatar = true;
357
+    } else {
358
+        // We want to show the avatar when the video is muted or not exists
359
+        // that is when 'true' or 'null' is returned
360
+        showAvatar = !this.stream || this.stream.isMuted();
361
+    }
362
+
363
+    if (video && video.length > 0) {
364
+        setVisibility(video, showVideo);
383
     }
365
     }
366
+    setVisibility(avatar, showAvatar);
384
 
367
 
385
-    if (this.VideoLayout.isCurrentlyOnLarge(this.id)
386
-        && this.VideoLayout.isLargeVideoVisible()) {
368
+    var showDisplayName = !showVideo && !showAvatar;
387
 
369
 
388
-        this.VideoLayout.showLargeVideoAvatar(show);
389
-        setVisibility(avatar, false);
390
-        setVisibility(video, false);
391
-    } else {
392
-        if (video && video.length > 0) {
393
-            setVisibility(video, !show);
394
-        }
395
-        setVisibility(avatar, show);
370
+    if (showDisplayName) {
371
+        this.showDisplayName(this.VideoLayout.isLargeVideoVisible());
372
+    }
373
+    else {
374
+        this.showDisplayName(false);
396
     }
375
     }
397
 };
376
 };
398
 
377
 

+ 31
- 11
modules/UI/videolayout/VideoLayout.js View File

2
 /* jshint -W101 */
2
 /* jshint -W101 */
3
 
3
 
4
 import AudioLevels from "../audio_levels/AudioLevels";
4
 import AudioLevels from "../audio_levels/AudioLevels";
5
+import Avatar from "../avatar/Avatar";
5
 import BottomToolbar from "../toolbars/BottomToolbar";
6
 import BottomToolbar from "../toolbars/BottomToolbar";
6
 
7
 
7
 import UIEvents from "../../../service/UI/UIEvents";
8
 import UIEvents from "../../../service/UI/UIEvents";
262
     onRemoteStreamAdded (stream) {
263
     onRemoteStreamAdded (stream) {
263
         let id = stream.getParticipantId();
264
         let id = stream.getParticipantId();
264
         remoteVideos[id].addRemoteStreamElement(stream);
265
         remoteVideos[id].addRemoteStreamElement(stream);
266
+
267
+        // if track is muted make sure we reflect that
268
+        if(stream.isMuted())
269
+        {
270
+            if(stream.getType() === "audio")
271
+                this.onAudioMute(stream.getParticipantId(), true);
272
+            else
273
+                this.onVideoMute(stream.getParticipantId(), true);
274
+        }
265
     },
275
     },
266
 
276
 
267
     /**
277
     /**
499
      */
509
      */
500
     onVideoMute (id, value) {
510
     onVideoMute (id, value) {
501
         if (APP.conference.isLocalId(id)) {
511
         if (APP.conference.isLocalId(id)) {
502
-            localVideoThumbnail.showVideoIndicator(value);
512
+            localVideoThumbnail.setMutedView(value);
503
         } else {
513
         } else {
504
             var remoteVideo = remoteVideos[id];
514
             var remoteVideo = remoteVideos[id];
505
-            remoteVideo.showVideoIndicator(value);
515
+            remoteVideo.setMutedView(value);
506
 
516
 
507
             var el = remoteVideo.selectVideoElement();
517
             var el = remoteVideo.selectVideoElement();
508
             if (!value)
518
             if (!value)
510
             else
520
             else
511
                 el.hide();
521
                 el.hide();
512
         }
522
         }
523
+
524
+        if(this.isCurrentlyOnLarge(id))
525
+            largeVideo.showAvatar(value);
513
     },
526
     },
514
 
527
 
515
     /**
528
     /**
960
                 eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, id);
973
                 eventEmitter.emit(UIEvents.SELECTED_ENDPOINT, id);
961
             }
974
             }
962
             if (currentId) {
975
             if (currentId) {
963
-                let currentSmallVideo = this.getSmallVideo(currentId);
964
-                currentSmallVideo && currentSmallVideo.enableDominantSpeaker(false);
976
+                var oldSmallVideo = this.getSmallVideo(currentId);
965
             }
977
             }
966
 
978
 
967
             let smallVideo = this.getSmallVideo(id);
979
             let smallVideo = this.getSmallVideo(id);
968
 
980
 
969
             let videoType = this.getRemoteVideoType(id);
981
             let videoType = this.getRemoteVideoType(id);
970
-            largeVideo.updateLargeVideo(smallVideo.stream, videoType);
982
+            largeVideo.updateLargeVideo(
983
+                smallVideo.stream,
984
+                videoType,
985
+                // LargeVideoUpdatedCallBack
986
+                function() {
987
+                    // update current small video and the old one
988
+                    smallVideo.updateView();
989
+                    oldSmallVideo && oldSmallVideo.updateView();
990
+
991
+                    // change the avatar url on large
992
+                    largeVideo.updateAvatar(Avatar.getThumbUrl(smallVideo.id));
993
+                    // show the avatar on large if needed
994
+                    largeVideo.showAvatar(show);
995
+                });
971
 
996
 
972
-            smallVideo.enableDominantSpeaker(true);
973
         } else if (currentId) {
997
         } else if (currentId) {
974
             let currentSmallVideo = this.getSmallVideo(currentId);
998
             let currentSmallVideo = this.getSmallVideo(currentId);
975
-            currentSmallVideo.showAvatar();
999
+            currentSmallVideo.updateView();
976
         }
1000
         }
977
     },
1001
     },
978
 
1002
 
979
-    showLargeVideoAvatar (show) {
980
-        largeVideo && largeVideo.showAvatar(show);
981
-    },
982
-
983
     addLargeVideoContainer (type, container) {
1003
     addLargeVideoContainer (type, container) {
984
         largeVideo && largeVideo.addContainer(type, container);
1004
         largeVideo && largeVideo.addContainer(type, container);
985
     },
1005
     },

Loading…
Cancel
Save