ソースを参照

Apply max bitrate of 500Kbps on desktop streams and set the contentHint attribute on the track to 'detail'. (#992)

Enable/disable this feature using 'capScreenshareBitrate' testing flag in config.js and send analytics
events to Amplitude to indicate which type of screensharing is enabled.
dev1
Jaya Allamsetty 6年前
コミット
a6fd643e06
3個のファイルの変更145行の追加5行の削除
  1. 27
    0
      JitsiMeetJS.js
  2. 78
    3
      modules/RTC/TraceablePeerConnection.js
  3. 40
    2
      modules/xmpp/JingleSessionPC.js

+ 27
- 0
JitsiMeetJS.js ファイルの表示

386
                     }
386
                     }
387
                 }
387
                 }
388
 
388
 
389
+                // set the contentHint to "detail" for desktop tracks
390
+                // eslint-disable-next-line prefer-const
391
+                for (const track of tracks) {
392
+                    if (track.type === MediaType.VIDEO
393
+                        && track.videoType === 'desktop') {
394
+                        this.setVideoTrackContentHints(track.track, 'detail');
395
+                    }
396
+                }
397
+
389
                 return tracks;
398
                 return tracks;
390
             })
399
             })
391
             .catch(error => {
400
             .catch(error => {
565
         Statistics.reportGlobalError(error);
574
         Statistics.reportGlobalError(error);
566
     },
575
     },
567
 
576
 
577
+    /**
578
+     * Set the contentHint on the transmitted stream track to indicate
579
+     * charaterstics in the video stream, which informs PeerConnection
580
+     * on how to encode the track (to prefer motion or individual frame detail)
581
+     * @param {MediaStreamTrack} track - the track that is transmitted
582
+     * @param {String} hint - contentHint value that needs to be set on the track
583
+     */
584
+    setVideoTrackContentHints(track, hint) {
585
+        if ('contentHint' in track) {
586
+            track.contentHint = hint;
587
+            if (track.contentHint !== hint) {
588
+                logger.debug('Invalid video track contentHint');
589
+            }
590
+        } else {
591
+            logger.debug('MediaStreamTrack contentHint attribute not supported');
592
+        }
593
+    },
594
+
568
     /* eslint-enable max-params */
595
     /* eslint-enable max-params */
569
 
596
 
570
     /**
597
     /**

+ 78
- 3
modules/RTC/TraceablePeerConnection.js ファイルの表示

26
 const SIM_LAYER_2_RID = '2';
26
 const SIM_LAYER_2_RID = '2';
27
 const SIM_LAYER_3_RID = '3';
27
 const SIM_LAYER_3_RID = '3';
28
 const SIM_LAYER_RIDS = [ SIM_LAYER_1_RID, SIM_LAYER_2_RID, SIM_LAYER_3_RID ];
28
 const SIM_LAYER_RIDS = [ SIM_LAYER_1_RID, SIM_LAYER_2_RID, SIM_LAYER_3_RID ];
29
+const SIM_LAYER_BITRATES_BPS = [ 200000, 700000, 2500000 ];
30
+const DESKSTOP_SHARE_RATE = 500000;
29
 
31
 
30
 /* eslint-disable max-params */
32
 /* eslint-disable max-params */
31
 
33
 
45
  * @param {boolean} options.disableRtx if set to 'true' will disable the RTX
47
  * @param {boolean} options.disableRtx if set to 'true' will disable the RTX
46
  * @param {boolean} options.enableFirefoxSimulcast if set to 'true' will enable
48
  * @param {boolean} options.enableFirefoxSimulcast if set to 'true' will enable
47
  * experimental simulcast support on Firefox.
49
  * experimental simulcast support on Firefox.
50
+ * @param {boolean} options.capScreenshareBitrate if set to 'true' simulcast will
51
+ * be disabled for screenshare and a max bitrate of 500Kbps will applied on the
52
+ * stream.
48
  * @param {boolean} options.disableH264 If set to 'true' H264 will be
53
  * @param {boolean} options.disableH264 If set to 'true' H264 will be
49
  *      disabled by removing it from the SDP.
54
  *      disabled by removing it from the SDP.
50
  * @param {boolean} options.preferH264 if set to 'true' H264 will be preferred
55
  * @param {boolean} options.preferH264 if set to 'true' H264 will be preferred
1883
         });
1888
         });
1884
     };
1889
     };
1885
 
1890
 
