Bladeren bron

fix(video-quality): Adjust encodings bitrates/scalefactor for high capture resolutions (#2436)

* fix(video-quality): Adjust encodings bitrates/scalefactor for high capture resolutions.
When the client is configured to capture camera sources at 1080p or higher, adjust the bitrates and the encodings scale factor accordingly.

* squash: Address review comments
Fix the bitrates set on the remote description and also bump up the bitrates for 1080p, 4k and screenshare.

* squash: Address some more review comments.
release-8443
Jaya Allamsetty 1 jaar geleden
bovenliggende
commit
f470b5f4fa
No account linked to committer's email address

+ 90
- 59
modules/RTC/TPCUtils.js Bestand weergeven

@@ -6,25 +6,19 @@ import CodecMimeType from '../../service/RTC/CodecMimeType';
6 6
 import { MediaDirection } from '../../service/RTC/MediaDirection';
7 7
 import { MediaType } from '../../service/RTC/MediaType';
8 8
 import { getSourceIndexFromSourceName } from '../../service/RTC/SignalingLayer';
9
-import { STANDARD_CODEC_SETTINGS } from '../../service/RTC/StandardVideoSettings';
9
+import {
10
+    SIM_LAYERS,
11
+    STANDARD_CODEC_SETTINGS,
12
+    VIDEO_QUALITY_LEVELS,
13
+    VIDEO_QUALITY_SETTINGS
14
+} from '../../service/RTC/StandardVideoSettings';
10 15
 import VideoEncoderScalabilityMode from '../../service/RTC/VideoEncoderScalabilityMode';
11 16
 import { VideoType } from '../../service/RTC/VideoType';
12 17
 import browser from '../browser';
13 18
 
14 19
 const logger = getLogger(__filename);
15
-const DESKTOP_SHARE_RATE = 500000;
16
-const SIM_LAYER_1_RID = '1';
17
-const SIM_LAYER_2_RID = '2';
18
-const SIM_LAYER_3_RID = '3';
19 20
 const VIDEO_CODECS = [ CodecMimeType.AV1, CodecMimeType.H264, CodecMimeType.VP8, CodecMimeType.VP9 ];
20 21
 
21
-// TODO - need to revisit these settings when 4K is the captured resolution. We can change the LD scale factor to 6
22
-// instead of 4 so that the lowest resolution will be 360p instead of 540p.
23
-export const HD_SCALE_FACTOR = 1.0;
24
-export const LD_SCALE_FACTOR = 4.0;
25
-export const SD_SCALE_FACTOR = 2.0;
26
-export const SIM_LAYER_RIDS = [ SIM_LAYER_1_RID, SIM_LAYER_2_RID, SIM_LAYER_3_RID ];
27
-
28 22
 /**
29 23
  * Handles track related operations on TraceablePeerConnection when browser is
30 24
  * running in unified plan mode.
@@ -38,6 +32,9 @@ export class TPCUtils {
38 32
     constructor(peerconnection) {
39 33
         this.pc = peerconnection;
40 34
         this.codecSettings = clonedeep(STANDARD_CODEC_SETTINGS);
35
+        this.l0ScaleFactor = SIM_LAYERS[0].scaleFactor;
36
+        this.l1ScaleFactor = SIM_LAYERS[1].scaleFactor;
37
+        this.l2ScaleFactor = SIM_LAYERS[2].scaleFactor;
41 38
         const videoQualitySettings = this.pc.options?.videoQuality;
42 39
 
43 40
         if (videoQualitySettings) {
@@ -50,7 +47,9 @@ export class TPCUtils {
50 47
                         && videoQualitySettings.maxbitratesvideo[codec.toUpperCase()]);
51 48
 
52 49
                 if (bitrateSettings) {
53
-                    [ 'low', 'standard', 'high', 'ssHigh' ].forEach(value => {
50
+                    const settings = Object.values(VIDEO_QUALITY_SETTINGS);
51
+
52
+                    [ ...settings, 'ssHigh' ].forEach(value => {
54 53
                         if (bitrateSettings[value]) {
55 54
                             this.codecSettings[codec].maxBitratesVideo[value] = bitrateSettings[value];
56 55
                         }
@@ -88,40 +87,56 @@ export class TPCUtils {
88 87
      */
89 88
     _calculateActiveEncodingParams(localVideoTrack, codec, newHeight) {
90 89
         const codecBitrates = this.codecSettings[codec].maxBitratesVideo;
91
-        const height = localVideoTrack.getHeight();
92
-        const desktopShareBitrate = this.pc.options?.videoQuality?.desktopbitrate || DESKTOP_SHARE_RATE;
90
+        const trackCaptureHeight = localVideoTrack.getHeight();
91
+        const effectiveNewHeight = newHeight > trackCaptureHeight ? trackCaptureHeight : newHeight;
92
+        const desktopShareBitrate = this.pc.options?.videoQuality?.desktopbitrate || codecBitrates.ssHigh;
93 93
         const isScreenshare = localVideoTrack.getVideoType() === VideoType.DESKTOP;
94 94
         let scalabilityMode = this.codecSettings[codec].useKSVC
95 95
             ? VideoEncoderScalabilityMode.L3T3_KEY : VideoEncoderScalabilityMode.L3T3;
96
-        let maxBitrate = codecBitrates.high;
96
+        const { height, level } = VIDEO_QUALITY_LEVELS.find(lvl => lvl.height <= effectiveNewHeight);
97
+        let maxBitrate;
98
+        let scaleResolutionDownBy = this.l2ScaleFactor;
97 99
 
98 100
         if (this._isScreenshareBitrateCapped(localVideoTrack)) {
99 101
             scalabilityMode = VideoEncoderScalabilityMode.L1T3;
100 102
             maxBitrate = desktopShareBitrate;
101
-        } else if (localVideoTrack.getVideoType() === VideoType.DESKTOP) {
103
+        } else if (isScreenshare) {
102 104
             maxBitrate = codecBitrates.ssHigh;
105
+        } else {
106
+            maxBitrate = codecBitrates[level];
107
+            effectiveNewHeight && (scaleResolutionDownBy = trackCaptureHeight / effectiveNewHeight);
108
+
109
+            if (height !== effectiveNewHeight) {
110
+                logger.debug(`Quality level with height=${height} was picked when requested height=${newHeight} for`
111
+                    + `track with capture height=${trackCaptureHeight}`);
112
+            }
103 113
         }
104 114
 
105 115
         const config = {
106
-            active: newHeight > 0,
116
+            active: effectiveNewHeight > 0,
107 117
             maxBitrate,
108 118
             scalabilityMode,
109
-            scaleResolutionDownBy: HD_SCALE_FACTOR
119
+            scaleResolutionDownBy
110 120
         };
111 121
 
112
-        if (newHeight >= height || newHeight === 0 || isScreenshare) {
122
+        if (!config.active || isScreenshare) {
113 123
             return config;
114 124
         }
115 125
 
116
-        if (newHeight >= height / SD_SCALE_FACTOR) {
117
-            config.maxBitrate = codecBitrates.standard;
126
+        // Configure the sender to send all 3 spatial layers for resolutions 720p and higher.
127
+        switch (level) {
128
+        case VIDEO_QUALITY_SETTINGS.ULTRA:
129
+        case VIDEO_QUALITY_SETTINGS.FULL:
130
+        case VIDEO_QUALITY_SETTINGS.HIGH:
131
+            config.scalabilityMode = this.codecSettings[codec].useKSVC
132
+                ? VideoEncoderScalabilityMode.L3T3_KEY : VideoEncoderScalabilityMode.L3T3;
133
+            break;
134
+        case VIDEO_QUALITY_SETTINGS.STANDARD:
118 135
             config.scalabilityMode = this.codecSettings[codec].useKSVC
119 136
                 ? VideoEncoderScalabilityMode.L2T3_KEY : VideoEncoderScalabilityMode.L2T3;
120
-            config.scaleResolutionDownBy = SD_SCALE_FACTOR;
121
-        } else {
122
-            config.maxBitrate = codecBitrates.low;
137
+            break;
138
+        default:
123 139
             config.scalabilityMode = VideoEncoderScalabilityMode.L1T3;
124
-            config.scaleResolutionDownBy = LD_SCALE_FACTOR;
125 140
         }
126 141
 
127 142
         return config;
@@ -133,19 +148,21 @@ export class TPCUtils {
133 148
      * @param {JitsiLocalTrack} localTrack
134 149
      */
135 150
     _getStreamEncodings(localTrack) {
151
+        if (localTrack.isAudioTrack()) {
152
+            return [ { active: this.pc.audioTransferActive } ];
153
+        }
154
+
136 155
         const codec = this.pc.getConfiguredVideoCodec();
137
-        const encodings = this._getVideoStreamEncodings(localTrack.getVideoType(), codec);
156
+        const encodings = this._getVideoStreamEncodings(localTrack, codec);
138 157
 
139
-        if (this.pc.isSpatialScalabilityOn() && localTrack.isVideoTrack()) {
158
+        if (this.pc.isSpatialScalabilityOn()) {
140 159
             return encodings;
141 160
         }
142 161
 
143
-        return localTrack.isVideoTrack()
144
-            ? [ {
145
-                active: this.pc.videoTransferActive,
146
-                maxBitrate: this.codecSettings[codec].maxBitratesVideo.high
147
-            } ]
148
-            : [ { active: this.pc.audioTransferActive } ];
162
+        return [ {
163
+            active: this.pc.videoTransferActive,
164
+            maxBitrate: this.codecSettings[codec].maxBitratesVideo.high
165
+        } ];
149 166
     }
150 167
 
151 168
     /**
@@ -161,13 +178,26 @@ export class TPCUtils {
161 178
      * scaleResolutionDownBy - the factor by which the encoding is scaled down from the
162 179
      *  original resolution of the captured video.
163 180
      *
164
-     * @param {VideoType} videoType
181
+     * @param {JitsiLocalTrack} localTrack
165 182
      * @param {String} codec
166 183
      */
167
-    _getVideoStreamEncodings(videoType, codec) {
184
+    _getVideoStreamEncodings(localTrack, codec) {
185
+        const captureResolution = localTrack.getHeight();
168 186
         const codecBitrates = this.codecSettings[codec].maxBitratesVideo;
187
+        const videoType = localTrack.getVideoType();
188
+        const { level } = VIDEO_QUALITY_LEVELS.find(lvl => lvl.height <= captureResolution);
189
+        const maxBitrate = codecBitrates[level];
190
+
191
+        if (level === VIDEO_QUALITY_SETTINGS.ULTRA) {
192
+            this.l1ScaleFactor = 6.0; // 360p
193
+            this.l0ScaleFactor = 12.0; // 180p
194
+        } else if (level === VIDEO_QUALITY_SETTINGS.FULL) {
195
+            this.l1ScaleFactor = 3.0; // 360p
196
+            this.l0ScaleFactor = 6.0; // 180p
197
+        }
198
+
169 199
         const maxVideoBitrate = videoType === VideoType.DESKTOP
170
-            ? codecBitrates.ssHigh : codecBitrates.high;
200
+            ? codecBitrates.ssHigh : maxBitrate;
171 201
 
172 202
         // The SSRCs on older versions of Firefox are reversed in SDP, i.e., they have resolution order of 1:2:4 as
173 203
         // opposed to Chromium and other browsers. This has been reverted in Firefox 117 as part of the below commit.
@@ -181,20 +211,20 @@ export class TPCUtils {
181 211
             {
182 212
                 active: this.pc.videoTransferActive,
183 213
                 maxBitrate: reversedEncodings ? maxVideoBitrate : codecBitrates.low,
184
-                rid: SIM_LAYER_1_RID,
185
-                scaleResolutionDownBy: reversedEncodings ? HD_SCALE_FACTOR : LD_SCALE_FACTOR
214
+                rid: SIM_LAYERS[0].rid,
215
+                scaleResolutionDownBy: reversedEncodings ? this.l2ScaleFactor : this.l0ScaleFactor
186 216
             },
187 217
             {
188 218
                 active: this.pc.videoTransferActive,
189 219
                 maxBitrate: codecBitrates.standard,
190
-                rid: SIM_LAYER_2_RID,
191
-                scaleResolutionDownBy: SD_SCALE_FACTOR
220
+                rid: SIM_LAYERS[1].rid,
221
+                scaleResolutionDownBy: this.l1ScaleFactor
192 222
             },
193 223
             {
194 224
                 active: this.pc.videoTransferActive,
195 225
                 maxBitrate: reversedEncodings ? codecBitrates.low : maxVideoBitrate,
196
-                rid: SIM_LAYER_3_RID,
197
-                scaleResolutionDownBy: reversedEncodings ? LD_SCALE_FACTOR : HD_SCALE_FACTOR
226
+                rid: SIM_LAYERS[2].rid,
227
+                scaleResolutionDownBy: reversedEncodings ? this.l0ScaleFactor : this.l2ScaleFactor
198 228
             }
199 229
         ];
200 230
 
@@ -214,8 +244,8 @@ export class TPCUtils {
214 244
                 {
215 245
                     active: this.pc.videoTransferActive,
216 246
                     maxBitrate: maxVideoBitrate,
217
-                    rid: SIM_LAYER_1_RID,
218
-                    scaleResolutionDownBy: HD_SCALE_FACTOR,
247
+                    rid: SIM_LAYERS[0].rid,
248
+                    scaleResolutionDownBy: this.l2ScaleFactor,
219 249
                     scalabilityMode: this.codecSettings[codec].useKSVC
220 250
                         ? VideoEncoderScalabilityMode.L3T3_KEY : VideoEncoderScalabilityMode.L3T3
221 251
                 },
@@ -329,7 +359,7 @@ export class TPCUtils {
329 359
      */
330 360
     calculateEncodingsActiveState(localVideoTrack, codec, newHeight) {
331 361
         const height = localVideoTrack.getHeight();
332
-        const videoStreamEncodings = this._getVideoStreamEncodings(localVideoTrack.getVideoType(), codec);
362
+        const videoStreamEncodings = this._getVideoStreamEncodings(localVideoTrack, codec);
333 363
         const encodingsState = videoStreamEncodings
334 364
         .map(encoding => height / encoding.scaleResolutionDownBy)
335 365
         .map((frameHeight, idx) => {
@@ -353,11 +383,11 @@ export class TPCUtils {
353 383
                         // but the requested resolution is 180. Since getParameters doesn't give us information about
354 384
                         // the resolutions of the simulcast encodings, we have to rely on our initial config for the
355 385
                         // simulcast streams.
356
-                        || videoStreamEncodings[idx]?.scaleResolutionDownBy === LD_SCALE_FACTOR;
386
+                        || videoStreamEncodings[idx]?.scaleResolutionDownBy === this.l0ScaleFactor;
357 387
                 } else {
358 388
                     // For screenshare, keep the HD layer enabled always and the lower layers only for high fps
359 389
                     // screensharing.
360
-                    active = videoStreamEncodings[idx].scaleResolutionDownBy === HD_SCALE_FACTOR
390
+                    active = videoStreamEncodings[idx].scaleResolutionDownBy === this.l2ScaleFactor
361 391
                         || !this._isScreenshareBitrateCapped(localVideoTrack);
362 392
                 }
363 393
             }
@@ -378,8 +408,9 @@ export class TPCUtils {
378 408
      * @returns {Array<number>}
379 409
      */
380 410
     calculateEncodingsBitrates(localVideoTrack, codec, newHeight) {
381
-        const desktopShareBitrate = this.pc.options?.videoQuality?.desktopbitrate || DESKTOP_SHARE_RATE;
382
-        const encodingsBitrates = this._getVideoStreamEncodings(localVideoTrack.getVideoType(), codec)
411
+        const codecBitrates = this.codecSettings[codec].maxBitratesVideo;
412
+        const desktopShareBitrate = this.pc.options?.videoQuality?.desktopbitrate || codecBitrates.ssHigh;
413
+        const encodingsBitrates = this._getVideoStreamEncodings(localVideoTrack, codec)
383 414
         .map((encoding, idx) => {
384 415
             let bitrate = encoding.maxBitrate;
385 416
 
@@ -447,7 +478,7 @@ export class TPCUtils {
447 478
      */
448 479
     calculateEncodingsScaleFactor(localVideoTrack, codec, maxHeight) {
449 480
         if (this.pc.isSpatialScalabilityOn() && this.isRunningInSimulcastMode(codec)) {
450
-            return this._getVideoStreamEncodings(localVideoTrack.getVideoType(), codec)
481
+            return this._getVideoStreamEncodings(localVideoTrack, codec)
451 482
                 .map(encoding => encoding.scaleResolutionDownBy);
452 483
         }
453 484
 
@@ -537,19 +568,18 @@ export class TPCUtils {
537 568
         const hasIncorrectConfig = this.pc._capScreenshareBitrate
538 569
             ? parameters.encodings.every(encoding => encoding.active)
539 570
             : parameters.encodings.some(encoding => !encoding.active);
540
-        const videoType = localVideoTrack.getVideoType();
541 571
 
542 572
         // Check if every encoding is active for screenshare track when low fps screenshare is configured or some
543 573
         // of the encodings are disabled when high fps screenshare is configured. In both these cases, the track
544 574
         // encodings need to be reconfigured. This is needed when p2p->jvb switch happens and new sender constraints
545 575
         // are not received by the client.
546
-        if (videoType === VideoType.DESKTOP && hasIncorrectConfig) {
576
+        if (localVideoTrack.getVideoType() === VideoType.DESKTOP && hasIncorrectConfig) {
547 577
             return null;
548 578
         }
549 579
 
550 580
         for (const encoding in parameters.encodings) {
551 581
             if (parameters.encodings[encoding].active) {
552
-                const encodingConfig = this._getVideoStreamEncodings(videoType, codec);
582
+                const encodingConfig = this._getVideoStreamEncodings(localVideoTrack, codec);
553 583
                 const scaleResolutionDownBy
554 584
                     = this.pc.isSpatialScalabilityOn()
555 585
                         ? encodingConfig[encoding].scaleResolutionDownBy
@@ -579,15 +609,15 @@ export class TPCUtils {
579 609
         }
580 610
         const rids = [
581 611
             {
582
-                id: SIM_LAYER_1_RID,
612
+                id: SIM_LAYERS[0].rid,
583 613
                 direction: 'recv'
584 614
             },
585 615
             {
586
-                id: SIM_LAYER_2_RID,
616
+                id: SIM_LAYERS[1].rid,
587 617
                 direction: 'recv'
588 618
             },
589 619
             {
590
-                id: SIM_LAYER_3_RID,
620
+                id: SIM_LAYERS[2].rid,
591 621
                 direction: 'recv'
592 622
             }
593 623
         ];
@@ -595,9 +625,10 @@ export class TPCUtils {
595 625
         // Firefox 72 has stopped parsing the legacy rid= parameters in simulcast attributes.
596 626
         // eslint-disable-next-line max-len
597 627
         // https://www.fxsitecompat.dev/en-CA/docs/2019/pt-and-rid-in-webrtc-simulcast-attributes-are-no-longer-supported/
628
+        const ridLine = rids.map(val => val.id).join(';');
598 629
         const simulcastLine = browser.isFirefox() && browser.isVersionGreaterThan(71)
599
-            ? `recv ${SIM_LAYER_RIDS.join(';')}`
600
-            : `recv rid=${SIM_LAYER_RIDS.join(';')}`;
630
+            ? `recv ${ridLine}`
631
+            : `recv rid=${ridLine}`;
601 632
         const sdp = transform.parse(desc.sdp);
602 633
         const mLines = sdp.media.filter(m => m.type === MediaType.VIDEO);
603 634
         const senderMids = Array.from(this.pc._localTrackTransceiverMids.values());

+ 495
- 150
modules/RTC/TPCUtils.spec.js
Diff onderdrukt omdat het te groot bestand
Bestand weergeven


+ 18
- 29
modules/RTC/TraceablePeerConnection.js Bestand weergeven

@@ -8,6 +8,7 @@ import { MediaType } from '../../service/RTC/MediaType';
8 8
 import RTCEvents from '../../service/RTC/RTCEvents';
9 9
 import * as SignalingEvents from '../../service/RTC/SignalingEvents';
10 10
 import { getSourceIndexFromSourceName } from '../../service/RTC/SignalingLayer';
11
+import { VIDEO_QUALITY_LEVELS } from '../../service/RTC/StandardVideoSettings';
11 12
 import { VideoType } from '../../service/RTC/VideoType';
12 13
 import { SS_DEFAULT_FRAME_RATE } from '../RTC/ScreenObtainer';
13 14
 import browser from '../browser';
@@ -21,7 +22,7 @@ import { SdpTransformWrap } from '../sdp/SdpTransformUtil';
21 22
 
22 23
 import JitsiRemoteTrack from './JitsiRemoteTrack';
23 24
 import RTC from './RTC';
24
-import { SIM_LAYER_RIDS, TPCUtils } from './TPCUtils';
25
+import { TPCUtils } from './TPCUtils';
25 26
 
26 27
 // FIXME SDP tools should end up in some kind of util module
27 28
 
@@ -284,7 +285,7 @@ export default function TraceablePeerConnection(
284 285
 
285 286
     this.interop = new Interop();
286 287
 
287
-    this.simulcast = new SdpSimulcast({ numOfLayers: SIM_LAYER_RIDS.length });
288
+    this.simulcast = new SdpSimulcast();
288 289
 
289 290
     /**
290 291
      * Munges local SDP provided to the Jingle Session in order to prevent from
@@ -300,12 +301,6 @@ export default function TraceablePeerConnection(
300 301
     this.eventEmitter = rtc.eventEmitter;
301 302
     this.rtxModifier = new RtxModifier();
302 303
 
303
-    /**
304
-     * The height constraint applied on the video sender. The default value is 2160 (4K) when layer suspension is
305
-     * explicitly disabled.
306
-     */
307
-    this._senderVideoMaxHeight = 2160;
308
-
309 304
     /**
310 305
      * The height constraints to be applied on the sender per local video source (source name as the key).
311 306
      * @type {Map<string, number>}
@@ -500,21 +495,6 @@ TraceablePeerConnection.prototype.getDesiredMediaDirection = function(mediaType,
500 495
     return hasLocalSource ? MediaDirection.RECVONLY : MediaDirection.INACTIVE;
501 496
 };
502 497
 
503
-/**
504
- * Returns the MID of the m-line associated with the local desktop track (if it exists).
505
- *
506
- * @returns {Number|null}
507
- */
508
-TraceablePeerConnection.prototype._getDesktopTrackMid = function() {
509
-    const desktopTrack = this.getLocalVideoTracks().find(track => track.getVideoType() === VideoType.DESKTOP);
510
-
511
-    if (desktopTrack) {
512
-        return Number(this._localTrackTransceiverMids.get(desktopTrack.rtcId));
513
-    }
514
-
515
-    return null;
516
-};
517
-
518 498
 /**
519 499
  * Returns the list of RTCRtpReceivers created for the source of the given media type associated with
520 500
  * the set of remote endpoints specified.
@@ -2067,14 +2047,23 @@ TraceablePeerConnection.prototype._setMaxBitrates = function(description, isLoca
2067 2047
     for (const mLine of mLines) {
2068 2048
         const isDoingVp9KSvc = currentCodec === CodecMimeType.VP9
2069 2049
             && !codecScalabilityModeSettings.scalabilityModeEnabled;
2050
+        const localTrack = this.getLocalVideoTracks()
2051
+            .find(track => this._localTrackTransceiverMids.get(track.rtcId) === mLine.mid.toString());
2052
+
2053
+        if ((isDoingVp9KSvc || this.tpcUtils._isRunningInFullSvcMode(currentCodec)) && localTrack) {
2054
+            let maxBitrate;
2055
+
2056
+            if (localTrack.getVideoType() === VideoType.DESKTOP) {
2057
+                maxBitrate = codecScalabilityModeSettings.maxBitratesVideo.ssHigh;
2058
+            } else {
2059
+                const { level } = VIDEO_QUALITY_LEVELS.find(lvl => lvl.height <= localTrack.getHeight());
2060
+
2061
+                maxBitrate = codecScalabilityModeSettings.maxBitratesVideo[level];
2062
+            }
2070 2063
 
2071
-        if (isDoingVp9KSvc || this.tpcUtils._isRunningInFullSvcMode(currentCodec)) {
2072
-            const bitrates = codecScalabilityModeSettings.maxBitratesVideo;
2073
-            const mid = mLine.mid;
2074
-            const isSharingScreen = mid === this._getDesktopTrackMid();
2075
-            const limit = Math.floor((isSharingScreen ? bitrates.ssHigh : bitrates.high) / 1000);
2064
+            const limit = Math.floor(maxBitrate / 1000);
2076 2065
 
2077
-            // Use only the HD bitrate for now as there is no API available yet for configuring
2066
+            // Use only the highest spatial layer bitrates for now as there is no API available yet for configuring
2078 2067
             // the bitrates on the individual SVC layers.
2079 2068
             mLine.bandwidth = [ {
2080 2069
                 type: 'AS',

+ 16
- 45
modules/connectivity/ConnectionQuality.js Bestand weergeven

@@ -1,8 +1,8 @@
1 1
 import { getLogger } from '@jitsi/logger';
2 2
 
3 3
 import * as ConferenceEvents from '../../JitsiConferenceEvents';
4
-import CodecMimeType from '../../service/RTC/CodecMimeType';
5 4
 import * as RTCEvents from '../../service/RTC/RTCEvents';
5
+import { VIDEO_QUALITY_LEVELS } from '../../service/RTC/StandardVideoSettings';
6 6
 import * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';
7 7
 
8 8
 const Resolutions = require('../../service/RTC/Resolutions');
@@ -17,33 +17,6 @@ const logger = getLogger(__filename);
17 17
  */
18 18
 const STATS_MESSAGE_TYPE = 'stats';
19 19
 
20
-const kSimulcastFormats = [
21
-    {
22
-        height: 1080,
23
-        target: 'high'
24
-    },
25
-    {
26
-        height: 720,
27
-        target: 'high'
28
-    },
29
-    {
30
-        height: 540,
31
-        target: 'standard'
32
-    },
33
-    {
34
-        height: 360,
35
-        target: 'standard'
36
-    },
37
-    {
38
-        height: 270,
39
-        target: 'low'
40
-    },
41
-    {
42
-        height: 180,
43
-        target: 'low'
44
-    }
45
-];
46
-
47 20
 /**
48 21
  * The maximum bitrate to use as a measurement against the participant's current
49 22
  * bitrate. This cap helps in the cases where the participant's bitrate is high
@@ -61,32 +34,32 @@ let startBitrate = 800;
61 34
  * @param simulcast {boolean} whether simulcast is enabled or not.
62 35
  * @param resolution {Resolution} the resolution.
63 36
  * @param millisSinceStart {number} the number of milliseconds since sending video started.
64
- * @param videoQualitySettings {Object} the bitrate and codec settings for the local video source.
37
+ * @param bitrates {Object} the bitrates for the local video source.
65 38
  */
66
-function getTarget(simulcast, resolution, millisSinceStart, videoQualitySettings) {
39
+function getTarget(simulcast, resolution, millisSinceStart, bitrates) {
67 40
     let target = 0;
68 41
     let height = Math.min(resolution.height, resolution.width);
69 42
 
70 43
     // Find the first format with height no bigger than ours.
71
-    let simulcastFormat = kSimulcastFormats.find(f => f.height <= height);
44
+    let qualityLevel = VIDEO_QUALITY_LEVELS.find(f => f.height <= height);
72 45
 
73
-    if (simulcastFormat && simulcast && videoQualitySettings.codec === CodecMimeType.VP8) {
46
+    if (qualityLevel && simulcast) {
74 47
         // Sum the target fields from all simulcast layers for the given
75 48
         // resolution (e.g. 720p + 360p + 180p) for VP8 simulcast.
76
-        for (height = simulcastFormat.height; height >= 180; height /= 2) {
49
+        for (height = qualityLevel.height; height >= 180; height /= 2) {
77 50
             const targetHeight = height;
78 51
 
79
-            simulcastFormat = kSimulcastFormats.find(f => f.height === targetHeight);
80
-            if (simulcastFormat) {
81
-                target += videoQualitySettings[simulcastFormat.target];
52
+            qualityLevel = VIDEO_QUALITY_LEVELS.find(f => f.height === targetHeight);
53
+            if (qualityLevel) {
54
+                target += bitrates[qualityLevel.level];
82 55
             } else {
83 56
                 break;
84 57
             }
85 58
         }
86
-    } else if (simulcastFormat) {
59
+    } else if (qualityLevel) {
87 60
         // For VP9 SVC, H.264 (simulcast automatically disabled) and p2p, target bitrate will be
88 61
         // same as that of the individual stream bitrate.
89
-        target = videoQualitySettings[simulcastFormat.target];
62
+        target = bitrates[qualityLevel.level];
90 63
     }
91 64
 
92 65
     // Allow for an additional 1 second for ramp up -- delay any initial drop
@@ -334,19 +307,17 @@ export default class ConnectionQuality {
334 307
             const activeTPC = this._conference.getActivePeerConnection();
335 308
 
336 309
             if (activeTPC) {
337
-                const isSimulcastOn = activeTPC.isSpatialScalabilityOn();
338
-                const videoQualitySettings = activeTPC.getTargetVideoBitrates();
339
-
340
-                // Add the codec info as well.
341
-                videoQualitySettings.codec = activeTPC.getConfiguredVideoCodec();
342
-
343 310
                 // Time since sending of video was enabled.
344 311
                 const millisSinceStart = window.performance.now()
345 312
                     - Math.max(this._timeVideoUnmuted, this._timeIceConnected);
346 313
                 const statsInterval = this._options.config?.pcStatsInterval ?? 10000;
347 314
 
348 315
                 // Expected sending bitrate in perfect conditions.
349
-                let target = getTarget(isSimulcastOn, resolution, millisSinceStart, videoQualitySettings);
316
+                let target = getTarget(
317
+                    activeTPC.doesTrueSimulcast(),
318
+                    resolution,
319
+                    millisSinceStart,
320
+                    activeTPC.getTargetVideoBitrates());
350 321
 
351 322
                 target = Math.min(target, MAX_TARGET_BITRATE);
352 323
 

+ 5
- 14
modules/sdp/SdpSimulcast.ts Bestand weergeven

@@ -1,19 +1,14 @@
1 1
 import { MediaDirection } from '../../service/RTC/MediaDirection';
2 2
 import { MediaType } from '../../service/RTC/MediaType';
3
+import { SIM_LAYERS } from '../../service/RTC/StandardVideoSettings';
3 4
 
4 5
 import * as transform from 'sdp-transform';
5 6
 
6
-const DEFAULT_NUM_OF_LAYERS = 3;
7
-
8 7
 interface Description {
9 8
     type: RTCSdpType;
10 9
     sdp: string;
11 10
 }
12 11
 
13
-interface Options {
14
-    numOfLayers?: number
15
-}
16
-
17 12
 /**
18 13
  * This class handles SDP munging for enabling simulcast for local video streams in Unified plan. A set of random SSRCs
19 14
  * are generated for the higher layer streams and they are cached for a given mid. The cached SSRCs are then reused on
@@ -22,7 +17,7 @@ interface Options {
22 17
  * to a given endpoint.
23 18
  */
24 19
 export default class SdpSimulcast {
25
-    private _options: Options;
20
+    private _numOfLayers: number;
26 21
     private _ssrcCache: Map<string, Array<number>>;
27 22
 
28 23
     /**
@@ -30,13 +25,9 @@ export default class SdpSimulcast {
30 25
      *
31 26
      * @param options
32 27
      */
33
-    constructor(options: Options) {
34
-        this._options = options;
28
+    constructor() {
35 29
         this._ssrcCache = new Map();
36
-
37
-        if (!this._options.numOfLayers) {
38
-            this._options.numOfLayers = DEFAULT_NUM_OF_LAYERS;
39
-        }
30
+        this._numOfLayers = SIM_LAYERS.length;
40 31
     }
41 32
 
42 33
     /**
@@ -120,7 +111,7 @@ export default class SdpSimulcast {
120 111
         // Generate SIM layers.
121 112
         const simSsrcs = [];
122 113
 
123
-        for (let i = 0; i < this._options.numOfLayers - 1; ++i) {
114
+        for (let i = 0; i < this._numOfLayers - 1; ++i) {
124 115
             const simSsrc = this._generateSsrc();
125 116
 
126 117
             addAssociatedAttributes(mLine, simSsrc);

+ 107
- 4
service/RTC/StandardVideoSettings.ts Bestand weergeven

@@ -1,5 +1,21 @@
1 1
 import browser from '../../modules/browser';
2 2
 
3
+// Default simulcast encodings config.
4
+export const SIM_LAYERS = [
5
+    {
6
+        rid: '1',
7
+        scaleFactor: 4.0
8
+    },
9
+    {
10
+        rid: '2',
11
+        scaleFactor: 2.0
12
+    },
13
+    {
14
+        rid: '3',
15
+        scaleFactor: 1.0
16
+    }
17
+];
18
+
3 19
 /**
4 20
  * Standard scalability mode settings for different video codecs and the default bitrates.
5 21
  */
@@ -9,7 +25,10 @@ export const STANDARD_CODEC_SETTINGS = {
9 25
             low: 100000,
10 26
             standard: 300000,
11 27
             high: 1000000,
12
-            ssHigh: 2500000
28
+            fullHd: 1200000,
29
+            ultraHd: 2500000,
30
+            ssHigh: 2500000,
31
+            none: 0
13 32
         },
14 33
         scalabilityModeEnabled: browser.supportsScalabilityModeAPI(),
15 34
         useSimulcast: false, // defaults to SVC.
@@ -20,7 +39,10 @@ export const STANDARD_CODEC_SETTINGS = {
20 39
             low: 200000,
21 40
             standard: 500000,
22 41
             high: 1500000,
23
-            ssHigh: 2500000
42
+            fullHd: 2000000,
43
+            ultraHd: 4000000,
44
+            ssHigh: 2500000,
45
+            none: 0
24 46
         },
25 47
         scalabilityModeEnabled: browser.supportsScalabilityModeAPI()
26 48
     },
@@ -29,7 +51,10 @@ export const STANDARD_CODEC_SETTINGS = {
29 51
             low: 200000,
30 52
             standard: 500000,
31 53
             high: 1500000,
32
-            ssHigh: 2500000
54
+            fullHd: 2000000,
55
+            ultraHd: 4000000,
56
+            ssHigh: 2500000,
57
+            none: 0
33 58
         },
34 59
         scalabilityModeEnabled: false
35 60
     },
@@ -38,10 +63,88 @@ export const STANDARD_CODEC_SETTINGS = {
38 63
             low: 100000,
39 64
             standard: 300000,
40 65
             high: 1200000,
41
-            ssHigh: 2500000
66
+            fullHd: 1500000,
67
+            ultraHd: 3000000,
68
+            ssHigh: 2500000,
69
+            none: 0
42 70
         },
43 71
         scalabilityModeEnabled: browser.supportsScalabilityModeAPI(),
44 72
         useSimulcast: false, // defaults to SVC.
45 73
         useKSVC: true // defaults to L3T3_KEY for SVC mode.
46 74
     }
47 75
 };
76
+
77
+/**
78
+ * Standard video resolutions and the corresponding quality level that will be picked for the given resolution.
79
+ * For quality levels:
80
+ * 'high' and above - the encoder will be configured to encode 3 spatial layers.
81
+ * 'standard' - the encoder will be configured to encode 2 spatial laters.
82
+ * 'low' - the encoder will be configured to encode only 1 spatial layer.
83
+ * In all the above cases, each of the layers will again have 3 temporal layers, except for VP8 codec for which only
84
+ * 2 temporal layers are configured by default.
85
+ */
86
+export const VIDEO_QUALITY_LEVELS = [
87
+    {
88
+        height: 2160,
89
+        level: 'ultraHd'
90
+    },
91
+    {
92
+        height: 1080,
93
+        level: 'fullHd'
94
+    },
95
+    {
96
+        height: 720,
97
+        level: 'high'
98
+    },
99
+    {
100
+        height: 540,
101
+        level: 'standard'
102
+    },
103
+    {
104
+        height: 480,
105
+        level: 'standard'
106
+    },
107
+    {
108
+        height: 360,
109
+        level: 'standard'
110
+    },
111
+    {
112
+        height: 270,
113
+        level: 'low'
114
+    },
115
+    {
116
+        height: 180,
117
+        level: 'low'
118
+    },
119
+    {
120
+        height: 90,
121
+        level: 'low'
122
+    },
123
+    {
124
+        height: 0,
125
+        level: 'none'
126
+    }
127
+];
128
+
129
+/**
130
+ * Enumerate the supported video resolutions.
131
+ */
132
+export enum VIDEO_QUALITY_SETTINGS {
133
+    // 3840x2160 or 4k.
134
+    ULTRA = 'ultraHd',
135
+
136
+    // 1920x1080 or full High Definition.
137
+    FULL = 'fullHd',
138
+
139
+    // 1280x720 or High Definition.
140
+    HIGH = 'high',
141
+
142
+    // 640x360 or Standard Definition.
143
+    STANDARD = 'standard',
144
+
145
+    // 320x180 or Low Definition.
146
+    LOW = 'low',
147
+
148
+    // When the camera is turned off.
149
+    NONE = 'none'
150
+};

+ 0
- 3
types/hand-crafted/modules/RTC/TPCUtils.d.ts Bestand weergeven

@@ -1,7 +1,4 @@
1 1
 import JitsiLocalTrack from './JitsiLocalTrack';
2
-import { MediaType } from '../../service/RTC/MediaType';
3
-
4
-export const SIM_LAYER_RIDS: string[];
5 2
 
6 3
 export default class TPCUtils {
7 4
   constructor(peerconnection: unknown, videoBitrates: unknown); // TODO:

Laden…
Annuleren
Opslaan