Преглед на файлове

ref(TPC) Configure encodings in one go. (#1739)

* ref(TPC) Configure encodings in one go.
Configure the active state, maxBitrate and degradation preference in one go instead of configuring them separately.

* squash: Address review comments.

* squash: fix a comment.
tags/v0.0.2
Jaya Allamsetty преди 4 години
родител
ревизия
d27a510f84
No account linked to committer's email address

+ 2
- 2
modules/RTC/MockClasses.js Целия файл

@@ -66,9 +66,9 @@ export class MockPeerConnection {
66 66
     }
67 67
 
68 68
     /**
69
-     * {@link TraceablePeerConnection.setSenderVideoConstraint}.
69
+     * {@link TraceablePeerConnection.setSenderVideoConstraints}.
70 70
      */
71
-    setSenderVideoConstraint() {
71
+    setSenderVideoConstraints() {
72 72
     }
73 73
 
74 74
     /**

+ 98
- 28
modules/RTC/TPCUtils.js Целия файл

@@ -3,13 +3,21 @@ import transform from 'sdp-transform';
3 3
 
4 4
 import MediaDirection from '../../service/RTC/MediaDirection';
5 5
 import * as MediaType from '../../service/RTC/MediaType';
6
+import VideoType from '../../service/RTC/VideoType';
6 7
 import browser from '../browser';
7 8
 
8 9
 const logger = getLogger(__filename);
10
+const DESKTOP_SHARE_RATE = 500000;
11
+const LD_BITRATE = 200000;
12
+const SD_BITRATE = 700000;
9 13
 const SIM_LAYER_1_RID = '1';
10 14
 const SIM_LAYER_2_RID = '2';
11 15
 const SIM_LAYER_3_RID = '3';
12 16
 
17
+export const HD_BITRATE = 2500000;
18
+export const HD_SCALE_FACTOR = 1;
19
+export const LD_SCALE_FACTOR = 4;
20
+export const SD_SCALE_FACTOR = 2;
13 21
 export const SIM_LAYER_RIDS = [ SIM_LAYER_1_RID, SIM_LAYER_2_RID, SIM_LAYER_3_RID ];
14 22
 
15 23
 /**
@@ -21,12 +29,21 @@ export class TPCUtils {
21 29
      * Creates a new instance for a given TraceablePeerConnection
22 30
      *
23 31
      * @param peerconnection - the tpc instance for which we have utility functions.
24
-     * @param videoBitrates - the bitrates to be configured on the video senders for
25
-     * different resolutions both in unicast and simulcast mode.
26 32
      */
27
-    constructor(peerconnection, videoBitrates) {
33
+    constructor(peerconnection) {
28 34
         this.pc = peerconnection;
29
-        this.videoBitrates = videoBitrates.VP8 || videoBitrates;
35
+        const bitrateSettings = this.pc.options?.videoQuality?.maxBitratesVideo;
36
+        const standardBitrates = {
37
+            low: LD_BITRATE,
38
+            standard: SD_BITRATE,
39
+            high: HD_BITRATE
40
+        };
41
+
42
+        // Check if the max. bitrates for video are specified through config.js videoQuality settings.
43
+        // Right now only VP8 bitrates are configured on the simulcast encodings, VP9 bitrates have to be
44
+        // configured on the SDP using b:AS line.
45
+        this.videoBitrates = bitrateSettings ?? standardBitrates;
46
+        const encodingBitrates = this.videoBitrates.VP8 ?? this.videoBitrates;
30 47
 
31 48
         /**
32 49
          * The startup configuration for the stream encodings that are applicable to
@@ -44,21 +61,21 @@ export class TPCUtils {
44 61
         this.localStreamEncodingsConfig = [
45 62
             {
46 63
                 active: true,
47
-                maxBitrate: browser.isFirefox() ? this.videoBitrates.high : this.videoBitrates.low,
64
+                maxBitrate: browser.isFirefox() ? encodingBitrates.high : encodingBitrates.low,
48 65
                 rid: SIM_LAYER_1_RID,
49
-                scaleResolutionDownBy: browser.isFirefox() ? 1.0 : 4.0
66
+                scaleResolutionDownBy: browser.isFirefox() ? HD_SCALE_FACTOR : LD_SCALE_FACTOR
50 67
             },
51 68
             {
52 69
                 active: true,
53
-                maxBitrate: this.videoBitrates.standard,
70
+                maxBitrate: encodingBitrates.standard,
54 71
                 rid: SIM_LAYER_2_RID,
55
-                scaleResolutionDownBy: 2.0
72
+                scaleResolutionDownBy: SD_SCALE_FACTOR
56 73
             },
57 74
             {
58 75
                 active: true,
59
-                maxBitrate: browser.isFirefox() ? this.videoBitrates.low : this.videoBitrates.high,
76
+                maxBitrate: browser.isFirefox() ? encodingBitrates.low : encodingBitrates.high,
60 77
                 rid: SIM_LAYER_3_RID,
61
-                scaleResolutionDownBy: browser.isFirefox() ? 4.0 : 1.0
78
+                scaleResolutionDownBy: browser.isFirefox() ? LD_SCALE_FACTOR : HD_SCALE_FACTOR
62 79
             }
63 80
         ];
64 81
     }
@@ -273,29 +290,82 @@ export class TPCUtils {
273 290
     }
274 291
 
275 292
     /**
276
-     * Obtains the current local video track's height constraints based on the
277
-     * initial stream encodings configuration on the sender and the resolution
278
-     * of the current local track added to the peerconnection.
279
-     * @param {MediaStreamTrack} localTrack local video track
280
-     * @returns {Array[number]} an array containing the resolution heights of
281
-     * simulcast streams configured on the video sender.
293
+     * Returns the calculated active state of the simulcast encodings based on the frame height requested for the send
294
+     * stream. All the encodings that have a resolution lower than the frame height requested will be enabled.
295
+     *
296
+     * @param {JitsiLocalTrack} localVideoTrack The local video track.
297
+     * @param {number} newHeight The resolution requested for the video track.
298
+     * @returns {Array<boolean>}
282 299
      */
283
-    getLocalStreamHeightConstraints(localTrack) {
284
-        // React-native hasn't implemented MediaStreamTrack getSettings yet.
285
-        if (browser.isReactNative()) {
286
-            return null;
287
-        }
300
+    calculateEncodingsActiveState(localVideoTrack, newHeight) {
301
+        const localTrack = localVideoTrack.getTrack();
302
+        const { height } = localTrack.getSettings();
303
+        const encodingsState = this.localStreamEncodingsConfig
304
+        .map(encoding => height / encoding.scaleResolutionDownBy)
305
+        .map((frameHeight, idx) => {
306
+            let active = localVideoTrack.getVideoType() === VideoType.CAMERA
307
+
308
+                // Keep the LD stream enabled even when the LD stream's resolution is higher than of the requested
309
+                // resolution. This can happen when camera is captured at resolutions higher than 720p but the
310
+                // requested resolution is 180. Since getParameters doesn't give us information about the resolutions
311
+                // of the simulcast encodings, we have to rely on our initial config for the simulcast streams.
312
+                ? newHeight > 0 && this.localStreamEncodingsConfig[idx]?.scaleResolutionDownBy === LD_SCALE_FACTOR
313
+                    ? true
314
+                    : frameHeight <= newHeight
315
+
316
+                // Keep all the encodings for desktop track active.
317
+                : true;
318
+
319
+            // Disable the lower spatial layers for screensharing in Unified plan when low fps screensharing is in
320
+            // progress. Sending all three streams often results in the browser suspending the high resolution in low
321
+            // b/w and cpu cases, especially on the low end machines. Suspending the low resolution streams ensures
322
+            // that the highest resolution stream is available always. Safari is an exception here since it does not
323
+            // send the desktop stream at all if only the high resolution stream is enabled.
324
+            if (this.pc.isSharingLowFpsScreen()
325
+                && this.pc.usesUnifiedPlan()
326
+                && !browser.isWebKitBased()
327
+                && this.localStreamEncodingsConfig[idx].scaleResolutionDownBy !== HD_SCALE_FACTOR) {
328
+                active = false;
329
+            }
288 330
 
289
-        const localVideoHeightConstraints = [];
331
+            return active;
332
+        });
290 333
 
291
-        // Firefox doesn't return the height of the desktop track, assume a min. height of 720.
292
-        const { height = 720 } = localTrack.getSettings();
334
+        return encodingsState;
335
+    }
293 336
 
294
-        for (const encoding of this.localStreamEncodingsConfig) {
295
-            localVideoHeightConstraints.push(height / encoding.scaleResolutionDownBy);
296
-        }
337
+    /**
338
+     * Returns the calculates max bitrates that need to be configured on the simulcast encodings based on the video
339
+     * type and other considerations associated with screenshare.
340
+     *
341
+     * @param {JitsiLocalTrack} localVideoTrack The local video track.
342
+     * @returns {Array<number>}
343
+     */
344
+    calculateEncodingsBitrates(localVideoTrack) {
345
+        const videoType = localVideoTrack.getVideoType();
346
+        const desktopShareBitrate = this.pc.options?.videoQuality?.desktopBitrate || DESKTOP_SHARE_RATE;
347
+        const presenterEnabled = localVideoTrack._originalStream
348
+            && localVideoTrack._originalStream.id !== localVideoTrack.getStreamId();
349
+
350
+        const encodingsBitrates = this.localStreamEncodingsConfig
351
+        .map(encoding => {
352
+            const bitrate = this.pc.isSharingLowFpsScreen() && !browser.isWebKitBased()
353
+
354
+                // For low fps screensharing, set a max bitrate of 500 Kbps when presenter is not turned on, 2500 Kbps
355
+                // otherwise.
356
+                ? presenterEnabled ? HD_BITRATE : desktopShareBitrate
357
+
358
+                // For high fps screenshare, 'maxBitrate' setting must be cleared on Chrome in plan-b, because
359
+                // if simulcast is enabled for screen and maxBitrates are set then Chrome will not send the
360
+                // desktop stream.
361
+                : videoType === VideoType.DESKTOP && browser.isChromiumBased() && !this.pc.usesUnifiedPlan()
362
+                    ? undefined
363
+                    : encoding.maxBitrate;
364
+
365
+            return bitrate;
366
+        });
297 367
 
298
-        return localVideoHeightConstraints;
368
+        return encodingsBitrates;
299 369
     }
300 370
 
301 371
     /**

+ 79
- 213
modules/RTC/TraceablePeerConnection.js Целия файл

@@ -23,17 +23,18 @@ import * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
23 23
 import JitsiRemoteTrack from './JitsiRemoteTrack';
24 24
 import RTC from './RTC';
25 25
 import RTCUtils from './RTCUtils';
26
-import { SIM_LAYER_RIDS, TPCUtils } from './TPCUtils';
26
+import {
27
+    HD_BITRATE,
28
+    HD_SCALE_FACTOR,
29
+    SIM_LAYER_RIDS,
30
+    TPCUtils
31
+} from './TPCUtils';
27 32
 
28 33
 // FIXME SDP tools should end up in some kind of util module
29 34
 
30 35
 const logger = getLogger(__filename);
31 36
 const DEGRADATION_PREFERENCE_CAMERA = 'maintain-framerate';
32 37
 const DEGRADATION_PREFERENCE_DESKTOP = 'maintain-resolution';
33
-const DESKTOP_SHARE_RATE = 500000;
34
-const HD_BITRATE = 2500000;
35
-const LD_BITRATE = 200000;
36
-const SD_BITRATE = 700000;
37 38
 
38 39
 /* eslint-disable max-params */
39 40
 
@@ -224,21 +225,7 @@ export default function TraceablePeerConnection(
224 225
 
225 226
     this.peerconnection = new RTCUtils.RTCPeerConnectionType(pcConfig, safeConstraints);
226 227
 
227
-    // The standard video bitrates are used in Unified plan when switching
228
-    // between camera/desktop tracks on the same sender.
229
-    const standardVideoBitrates = {
230
-        low: LD_BITRATE,
231
-        standard: SD_BITRATE,
232
-        high: HD_BITRATE
233
-    };
234
-
235
-    // Check if the max. bitrates for video are specified through config.js videoQuality settings.
236
-    // These bitrates will be applied on all browsers for camera sources in both simulcast and p2p mode.
237
-    this.videoBitrates = this.options.videoQuality && this.options.videoQuality.maxBitratesVideo
238
-        ? this.options.videoQuality.maxBitratesVideo
239
-        : standardVideoBitrates;
240
-
241
-    this.tpcUtils = new TPCUtils(this, this.videoBitrates);
228
+    this.tpcUtils = new TPCUtils(this);
242 229
     this.updateLog = [];
243 230
     this.stats = {};
244 231
     this.statsinterval = null;
@@ -293,9 +280,10 @@ export default function TraceablePeerConnection(
293 280
     this.rtxModifier = new RtxModifier();
294 281
 
295 282
     /**
296
-     * The height constraint applied on the video sender.
283
+     * The height constraint applied on the video sender. The default value is 2160 (4K) when layer suspension is
284
+     * explicitly disabled.
297 285
      */
298
-    this.senderVideoMaxHeight = null;
286
+    this._senderVideoMaxHeight = 2160;
299 287
 
300 288
     // override as desired
301 289
     this.trace = (what, info) => {
@@ -724,7 +712,7 @@ TraceablePeerConnection.prototype.getRemoteSourceInfoByParticipant = function(id
724 712
 TraceablePeerConnection.prototype.getTargetVideoBitrates = function() {
725 713
     const currentCodec = this.getConfiguredVideoCodec();
726 714
 
727
-    return this.videoBitrates[currentCodec.toUpperCase()] || this.videoBitrates;
715
+    return this.tpcUtils.videoBitrates[currentCodec.toUpperCase()] || this.tpcUtils.videoBitrates;
728 716
 };
729 717
 
730 718
 /**
@@ -1593,7 +1581,7 @@ TraceablePeerConnection.prototype._getSSRC = function(rtcId) {
1593 1581
  * @private
1594 1582
  * @returns {boolean} Returns true if 5 fps screensharing is in progress, false otherwise.
1595 1583
  */
1596
-TraceablePeerConnection.prototype._isSharingLowFpsScreen = function() {
1584
+TraceablePeerConnection.prototype.isSharingLowFpsScreen = function() {
1597 1585
     return this._isSharingScreen() && this._capScreenshareBitrate;
1598 1586
 };
1599 1587
 
@@ -1649,7 +1637,7 @@ TraceablePeerConnection.prototype._mungeCodecOrder = function(description) {
1649 1637
         // as soon as the browser switches to VP9.
1650 1638
         if (this.codecPreference.mimeType === CodecMimeType.VP9
1651 1639
             && this.getConfiguredVideoCodec() === CodecMimeType.VP9) {
1652
-            const bitrates = this.videoBitrates.VP9 || this.videoBitrates;
1640
+            const bitrates = this.tpcUtils.videoBitrates.VP9 || this.tpcUtils.videoBitrates;
1653 1641
             const hdBitrate = bitrates.high ? bitrates.high : HD_BITRATE;
1654 1642
             const limit = Math.floor((this._isSharingScreen() ? HD_BITRATE : hdBitrate) / 1000);
1655 1643
 
@@ -2243,6 +2231,15 @@ TraceablePeerConnection.prototype._mungeOpus = function(description) {
2243 2231
     });
2244 2232
 };
2245 2233
 
2234
+/**
2235
+ * Configures the stream encodings depending on the video type and the bitrates configured.
2236
+ *
2237
+ * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.
2238
+ */
2239
+TraceablePeerConnection.prototype.configureSenderVideoEncodings = function() {
2240
+    return this.setSenderVideoConstraints(this._senderVideoMaxHeight);
2241
+};
2242
+
2246 2243
 TraceablePeerConnection.prototype.setLocalDescription = function(description) {
2247 2244
     let localSdp = description;
2248 2245
 
@@ -2319,131 +2316,6 @@ TraceablePeerConnection.prototype.setAudioTransferActive = function(active) {
2319 2316
     return changed;
2320 2317
 };
2321 2318
 
2322
-/**
2323
- * Sets the degradation preference on the video sender. This setting determines if
2324
- * resolution or framerate will be preferred when bandwidth or cpu is constrained.
2325
- * Sets it to 'maintain-framerate' when a camera track is added to the pc, sets it
2326
- * to 'maintain-resolution' when a desktop track is being shared instead.
2327
- * @returns {Promise<void>}
2328
- */
2329
-TraceablePeerConnection.prototype.setSenderVideoDegradationPreference = function() {
2330
-    if (!this.peerconnection.getSenders) {
2331
-        logger.debug(`${this} Browser does not support RTCRtpSender`);
2332
-
2333
-        return Promise.resolve();
2334
-    }
2335
-    const localVideoTrack = this.getLocalVideoTrack();
2336
-    const videoSender = this.findSenderByKind(MediaType.VIDEO);
2337
-
2338
-    if (!videoSender) {
2339
-        return Promise.resolve();
2340
-    }
2341
-    const parameters = videoSender.getParameters();
2342
-    const preference = this._isSharingLowFpsScreen()
2343
-
2344
-        // Prefer resolution for low fps share.
2345
-        ? DEGRADATION_PREFERENCE_DESKTOP
2346
-
2347
-        // Prefer frame-rate for high fps share and camera.
2348
-        : DEGRADATION_PREFERENCE_CAMERA;
2349
-
2350
-    logger.info(`${this} Setting a degradation preference [preference=${preference},track=${localVideoTrack}`);
2351
-    parameters.degradationPreference = preference;
2352
-    this.tpcUtils.updateEncodingsResolution(parameters);
2353
-
2354
-    return videoSender.setParameters(parameters);
2355
-};
2356
-
2357
-/**
2358
- * Sets the max bitrate on the RTCRtpSender so that the
2359
- * bitrate of the enocder doesn't exceed the configured value.
2360
- * This is needed for the desktop share until spec-complaint
2361
- * simulcast is implemented.
2362
- * @param {JitsiLocalTrack} localTrack - the local track whose
2363
- * max bitrate is to be configured.
2364
- * @returns {Promise<void>}
2365
- */
2366
-TraceablePeerConnection.prototype.setMaxBitRate = function() {
2367
-    // For VP9, max bitrate is configured by setting b=AS value in SDP. Browsers do
2368
-    // not yet support setting max bitrates for individual VP9 SVC layers.
2369
-    if (this.getConfiguredVideoCodec() === CodecMimeType.VP9 || !window.RTCRtpSender) {
2370
-        return Promise.resolve();
2371
-    }
2372
-    const localVideoTrack = this.getLocalVideoTrack();
2373
-
2374
-    if (!localVideoTrack) {
2375
-        return Promise.resolve();
2376
-    }
2377
-
2378
-    const videoType = localVideoTrack.getVideoType();
2379
-
2380
-    // Apply the maxbitrates on the video track when one of the conditions is met.
2381
-    // 1. Max. bitrates for video are specified through videoQuality settings in config.js
2382
-    // 2. Track is a low fps desktop track.
2383
-    // 3. The client is running in Unified plan mode (the same sender is re-used for different types
2384
-    // of tracks so bitrates have to be configured whenever the local tracks are replaced).
2385
-    if (!(this.options?.videoQuality?.maxBitratesVideo || this._isSharingLowFpsScreen() || this._usesUnifiedPlan)) {
2386
-        return Promise.resolve();
2387
-    }
2388
-
2389
-    const presenterEnabled = localVideoTrack._originalStream
2390
-        && localVideoTrack._originalStream.id !== localVideoTrack.getStreamId();
2391
-    const videoSender = this.findSenderByKind(MediaType.VIDEO);
2392
-
2393
-    if (!videoSender) {
2394
-        return Promise.resolve();
2395
-    }
2396
-    const parameters = videoSender.getParameters();
2397
-
2398
-    if (!parameters.encodings?.length) {
2399
-        return Promise.resolve();
2400
-    }
2401
-
2402
-    if (this.isSimulcastOn()) {
2403
-        for (const encoding in parameters.encodings) {
2404
-            if (parameters.encodings.hasOwnProperty(encoding)) {
2405
-                const bitrate = this._isSharingLowFpsScreen()
2406
-
2407
-                    // For low fps screensharing, set a max bitrate of 500 Kbps when presenter is not turned on.
2408
-                    // FIXME the top 'isSimulcastOn' condition is confusing for screensharing, because
2409
-                    // if capScreenshareBitrate option is enabled then simulcast is turned off for the stream.
2410
-                    ? presenterEnabled ? HD_BITRATE : DESKTOP_SHARE_RATE
2411
-
2412
-                    // For high fps screenshare, 'maxBitrate' setting must be cleared on Chrome, because if simulcast is
2413
-                    // enabled for screen and maxBitrates are set then Chrome will not send the desktop stream.
2414
-                    : videoType === VideoType.DESKTOP && browser.isChromiumBased()
2415
-                        ? undefined
2416
-                        : this.tpcUtils.localStreamEncodingsConfig[encoding].maxBitrate;
2417
-
2418
-                logger.info(`${this} Setting a max bitrate of ${bitrate} bps on layer `
2419
-                    + `${this.tpcUtils.localStreamEncodingsConfig[encoding].rid}`);
2420
-                parameters.encodings[encoding].maxBitrate = bitrate;
2421
-            }
2422
-        }
2423
-    } else {
2424
-        // Do not change the max bitrate for desktop tracks in non-simulcast mode.
2425
-        let bitrate = this.getTargetVideoBitrates()?.high;
2426
-
2427
-        if (videoType === VideoType.CAMERA) {
2428
-            // Determine the bitrates based on the sender constraint applied for unicast tracks.
2429
-            const scaleFactor = this.senderVideoMaxHeight
2430
-                ? Math.floor(localVideoTrack.resolution / this.senderVideoMaxHeight)
2431
-                : 1;
2432
-            const encoding = this.tpcUtils.localStreamEncodingsConfig
2433
-                .find(layer => layer.scaleResolutionDownBy === scaleFactor);
2434
-
2435
-            if (encoding) {
2436
-                logger.info(`${this} Setting max bitrate=${encoding.maxBitrate} bps on track=${localVideoTrack}`);
2437
-                bitrate = encoding.maxBitrate;
2438
-            }
2439
-        }
2440
-        parameters.encodings[0].maxBitrate = bitrate;
2441
-    }
2442
-    this.tpcUtils.updateEncodingsResolution(parameters);
2443
-
2444
-    return videoSender.setParameters(parameters);
2445
-};
2446
-
2447 2319
 TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
2448 2320
     this.trace('setRemoteDescription::preTransform', dumpSDP(description));
2449 2321
 
@@ -2519,16 +2391,14 @@ TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
2519 2391
 };
2520 2392
 
2521 2393
 /**
2522
- * Changes the resolution of the video stream that is sent to the peer based on
2523
- * the user preferred value. If simulcast is enabled on the peerconection, all the
2524
- * simulcast encodings that have a resolution height lower or equal to the value
2525
- * provided will remain active. For the non-simulcast case, video constraint is
2526
- * applied on the track.
2527
- * @param {number} frameHeight - The user preferred max frame height.
2528
- * @returns {Promise} promise that will be resolved when the operation is
2529
- * successful and rejected otherwise.
2394
+ * Changes the resolution of the video stream that is sent to the peer based on the resolution requested by the peer
2395
+ * and user preference, sets the degradation preference on the sender based on the video type, configures the maximum
2396
+ * bitrates on the send stream.
2397
+ *
2398
+ * @param {number} frameHeight - The max frame height to be imposed on the outgoing video stream.
2399
+ * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.
2530 2400
  */
2531
-TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeight = null) {
2401
+TraceablePeerConnection.prototype.setSenderVideoConstraints = function(frameHeight) {
2532 2402
     if (frameHeight < 0) {
2533 2403
         throw new Error(`Invalid frameHeight: ${frameHeight}`);
2534 2404
     }
@@ -2538,20 +2408,7 @@ TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeigh
2538 2408
         return Promise.resolve();
2539 2409
     }
2540 2410
 
2541
-    // Need to explicitly check for null as 0 is falsy, but a valid value
2542
-    const newHeight = frameHeight === null ? this.senderVideoMaxHeight : frameHeight;
2543
-
2544
-    this.senderVideoMaxHeight = newHeight;
2545
-
2546
-    // If layer suspension is disabled and sender constraint is not configured for the conference,
2547
-    // resolve here so that the encodings stay enabled. This can happen in custom apps built using
2548
-    // lib-jitsi-meet.
2549
-    if (newHeight === null) {
2550
-        return Promise.resolve();
2551
-    }
2552
-
2553
-    logger.log(`${this} senderVideoMaxHeight: ${newHeight}`);
2554
-
2411
+    this._senderVideoMaxHeight = frameHeight;
2555 2412
     const localVideoTrack = this.getLocalVideoTrack();
2556 2413
 
2557 2414
     if (!localVideoTrack || localVideoTrack.isMuted()) {
@@ -2568,62 +2425,71 @@ TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeigh
2568 2425
         return Promise.resolve();
2569 2426
     }
2570 2427
 
2571
-    if (this.isSimulcastOn()) {
2572
-        // Determine the encodings that need to stay enabled based on the new frameHeight provided.
2573
-        this.encodingsEnabledState = this.tpcUtils.getLocalStreamHeightConstraints(localVideoTrack.track)
2574
-            .map(height => height <= newHeight);
2575
-
2576
-        // Always keep the LD stream enabled, specifically when the LD stream's resolution is higher than of the
2577
-        // requested resolution. This can happen when camera is captured at resolutions higher than 720p but the
2578
-        // requested resolution is 180. Since getParameters doesn't give us information about the resolutions
2579
-        // of the simulcast encodings, we have to rely on our initial config for the simulcast streams.
2580
-        const ldStreamIndex = this.tpcUtils.localStreamEncodingsConfig
2581
-            .findIndex(layer => layer.scaleResolutionDownBy === 4.0);
2582
-
2583
-        if (newHeight > 0 && ldStreamIndex !== -1) {
2584
-            this.encodingsEnabledState[ldStreamIndex] = true;
2585
-        }
2428
+    // Set the degradation preference.
2429
+    const preference = this.isSharingLowFpsScreen()
2430
+        ? DEGRADATION_PREFERENCE_DESKTOP // Prefer resolution for low fps share.
2431
+        : DEGRADATION_PREFERENCE_CAMERA; // Prefer frame-rate for high fps share and camera.
2586 2432
 
2587
-        // Disable the lower spatial layers for screensharing in Unified plan when low fps screensharing is in progress
2588
-        // There is no way to enable or disable simulcast during the call since we are re-using the same sender.
2589
-        // Safari is an exception here since it does not send the desktop stream at all if only the high resolution
2590
-        // stream is enabled.
2591
-        if (this._isSharingLowFpsScreen() && this._usesUnifiedPlan && !browser.isWebKitBased()) {
2592
-            const highResolutionEncoding = browser.isFirefox() ? 0 : this.encodingsEnabledState.length - 1;
2433
+    parameters.degradationPreference = preference;
2434
+    logger.info(`${this} Setting degradation preference [preference=${preference},track=${localVideoTrack}`);
2593 2435
 
2594
-            this.encodingsEnabledState = this.encodingsEnabledState
2595
-                .map((encoding, idx) => idx === highResolutionEncoding);
2596
-        }
2436
+    // Calculate the encodings active state based on the resolution requested by the bridge.
2437
+    this.encodingsEnabledState = this.tpcUtils.calculateEncodingsActiveState(localVideoTrack, frameHeight);
2438
+    const maxBitrates = this.tpcUtils.calculateEncodingsBitrates(localVideoTrack);
2439
+    const videoType = localVideoTrack.getVideoType();
2597 2440
 
2441
+    if (this.isSimulcastOn()) {
2598 2442
         for (const encoding in parameters.encodings) {
2599 2443
             if (parameters.encodings.hasOwnProperty(encoding)) {
2600 2444
                 parameters.encodings[encoding].active = this.encodingsEnabledState[encoding];
2445
+
2446
+                // Firefox doesn't follow the spec and lets application specify the degradation preference on the
2447
+                // encodings.
2448
+                browser.isFirefox() && (parameters.encodings[encoding].degradationPreference = preference);
2449
+
2450
+                // Max bitrates are configured on the encodings only for VP8.
2451
+                if (this.getConfiguredVideoCodec() === CodecMimeType.VP8
2452
+                    && (this.options?.videoQuality?.maxBitratesVideo
2453
+                        || this.isSharingLowFpsScreen()
2454
+                        || this._usesUnifiedPlan)) {
2455
+                    parameters.encodings[encoding].maxBitrate = maxBitrates[encoding];
2456
+                }
2601 2457
             }
2602 2458
         }
2603 2459
         this.tpcUtils.updateEncodingsResolution(parameters);
2604
-    } else if (newHeight > 0) {
2460
+
2461
+    // For p2p and cases and where simulcast is explicitly disabled.
2462
+    } else if (frameHeight > 0) {
2605 2463
         // Do not scale down encodings for desktop tracks for non-simulcast case.
2606
-        parameters.encodings[0].scaleResolutionDownBy
2607
-            = localVideoTrack.videoType === VideoType.DESKTOP || localVideoTrack.resolution <= newHeight
2608
-                ? 1
2609
-                : Math.floor(localVideoTrack.resolution / newHeight);
2464
+        const scaleFactor = videoType === VideoType.DESKTOP || localVideoTrack.resolution <= frameHeight
2465
+            ? HD_SCALE_FACTOR
2466
+            : Math.floor(localVideoTrack.resolution / frameHeight);
2467
+
2610 2468
         parameters.encodings[0].active = true;
2469
+        parameters.encodings[0].scaleResolutionDownBy = scaleFactor;
2470
+
2471
+        // Firefox doesn't follow the spec and lets application specify the degradation preference on the encodings.
2472
+        browser.isFirefox() && (parameters.encodings[0].degradationPreference = preference);
2473
+
2474
+        // Configure the bitrate.
2475
+        if (this.getConfiguredVideoCodec() === CodecMimeType.VP8 && this.options?.videoQuality?.maxBitratesVideo) {
2476
+            let bitrate = this.getTargetVideoBitrates()?.high;
2477
+
2478
+            if (videoType === VideoType.CAMERA) {
2479
+                bitrate = this.tpcUtils.localStreamEncodingsConfig
2480
+                    .find(layer => layer.scaleResolutionDownBy === scaleFactor)?.maxBitrate ?? bitrate;
2481
+            }
2482
+            parameters.encodings[0].maxBitrate = bitrate;
2483
+        }
2611 2484
     } else {
2612
-        parameters.encodings[0].scaleResolutionDownBy = undefined;
2613 2485
         parameters.encodings[0].active = false;
2614 2486
     }
2615 2487
 
2616
-    logger.info(`${this} setting max height=${newHeight},encodings=${JSON.stringify(parameters.encodings)}`);
2488
+    logger.info(`${this} setting max height=${frameHeight},encodings=${JSON.stringify(parameters.encodings)}`);
2617 2489
 
2618 2490
     return videoSender.setParameters(parameters).then(() => {
2619
-        localVideoTrack.maxEnabledResolution = newHeight;
2491
+        localVideoTrack.maxEnabledResolution = frameHeight;
2620 2492
         this.eventEmitter.emit(RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED, localVideoTrack);
2621
-
2622
-        // Max bitrate needs to be reconfigured on the sender in p2p/non-simulcast case if needed when
2623
-        // the send resolution changes.
2624
-        if (this.isP2P || !this.isSimulcastOn()) {
2625
-            return this.setMaxBitRate();
2626
-        }
2627 2493
     });
2628 2494
 };
2629 2495
 
@@ -2827,7 +2693,7 @@ TraceablePeerConnection.prototype._createOfferOrAnswer = function(
2827 2693
             if (this.isSimulcastOn() && browser.usesSdpMungingForSimulcast()
2828 2694
                 && (localVideoTrack?.getVideoType() === VideoType.CAMERA
2829 2695
                 || this._usesUnifiedPlan
2830
-                || !this._isSharingLowFpsScreen())) {
2696
+                || !this.isSharingLowFpsScreen())) {
2831 2697
                 // eslint-disable-next-line no-param-reassign
2832 2698
                 resultSdp = this.simulcast.mungeLocalDescription(resultSdp);
2833 2699
                 this.trace(
@@ -3029,7 +2895,7 @@ TraceablePeerConnection.prototype.generateNewStreamSSRCInfo = function(track) {
3029 2895
 
3030 2896
     // Configure simulcast for camera tracks and desktop tracks that need simulcast.
3031 2897
     if (this.isSimulcastOn()
3032
-        && (track.getVideoType() === VideoType.CAMERA || !this._isSharingLowFpsScreen())) {
2898
+        && (track.getVideoType() === VideoType.CAMERA || !this.isSharingLowFpsScreen())) {
3033 2899
         ssrcInfo = {
3034 2900
             ssrcs: [],
3035 2901
             groups: []

+ 0
- 6
modules/qualitycontrol/SendVideoController.js Целия файл

@@ -54,12 +54,6 @@ export class SendVideoController {
54 54
                     this._propagateSendMaxFrameHeight();
55 55
                 }
56 56
             });
57
-
58
-        // Set the degradation preference on the local video track.
59
-        mediaSession.setSenderVideoDegradationPreference();
60
-
61
-        // Set the max bitrates on video sender if they are specified in config.js videoQuality settings.
62
-        mediaSession.setSenderMaxBitrates();
63 57
     }
64 58
 
65 59
     /**

+ 0
- 10
modules/qualitycontrol/SendVideoController.spec.js Целия файл

@@ -24,16 +24,6 @@ class MockJingleSessionPC extends Listenable {
24 24
         return this._remoteRecvMaxFrameHeight;
25 25
     }
26 26
 
27
-    // eslint-disable-next-line no-empty-function
28
-    setSenderVideoDegradationPreference() {
29
-
30
-    }
31
-
32
-    // eslint-disable-next-line no-empty-function
33
-    setSenderMaxBitrates() {
34
-
35
-    }
36
-
37 27
     setSenderVideoConstraint(senderVideoConstraint) {
38 28
         this.senderVideoConstraint = senderVideoConstraint;
39 29
     }

+ 11
- 40
modules/xmpp/JingleSessionPC.js Целия файл

@@ -1476,20 +1476,6 @@ export default class JingleSessionPC extends JingleSession {
1476 1476
             IQ_TIMEOUT);
1477 1477
     }
1478 1478
 
1479
-    /**
1480
-     * Sets the maximum bitrates on the local video track. Bitrate values from
1481
-     * videoQuality settings in config.js will be used for configuring the sender.
1482
-     * @returns {Promise<void>} promise that will be resolved when the operation is
1483
-     * successful and rejected otherwise.
1484
-     */
1485
-    setSenderMaxBitrates() {
1486
-        if (this._assertNotEnded()) {
1487
-            return this.peerconnection.setMaxBitRate();
1488
-        }
1489
-
1490
-        return Promise.resolve();
1491
-    }
1492
-
1493 1479
     /**
1494 1480
      * Sets the resolution constraint on the local camera track.
1495 1481
      * @param {number} maxFrameHeight - The user preferred max frame height.
@@ -1508,21 +1494,11 @@ export default class JingleSessionPC extends JingleSession {
1508 1494
                 return this.setMediaTransferActive(true, videoActive);
1509 1495
             }
1510 1496
 
1511
-            return this.peerconnection.setSenderVideoConstraint(maxFrameHeight);
1512
-        }
1513
-
1514
-        return Promise.resolve();
1515
-    }
1497
+            const promise = maxFrameHeight
1498
+                ? this.peerconnection.setSenderVideoConstraints(maxFrameHeight)
1499
+                : this.peerconnection.configureSenderVideoEncodings();
1516 1500
 
1517
-    /**
1518
-     * Sets the degradation preference on the video sender. This setting determines if
1519
-     * resolution or framerate will be preferred when bandwidth or cpu is constrained.
1520
-     * @returns {Promise<void>} promise that will be resolved when the operation is
1521
-     * successful and rejected otherwise.
1522
-     */
1523
-    setSenderVideoDegradationPreference() {
1524
-        if (this._assertNotEnded()) {
1525
-            return this.peerconnection.setSenderVideoDegradationPreference();
1501
+            return promise;
1526 1502
         }
1527 1503
 
1528 1504
         return Promise.resolve();
@@ -2110,14 +2086,11 @@ export default class JingleSessionPC extends JingleSession {
2110 2086
                     }
2111 2087
 
2112 2088
                     return promise.then(() => {
2113
-                        if (newTrack && newTrack.isVideoTrack()) {
2089
+                        if (newTrack?.isVideoTrack()) {
2114 2090
                             logger.debug(`${this} replaceTrack worker: configuring video stream`);
2115 2091
 
2116
-                            // FIXME set all sender parameters in one go?
2117
-                            // Set the degradation preference on the new video sender.
2118
-                            return this.peerconnection.setSenderVideoDegradationPreference()
2119
-                                .then(() => this.peerconnection.setSenderVideoConstraint())
2120
-                                .then(() => this.peerconnection.setMaxBitRate());
2092
+                            // Configure the video encodings after the track is replaced.
2093
+                            return this.peerconnection.configureSenderVideoEncodings();
2121 2094
                         }
2122 2095
                     });
2123 2096
                 })
@@ -2262,12 +2235,10 @@ export default class JingleSessionPC extends JingleSession {
2262 2235
         return this._addRemoveTrackAsMuteUnmute(
2263 2236
             false /* add as unmute */, track)
2264 2237
             .then(() => {
2265
-                // Apply the video constraints, max bitrates and degradation preference on
2266
-                // the video sender if needed.
2267
-                if (track.isVideoTrack() && browser.doesVideoMuteByStreamRemove()) {
2268
-                    return this.setSenderMaxBitrates()
2269
-                        .then(() => this.setSenderVideoDegradationPreference())
2270
-                        .then(() => this.setSenderVideoConstraint());
2238
+                // Configure the video encodings after the track is unmuted. If the user joins the call muted and
2239
+                // unmutes it the first time, all the parameters need to be configured.
2240
+                if (track.isVideoTrack()) {
2241
+                    return this.peerconnection.configureSenderVideoEncodings();
2271 2242
                 }
2272 2243
             });
2273 2244
     }

Loading…
Отказ
Запис