pub trait Interceptor:
Protocol<TaggedPacket, TaggedPacket, (), Rout = TaggedPacket, Wout = TaggedPacket, Eout = (), Time = Instant, Error = Error>
+ Send
+ Sync {
// Required methods
fn bind_local_stream(&mut self, info: &StreamInfo);
fn unbind_local_stream(&mut self, info: &StreamInfo);
fn bind_remote_stream(&mut self, info: &StreamInfo);
fn unbind_remote_stream(&mut self, info: &StreamInfo);
// Provided method
fn with<O, F>(self, f: F) -> O
where Self: Sized,
F: FnOnce(Self) -> O,
O: Interceptor { ... }
}Expand description
Trait for RTP/RTCP interceptors with fixed Protocol type parameters.
Interceptor is a marker trait that requires implementors to also implement
sansio::Protocol with specific fixed type parameters for RTP/RTCP processing:
Rin,Win,Rout,Wout=TaggedPacketEin,Eout=()Time=InstantError=shared::error::Error
This trait adds stream binding methods and provides a with()
method for composable chaining of interceptors.
§Creating Custom Interceptors
§Using Derive Macros (Recommended)
The easiest way to create a custom interceptor is using the derive macros:
use rtc_interceptor::{Interceptor, StreamInfo, TaggedPacket, interceptor};
use sansio::Protocol;
use shared::error::Error; // the generated `Protocol` impl names it
use std::collections::VecDeque;
#[derive(Interceptor)]
pub struct MyInterceptor<P: Interceptor> {
#[next]
next: P, // The next interceptor in the chain
buffer: VecDeque<TaggedPacket>,
}
#[interceptor]
impl<P: Interceptor> MyInterceptor<P> {
#[overrides]
fn handle_read(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
// Custom logic here
self.next.handle_read(msg)
}
}The #[derive(Interceptor)] macro requires a #[next] field that contains the
next interceptor in the chain. The #[interceptor] attribute on the impl block
generates the Protocol and Interceptor trait implementations, delegating
non-overridden methods to the next interceptor.
Use #[overrides] to mark methods with custom implementations.
§Manual Implementation
For more control, you can implement the traits manually. The sketch below omits the
Protocol method bodies, so it is not compiled — see NoopInterceptor for a complete
hand-written implementation:
pub struct MyInterceptor<P> {
inner: P,
}
impl<P: Interceptor> Protocol<TaggedPacket, TaggedPacket, ()> for MyInterceptor<P> {
type Rout = TaggedPacket;
type Wout = TaggedPacket;
type Eout = ();
type Time = Instant;
type Error = shared::error::Error;
// ... implement Protocol methods
}
impl<P: Interceptor> Interceptor for MyInterceptor<P> {
fn bind_local_stream(&mut self, _info: &StreamInfo) {}
fn unbind_local_stream(&mut self, _info: &StreamInfo) {}
fn bind_remote_stream(&mut self, _info: &StreamInfo) {}
fn unbind_remote_stream(&mut self, _info: &StreamInfo) {}
}§Using with Registry
A builder is just a closure from the next layer to the wrapping one, so a custom interceptor can be added the same way as a built-in:
use rtc_interceptor::{Registry, SenderReportBuilder};
let registry = Registry::new().with(SenderReportBuilder::new().build());
// ...or with a closure: `.with(|inner| MyInterceptor { next: inner, .. })`Required Methods§
Sourcefn bind_local_stream(&mut self, info: &StreamInfo)
fn bind_local_stream(&mut self, info: &StreamInfo)
bind_local_stream lets you modify any outgoing RTP packets. It is called once for per LocalStream. The returned method will be called once per rtp packet.
Sourcefn unbind_local_stream(&mut self, info: &StreamInfo)
fn unbind_local_stream(&mut self, info: &StreamInfo)
unbind_local_stream is called when the Stream is removed. It can be used to clean up any data related to that track.
Sourcefn bind_remote_stream(&mut self, info: &StreamInfo)
fn bind_remote_stream(&mut self, info: &StreamInfo)
bind_remote_stream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method will be called once per rtp packet.
Sourcefn unbind_remote_stream(&mut self, info: &StreamInfo)
fn unbind_remote_stream(&mut self, info: &StreamInfo)
unbind_remote_stream is called when the Stream is removed. It can be used to clean up any data related to that track.
Provided Methods§
Sourcefn with<O, F>(self, f: F) -> O
fn with<O, F>(self, f: F) -> O
Wrap this interceptor with another layer.
The wrapper function receives self and returns a new interceptor
that wraps it.
§Example
use rtc_interceptor::{Interceptor, NoopInterceptor, SenderReportBuilder};
use std::time::Duration;
// `Interceptor` must be in scope for `with` to resolve.
let chain = NoopInterceptor::new()
.with(SenderReportBuilder::new().with_interval(Duration::from_secs(1)).build());Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl<P: Interceptor + ?Sized> Interceptor for &mut P
Blanket implementation for mutable references.
impl<P: Interceptor + ?Sized> Interceptor for &mut P
Blanket implementation for mutable references.
This lets a borrowed chain satisfy an Interceptor bound, so a function taking
I: Interceptor by value can be called with &mut chain and leave ownership with the
caller. It mirrors sansio::Protocol’s own &mut P implementation, and the same idiom
in std (impl Read for &mut R, impl Iterator for &mut I).
This is only expressible because Interceptor does not require 'static: &'a mut P
outlives only 'a. See Registry::boxed, which carries that bound locally instead.