瀏覽代碼

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 年之前
父節點
當前提交
f3e7952e51

+ 5
- 5
lang/main.json 查看文件

24
         "speaker": "Speaker"
24
         "speaker": "Speaker"
25
     },
25
     },
26
     "audioOnly": {
26
     "audioOnly": {
27
-        "audioOnly": "Audio only"
27
+        "audioOnly": "Low bandwidth"
28
     },
28
     },
29
     "calendarSync": {
29
     "calendarSync": {
30
         "addMeetingURL": "Add a meeting link",
30
         "addMeetingURL": "Add a meeting link",
584
             "videoblur": "Toggle video blur"
584
             "videoblur": "Toggle video blur"
585
         },
585
         },
586
         "addPeople": "Add people to your call",
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
         "audioRoute": "Select the sound device",
589
         "audioRoute": "Select the sound device",
590
         "authenticate": "Authenticate",
590
         "authenticate": "Authenticate",
591
         "callQuality": "Manage video quality",
591
         "callQuality": "Manage video quality",
663
     },
663
     },
664
     "videoStatus": {
664
     "videoStatus": {
665
         "audioOnly": "AUD",
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
         "callQuality": "Video Quality",
667
         "callQuality": "Video Quality",
668
         "hd": "HD",
668
         "hd": "HD",
669
         "hdTooltip": "Viewing high definition video",
669
         "hdTooltip": "Viewing high definition video",
670
         "highDefinition": "High definition",
670
         "highDefinition": "High definition",
671
         "labelTooiltipNoVideo": "No video",
671
         "labelTooiltipNoVideo": "No video",
672
-        "labelTooltipAudioOnly": "Audio-only mode enabled",
672
+        "labelTooltipAudioOnly": "Low bandwidth mode enabled",
673
         "ld": "LD",
673
         "ld": "LD",
674
         "ldTooltip": "Viewing low definition video",
674
         "ldTooltip": "Viewing low definition video",
675
         "lowDefinition": "Low definition",
675
         "lowDefinition": "Low definition",

+ 2
- 1
modules/UI/videolayout/LargeVideoManager.js 查看文件

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

+ 23
- 2
react/features/base/lastn/middleware.js 查看文件

3
 import { getLogger } from 'jitsi-meet-logger';
3
 import { getLogger } from 'jitsi-meet-logger';
4
 
4
 
5
 import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
5
 import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
6
+import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes';
6
 import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
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
 import { CONFERENCE_JOINED } from '../conference/actionTypes';
11
 import { CONFERENCE_JOINED } from '../conference/actionTypes';
12
+import { getParticipantById } from '../participants/functions';
10
 import { MiddlewareRegistry } from '../redux';
13
 import { MiddlewareRegistry } from '../redux';
11
 
14
 
12
 declare var APP: Object;
15
 declare var APP: Object;
19
     switch (action.type) {
22
     switch (action.type) {
20
     case APP_STATE_CHANGED:
23
     case APP_STATE_CHANGED:
21
     case CONFERENCE_JOINED:
24
     case CONFERENCE_JOINED:
25
+    case SCREEN_SHARE_PARTICIPANTS_UPDATED:
26
+    case SELECT_LARGE_VIDEO_PARTICIPANT:
22
     case SET_AUDIO_ONLY:
27
     case SET_AUDIO_ONLY:
23
     case SET_FILMSTRIP_ENABLED:
28
     case SET_FILMSTRIP_ENABLED:
29
+    case SET_TILE_VIEW:
24
         _updateLastN(store);
30
         _updateLastN(store);
25
         break;
31
         break;
26
     }
32
     }
52
     const defaultLastN = typeof config.channelLastN === 'undefined' ? -1 : config.channelLastN;
58
     const defaultLastN = typeof config.channelLastN === 'undefined' ? -1 : config.channelLastN;
53
     let lastN = defaultLastN;
59
     let lastN = defaultLastN;
54
 
60
 
55
-    if (audioOnly || appState !== 'active') {
61
+    if (appState !== 'active') {
56
         lastN = 0;
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
     } else if (!filmStripEnabled) {
74
     } else if (!filmStripEnabled) {
58
         lastN = 1;
75
         lastN = 1;
59
     }
76
     }
60
 
77
 
78
+    if (conference.getLastN() === lastN) {
79
+        return;
80
+    }
81
+
61
     logger.info(`Setting last N to: ${lastN}`);
82
     logger.info(`Setting last N to: ${lastN}`);
62
 
83
 
63
     try {
84
     try {

+ 1
- 3
react/features/base/participants/components/ParticipantView.native.js 查看文件

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

+ 29
- 23
react/features/base/participants/functions.js 查看文件

299
 
299
 
300
 /**
300
 /**
301
  * Returns true if the video of the participant should be rendered.
301
  * Returns true if the video of the participant should be rendered.
302
+ * NOTE: This is currently only used on mobile.
302
  *
303
  *
303
  * @param {Object|Function} stateful - Object or function that can be resolved
304
  * @param {Object|Function} stateful - Object or function that can be resolved
304
  * to the Redux state.
305
  * to the Redux state.
305
  * @param {string} id - The ID of the participant.
306
  * @param {string} id - The ID of the participant.
306
  * @returns {boolean}
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
     const state = toState(stateful);
310
     const state = toState(stateful);
311
     const participant = getParticipantById(state, id);
311
     const participant = getParticipantById(state, id);
312
 
312
 
314
         return false;
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
     const audioOnly = state['features/base/audio-only'].enabled;
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
 /**

Loading…
取消
儲存