瀏覽代碼

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 年之前
父節點
當前提交
1f3f85978d
沒有連結到貢獻者的電子郵件帳戶。
共有 2 個檔案被更改,包括 73 行新增129 行删除
  1. 12
    1
      modules/RTC/TraceablePeerConnection.js
  2. 61
    128
      modules/connectivity/ConnectionQuality.js

+ 12
- 1
modules/RTC/TraceablePeerConnection.js 查看文件

701
     return removeSsrcInfo;
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
  * Tries to find {@link JitsiTrack} for given SSRC number. It will search both
716
  * Tries to find {@link JitsiTrack} for given SSRC number. It will search both
706
  * local and remote tracks bound to this instance.
717
  * local and remote tracks bound to this instance.
2321
         }
2332
         }
2322
     } else {
2333
     } else {
2323
         // Do not change the max bitrate for desktop tracks in non-simulcast mode.
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
         if (videoType === VideoType.CAMERA) {
2337
         if (videoType === VideoType.CAMERA) {
2327
             // Determine the bitrates based on the sender constraint applied for unicast tracks.
2338
             // Determine the bitrates based on the sender constraint applied for unicast tracks.

+ 61
- 128
modules/connectivity/ConnectionQuality.js 查看文件

1
 import { getLogger } from 'jitsi-meet-logger';
1
 import { getLogger } from 'jitsi-meet-logger';
2
 
2
 
3
 import * as ConferenceEvents from '../../JitsiConferenceEvents';
3
 import * as ConferenceEvents from '../../JitsiConferenceEvents';
4
+import CodecMimeType from '../../service/RTC/CodecMimeType';
4
 import * as RTCEvents from '../../service/RTC/RTCEvents';
5
 import * as RTCEvents from '../../service/RTC/RTCEvents';
5
 import * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';
6
 import * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';
7
+import browser from '../browser';
6
 
8
 
7
 const Resolutions = require('../../service/RTC/Resolutions');
9
 const Resolutions = require('../../service/RTC/Resolutions');
8
 const VideoType = require('../../service/RTC/VideoType');
10
 const VideoType = require('../../service/RTC/VideoType');
16
  */
18
  */
17
 const STATS_MESSAGE_TYPE = 'stats';
19
 const STATS_MESSAGE_TYPE = 'stats';
18
 
20
 
19
-/**
20
- * See media/engine/simulcast.ss from webrtc.org
21
- */
22
 const kSimulcastFormats = [
21
 const kSimulcastFormats = [
23
     { width: 1920,
22
     { width: 1920,
24
         height: 1080,
23
         height: 1080,
25
         layers: 3,
24
         layers: 3,
26
-        max: 5000,
27
-        target: 4000,
28
-        min: 800 },
25
+        target: 'high',
26
+        targetRN: 4000000 },
29
     { width: 1280,
27
     { width: 1280,
30
         height: 720,
28
         height: 720,
31
         layers: 3,
29
         layers: 3,
32
-        max: 2500,
33
-        target: 2500,
34
-        min: 600 },
30
+        target: 'high',
31
+        targetRN: 2500000 },
35
     { width: 960,
32
     { width: 960,
36
         height: 540,
33
         height: 540,
37
         layers: 3,
34
         layers: 3,
38
-        max: 900,
39
-        target: 900,
40
-        min: 450 },
35
+        target: 'standard',
36
+        targetRN: 900000 },
41
     { width: 640,
37
     { width: 640,
42
         height: 360,
38
         height: 360,
43
         layers: 2,
39
         layers: 2,
44
-        max: 700,
45
-        target: 500,
46
-        min: 150 },
40
+        target: 'standard',
41
+        targetRN: 500000 },
47
     { width: 480,
42
     { width: 480,
48
         height: 270,
43
         height: 270,
49
         layers: 2,
44
         layers: 2,
50
-        max: 450,
51
-        target: 350,
52
-        min: 150 },
45
+        target: 'low',
46
+        targetRN: 350000 },
53
     { width: 320,
47
     { width: 320,
54
         height: 180,
48
         height: 180,
55
         layers: 1,
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
  */
63
  */
71
 let startBitrate = 800;
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
  * Gets the expected bitrate (in kbps) in perfect network conditions.
67
  * Gets the expected bitrate (in kbps) in perfect network conditions.
83
  * @param simulcast {boolean} whether simulcast is enabled or not.
68
  * @param simulcast {boolean} whether simulcast is enabled or not.
84
  * @param resolution {Resolution} the resolution.
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
     // Completely ignore the bitrate in the first 5 seconds, as the first
74
     // Completely ignore the bitrate in the first 5 seconds, as the first
90
     // event seems to fire very early and the value is suspicious and causes
75
     // event seems to fire very early and the value is suspicious and causes
91
     // false positives.
76
     // false positives.
96
     let target = 0;
81
     let target = 0;
97
     let height = Math.min(resolution.height, resolution.width);
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
     // Allow for an additional 1 second for ramp up -- delay any initial drop
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
          */
181
          */
206
         this._timeVideoUnmuted = -1;
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
         // We assume a global startBitrate value for the sake of simplicity.
184
         // We assume a global startBitrate value for the sake of simplicity.
216
         if (options.config.startBitrate && options.config.startBitrate > 0) {
185
         if (options.config.startBitrate && options.config.startBitrate > 0) {
217
             startBitrate = options.config.startBitrate;
186
             startBitrate = options.config.startBitrate;
256
                 this._updateRemoteStats(participant.getId(), payload);
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
         // Save the last time we were unmuted.
231
         // Save the last time we were unmuted.
272
         conference.on(
232
         conference.on(
320
 
280
 
321
     /**
281
     /**
322
      * Calculates a new "connection quality" value.
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
      * @param isMuted {boolean} whether the local video is muted.
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
      * @returns {*} the newly calculated connection quality.
286
      * @returns {*} the newly calculated connection quality.
329
      */
287
      */
330
     _calculateConnectionQuality(videoType, isMuted, resolutionName) {
288
     _calculateConnectionQuality(videoType, isMuted, resolutionName) {
383
                 quality = 0; // Still 1 bar, but slower climb-up.
341
                 quality = 0; // Still 1 bar, but slower climb-up.
384
             }
342
             }
385
         } else {
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
             const activeTPC = this._conference.getActivePeerConnection();
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
             // Whatever the bitrate, drop early if there is significant loss
365
             // Whatever the bitrate, drop early if there is significant loss
427
             if (packetLoss && packetLoss >= 10) {
366
             if (packetLoss && packetLoss >= 10) {
428
                 quality = Math.min(quality, 30);
367
                 quality = Math.min(quality, 30);
433
         if (this._lastConnectionQualityUpdate > 0) {
372
         if (this._lastConnectionQualityUpdate > 0) {
434
             const maxIncreasePerSecond = 2;
373
             const maxIncreasePerSecond = 2;
435
             const prevConnectionQuality = this._localStats.connectionQuality;
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
         return Math.min(100, quality);
380
         return Math.min(100, quality);

Loading…
取消
儲存