|
@@ -6,6 +6,7 @@ import transform from 'sdp-transform';
|
6
|
6
|
import * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
|
7
|
7
|
import JitsiRemoteTrack from './JitsiRemoteTrack';
|
8
|
8
|
import * as MediaType from '../../service/RTC/MediaType';
|
|
9
|
+import BandwidthLimiter from './BandwidthLimiter';
|
9
|
10
|
import LocalSdpMunger from './LocalSdpMunger';
|
10
|
11
|
import RTC from './RTC';
|
11
|
12
|
import RTCUtils from './RTCUtils';
|
|
@@ -49,6 +50,9 @@ const SIM_LAYER_RIDS = [ SIM_LAYER_1_RID, SIM_LAYER_2_RID, SIM_LAYER_3_RID ];
|
49
|
50
|
* disabled by removing it from the SDP.
|
50
|
51
|
* @param {boolean} options.preferH264 if set to 'true' H264 will be preferred
|
51
|
52
|
* over other video codecs.
|
|
53
|
+ * @param {boolean} options.enableLayerSuspension if set to 'true', we will
|
|
54
|
+ * cap the video send bitrate when we are told we have not been selected by
|
|
55
|
+ * any endpoints (and therefore the non-thumbnail streams are not in use).
|
52
|
56
|
*
|
53
|
57
|
* FIXME: initially the purpose of TraceablePeerConnection was to be able to
|
54
|
58
|
* debug the peer connection. Since many other responsibilities have been added
|
|
@@ -205,6 +209,8 @@ export default function TraceablePeerConnection(
|
205
|
209
|
*/
|
206
|
210
|
this.localSdpMunger = new LocalSdpMunger(this);
|
207
|
211
|
|
|
212
|
+ this.bandwidthLimiter = new BandwidthLimiter();
|
|
213
|
+
|
208
|
214
|
/**
|
209
|
215
|
* TracablePeerConnection uses RTC's eventEmitter
|
210
|
216
|
* @type {EventEmitter}
|
|
@@ -212,6 +218,12 @@ export default function TraceablePeerConnection(
|
212
|
218
|
this.eventEmitter = rtc.eventEmitter;
|
213
|
219
|
this.rtxModifier = new RtxModifier();
|
214
|
220
|
|
|
221
|
+ /**
|
|
222
|
+ * Whether or not this endpoint has been selected
|
|
223
|
+ * by a remote participant (via the bridge)
|
|
224
|
+ */
|
|
225
|
+ this.isSelected = true;
|
|
226
|
+
|
215
|
227
|
// override as desired
|
216
|
228
|
this.trace = (what, info) => {
|
217
|
229
|
logger.debug(what, info);
|
|
@@ -1043,6 +1055,20 @@ function extractSSRCMap(desc) {
|
1043
|
1055
|
return ssrcMap;
|
1044
|
1056
|
}
|
1045
|
1057
|
|
|
1058
|
+/**
|
|
1059
|
+ * Get the bitrate cap we should enforce for video given whether or not
|
|
1060
|
+ * we are selected
|
|
1061
|
+ * @param {boolean} isSelected whether or not we (the local endpoint) is
|
|
1062
|
+ * selected by any other endpoints (meaning its HD stream is in use)
|
|
1063
|
+ * @return {Number} the bitrate cap in kbps, or null if there should be
|
|
1064
|
+ * no cap
|
|
1065
|
+ */
|
|
1066
|
+function getSuspensionBitrateKbps(isSelected) {
|
|
1067
|
+ // eslint-disable-next-line max-len
|
|
1068
|
+ // https://codesearch.chromium.org/chromium/src/third_party/webrtc/media/engine/simulcast.cc?l=55&rcl=28deb90728c06a35d8847d2aeda2fc1aee105c5e
|
|
1069
|
+ return isSelected ? null : 200;
|
|
1070
|
+}
|
|
1071
|
+
|
1046
|
1072
|
/**
|
1047
|
1073
|
* Takes a SessionDescription object and returns a "normalized" version.
|
1048
|
1074
|
* Currently it only takes care of ordering the a=ssrc lines.
|
|
@@ -1852,6 +1878,21 @@ TraceablePeerConnection.prototype.setRemoteDescription = function(
|
1852
|
1878
|
});
|
1853
|
1879
|
}
|
1854
|
1880
|
|
|
1881
|
+ if (this.options.enableLayerSuspension) {
|
|
1882
|
+ logger.debug('Layer suspension enabled,'
|
|
1883
|
+ + `currently selected? ${this.isSelected}`);
|
|
1884
|
+ const bitrateCapKbps = getSuspensionBitrateKbps(this.isSelected);
|
|
1885
|
+
|
|
1886
|
+ this.bandwidthLimiter.setBandwidthLimit('video', bitrateCapKbps);
|
|
1887
|
+ logger.debug(`Layer suspension got bitrate cap of ${bitrateCapKbps}`);
|
|
1888
|
+ description.sdp
|
|
1889
|
+ = this.bandwidthLimiter.enforceBandwithLimit(description.sdp);
|
|
1890
|
+ this.trace(
|
|
1891
|
+ 'setRemoteDescription::postTransform '
|
|
1892
|
+ + '(layer suspension bitrate cap)',
|
|
1893
|
+ dumpSDP(description));
|
|
1894
|
+ }
|
|
1895
|
+
|
1855
|
1896
|
// If the browser uses unified plan, transform to it first
|
1856
|
1897
|
if (browser.usesUnifiedPlan()) {
|
1857
|
1898
|
// eslint-disable-next-line no-param-reassign
|
|
@@ -2486,6 +2527,14 @@ TraceablePeerConnection.prototype.generateNewStreamSSRCInfo = function(track) {
|
2486
|
2527
|
return ssrcInfo;
|
2487
|
2528
|
};
|
2488
|
2529
|
|
|
2530
|
+/**
|
|
2531
|
+ * Set whether or not the endpoint is 'selected' by other endpoints, meaning
|
|
2532
|
+ * it appears on their main stage
|
|
2533
|
+ */
|
|
2534
|
+TraceablePeerConnection.prototype.setIsSelected = function(isSelected) {
|
|
2535
|
+ this.isSelected = isSelected;
|
|
2536
|
+};
|
|
2537
|
+
|
2489
|
2538
|
/**
|
2490
|
2539
|
* Creates a text representation of this <tt>TraceablePeerConnection</tt>
|
2491
|
2540
|
* instance.
|