Skip to main content

Interceptor

Trait Interceptor 

Source
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:

This trait adds stream binding methods and provides a with() method for composable chaining of interceptors.

§Creating Custom Interceptors

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§

Source

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.

Source

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.

Source

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.

Source

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§

Source

fn with<O, F>(self, f: F) -> O
where Self: Sized, F: FnOnce(Self) -> O, O: Interceptor,

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.

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.

Source§

impl<P: Interceptor + ?Sized> Interceptor for Box<P>

Implementors§