1891
+/**
1892
+ * Sets the max bitrate on the RTCRtpSender so that the
1893
+ * bitrate of the enocder doesn't exceed the configured value.
1894
+ * This is needed for the desktop share until spec-complaint
1895
+ * simulcast is implemented.
1896
+ * @param {JitsiLocalTrack} localTrack - the local track whose
1897
+ * max bitrate is to be configured.
1898
+ */
1899
+TraceablePeerConnection.prototype.setMaxBitRate = function(localTrack) {
1900
+    const mediaType = localTrack.type;
1901
+
1902
+    if (!this.options.capScreenshareBitrate
1903
+        || mediaType === MediaType.AUDIO) {
1904
+
1905
+        return;
1906
+    }
1907
+    if (!this.peerconnection.getSenders) {
1908
+        logger.debug('Browser doesn\'t support RTCRtpSender');
1909
+
1910
+        return;
1911
+    }
1912
+    const videoType = localTrack.videoType;
1913
+    const trackId = localTrack.track.id;
1914
+
1915
+    this.peerconnection.getSenders()
1916
+        .filter(s => s.track && s.track.id === trackId)
1917
+        .forEach(sender => {
1918
+            try {
1919
+                const parameters = sender.getParameters();
1920
+
1921
+                if (parameters.encodings && parameters.encodings.length) {
1922
+                    logger.info('Setting max bitrate on video stream');
1923
+                    for (const encoding in parameters.encodings) {
1924
+                        if (parameters.encodings.hasOwnProperty(encoding)) {
1925
+                            parameters.encodings[encoding].maxBitrate
1926
+                                = videoType === 'desktop'
1927
+                                    ? DESKSTOP_SHARE_RATE
1928
+                                    : SIM_LAYER_BITRATES_BPS[encoding];
1929
+                        }
1930
+                    }
1931
+                    sender.setParameters(parameters);
1932
+                }
1933
+            } catch (err) {
1934
+                logger.error('Browser does not support getParameters/setParamters '
1935
+                    + 'or setting max bitrate on the encodings: ', err);
1936
+            }
1937
+        });
1938
+};
1939
+
1886
 TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
1940
 TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
1887
     this.trace('setRemoteDescription::preTransform', dumpSDP(description));
1941
     this.trace('setRemoteDescription::preTransform', dumpSDP(description));
1888
 
1942
 
2240
     return this._createOfferOrAnswer(true /* offer */, constraints);
2294
     return this._createOfferOrAnswer(true /* offer */, constraints);
2241
 };
2295
 };
2242
 
2296
 
2297
+/**
2298
+ * Checks if a camera track has been added to the peerconnection
2299
+ * @param {TraceablePeerConnection} peerConnection
2300
+ * @return {boolean} <tt>true</tt> if the peerconnection has
2301
+ * a camera track for its video source <tt>false</tt> otherwise.
2302
+ */
2303
+function hasCameraTrack(peerConnection) {
2304
+    return peerConnection.getLocalTracks()
2305
+        .some(t => t.videoType === 'camera');
2306
+}
2307
+
2243
 TraceablePeerConnection.prototype._createOfferOrAnswer = function(
2308
 TraceablePeerConnection.prototype._createOfferOrAnswer = function(
2244
         isOffer,
2309
         isOffer,
2245
         constraints) {
2310
         constraints) {
2298
                     dumpSDP(resultSdp));
2363
                     dumpSDP(resultSdp));
2299
             }
2364
             }
2300
 
2365
 
