in src/videodownlinkbandwidthpolicy/VideoPriorityBasedPolicy.ts [583:683]
private determineTargetRate(): number {
let targetBitrate = 0;
const now = Date.now();
// Startup phase handling. During this period the estimate can be 0 or
// could still be slowly hunting for a steady state. This startup ramp up
// can cause a series of subscribes which can be distracting. During this
// time just use our configured default value
if (this.downlinkStats.bandwidthEstimateKbps !== 0) {
if (this.firstEstimateTimestamp === 0) {
this.firstEstimateTimestamp = now;
}
// handle startup state where estimator is still converging.
if (this.startupPeriod) {
// Drop out of startup period if
// - estimate is above default
// - get packet loss and have a valid estimate
// - startup period has expired and rate is not still increasing
if (
this.downlinkStats.bandwidthEstimateKbps >
VideoPriorityBasedPolicy.DEFAULT_BANDWIDTH_KBPS ||
this.downlinkStats.packetsLost > 0 ||
(now - this.firstEstimateTimestamp > VideoPriorityBasedPolicy.STARTUP_PERIOD_MS &&
this.downlinkStats.bandwidthEstimateKbps <=
this.prevDownlinkStats.bandwidthEstimateKbps)
) {
this.startupPeriod = false;
this.prevTargetRateKbps = this.downlinkStats.bandwidthEstimateKbps;
}
}
// If we are in the startup period and we haven't detected any packet loss, then
// keep it at the default to let the estimation get to a steady state
if (this.startupPeriod) {
targetBitrate = VideoPriorityBasedPolicy.DEFAULT_BANDWIDTH_KBPS;
} else {
// We rely on our target bitrate being above what we are receiving to mark a probe as complete,
// however in browsers, the estimate can heavily lag behind the actual receive rate, especially when low.
//
// To mitigate this we override with the actual estimate plus some buffer if we aren't seeing packet loss.
if (
this.rateProbeState === RateProbeState.Probing &&
this.downlinkStats.usedBandwidthKbps > this.downlinkStats.bandwidthEstimateKbps &&
this.downlinkStats.packetsLost < VideoPriorityBasedPolicy.SPURIOUS_PACKET_LOST_THRESHOLD
) {
this.logger.info(
`bwe: In probe state, overriding estimate ${this.downlinkStats.bandwidthEstimateKbps} with actual receive bitrate ${this.downlinkStats.usedBandwidthKbps}`
);
targetBitrate =
this.downlinkStats.usedBandwidthKbps +
VideoPriorityBasedPolicy.USED_BANDWIDTH_OVERRIDE_BUFFER_KBPS;
} else {
targetBitrate = this.downlinkStats.bandwidthEstimateKbps;
}
}
} else {
if (this.firstEstimateTimestamp === 0) {
targetBitrate = VideoPriorityBasedPolicy.DEFAULT_BANDWIDTH_KBPS;
} else {
targetBitrate = this.prevTargetRateKbps;
}
}
// Estimated downlink rate can follow actual bandwidth or fall for a short period of time
// due to the absolute send time estimator incorrectly thinking that a delay in packets is
// a precursor to packet loss. We have seen too many false positives on this, so we
// will ignore largish drops in the estimate if there is no packet loss
if (
!this.startupPeriod &&
((this.usingPrevTargetRate &&
this.downlinkStats.bandwidthEstimateKbps < this.prevTargetRateKbps) ||
this.downlinkStats.bandwidthEstimateKbps <
(this.prevTargetRateKbps *
(100 - VideoPriorityBasedPolicy.LARGE_RATE_CHANGE_TRIGGER_PERCENT)) /
100 ||
this.downlinkStats.bandwidthEstimateKbps <
(this.downlinkStats.usedBandwidthKbps *
VideoPriorityBasedPolicy.LARGE_RATE_CHANGE_TRIGGER_PERCENT) /
100) &&
this.downlinkStats.packetsLost === 0
) {
// Set target to be the same as last
this.logger.debug(() => {
return 'bwe: ValidateRate: Using Previous rate ' + this.prevTargetRateKbps;
});
this.usingPrevTargetRate = true;
targetBitrate = this.prevTargetRateKbps;
} else {
this.usingPrevTargetRate = false;
}
// Cap total receive bitrate at 15000 kbps
if (targetBitrate > 15000) {
this.logger.warn(
'bwe: ' +
targetBitrate +
' exceeds maximum limit (15000). Limit TargetDisplaySize with VideoPreferences to avoid this.'
);
}
return Math.min(targetBitrate, 15000);
}