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

feat: Set degradation preference on video senders (#1229)

* feat: Set degradation preference on video senders
Use 'maintain-framerate' for camera tracks and 'maintain-resolution' for desktop tracks

* ref: apply cached video contraints and degradation preference on unmute
Since the sender encodings are available only after the renegotiation is complete (on chrome/safari), constraints/preferences have to be applied after renegotiation is complete.
master
Jaya Allamsetty преди 4 години
родител
ревизия
4fec06db7f
No account linked to committer's email address

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

@@ -6,10 +6,6 @@ import transform from 'sdp-transform';
6 6
 
7 7
 import * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
8 8
 import JitsiRemoteTrack from './JitsiRemoteTrack';
9
-import {
10
-    TRACK_ADDED,
11
-    TRACK_MUTE_CHANGED
12
-} from '../../JitsiConferenceEvents';
13 9
 import * as MediaType from '../../service/RTC/MediaType';
14 10
 import * as VideoType from '../../service/RTC/VideoType';
15 11
 import LocalSdpMunger from './LocalSdpMunger';
@@ -30,7 +26,8 @@ import * as SignalingEvents from '../../service/RTC/SignalingEvents';
30 26
 const logger = getLogger(__filename);
31 27
 const MAX_BITRATE = 2500000;
32 28
 const DESKSTOP_SHARE_RATE = 500000;
33
-
29
+const DEGRADATION_PREFERENCE_CAMERA = 'maintain-framerate';
30
+const DEGRADATION_PREFERENCE_DESKTOP = 'maintain-resolution';
34 31
 /* eslint-disable max-params */
35 32
 
36 33
 /**
@@ -250,6 +247,11 @@ export default function TraceablePeerConnection(
250 247
     this.eventEmitter = rtc.eventEmitter;
251 248
     this.rtxModifier = new RtxModifier();
252 249
 
250
+    /**
251
+     * The height constraint applied on the video sender.
252
+     */
253
+    this.senderVideoMaxHeight = null;
254
+
253 255
     // override as desired
254 256
     this.trace = (what, info) => {
255 257
         logger.debug(what, info);
@@ -340,29 +342,6 @@ export default function TraceablePeerConnection(
340 342
         }, 1000);
341 343
     }
342 344
 
343
-    // Set sender video constraints when a new local video track is added
344
-    // to the conference or when it is unmuted.
345
-    this.senderVideoMaxHeight = null;
346
-    const maybeSetSenderVideoConstraints = track => {
347
-        if (track.isLocal()
348
-            && !track.isMuted()
349
-            && track.isVideoTrack()
350
-            && track.videoType === VideoType.CAMERA
351
-            && this.senderVideoMaxHeight) {
352
-            this.setSenderVideoConstraint(this.senderVideoMaxHeight)
353
-                .catch(err => {
354
-                    logger.error(`Settings sender video constraints failed: ${err}`);
355
-                });
356
-        }
357
-    };
358
-
359
-    this.rtc.conference.on(
360
-        TRACK_ADDED,
361
-        maybeSetSenderVideoConstraints);
362
-    this.rtc.conference.on(
363
-        TRACK_MUTE_CHANGED,
364
-        maybeSetSenderVideoConstraints);
365
-
366 345
     logger.info(`Create new ${this}`);
367 346
 }
368 347
 
@@ -1916,6 +1895,43 @@ TraceablePeerConnection.prototype.setAudioTransferActive = function(active) {
1916 1895
     return changed;
1917 1896
 };
1918 1897
 
1898
+/**
1899
+ * Sets the degradation preference on the video sender. This setting determines if
1900
+ * resolution or framerate will be preferred when bandwidth or cpu is constrained.
1901
+ * Sets it to 'maintain-framerate' when a camera track is added to the pc, sets it
1902
+ * to 'maintain-resolution' when a desktop track is being shared instead.
1903
+ * @returns {void}
1904
+ */
1905
+TraceablePeerConnection.prototype.setSenderVideoDegradationPreference = function() {
1906
+    if (!this.peerconnection.getSenders) {
1907
+        logger.debug('Browser does not support RTCRtpSender');
1908
+
1909
+        return;
1910
+    }
1911
+    const localVideoTrack = Array.from(this.localTracks.values()).find(t => t.isVideoTrack());
1912
+    const videoSender = this.findSenderByKind(MediaType.VIDEO);
1913
+
1914
+    if (!videoSender) {
1915
+        return;
1916
+    }
1917
+    const parameters = videoSender.getParameters();
1918
+
1919
+    if (!parameters.encodings || !parameters.encodings.length) {
1920
+        return;
1921
+    }
1922
+    for (const encoding in parameters.encodings) {
1923
+        if (parameters.encodings.hasOwnProperty(encoding)) {
1924
+            const preference = localVideoTrack.videoType === VideoType.CAMERA
1925
+                ? DEGRADATION_PREFERENCE_CAMERA
1926
+                : DEGRADATION_PREFERENCE_DESKTOP;
1927
+
1928
+            logger.info(`Setting video sender degradation preference on ${this} to ${preference}`);
1929
+            parameters.encodings[encoding].degradationPreference = preference;
1930
+        }
1931
+    }
1932
+    videoSender.setParameters(parameters);
1933
+};
1934
+
1919 1935
 /**
1920 1936
  * Sets the max bitrate on the RTCRtpSender so that the
1921 1937
  * bitrate of the enocder doesn't exceed the configured value.
@@ -1925,16 +1941,13 @@ TraceablePeerConnection.prototype.setAudioTransferActive = function(active) {
1925 1941
  * max bitrate is to be configured.
1926 1942
  */
