Skip to main content

Slot

Enum Slot 

Source
#[non_exhaustive]
#[repr(usize)]
pub enum Slot {
Show 14 variants CongestionControl = 1_000, TwccSender = 2_000, Pacer = 3_000, NackResponder = 4_000, FecEncoder = 5_000, FecDecoder = 6_000, NackGenerator = 7_000, TwccReceiver = 8_000, Rfc8888 = 9_000, ReceiverReport = 10_000, SenderReport = 11_000, IntervalPli = 12_000, JitterBuffer = 13_000, Custom(usize),
}
Expand description

Where an interceptor belongs in the chain, measured by distance from the wire.

This is the chain contract’s ordering table expressed as data, so that one place decides it and a test can check a builder against it. The doc comments carry that table’s indices; the gaps are slots nothing fills yet.

Read walks the list forwards and write walks it in reverse, so a smaller slot is closer to the network in both directions.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

CongestionControl = 1_000

CongestionControlInterceptor — the send history, and the ingest of returning feedback.

Both legs. Read: ingests inbound TWCC or CCFB and hands the reports to the estimator. Write: records every departing RTP packet in the send history.

Why here — wire-most. The write walk runs from the application down to the wire, so the lowest slot is the last thing a departing packet meets. Two facts depend on that. The departure instant it records is the moment the packet actually left, after the pacer held it; recording at enqueue instead would charge the pacer’s own queueing delay to the network and drive the estimate down for a delay this endpoint created. And the transport-wide sequence number the history keys on has already been assigned at 2_000, so a report naming that number can be matched to the packet that carried it.

§

TwccSender = 2_000

TwccSenderInterceptor — stamps each departing RTP packet with the transport-wide sequence number the remote will report against.

Outbound only. Inbound packets pass through untouched.

Why here — below every generator, above the history. The write walk must reach it before Slot::CongestionControl, or the history would key on a number that does not exist yet. It must sit below everything that produces a packet — the NACK responder at 4_000, the FEC encoder at 5_000, every RTCP generator above them — because a packet that never passes this slot is never numbered, and the remote cannot report on what it cannot name. A retransmission is exactly that case.

§

Pacer = 3_000

PacerInterceptor — gates departures, releasing at the estimated rate.

Outbound, with one inbound read. Write: queues RTP and releases it on a timer; RTCP passes straight through, because feedback is only useful while it is fresh. Read: observes Attribute::TargetBitrateChanged going past.

Why here — the meter every generated byte must cross. Everything that produces a packet sits application-ward of this slot, so retransmissions, FEC repair and generated RTCP are all metered rather than bursting past the estimate. It is above the TWCC sender so that numbering happens at release rather than at enqueue, which keeps the numbers in the order the packets actually reach the wire.

The estimate reaches it on the read leg because that is the only leg it can: the controller is wire-ward of here, so on the write leg it sees packets after this interceptor — too late to inform it.

§

NackResponder = 4_000

NackResponderInterceptor — answers a NACK by resending from its own buffer.

Both legs. Write: buffers each departing RTP packet against a later request. Read: watches for inbound NACK and queues the retransmissions it asks for.

Why here — the lowest of the generators. A retransmission it emits re-enters the belt at this slot and continues down, so it is still paced (3_000), numbered (2_000) and recorded (1_000). It has to be: a retransmission is new bytes on the wire, and an estimator that does not see them believes the path is carrying less than it is — then raises the rate during loss, which is the worst moment to do it.

§

FecEncoder = 5_000

FlexFec03SendInterceptor — generates repair packets for the media it sees leaving.

Outbound only.

Why here — a generator, so above the pacer. Its repair packets are real bytes and are metered and recorded like any other. Being above the NACK responder also means the media it protects has already been buffered for retransmission, so the two recovery mechanisms cover the same packets rather than racing to protect different ones.

§

FecDecoder = 6_000

FlexFec03ReceiveInterceptor — rebuilds packets the path dropped.

Inbound only. Nothing on the write leg.

Why here — before anything reads a sequence number. The read walk runs wire to application, so this recovers a packet before the NACK generator at 7_000 can notice it was missing. Placed the other way round, this endpoint would ask the remote to retransmit packets it was about to rebuild locally — paying for the same data twice, and adding a round trip to data it already had.

§

NackGenerator = 7_000

NackGeneratorInterceptor — asks the remote for what did not arrive.

Both legs. Read: detects gaps in the inbound sequence space. Write: emits NACK on a timer.

Why here — after recovery, before re-timing. After the FEC decoder (6_000), so a rebuilt packet counts as arrived and is not requested again. Before the jitter buffer (13_000), so it judges loss from arrival order rather than from playout order. And, being a generator, application-ward of the pacer so its NACKs are metered.

§

TwccReceiver = 8_000

TwccReceiverInterceptor — reports arrival times to the remote sender’s congestion controller.

Both legs. Read: records when each inbound packet arrived. Write: emits TransportLayerCC on a timer.

