Bläddra i källkod

fix(connection-quality): Calculate target bps based on videoQuality settings.

Calculate the target bps based on the video quality settings and the codec configured on the peerconnection.
Hardcode target video bitrates for RN since it doesn't support setting max bitrates.
dev1
Jaya Allamsetty 4 år sedan
förälder
incheckning
1f3f85978d
Inget konto är kopplat till bidragsgivarens mejladress
2 ändrade filer med 73 tillägg och 129 borttagningar
  1. 12
    1
      modules/RTC/TraceablePeerConnection.js
  2. 61
    128
      modules/connectivity/ConnectionQuality.js

+ 12
- 1
modules/RTC/TraceablePeerConnection.js Visa fil

@@ -701,6 +701,17 @@ TraceablePeerConnection.prototype.getRemoteSourceInfoByParticipant = function(id
701 701
     return removeSsrcInfo;
702 702
 };
703 703
 
704
+/**
705
+ * Returns the target bitrates configured for the local video source.
706
+ *
707
+ * @returns {Object}
708
+ */
709
+TraceablePeerConnection.prototype.getTargetVideoBitrates = function() {
710
+    const currentCodec = this.getConfiguredVideoCodec();
711
+
712
+    return this.videoBitrates[currentCodec.toUpperCase()] || this.videoBitrates;
713
+};
714
+
704 715
 /**
705 716
  * Tries to find {@link JitsiTrack} for given SSRC number. It will search both
706 717
  * local and remote tracks bound to this instance.
@@ -2321,7 +2332,7 @@ TraceablePeerConnection.prototype.setMaxBitRate = function() {
2321 2332
         }
2322 2333
     } else {
2323 2334
         // Do not change the max bitrate for desktop tracks in non-simulcast mode.
2324
-        let bitrate = this.videoBitrates.high;
2335
+        let bitrate = this.getTargetVideoBitrates()?.high;
2325 2336
 
2326 2337
         if (videoType === VideoType.CAMERA) {
2327 2338
             // Determine the bitrates based on the sender constraint applied for unicast tracks.

+ 61
- 128
modules/connectivity/ConnectionQuality.js Visa fil

@@ -1,8 +1,10 @@
1 1
 import { getLogger } from 'jitsi-meet-logger';
2 2
 
3 3
 import * as ConferenceEvents from '../../JitsiConferenceEvents';
4
+import CodecMimeType from '../../service/RTC/CodecMimeType';
4 5
 import * as RTCEvents from '../../service/RTC/RTCEvents';
5 6
 import * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';
7
+import browser from '../browser';
6 8
 
7 9
 const Resolutions = require('../../service/RTC/Resolutions');
8 10
 const VideoType = require('../../service/RTC/VideoType');
@@ -16,46 +18,37 @@ const logger = getLogger(__filename);
16 18
  */
17 19
 const STATS_MESSAGE_TYPE = 'stats';
18 20
 
19
-/**
20
- * See media/engine/simulcast.ss from webrtc.org
21
- */
22 21
 const kSimulcastFormats = [
23 22
     { width: 1920,
24 23
         height: 1080,
25 24
         layers: 3,
26
-        max: 5000,
27
-        target: 4000,
28
-        min: 800 },
25
+        target: 'high',
26
+        targetRN: 4000000 },
29 27
     { width: 1280,
30 28
         height: 720,
31 29
         layers: 3,
32
-        max: 2500,
33
-        target: 2500,
34
-        min: 600 },
30
+        target: 'high',
31
+        targetRN: 2500000 },
35 32
     { width: 960,
36 33
         height: 540,
37 34
         layers: 3,
38
-        max: 900,
39
-        target: 900,
40
-        min: 450 },
35
+        target: 'standard',
36
+        targetRN: 900000 },
41 37
     { width: 640,
42 38
         height: 360,
43 39
         layers: 2,
44
-        max: 700,
45
-        target: 500,
46
-        min: 150 },
40
+        target: 'standard',
41
+        targetRN: 500000 },
47 42
     { width: 480,
48 43
         height: 270,
49 44
         layers: 2,
50
-        max: 450,
51
-        target: 350,
52
-        min: 150 },
45
+        target: 'low',
46
+        targetRN: 350000 },
53 47
     { width: 320,
54 48
         height: 180,
55 49
         layers: 1,
56
-        max: 200,
57
-        target: 150,
58
-        min: 30 }
50
+        target: 'low',
51
+        targetRN: 150000 }
59 52
 ];
60 53
 
61 54
 /**
@@ -70,22 +63,14 @@ const MAX_TARGET_BITRATE = 2500;
70 63
  */
71 64
 let startBitrate = 800;
72 65
 
73
-
74
-/**
75
- * The current cap (in kbps) put on the video stream (or null if there isn't
76
- * a cap).  If there is a cap, we'll take it into account when calculating
77
- * the current quality.
78
- */
79
-let videoBitrateCap = null;
80
-
81 66
 /**
82 67
  * Gets the expected bitrate (in kbps) in perfect network conditions.
83 68
  * @param simulcast {boolean} whether simulcast is enabled or not.
84 69
  * @param resolution {Resolution} the resolution.
85
- * @param millisSinceStart {number} the number of milliseconds since sending
86
- * video started.
70
+ * @param millisSinceStart {number} the number of milliseconds since sending video started.
71
+ * @param videoQualitySettings {Object} the bitrate and codec settings for the local video source.
87 72
  */
