Ver código fonte

audio-only: implement initial "low bandwidth mode"

It's an evolution of audio-only mode, where we also allow for receiving a remote
screen-share.

Diving deeper: this basically sets last N to 1 or 0 depending on the
availability of a screen-share.
master
Saúl Ibarra Corretgé 6 anos atrás
pai
commit
f3e7952e51

+ 5
- 5
lang/main.json Ver arquivo

@@ -24,7 +24,7 @@
24 24
         "speaker": "Speaker"
25 25
     },
26 26
     "audioOnly": {
27
-        "audioOnly": "Audio only"
27
+        "audioOnly": "Low bandwidth"
28 28
     },
29 29
     "calendarSync": {
30 30
         "addMeetingURL": "Add a meeting link",
@@ -584,8 +584,8 @@
584 584
             "videoblur": "Toggle video blur"
585 585
         },
586 586
         "addPeople": "Add people to your call",
587
-        "audioOnlyOff": "Disable audio only mode",
588
-        "audioOnlyOn": "Enable audio only mode",
587
+        "audioOnlyOff": "Disable low bandwidth mode",
588
+        "audioOnlyOn": "Enable low bandwidth mode",
589 589
         "audioRoute": "Select the sound device",
590 590
         "authenticate": "Authenticate",
591 591
         "callQuality": "Manage video quality",
@@ -663,13 +663,13 @@
663 663
     },
