Skip to main content

BandwidthEstimator

Trait BandwidthEstimator 

Source
pub trait BandwidthEstimator: Send + Sync {
    // Required methods
    fn on_reports(&mut self, now: Instant, reports: &[PacketReport]);
    fn target_bitrate(&self) -> f64;

    // Provided methods
    fn handle_timeout(&mut self, _now: Instant) { ... }
    fn poll_timeout(&self) -> Option<Instant> { ... }
    fn stats(&self) -> EstimatorStats { ... }
}
Expand description

A congestion control algorithm: acknowledged packets in, a target bitrate out.

§Why this is not an Interceptor

An estimator does not transform packets, it observes them. Making it an interceptor would give it a position in the chain ordering it does not need, four bind methods it has no use for, and — fatally — bury it inside a Box<dyn Interceptor> the application cannot reach. CongestionControlInterceptor is the interceptor; this is the algorithm it drives.

§Why the seam is here rather than at the RTCP packet

Upstream’s equivalent interface has six methods, of which one returns a writer, one takes raw RTCP, and one takes a callback. A custom estimator there must parse feedback, own a history of sent packets, own a pacer, and correctly wrap a writer — four responsibilities that have nothing to do with the algorithm, reimplemented per algorithm.

Here PacketReport is already resolved by History: departure joined with arrival, per packet, in send order. What is left is a function from acknowledgements to a number, which is what a congestion control algorithm actually is.

§Clocks

There are none. Every instant arrives as a parameter, so a test can pin an exact bitrate trajectory for a given feedback sequence rather than asserting that something eventually happens.

Required Methods§

Source

fn on_reports(&mut self, now: Instant, reports: &[PacketReport])

Packets whose fate the remote has now reported, in send order.

Each report carries the instant it left this endpoint — the pacer’s release instant, not the instant the application enqueued it — the instant it arrived on the receiver’s clock, its size, and whether it arrived at all. That is everything a delay-based or loss-based estimator needs.

May be called with an empty slice; an implementation should treat that as “no news”.

Source

fn target_bitrate(&self) -> f64

The current estimate, in bits per second.

Read after every on_reports and after every handle_timeout; a change is what reaches the pacer.

Provided Methods§

Source

fn handle_timeout(&mut self, _now: Instant)

Periodic work, for an estimator that has any. Most do not.

Source

fn poll_timeout(&self) -> Option<Instant>

When this estimator next wants waking, or None if it does not.

None when idle, and the instant must advance — a deadline at or before the now just handed to handle_timeout is a busy-loop that wakes the whole chain.

Source

fn stats(&self) -> EstimatorStats

Whatever the algorithm wants to expose. Never load-bearing.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§