Why here — the write leg is what pins it. It reads as a receive-side interceptor, and moving it wire-ward looks harmless because nothing it does affects what this endpoint sends. It does not work: it generates, and below the pacer its feedback would leave unpaced and unrecorded by the send history. It is also an arrival recorder, so it must precede the jitter buffer — see Slot::JitterBuffer.

§

Rfc8888 = 9_000

Rfc8888Interceptor — the same job as Slot::TwccReceiver in a different format.

Both legs, and pinned by the same two constraints: a generator above the pacer, an arrival recorder before the jitter buffer. It sits next to the TWCC receiver because the two are alternatives — registering both reports every packet to the remote twice, and its estimator cannot tell the two formats apart, so it reads the path as carrying double.

§

ReceiverReport = 10_000

ReceiverReportInterceptor — RFC 3550 reception quality, not congestion-control feedback.

Both legs. Read: accumulates loss, jitter and the extended sequence number from inbound RTP. Write: emits RR on a timer.

Why here — the same pair of constraints as the arrival recorders above. Above the pacer because it generates; before the jitter buffer because the jitter it measures must be the path’s, not this endpoint’s buffering.

§

SenderReport = 11_000

SenderReportInterceptor — emits SR on a timer, describing what this endpoint has sent.

Outbound only.

Why here — generator, and nothing else constrains it. Above the pacer so its reports are metered. Nothing inbound informs it, so it has no read-side ordering requirement and its exact position among the generators does not matter.

§

IntervalPli = 12_000

IntervalPliInterceptor — asks the remote for a keyframe on a timer.

Outbound only.

Why here — generator, and nothing else constrains it, exactly as for Slot::SenderReport.

§

JitterBuffer = 13_000

JitterBufferInterceptor — holds inbound packets to smooth arrival jitter, then releases them in order on a timer.

Inbound only.

Why here — application-most, because it re-times what passes through it. Every arrival recorder must precede it. One placed after would read a packet’s playout instant and report it to the remote as its arrival time; the remote’s congestion controller would then see this endpoint’s own buffering depth as network delay variation — a delay signal manufactured locally and indistinguishable, at the far end, from a congested path.

§

Custom(usize)

Anywhere else, for an interceptor this crate knows nothing about.

The named slots are spaced a thousand apart so one of your own fits between any two of them without renumbering anything: Slot::from(6_500) sits after the FEC decoder and before the NACK generator. Reach it through From<usize> rather than by naming the variant, so the spelling survives this gaining a richer representation.

Choosing a number. Work out which legs your interceptor uses, then apply the same rules the named slots obey:

  • It produces packets — retransmissions, repair, RTCP, anything the wire has not seen yet. Put it above Slot::Pacer (> 3_000), or its output leaves unpaced and the send history never counts the bytes. This is the constraint people miss, because an interceptor that only reports on what it received still produces packets to report with.
  • It reads inbound sequence numbers or arrival times — loss detection, arrival recording, reception statistics. Put it below Slot::JitterBuffer (< 13_000), so it sees the order and timing the path produced rather than the order this endpoint replays.
  • It repairs or recovers inbound packets. Put it below anything that would otherwise ask for them again — below Slot::NackGenerator (< 7_000), as the FEC decoder is.
  • It only observes, and emits nothing. Nothing pins it; pick a slot that reads well next to its neighbours.

Both legs walk this one list — read from low to high, write from high to low — so a slot is a position in both directions at once. An interceptor that acts on each leg is subject to the constraints of each, and those can pull in opposite directions: Slot::TwccReceiver is the worked example.

Implementations§

Source§

impl Slot

Source

pub const fn slot(self) -> usize

Where this sits, as a distance from the wire.

The named slots are the thousands; a custom one is whatever it was built from.

Trait Implementations§

Source§

impl Clone for Slot

Source§

fn clone(&self) -> Slot

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Slot

Source§

impl Debug for Slot

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Slot

Source§

impl From<Slot> for usize

Source§

fn from(slot: Slot) -> Self

Converts to this type from the input type.
Source§

impl From<usize> for Slot

A position of your own. See Slot::Custom.

Source§

fn from(position: usize) -> Self

Converts to this type from the input type.
Source§

impl Hash for Slot

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Ord for Slot

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 (const: unstable) · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 (const: unstable) · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 (const: unstable) · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

fn clamp_to<R>(self, range: R) -> Self
where Self: Sized, R: ClampBounds<Self>,

🔬This is a nightly-only experimental API. (clamp_to)
Restrict a value to a certain range. Read more
Source§

impl PartialEq for Slot

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl PartialOrd for Slot

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 (const: unstable) · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 (const: unstable) · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 (const: unstable) · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 (const: unstable) · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more

Auto Trait Implementations§

§

impl Freeze for Slot

§

impl RefUnwindSafe for Slot

§

impl Send for Slot

§

impl Sync for Slot

§

impl Unpin for Slot

§

impl UnsafeUnpin for Slot

§

impl UnwindSafe for Slot

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.