664 664
     "videoStatus": {
665 665
         "audioOnly": "AUD",
666
-        "audioOnlyExpanded": "You are in audio only mode. This mode saves bandwidth but you won't see videos of others.",
666
+        "audioOnlyExpanded": "You are in low bandwidth mode. In this mode you will receive only audio and screen sharing.",
667 667
         "callQuality": "Video Quality",
668 668
         "hd": "HD",
669 669
         "hdTooltip": "Viewing high definition video",
670 670
         "highDefinition": "High definition",
671 671
         "labelTooiltipNoVideo": "No video",
672
-        "labelTooltipAudioOnly": "Audio-only mode enabled",
672
+        "labelTooltipAudioOnly": "Low bandwidth mode enabled",
673 673
         "ld": "LD",
674 674
         "ldTooltip": "Viewing low definition video",
675 675
         "lowDefinition": "Low definition",

+ 2
- 1
modules/UI/videolayout/LargeVideoManager.js Ver arquivo

@@ -12,6 +12,7 @@ import { PresenceLabel } from '../../../react/features/presence-status';
12 12
 
13 13
 const logger = require('jitsi-meet-logger').getLogger(__filename);
14 14
 
15
+import { VIDEO_TYPE } from '../../../react/features/base/media';
15 16
 import {
16 17
     JitsiParticipantConnectionStatus
17 18
 } from '../../../react/features/base/lib-jitsi-meet';
@@ -232,7 +233,7 @@ export default class LargeVideoManager {
232 233
 
233 234
             const showAvatar
234 235
                 = isVideoContainer
235
-                    && (APP.conference.isAudioOnly() || !isVideoRenderable);
236
+                    && ((APP.conference.isAudioOnly() && videoType !== VIDEO_TYPE.DESKTOP) || !isVideoRenderable);
236 237
 
237 238
             let promise;
238 239
 

+ 23
- 2
react/features/base/lastn/middleware.js Ver arquivo

@@ -3,10 +3,13 @@
3 3
 import { getLogger } from 'jitsi-meet-logger';
4 4
 
5 5
 import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
6
+import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes';
6 7
 import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
8
+import { SCREEN_SHARE_PARTICIPANTS_UPDATED, SET_TILE_VIEW } from '../../video-layout/actionTypes';
7 9
 
8
-import { SET_AUDIO_ONLY } from '../audio-only';
10
+import { SET_AUDIO_ONLY } from '../audio-only/actionTypes';
9 11
 import { CONFERENCE_JOINED } from '../conference/actionTypes';
12
+import { getParticipantById } from '../participants/functions';
10 13
 import { MiddlewareRegistry } from '../redux';
11 14
 
12 15
 declare var APP: Object;
@@ -19,8 +22,11 @@ MiddlewareRegistry.register(store => next => action => {
19 22
     switch (action.type) {
20 23
     case APP_STATE_CHANGED:
21 24
     case CONFERENCE_JOINED:
25
+    case SCREEN_SHARE_PARTICIPANTS_UPDATED:
26
+    case SELECT_LARGE_VIDEO_PARTICIPANT:
22 27
     case SET_AUDIO_ONLY:
23 28
     case SET_FILMSTRIP_ENABLED:
29
+    case SET_TILE_VIEW:
24 30
         _updateLastN(store);
25 31
         break;
26 32
     }
@@ -52,12 +58,27 @@ function _updateLastN({ getState }) {
52 58
     const defaultLastN = typeof config.channelLastN === 'undefined' ? -1 : config.channelLastN;
53 59
     let lastN = defaultLastN;
54 60
 
55
-    if (audioOnly || appState !== 'active') {
61
+    if (appState !== 'active') {
56 62
         lastN = 0;
63
+    } else if (audioOnly) {
64
+        const { screenShares, tileViewEnabled } = state['features/video-layout'];
65
+        const largeVideoParticipantId = state['features/large-video'].participantId;
66
+        const largeVideoParticipant
67
+            = largeVideoParticipantId ? getParticipantById(state, largeVideoParticipantId) : undefined;
68
+
69
+        if (!tileViewEnabled && largeVideoParticipant && !largeVideoParticipant.local) {
70
+            lastN = (screenShares || []).includes(largeVideoParticipantId) ? 1 : 0;
71
+        } else {
72
+            lastN = 0;
73
+        }
57 74
     } else if (!filmStripEnabled) {
58 75
         lastN = 1;
59 76
     }
60 77
 
78
+    if (conference.getLastN() === lastN) {
79
+        return;
80
+    }
81
+
61 82
     logger.info(`Setting last N to: ${lastN}`);
62 83
 
63 84
     try {

+ 1
- 3
react/features/base/participants/components/ParticipantView.native.js Ver arquivo

@@ -185,8 +185,6 @@ class ParticipantView extends Component<Props> {
185 185
             tintStyle
186 186
         } = this.props;
187 187
 
188
-        const waitForVideoStarted = false;
189
-
190 188
         // If the connection has problems, we will "tint" the video / avatar.
191 189
         const connectionProblem
192 190
             = connectionStatus !== JitsiParticipantConnectionStatus.ACTIVE;
@@ -216,7 +214,7 @@ class ParticipantView extends Component<Props> {
216 214
                     && <VideoTrack
217 215
                         onPress = { onPress }
218 216
                         videoTrack = { videoTrack }
219
-                        waitForVideoStarted = { waitForVideoStarted }
217
+                        waitForVideoStarted = { false }
220 218
                         zOrder = { this.props.zOrder }
221 219
                         zoomEnabled = { this.props.zoomEnabled } /> }
222 220
 

+ 29
- 23
react/features/base/participants/functions.js Ver arquivo

@@ -299,14 +299,14 @@ export function isLocalParticipantModerator(
299 299
 
300 300
 /**
301 301
  * Returns true if the video of the participant should be rendered.
302
+ * NOTE: This is currently only used on mobile.
302 303
  *
303 304
  * @param {Object|Function} stateful - Object or function that can be resolved
304 305
  * to the Redux state.
305 306
  * @param {string} id - The ID of the participant.
306 307
  * @returns {boolean}
307 308
  */
308
-export function shouldRenderParticipantVideo(
309
-        stateful: Object | Function, id: string) {
309
+export function shouldRenderParticipantVideo(stateful: Object | Function, id: string) {
310 310
     const state = toState(stateful);
311 311
     const participant = getParticipantById(state, id);
312 312
 
@@ -314,29 +314,35 @@ export function shouldRenderParticipantVideo(
314 314
         return false;
315 315
     }
316 316
 
317
+    /* First check if we have an unmuted video track. */
318
+    const videoTrack
319
+        = getTrackByMediaTypeAndParticipant(state['features/base/tracks'], MEDIA_TYPE.VIDEO, id);
320
+
321
+    if (!shouldRenderVideoTrack(videoTrack, /* waitForVideoStarted */ false)) {
322
+        return false;
323
+    }
324
+
325
+    /* Then check if the participant connection is active. */
326
+    const connectionStatus = participant.connectionStatus || JitsiParticipantConnectionStatus.ACTIVE;
327
+
328
+    if (connectionStatus !== JitsiParticipantConnectionStatus.ACTIVE) {
329
+        return false;
330
+    }
331
+
332
+    /* Then check if audio-only mode is not active. */
317 333
     const audioOnly = state['features/base/audio-only'].enabled;
318
-    const connectionStatus = participant.connectionStatus
319
-        || JitsiParticipantConnectionStatus.ACTIVE;
320
-    const videoTrack = getTrackByMediaTypeAndParticipant(
321
-        state['features/base/tracks'],
322
-        MEDIA_TYPE.VIDEO,
323
-        id);
324
-
325
-    // Is the video to be rendered?
326
-    // FIXME It's currently impossible to have true as the value of
327
-    // waitForVideoStarted because videoTrack's state videoStarted will be
328
-    // updated only after videoTrack is rendered.
329
-    // XXX Note that, unlike on web, we don't render video when the
330
-    // connection status is interrupted, this is because the renderer
331
-    // doesn't retain the last frame forever, so we would end up with a
332
-    // black screen.
333
-    const waitForVideoStarted = false;
334
-
335
-    return !audioOnly
336
-        && (connectionStatus
337
-            === JitsiParticipantConnectionStatus.ACTIVE)
338
-        && shouldRenderVideoTrack(videoTrack, waitForVideoStarted);
339 334
 
335
+    if (!audioOnly) {
336
+        return true;
337
+    }
338
+
339
+    /* Last, check if the participant is sharing their screen and they are on stage. */
340
+    const screenShares = state['features/video-layout'].screenShares || [];
341
+    const largeVideoParticipantId = state['features/large-video'].participantId;
342
+    const participantIsInLargeVideoWithScreen
343
+        = participant.id === largeVideoParticipantId && screenShares.includes(participant.id);
344
+
345
+    return participantIsInLargeVideoWithScreen;
340 346
 }
341 347
 
342 348
 /**

Carregando…
Cancelar
Salvar