|
@@ -26,6 +26,18 @@ const VIDEO_RESOLUTION_POLL_INTERVAL = 2000;
|
26
|
26
|
* Manager for all Large containers.
|
27
|
27
|
*/
|
28
|
28
|
export default class LargeVideoManager {
|
|
29
|
+ /**
|
|
30
|
+ * Checks whether given container is a {@link VIDEO_CONTAINER_TYPE}.
|
|
31
|
+ * FIXME currently this is a workaround for the problem where video type is
|
|
32
|
+ * mixed up with container type.
|
|
33
|
+ * @param {string} containerType
|
|
34
|
+ * @return {boolean}
|
|
35
|
+ */
|
|
36
|
+ static isVideoContainer(containerType) {
|
|
37
|
+ return containerType === VIDEO_CONTAINER_TYPE
|
|
38
|
+ || containerType === DESKTOP_CONTAINER_TYPE;
|
|
39
|
+ }
|
|
40
|
+
|
29
|
41
|
constructor (emitter) {
|
30
|
42
|
/**
|
31
|
43
|
* The map of <tt>LargeContainer</tt>s where the key is the video
|
|
@@ -116,7 +128,8 @@ export default class LargeVideoManager {
|
116
|
128
|
this.enableLocalConnectionProblemFilter(true);
|
117
|
129
|
this._setLocalConnectionMessage("connection.RECONNECTING");
|
118
|
130
|
// Show the message only if the video is currently being displayed
|
119
|
|
- this.showLocalConnectionMessage(this.state === VIDEO_CONTAINER_TYPE);
|
|
131
|
+ this.showLocalConnectionMessage(
|
|
132
|
+ LargeVideoManager.isVideoContainer(this.state));
|
120
|
133
|
}
|
121
|
134
|
|
122
|
135
|
/**
|
|
@@ -146,7 +159,12 @@ export default class LargeVideoManager {
|
146
|
159
|
|
147
|
160
|
preUpdate.then(() => {
|
148
|
161
|
const { id, stream, videoType, resolve } = this.newStreamData;
|
149
|
|
- const isVideoFromCamera = videoType === VIDEO_CONTAINER_TYPE;
|
|
162
|
+
|
|
163
|
+ // FIXME this does not really make sense, because the videoType
|
|
164
|
+ // (camera or desktop) is a completely different thing than
|
|
165
|
+ // the video container type (Etherpad, SharedVideo, VideoContainer).
|
|
166
|
+ const isVideoContainer
|
|
167
|
+ = LargeVideoManager.isVideoContainer(videoType);
|
150
|
168
|
|
151
|
169
|
this.newStreamData = null;
|
152
|
170
|
|
|
@@ -158,34 +176,26 @@ export default class LargeVideoManager {
|
158
|
176
|
// change the avatar url on large
|
159
|
177
|
this.updateAvatar(Avatar.getAvatarUrl(id));
|
160
|
178
|
|
161
|
|
- // FIXME that does not really make sense, because the videoType
|
162
|
|
- // (camera or desktop) is a completely different thing than
|
163
|
|
- // the video container type (Etherpad, SharedVideo, VideoContainer).
|
164
|
|
- // ----------------------------------------------------------------
|
165
|
|
- // If the container is VIDEO_CONTAINER_TYPE, we need to check
|
166
|
|
- // its stream whether exist and is muted to set isVideoMuted
|
167
|
|
- // in rest of the cases it is false
|
168
|
|
- let showAvatar = isVideoFromCamera && (!stream || stream.isMuted());
|
169
|
|
-
|
170
|
179
|
// If the user's connection is disrupted then the avatar will be
|
171
|
180
|
// displayed in case we have no video image cached. That is if
|
172
|
|
- // there was a user switch(image is lost on stream detach) or if
|
|
181
|
+ // there was a user switch (image is lost on stream detach) or if
|
173
|
182
|
// the video was not rendered, before the connection has failed.
|
174
|
|
- const isConnectionActive = this._isConnectionActive(id);
|
175
|
|
-
|
176
|
|
- if (isVideoFromCamera
|
177
|
|
- && !isConnectionActive
|
178
|
|
- && (isUserSwitch || !container.wasVideoRendered)) {
|
179
|
|
- showAvatar = true;
|
180
|
|
- }
|
181
|
|
-
|
182
|
|
- // If audio only mode is enabled, always show the avatar for
|
183
|
|
- // videos from another participant.
|
184
|
|
- if (APP.conference.isAudioOnly()
|
185
|
|
- && (isVideoFromCamera
|
186
|
|
- || videoType === DESKTOP_CONTAINER_TYPE)) {
|
187
|
|
- showAvatar = true;
|
188
|
|
- }
|
|
183
|
+ const wasUsersImageCached
|
|
184
|
+ = !isUserSwitch && container.wasVideoRendered;
|
|
185
|
+ const isVideoMuted = !stream || stream.isMuted();
|
|
186
|
+
|
|
187
|
+ const connectionStatus
|
|
188
|
+ = APP.conference.getParticipantConnectionStatus(id);
|
|
189
|
+ const isVideoRenderable
|
|
190
|
+ = !isVideoMuted
|
|
191
|
+ && (APP.conference.isLocalId(id)
|
|
192
|
+ || connectionStatus
|
|
193
|
+ === ParticipantConnectionStatus.ACTIVE
|
|
194
|
+ || wasUsersImageCached);
|
|
195
|
+
|
|
196
|
+ let showAvatar
|
|
197
|
+ = isVideoContainer
|
|
198
|
+ && (APP.conference.isAudioOnly() || !isVideoRenderable);
|
189
|
199
|
|
190
|
200
|
let promise;
|
191
|
201
|
|
|
@@ -208,28 +218,31 @@ export default class LargeVideoManager {
|
208
|
218
|
this.updateLargeVideoAudioLevel(0);
|
209
|
219
|
}
|
210
|
220
|
|
|
221
|
+ const isConnectionInterrupted
|
|
222
|
+ = APP.conference.getParticipantConnectionStatus(id)
|
|
223
|
+ === ParticipantConnectionStatus.INTERRUPTED;
|
|
224
|
+ let messageKey = null;
|
|
225
|
+
|
|
226
|
+ if (isConnectionInterrupted) {
|
|
227
|
+ messageKey = "connection.USER_CONNECTION_INTERRUPTED";
|
|
228
|
+ } else if (connectionStatus
|
|
229
|
+ === ParticipantConnectionStatus.INACTIVE) {
|
|
230
|
+ messageKey = "connection.LOW_BANDWIDTH";
|
|
231
|
+ }
|
|
232
|
+
|
211
|
233
|
// Make sure no notification about remote failure is shown as
|
212
|
234
|
// its UI conflicts with the one for local connection interrupted.
|
213
|
235
|
// For the purposes of UI indicators, audio only is considered as
|
214
|
236
|
// an "active" connection.
|
215
|
|
- const isConnected
|
|
237
|
+ const overrideAndHide
|
216
|
238
|
= APP.conference.isAudioOnly()
|
217
|
|
- || APP.conference.isConnectionInterrupted()
|
218
|
|
- || isConnectionActive;
|
219
|
|
-
|
220
|
|
- // when isHavingConnectivityIssues, state can be inactive,
|
221
|
|
- // interrupted or restoring. We show different message for
|
222
|
|
- // interrupted and the rest.
|
223
|
|
- const isConnectionInterrupted =
|
224
|
|
- APP.conference.getParticipantConnectionStatus(id)
|
225
|
|
- === ParticipantConnectionStatus.INTERRUPTED;
|
|
239
|
+ || APP.conference.isConnectionInterrupted();
|
226
|
240
|
|
227
|
241
|
this.updateParticipantConnStatusIndication(
|
228
|
242
|
id,
|
229
|
|
- isConnected,
|
230
|
|
- (isConnectionInterrupted)
|
231
|
|
- ? "connection.USER_CONNECTION_INTERRUPTED"
|
232
|
|
- : "connection.LOW_BANDWIDTH");
|
|
243
|
+ !overrideAndHide && isConnectionInterrupted,
|
|
244
|
+ !overrideAndHide && messageKey !== null,
|
|
245
|
+ messageKey);
|
233
|
246
|
|
234
|
247
|
// resolve updateLargeVideo promise after everything is done
|
235
|
248
|
promise.then(resolve);
|
|
@@ -265,18 +278,20 @@ export default class LargeVideoManager {
|
265
|
278
|
* shown on the large video area.
|
266
|
279
|
*
|
267
|
280
|
* @param {string} id the id of remote participant(MUC nickname)
|
268
|
|
- * @param {boolean} isConnected true if the connection is active or false
|
269
|
|
- * when the user is having connectivity issues.
|
|
281
|
+ * @param {boolean} showProblemsIndication
|
|
282
|
+ * @param {boolean} showMessage
|
270
|
283
|
* @param {string} messageKey the i18n key of the message
|
271
|
284
|
*
|
272
|
285
|
* @private
|
273
|
286
|
*/
|
274
|
|
- updateParticipantConnStatusIndication (id, isConnected, messageKey) {
|
|
287
|
+ updateParticipantConnStatusIndication (
|
|
288
|
+ id, showProblemsIndication, showMessage, messageKey) {
|
275
|
289
|
|
276
|
290
|
// Apply grey filter on the large video
|
277
|
|
- this.videoContainer.showRemoteConnectionProblemIndicator(!isConnected);
|
|
291
|
+ this.videoContainer.showRemoteConnectionProblemIndicator(
|
|
292
|
+ showProblemsIndication);
|
278
|
293
|
|
279
|
|
- if (isConnected) {
|
|
294
|
+ if (!showMessage) {
|
280
|
295
|
// Hide the message
|
281
|
296
|
this.showRemoteConnectionMessage(false);
|
282
|
297
|
} else {
|
|
@@ -289,7 +304,7 @@ export default class LargeVideoManager {
|
289
|
304
|
|
290
|
305
|
// Show it now only if the VideoContainer is on top
|
291
|
306
|
this.showRemoteConnectionMessage(
|
292
|
|
- this.state === VIDEO_CONTAINER_TYPE);
|
|
307
|
+ LargeVideoManager.isVideoContainer(this.state));
|
293
|
308
|
}
|
294
|
309
|
}
|
295
|
310
|
|
|
@@ -412,15 +427,20 @@ export default class LargeVideoManager {
|
412
|
427
|
* Shows hides the "avatar" message which is to be displayed either in
|
413
|
428
|
* the middle of the screen or below the avatar image.
|
414
|
429
|
*
|
415
|
|
- * @param {null|boolean} show (optional) <tt>true</tt> to show the avatar
|
|
430
|
+ * @param {null|boolean} [show=null] <tt>true</tt> to show the avatar
|
416
|
431
|
* message or <tt>false</tt> to hide it. If not provided then the connection
|
417
|
432
|
* status of the user currently on the large video will be obtained form
|
418
|
433
|
* "APP.conference" and the message will be displayed if the user's
|
419
|
|
- * connection is interrupted.
|
|
434
|
+ * connection is either interrupted or inactive.
|
420
|
435
|
*/
|
421
|
436
|
showRemoteConnectionMessage (show) {
|
422
|
437
|
if (typeof show !== 'boolean') {
|
423
|
|
- show = !this._isConnectionActive(this.id);
|
|
438
|
+ const connStatus
|
|
439
|
+ = APP.conference.getParticipantConnectionStatus(this.id);
|
|
440
|
+
|
|
441
|
+ show = !APP.conference.isLocalId(this.id)
|
|
442
|
+ && (connStatus === ParticipantConnectionStatus.INTERRUPTED
|
|
443
|
+ || connStatus === ParticipantConnectionStatus.INACTIVE);
|
424
|
444
|
}
|
425
|
445
|
|
426
|
446
|
if (show) {
|
|
@@ -526,7 +546,7 @@ export default class LargeVideoManager {
|
526
|
546
|
// FIXME when video is being replaced with other content we need to hide
|
527
|
547
|
// companion icons/messages. It would be best if the container would
|
528
|
548
|
// be taking care of it by itself, but that is a bigger refactoring
|
529
|
|
- if (this.state === VIDEO_CONTAINER_TYPE) {
|
|
549
|
+ if (LargeVideoManager.isVideoContainer(this.state)) {
|
530
|
550
|
this.showWatermark(false);
|
531
|
551
|
this.showLocalConnectionMessage(false);
|
532
|
552
|
this.showRemoteConnectionMessage(false);
|
|
@@ -537,7 +557,7 @@ export default class LargeVideoManager {
|
537
|
557
|
let container = this.getContainer(type);
|
538
|
558
|
|
539
|
559
|
return container.show().then(() => {
|
540
|
|
- if (type === VIDEO_CONTAINER_TYPE) {
|
|
560
|
+ if (LargeVideoManager.isVideoContainer(type)) {
|
541
|
561
|
// FIXME when video appears on top of other content we need to
|
542
|
562
|
// show companion icons/messages. It would be best if
|
543
|
563
|
// the container would be taking care of it by itself, but that
|