1927 1943
 TraceablePeerConnection.prototype.setMaxBitRate = function(localTrack) {
1928
-    const mediaType = localTrack.type;
1929 1944
     const trackId = localTrack.track.id;
1930 1945
     const videoType = localTrack.videoType;
1931 1946
 
1932 1947
     // No need to set max bitrates on the streams in the following cases.
1933
-    // 1. When an audio track has been replaced.
1934
-    // 2. When a 'camera' track is replaced in plan-b mode, since its a new sender.
1935
-    // 3. When the config.js option for capping the SS bitrate is not enabled.
1936
-    if ((mediaType === MediaType.AUDIO)
1937
-        || (browser.usesPlanB() && !this.options.capScreenshareBitrate)
1948
+    // 1. When a 'camera' track is replaced in plan-b mode, since its a new sender.
1949
+    // 2. When the config.js option for capping the SS bitrate is not enabled.
1950
+    if ((browser.usesPlanB() && !this.options.capScreenshareBitrate)
1938 1951
         || (browser.usesPlanB() && videoType === VideoType.CAMERA)) {
1939 1952
         return;
1940 1953
     }
@@ -2066,8 +2079,13 @@ TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
2066 2079
  * @returns {Promise} promise that will be resolved when the operation is
2067 2080
  * successful and rejected otherwise.
2068 2081
  */
2069
-TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeight) {
2070
-    this.senderVideoMaxHeight = frameHeight;
2082
+TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeight = null) {
2083
+    const newHeight = frameHeight || this.senderVideoMaxHeight;
2084
+
2085
+    this.senderVideoMaxHeight = newHeight;
2086
+    if (!newHeight) {
2087
+        return Promise.resolve();
2088
+    }
2071 2089
     const localVideoTrack = Array.from(this.localTracks.values()).find(t => t.isVideoTrack());
2072 2090
 
2073 2091
     if (!localVideoTrack || localVideoTrack.isMuted() || localVideoTrack.videoType !== VideoType.CAMERA) {
@@ -2093,7 +2111,7 @@ TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeigh
2093 2111
                 // Determine the encodings that need to stay enabled based on the
2094 2112
                 // new frameHeight provided.
2095 2113
                 const encodingsEnabledState = this.tpcUtils.simulcastStreamConstraints
2096
-                    .map(constraint => constraint.height <= frameHeight);
2114
+                    .map(constraint => constraint.height <= newHeight);
2097 2115
                 const videoSender = this.findSenderByKind(MediaType.VIDEO);
2098 2116
 
2099 2117
                 if (!videoSender) {
@@ -2104,7 +2122,7 @@ TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeigh
2104 2122
                 if (!parameters || !parameters.encodings || !parameters.encodings.length) {
2105 2123
                     return Promise.reject(new Error('RTCRtpSendParameters not found for local video track'));
2106 2124
                 }
2107
-                logger.debug(`Setting max height of ${frameHeight} on local video`);
2125
+                logger.debug(`Setting max height of ${newHeight} on local video`);
2108 2126
                 for (const encoding in parameters.encodings) {
2109 2127
                     if (parameters.encodings.hasOwnProperty(encoding)) {
2110 2128
                         parameters.encodings[encoding].active = encodingsEnabledState[encoding];
@@ -2118,13 +2136,13 @@ TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeigh
2118 2136
     // Apply the height constraint on the local camera track
2119 2137
     const aspectRatio = (track.getSettings().width / track.getSettings().height).toPrecision(4);
2120 2138
 
2121
-    logger.debug(`Setting max height of ${frameHeight} on local video`);
2139
+    logger.debug(`Setting max height of ${newHeight} on local video`);
2122 2140
 
2123 2141
     return track.applyConstraints(
2124 2142
         {
2125 2143
             aspectRatio,
2126 2144
             height: {
2127
-                ideal: frameHeight
2145
+                ideal: newHeight
2128 2146
             }
2129 2147
         });
2130 2148
 };

+ 1
- 13
modules/proxyconnection/ProxyConnectionPC.js Целия файл

@@ -236,19 +236,7 @@ export default class ProxyConnectionPC {
236 236
          * A {@code JitsiConference} stub passed to the {@link RTC} module.
237 237
          * @type {Object}
238 238
          */
239
-        const conferenceStub = {
240
-            // FIXME: remove once the temporary code below is gone from
241
-            //  TraceablePeerConnection.
242
-            // TraceablePeerConnection:359
243
-            //  this.rtc.conference.on(
244
-            //         TRACK_ADDED,
245
-            //         maybeSetSenderVideoConstraints);
246
-            //     this.rtc.conference.on(
247
-            //         TRACK_MUTE_CHANGED,
248
-            //         maybeSetSenderVideoConstraints);
249
-            // eslint-disable-next-line no-empty-function
250
-            on: () => {}
251
-        };
239
+        const conferenceStub = {};
252 240
 
253 241
         /**
254 242
          * Create an instance of {@code RTC} as it is required for peer

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

@@ -43,6 +43,9 @@ export class QualityController {
43 43
             });
44 44
         this.preferredReceiveMaxFrameHeight
45 45
             && mediaSession.setReceiverVideoConstraint(this.preferredReceiveMaxFrameHeight);
46
+
47
+        // Set the degradation preference on the local video track.
48
+        mediaSession.setSenderVideoDegradationPreference();
46 49
     }
47 50
 
48 51
     /**

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

@@ -1410,6 +1410,17 @@ export default class JingleSessionPC extends JingleSession {
1410 1410
         return Promise.resolve();
1411 1411
     }
1412 1412
 
1413
+    /**
1414
+     * Sets the degradation preference on the video sender. This setting determines if
1415
+     * resolution or framerate will be preferred when bandwidth or cpu is constrained.
1416
+     * @returns {void}
1417
+     */
1418
+    setSenderVideoDegradationPreference() {
1419
+        if (this._assertNotEnded()) {
1420
+            this.peerconnection.setSenderVideoDegradationPreference();
1421
+        }
1422
+    }
1423
+
1413 1424
     /**
1414 1425
      * @inheritDoc
1415 1426
      */
@@ -1882,15 +1893,18 @@ export default class JingleSessionPC extends JingleSession {
1882 1893
                         finishedCallback /* will be called with en error */);
1883 1894
                     }
1884 1895
 
1885
-                    // Wait for the renegotation to be done if needed (plan-b) before adjusting
1886
-                    // the max bitrates on the video sender.
1887 1896
                     promise.then(() => {
1888
-                        // configure max bitrate only when media is routed
1889
-                        // through JVB. For p2p case, browser takes care of
1890
-                        // adjusting the uplink based on the feedback it
1891
-                        // gets from the peer.
1892
-                        if (newTrack && !this.isP2P) {
1893
-                            this.peerconnection.setMaxBitRate(newTrack);
1897
+                        if (newTrack && newTrack.isVideoTrack()) {
1898
+                            // Set the degradation preference on the new video sender.
1899
+                            this.peerconnection.setSenderVideoDegradationPreference();
1900
+
1901
+                            // Apply the cached video constraints on the new video sender.
1902
+                            this.peerconnection.setSenderVideoConstraint();
1903
+
1904
+                            // Configure max bitrate on the video sender when media is routed through JVB.
1905
+                            if (!this.isP2P) {
1906
+                                this.peerconnection.setMaxBitRate(newTrack);
1907
+                            }
1894 1908
                         }
1895 1909
                         finishedCallback();
1896 1910
                     }, finishedCallback /* will be called with en error */);
@@ -2038,7 +2052,15 @@ export default class JingleSessionPC extends JingleSession {
2038 2052
      */
2039 2053
     addTrackAsUnmute(track) {
2040 2054
         return this._addRemoveTrackAsMuteUnmute(
2041
-            false /* add as unmute */, track);
2055
+            false /* add as unmute */, track)
2056
+            .then(() => {
2057
+                // Apply the video constraints and degradation preference on
2058
+                // the video sender if needed.
2059
+                if (track.isVideoTrack() && browser.doesVideoMuteByStreamRemove()) {
2060
+                    this.peerconnection.setSenderVideoDegradationPreference();
2061
+                    this.peerconnection.setSenderVideoConstraint();
2062
+                }
2063
+            });
2042 2064
     }
2043 2065
 
2044 2066
     /**

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