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 → wireA 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 hereImplementations§
Source§impl Registry
impl Registry
Sourcepub fn with(self, interceptor: impl Interceptor + 'static) -> Self
pub fn with(self, interceptor: impl Interceptor + 'static) -> Self
Add an interceptor on the application side of everything added so far.
Sourcepub fn with_boxed(self, boxed_interceptor: BoxedInterceptor) -> Self
pub fn with_boxed(self, boxed_interceptor: BoxedInterceptor) -> Self
Add an interceptor that is already boxed, for a caller assembling a chain dynamically.
Sourcepub fn with_rtcp_readable(self) -> Self
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.
Sourcepub fn build(self) -> impl Interceptor
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.