Skip to main content

Registry

Struct Registry 

Source
pub struct Registry { /* private fields */ }
Expand description

Collects interceptors and assembles them into an [InterceptorChain].

§Order

Interceptors run in the order they are added, measured by distance from the wire: the first is closest to the network, the last closest to the application. Read walks that order, write walks it in reverse, so one list serves both directions and “closest to the wire” means one thing rather than opposite things per direction.

Registry::new()
    .with(a)   // closest to the wire
    .with(b)
    .with(c)   // closest to the application
    .build()

read:   a → b → c → application
write:  application → c → b → a → wire

A registry reads the way the chain runs, so getting the order right is a matter of reading it top to bottom. The nested registry it replaces added innermost first, which meant the list ran application-to-network on read and the composed order was the reverse of what the file looked like — register_default_interceptors ended up assembling TWCC receiver → RTCP reports → NACK generator, the opposite of what the chain contract documented, with nothing to catch it.

§Example

use rtc_interceptor::{NackGeneratorBuilder, Registry, TwccSenderBuilder};

let chain = Registry::new()
    .with(TwccSenderBuilder::new().build())     // closest to the wire
    .with(NackGeneratorBuilder::new().build())  // sees arrivals after it
    .build();                                   // the terminus is appended here

Implementations§

Source§

impl Registry

Source

pub fn new() -> Self

An empty registry.

Source

pub fn with(self, interceptor: impl Interceptor + 'static) -> Self

Add an interceptor on the application side of everything added so far.

Source

pub fn with_boxed(self, boxed_interceptor: BoxedInterceptor) -> Self

Add an interceptor that is already boxed, for a caller assembling a chain dynamically.

Source

pub fn with_rtcp_readable(self) -> Self

Make inbound RTCP readable by the application — it arrives from poll_read like media does — as well as acted on by the interceptors.

Off by default. RTCP is control traffic the interceptors act on: a receiver report feeds the sender statistics, a NACK is answered by the responder, transport-wide feedback drives the bandwidth estimate. An application that did not ask for it would find a stream of packets it cannot use interleaved with its media. Turn it on for an SFU relaying feedback, or a tool inspecting a session.

Outbound RTCP is unaffected; this is only about what arrives.

It has to be asked for here rather than arranged by an interceptor of your own. One that captured an RTCP packet and re-emitted it from poll_read would put the copy back on the belt behind itself, where NoopInterceptor is still ahead of it and drops it — the original and the copy both. The nested chain allowed that trick because a local poll_read queue was terminal and bypassed everything below it, which is precisely the bypass this design removes.

Source

pub fn build(self) -> impl Interceptor

Assemble the interceptor chain.

NoopInterceptor is appended last, so every chain decides what becomes of inbound RTCP. That is a property of a chain rather than something a caller opts into: left out, an application would get a stream of control traffic it never asked for, and the omission would look like working code. with_rtcp_readable is how a chain asks for it deliberately.

Trait Implementations§

Source§

impl Default for Registry

Source§

fn default() -> Registry

Returns the “default value” for a type. Read more

Auto Trait Implementations§

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> 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.