in src/videouplinkbandwidthpolicy/DefaultSimulcastUplinkPolicy.ts [100:201]
private calculateEncodingParameters(
numSendersChanged: boolean
): Map<string, RTCRtpEncodingParameters> {
// bitrates parameter min is not used for now
const newBitrates: BitrateParameters[] = [
new BitrateParameters(),
new BitrateParameters(),
new BitrateParameters(),
];
let hysteresisIncrease = 0,
hysteresisDecrease = 0;
if (this.currentActiveStreams === ActiveStreams.kHi) {
// Don't trigger redetermination based on rate if only one simulcast stream
hysteresisIncrease = this.lastUplinkBandwidthKbps + 1;
hysteresisDecrease = 0;
} else if (this.currentActiveStreams === ActiveStreams.kHiAndLow) {
hysteresisIncrease = 2400;
hysteresisDecrease = DefaultSimulcastUplinkPolicy.kHiDisabledRate;
} else if (this.currentActiveStreams === ActiveStreams.kMidAndLow) {
hysteresisIncrease = 1000;
hysteresisDecrease = DefaultSimulcastUplinkPolicy.kMidDisabledRate;
} else {
hysteresisIncrease = 300;
hysteresisDecrease = 0;
}
if (
numSendersChanged ||
this.lastUplinkBandwidthKbps >= hysteresisIncrease ||
this.lastUplinkBandwidthKbps <= hysteresisDecrease
) {
if (this.shouldDisableSimulcast) {
// See comment above `shouldDisableSimulcast` for usage.
//
// The value of `newActiveStreams` is somewhat irrelevant since in one to one calls
// we forward REMBs, so this single stream will adapt anywhere from < 100 kbps to 1200 kbps
// based on both sender and receiver network conditions. E.g. A receiver may calculate it's
// receive BWE as 300 kbps, send that in a REMB which is forwarded, and on receipt the sender
// will set its own BWE at 300 kbps, and start sending that as well (again, only for one-to-one
// calls). Additionally the value `kHi` is only relevant to the send side (via
// `encodingSimulcastLayersDidChange`) as it is not transmitted in anyform to the receiver.
//
// We use middle layer here to work around a bug in Chromium where
// it seems when a transceiver is created when BWE is low (e.g. on a reconnection),
// it will never reset the encoder even when `setParameters` is called. WebRTC bug
// #12788 seems to call a similar issue out as fixed for VP8, it's not clear if this
// is the same issue for H.264. Additionally we are not able to force a keyframe
// request from the backend since it will only be sending padding (which also
// don't have MID due to #10822). Since we don't scale when simulcast is disabled
// this doesn't have any end-user effect.
//
// Note that this still relies on a little bit (5-6 packets) of padding on reconnect
// and that technically the browser will still eventually try to send all 3 streams.
//
// Also note that due to some uninvestigated logic in bitrate allocation, Chromium
// will skip the bottom layer if we try setting it to 1200 kbps instead so it will
// still take a while to recover (as it needs to send padding until it reaches around
// 1000 kbps).
this.newActiveStreams = ActiveStreams.kHi;
newBitrates[0].maxBitrateKbps = 0;
newBitrates[1].maxBitrateKbps = 1200;
newBitrates[2].maxBitrateKbps = 0;
} else if (
this.numSenders <= 4 &&
this.lastUplinkBandwidthKbps >= DefaultSimulcastUplinkPolicy.kHiDisabledRate
) {
// 320x192+ (640x384) + 1280x768
this.newActiveStreams = ActiveStreams.kHiAndLow;
newBitrates[0].maxBitrateKbps = 300;
newBitrates[1].maxBitrateKbps = 0;
newBitrates[2].maxBitrateKbps = 1200;
} else if (this.lastUplinkBandwidthKbps >= DefaultSimulcastUplinkPolicy.kMidDisabledRate) {
// 320x192 + 640x384 + (1280x768)
this.newActiveStreams = ActiveStreams.kMidAndLow;
newBitrates[0].maxBitrateKbps = this.lastUplinkBandwidthKbps >= 350 ? 200 : 150;
newBitrates[1].maxBitrateKbps = this.numSenders <= 6 ? 600 : 350;
newBitrates[2].maxBitrateKbps = 0;
} else {
// 320x192 + 640x384 + (1280x768)
this.newActiveStreams = ActiveStreams.kLow;
newBitrates[0].maxBitrateKbps = 300;
newBitrates[1].maxBitrateKbps = 0;
newBitrates[2].maxBitrateKbps = 0;
}
const bitrates: number[] = newBitrates.map((v, _i, _a) => {
return v.maxBitrateKbps;
});
this.newQualityMap = this.fillEncodingParamWithBitrates(bitrates);
if (!this.encodingParametersEqual()) {
this.logger.info(
`simulcast: policy:calculateEncodingParameters bw:${
this.lastUplinkBandwidthKbps
} numSources:${this.numSenders} shouldDisableSimulcast:${
this.shouldDisableSimulcast
} newQualityMap: ${this.getQualityMapString(this.newQualityMap)}`
);
}
}
return this.newQualityMap;
}