88
-function getTarget(simulcast, resolution, millisSinceStart) {
73
+function getTarget(simulcast, resolution, millisSinceStart, videoQualitySettings) {
89 74
     // Completely ignore the bitrate in the first 5 seconds, as the first
90 75
     // event seems to fire very early and the value is suspicious and causes
91 76
     // false positives.
@@ -96,44 +81,35 @@ function getTarget(simulcast, resolution, millisSinceStart) {
96 81
     let target = 0;
97 82
     let height = Math.min(resolution.height, resolution.width);
98 83
 
99
-    if (simulcast) {
100
-        // Find the first format with height no bigger than ours.
101
-        let simulcastFormat = kSimulcastFormats.find(f => f.height <= height);
102
-
103
-        if (simulcastFormat) {
104
-            // Sum the target fields from all simulcast layers for the given
105
-            // resolution (e.g. 720p + 360p + 180p).
106
-            for (height = simulcastFormat.height; height >= 180; height /= 2) {
107
-                const targetHeight = height;
108
-
109
-                simulcastFormat
110
-                    = kSimulcastFormats.find(f => f.height === targetHeight);
111
-                if (simulcastFormat) {
112
-                    target += simulcastFormat.target;
113
-                } else {
114
-                    break;
115
-                }
84
+    // Find the first format with height no bigger than ours.
85
+    let simulcastFormat = kSimulcastFormats.find(f => f.height <= height);
86
+
87
+    if (simulcastFormat && simulcast && videoQualitySettings.codec === CodecMimeType.VP8) {
88
+        // Sum the target fields from all simulcast layers for the given
89
+        // resolution (e.g. 720p + 360p + 180p) for VP8 simulcast.
90
+        for (height = simulcastFormat.height; height >= 180; height /= 2) {
91
+            const targetHeight = height;
92
+
93
+            simulcastFormat = kSimulcastFormats.find(f => f.height === targetHeight);
94
+            if (simulcastFormat) {
95
+                target += browser.isReactNative()
96
+                    ? simulcastFormat.targetRN
97
+                    : videoQualitySettings[simulcastFormat.target];
98
+            } else {
99
+                break;
116 100
             }
117 101
         }
118
-    } else {
119
-        // See GetMaxDefaultVideoBitrateKbps in
120
-        // media/engine/webrtcvideoengine2.cc from webrtc.org
121
-        const pixels = resolution.width * resolution.height;
122
-
123
-        if (pixels <= 320 * 240) {
124
-            target = 600;
125
-        } else if (pixels <= 640 * 480) {
126
-            target = 1700;
127
-        } else if (pixels <= 960 * 540) {
128
-            target = 2000;
129
-        } else {
130
-            target = 2500;
131
-        }
102
+    } else if (simulcastFormat) {
103
+        // For VP9 SVC, H.264 (simulcast automatically disabled) and p2p, target bitrate will be
104
+        // same as that of the individual stream bitrate.
105
+        target = browser.isReactNative()
106
+            ? simulcastFormat.targetRN
107
+            : videoQualitySettings[simulcastFormat.target];
132 108
     }
133 109
 
134 110
     // Allow for an additional 1 second for ramp up -- delay any initial drop
135
-    // of connection quality by 1 second.
136
-    return Math.min(target, rampUp(Math.max(0, millisSinceStart - 1000)));
111
+    // of connection quality by 1 second. Convert target from bps to kbps.
112
+    return Math.min(target / 1000, rampUp(Math.max(0, millisSinceStart - 1000)));
137 113
 }
138 114
 
139 115
 /**
@@ -205,13 +181,6 @@ export default class ConnectionQuality {
205 181
          */
206 182
         this._timeVideoUnmuted = -1;
207 183
 
208
-        /**
209
-         * The time at which a video bitrate cap was last removed.  We use
210
-         * this to calculate how much time we, as a sender, have had to
211
-         * ramp-up
212
-         */
213
-        this._timeLastBwCapRemoved = -1;
214
-
215 184
         // We assume a global startBitrate value for the sake of simplicity.
216 185
         if (options.config.startBitrate && options.config.startBitrate > 0) {
217 186
             startBitrate = options.config.startBitrate;
@@ -256,17 +225,8 @@ export default class ConnectionQuality {
256 225
                 this._updateRemoteStats(participant.getId(), payload);
257 226
             });
258 227
 
259
-        // Listen to local statistics events originating from the RTC module
260
-        // and update the _localStats field.
261
-        // Oh, and by the way, the resolutions of all remote participants are
262
-        // also piggy-backed in these "local" statistics. It's obvious, really,
263
-        // if one carefully reads the *code* (but not the docs) in
264
-        // UI/VideoLayout/VideoLayout.js#updateLocalConnectionStats in
265
-        // jitsi-meet
266
-        // TODO: We should keep track of the remote resolution in _remoteStats,
267
-        // and notify about changes via separate events.
268
-        conference.statistics.addConnectionStatsListener(
269
-            this._updateLocalStats.bind(this));
228
+        // Listen to local statistics events originating from the RTC module and update the _localStats field.
229
+        conference.statistics.addConnectionStatsListener(this._updateLocalStats.bind(this));
270 230
 
271 231
         // Save the last time we were unmuted.
272 232
         conference.on(
@@ -320,11 +280,9 @@ export default class ConnectionQuality {
320 280
 
321 281
     /**
322 282
      * Calculates a new "connection quality" value.
323
-     * @param videoType {VideoType} the type of the video source (camera or
324
-     * a screen capture).
283
+     * @param videoType {VideoType} the type of the video source (camera or a screen capture).
325 284
      * @param isMuted {boolean} whether the local video is muted.
326
-     * @param resolutionName {Resolution} the input resolution used by the
327
-     * camera.
285
+     * @param resolutionName {Resolution} the input resolution used by the camera.
328 286
      * @returns {*} the newly calculated connection quality.
329 287
      */
330 288
     _calculateConnectionQuality(videoType, isMuted, resolutionName) {
@@ -383,46 +341,27 @@ export default class ConnectionQuality {
383 341
                 quality = 0; // Still 1 bar, but slower climb-up.
384 342
             }
385 343
         } else {
386
-            // Calculate a value based on the sending bitrate.
387
-
388
-            // Figure out if simulcast is in use
344
+            // Calculate a value based on the send video bitrate on the active TPC.
389 345
             const activeTPC = this._conference.getActivePeerConnection();
390
-            const isSimulcastOn
391
-                = Boolean(activeTPC && activeTPC.isSimulcastOn());
392 346
 
393
-            const newVideoBitrateCap
394
-                = activeTPC && activeTPC.bandwidthLimiter
395
-                && activeTPC.bandwidthLimiter.getBandwidthLimit('video');
347
+            if (activeTPC) {
348
+                const isSimulcastOn = activeTPC.isSimulcastOn();
349
+                const videoQualitySettings = activeTPC.getTargetVideoBitrates();
396 350
 
397
-            // If we had a cap set but there isn't one now, then it has
398
-            // just been 'lifted', so we should treat this like a new
399
-            // ramp up.
400
-            if (!newVideoBitrateCap && videoBitrateCap) {
401
-                this._timeLastBwCapRemoved = window.performance.now();
351
+                // Add the codec info as well.
352
+                videoQualitySettings.codec = activeTPC.getConfiguredVideoCodec();
402 353
 
403
-                // Set the start bitrate to whatever we were just capped to
404
-                startBitrate = videoBitrateCap;
405
-            }
406
-            videoBitrateCap = newVideoBitrateCap;
407
-
408
-            // time since sending of video was enabled.
409
-            const millisSinceStart = window.performance.now()
410
-                - Math.max(this._timeVideoUnmuted,
411
-                    this._timeIceConnected,
412
-                    this._timeLastBwCapRemoved);
413
-
414
-            // expected sending bitrate in perfect conditions
415
-            let target
416
-                = getTarget(isSimulcastOn, resolution, millisSinceStart);
354
+                // Time since sending of video was enabled.
355
+                const millisSinceStart = window.performance.now()
356
+                    - Math.max(this._timeVideoUnmuted, this._timeIceConnected);
417 357
 
418
-            target = Math.min(0.9 * target, MAX_TARGET_BITRATE);
358
+                // Expected sending bitrate in perfect conditions.
359
+                let target = getTarget(isSimulcastOn, resolution, millisSinceStart, videoQualitySettings);
419 360
 
420
-            if (videoBitrateCap) {
421
-                target = Math.min(target, videoBitrateCap);
361
+                target = Math.min(target, MAX_TARGET_BITRATE);
362
+                quality = 100 * this._localStats.bitrate.upload / target;
422 363
             }
423 364
 
424
-            quality = 100 * this._localStats.bitrate.upload / target;
425
-
426 365
             // Whatever the bitrate, drop early if there is significant loss
427 366
             if (packetLoss && packetLoss >= 10) {
428 367
                 quality = Math.min(quality, 30);
@@ -433,15 +372,9 @@ export default class ConnectionQuality {
433 372
         if (this._lastConnectionQualityUpdate > 0) {
434 373
             const maxIncreasePerSecond = 2;
435 374
             const prevConnectionQuality = this._localStats.connectionQuality;
436
-            const diffSeconds
437
-                = (window.performance.now() - this._lastConnectionQualityUpdate)
438
-                    / 1000;
439
-
440
-            quality
441
-                = Math.min(
442
-                    quality,
443
-                    prevConnectionQuality
444
-                        + (diffSeconds * maxIncreasePerSecond));
375
+            const diffSeconds = (window.performance.now() - this._lastConnectionQualityUpdate) / 1000;
376
+
377
+            quality = Math.min(quality, prevConnectionQuality + (diffSeconds * maxIncreasePerSecond));
445 378
         }
446 379
 
447 380
         return Math.min(100, quality);

Laddar…
Avbryt
Spara