Kaynağa Gözat

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 5 yıl önce
ebeveyn
işleme
4fec06db7f
No account linked to committer's email address

+ 58
- 40
modules/RTC/TraceablePeerConnection.js Dosyayı Görüntüle

6
 
6
 
7
 import * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
7
 import * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
8
 import JitsiRemoteTrack from './JitsiRemoteTrack';
8
 import JitsiRemoteTrack from './JitsiRemoteTrack';
9
-import {
10
-    TRACK_ADDED,
11
-    TRACK_MUTE_CHANGED
12
-} from '../../JitsiConferenceEvents';
13
 import * as MediaType from '../../service/RTC/MediaType';
9
 import * as MediaType from '../../service/RTC/MediaType';
14
 import * as VideoType from '../../service/RTC/VideoType';
10
 import * as VideoType from '../../service/RTC/VideoType';
15
 import LocalSdpMunger from './LocalSdpMunger';
11
 import LocalSdpMunger from './LocalSdpMunger';
30
 const logger = getLogger(__filename);
26
 const logger = getLogger(__filename);
31
 const MAX_BITRATE = 2500000;
27
 const MAX_BITRATE = 2500000;
32
 const DESKSTOP_SHARE_RATE = 500000;
28
 const DESKSTOP_SHARE_RATE = 500000;
33
-
29
+const DEGRADATION_PREFERENCE_CAMERA = 'maintain-framerate';
30
+const DEGRADATION_PREFERENCE_DESKTOP = 'maintain-resolution';
34
 /* eslint-disable max-params */
31
 /* eslint-disable max-params */
35
 
32
 
36
 /**
33
 /**
250
     this.eventEmitter = rtc.eventEmitter;
247
     this.eventEmitter = rtc.eventEmitter;
251
     this.rtxModifier = new RtxModifier();
248
     this.rtxModifier = new RtxModifier();
252
 
249
 
250
+    /**
251
+     * The height constraint applied on the video sender.
252
+     */
253
+    this.senderVideoMaxHeight = null;
254
+
253
     // override as desired
255
     // override as desired
254
     this.trace = (what, info) => {
256
     this.trace = (what, info) => {
255
         logger.debug(what, info);
257
         logger.debug(what, info);
340
         }, 1000);
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
     logger.info(`Create new ${this}`);
345
     logger.info(`Create new ${this}`);
367
 }
346
 }
368
 
347
 
1916
     return changed;
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
  * Sets the max bitrate on the RTCRtpSender so that the
1936
  * Sets the max bitrate on the RTCRtpSender so that the
1921
  * bitrate of the enocder doesn't exceed the configured value.
1937
  * bitrate of the enocder doesn't exceed the configured value.
1925
  * max bitrate is to be configured.
1941
  * max bitrate is to be configured.
1926
  */
1942
  */
1927
 TraceablePeerConnection.prototype.setMaxBitRate = function(localTrack) {
1943
 TraceablePeerConnection.prototype.setMaxBitRate = function(localTrack) {
1928
-    const mediaType = localTrack.type;
1929
     const trackId = localTrack.track.id;
1944
     const trackId = localTrack.track.id;
1930
     const videoType = localTrack.videoType;
1945
     const videoType = localTrack.videoType;
1931
 
1946
 
1932
     // No need to set max bitrates on the streams in the following cases.
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
         || (browser.usesPlanB() && videoType === VideoType.CAMERA)) {
1951
         || (browser.usesPlanB() && videoType === VideoType.CAMERA)) {
1939
         return;
1952
         return;
1940
     }
1953
     }
2066
  * @returns {Promise} promise that will be resolved when the operation is
2079
  * @returns {Promise} promise that will be resolved when the operation is
2067
  * successful and rejected otherwise.
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
     const localVideoTrack = Array.from(this.localTracks.values()).find(t => t.isVideoTrack());
2089
     const localVideoTrack = Array.from(this.localTracks.values()).find(t => t.isVideoTrack());
2072
 
2090
 
2073
     if (!localVideoTrack || localVideoTrack.isMuted() || localVideoTrack.videoType !== VideoType.CAMERA) {
2091
     if (!localVideoTrack || localVideoTrack.isMuted() || localVideoTrack.videoType !== VideoType.CAMERA) {
2093
                 // Determine the encodings that need to stay enabled based on the
2111
                 // Determine the encodings that need to stay enabled based on the
2094
                 // new frameHeight provided.
2112
                 // new frameHeight provided.
2095
                 const encodingsEnabledState = this.tpcUtils.simulcastStreamConstraints
2113
                 const encodingsEnabledState = this.tpcUtils.simulcastStreamConstraints
2096
-                    .map(constraint => constraint.height <= frameHeight);
2114
+                    .map(constraint => constraint.height <= newHeight);
2097
                 const videoSender = this.findSenderByKind(MediaType.VIDEO);
2115
                 const videoSender = this.findSenderByKind(MediaType.VIDEO);
2098
 
2116
 
2099
                 if (!videoSender) {
2117
                 if (!videoSender) {
2104
                 if (!parameters || !parameters.encodings || !parameters.encodings.length) {
2122
                 if (!parameters || !parameters.encodings || !parameters.encodings.length) {
2105
                     return Promise.reject(new Error('RTCRtpSendParameters not found for local video track'));
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
                 for (const encoding in parameters.encodings) {
2126
                 for (const encoding in parameters.encodings) {
2109
                     if (parameters.encodings.hasOwnProperty(encoding)) {
2127
                     if (parameters.encodings.hasOwnProperty(encoding)) {
2110
                         parameters.encodings[encoding].active = encodingsEnabledState[encoding];
2128
                         parameters.encodings[encoding].active = encodingsEnabledState[encoding];
2118
     // Apply the height constraint on the local camera track
2136
     // Apply the height constraint on the local camera track
2119
     const aspectRatio = (track.getSettings().width / track.getSettings().height).toPrecision(4);
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
     return track.applyConstraints(
2141
     return track.applyConstraints(
2124
         {
2142
         {
2125
             aspectRatio,
2143
             aspectRatio,
2126
             height: {
2144
             height: {
2127
-                ideal: frameHeight
2145
+                ideal: newHeight
2128
             }
2146
             }
2129
         });
2147
         });
2130
 };
2148
 };

+ 1
- 13
modules/proxyconnection/ProxyConnectionPC.js Dosyayı Görüntüle

236
          * A {@code JitsiConference} stub passed to the {@link RTC} module.
236
          * A {@code JitsiConference} stub passed to the {@link RTC} module.
237
          * @type {Object}
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
          * Create an instance of {@code RTC} as it is required for peer
242
          * Create an instance of {@code RTC} as it is required for peer

+ 3
- 0
modules/qualitycontrol/QualityController.js Dosyayı Görüntüle

43
             });
43
             });
44
         this.preferredReceiveMaxFrameHeight
44
         this.preferredReceiveMaxFrameHeight
45
             && mediaSession.setReceiverVideoConstraint(this.preferredReceiveMaxFrameHeight);
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 Dosyayı Görüntüle

1410
         return Promise.resolve();
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
      * @inheritDoc
1425
      * @inheritDoc
1415
      */
1426
      */
1882
                         finishedCallback /* will be called with en error */);
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
                     promise.then(() => {
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
                         finishedCallback();
1909
                         finishedCallback();
1896
                     }, finishedCallback /* will be called with en error */);
1910
                     }, finishedCallback /* will be called with en error */);
2038
      */
2052
      */
2039
     addTrackAsUnmute(track) {
2053
     addTrackAsUnmute(track) {
2040
         return this._addRemoveTrackAsMuteUnmute(
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…
İptal
Kaydet