2301
-            // Add simulcast streams if simulcast is enabled
2302
-            if (this.isSimulcastOn()) {
2366
+            // configure simulcast for camera tracks always and for
2367
+            // desktop tracks only when the testing flag for maxbitrates
2368
+            // in config.js is disabled.
2369
+            if (this.isSimulcastOn()
2370
+                && (!this.options.capScreenshareBitrate
2371
+                || (this.options.capScreenshareBitrate && hasCameraTrack(this)))) {
2303
                 // eslint-disable-next-line no-param-reassign
2372
                 // eslint-disable-next-line no-param-reassign
2304
                 resultSdp = this.simulcast.mungeLocalDescription(resultSdp);
2373
                 resultSdp = this.simulcast.mungeLocalDescription(resultSdp);
2305
                 this.trace(
2374
                 this.trace(
2500
     if (ssrcInfo) {
2569
     if (ssrcInfo) {
2501
         logger.error(`Will overwrite local SSRCs for track ID: ${rtcId}`);
2570
         logger.error(`Will overwrite local SSRCs for track ID: ${rtcId}`);
2502
     }
2571
     }
2503
-    if (this.isSimulcastOn()) {
2572
+
2573
+    // configure simulcast for camera tracks always and for
2574
+    // desktop tracks only when the testing flag for maxbitrates
2575
+    // in config.js is disabled.
2576
+    if (this.isSimulcastOn()
2577
+        && (!this.options.capScreenshareBitrate
2578
+        || (this.options.capScreenshareBitrate && hasCameraTrack(this)))) {
2504
         ssrcInfo = {
2579
         ssrcInfo = {
2505
             ssrcs: [],
2580
             ssrcs: [],
2506
             groups: []
2581
             groups: []

+ 40
- 2
modules/xmpp/JingleSessionPC.js ファイルの表示

274
         if (options.gatherStats) {
274
         if (options.gatherStats) {
275
             pcOptions.maxstats = DEFAULT_MAX_STATS;
275
             pcOptions.maxstats = DEFAULT_MAX_STATS;
276
         }
276
         }
277
-
277
+        pcOptions.capScreenshareBitrate = false;
278
         if (this.isP2P) {
278
         if (this.isP2P) {
279
             // simulcast needs to be disabled for P2P (121) calls
279
             // simulcast needs to be disabled for P2P (121) calls
280
             pcOptions.disableSimulcast = true;
280
             pcOptions.disableSimulcast = true;
295
             pcOptions.enableFirefoxSimulcast
295
             pcOptions.enableFirefoxSimulcast
296
                 = options.testing && options.testing.enableFirefoxSimulcast;
296
                 = options.testing && options.testing.enableFirefoxSimulcast;
297
             pcOptions.enableLayerSuspension = options.enableLayerSuspension;
297
             pcOptions.enableLayerSuspension = options.enableLayerSuspension;
298
+
299
+            // disable simulcast for screenshare and set the max bitrate to
300
+            // 500Kbps if the testing flag is present in config.js.
301
+            if (options.testing
302
+                && options.testing.capScreenshareBitrate
303
+                && typeof options.testing.capScreenshareBitrate === 'number') {
304
+                pcOptions.capScreenshareBitrate
305
+                    = Math.random()
306
+                    < options.testing.capScreenshareBitrate;
307
+            }
308
+        }
309
+
310
+        // send the corresponding amplitude events for simulcast screenshare
311
+        // and non-simulcast screenshare.
312
+        if (pcOptions.capScreenshareBitrate) {
313
+            Statistics.sendAnalyticsAndLog('nonSimulcastScreenSharing');
314
+        } else {
315
+            Statistics.sendAnalyticsAndLog('simulcastScreenSharing');
298
         }
316
         }
299
 
317
 
300
         if (options.startSilent) {
318
         if (options.startSilent) {
1668
 
1686
 
1669
             // NOTE the code below assumes that no more than 1 video track
1687
             // NOTE the code below assumes that no more than 1 video track
1670
             // can be added to the peer connection.
1688
             // can be added to the peer connection.
1671
-            // Transition from no video to video (possibly screen sharing)
1689
+            // Transition from camera to desktop share
1690
+            // or transition from one camera source to another.
1691
+            if (this.peerconnection.options.capScreenshareBitrate
1692
+                && oldTrack && newTrack && newTrack.isVideoTrack()) {
1693
+                // Clearing current primary SSRC will make
1694
+                // the SdpConsistency generate a new one which will result
1695
+                // with:
1696
+                // 1. source-remove for the old video stream.
1697
+                // 2. source-add for the new video stream.
1698
+                this.peerconnection.clearRecvonlySsrc();
1699
+            }
1700
+
1701
+            // Transition from no video to video (unmute).
1672
             if (!oldTrack && newTrack && newTrack.isVideoTrack()) {
1702
             if (!oldTrack && newTrack && newTrack.isVideoTrack()) {
1673
                 // Clearing current primary SSRC will make
1703
                 // Clearing current primary SSRC will make
1674
                 // the SdpConsistency generate a new one which will result
1704
                 // the SdpConsistency generate a new one which will result
1700
 
1730
 
1701
                             this.notifyMySSRCUpdate(
1731
                             this.notifyMySSRCUpdate(
1702
                                 new SDP(oldLocalSdp), newLocalSDP);
1732
                                 new SDP(oldLocalSdp), newLocalSDP);
1733
+
1734
+                            // configure max bitrate only when media is routed
1735
+                            // through JVB. For p2p case, browser takes care of
1736
+                            // adjusting the uplink based on the feedback it
1737
+                            // gets from the peer.
1738
+                            if (newTrack && !this.isP2P) {
1739
+                                this.peerconnection.setMaxBitRate(newTrack);
1740
+                            }
1703
                             finishedCallback();
1741
                             finishedCallback();
1704
                         },
1742
                         },
1705
                         finishedCallback /* will be called with en error */);
1743
                         finishedCallback /* will be called with en error */);

読み込み中…
キャンセル
保存