Skip to content

Instantly share code, notes, and snippets.

@plaidfinch
Last active April 30, 2025 13:51
Show Gist options
  • Save plaidfinch/00065b809a15ba62941070da950443fe to your computer and use it in GitHub Desktop.
Save plaidfinch/00065b809a15ba62941070da950443fe to your computer and use it in GitHub Desktop.
WebRTC.rs For LLMs and People

WebRTC Rust Library Documentation Summary

This directory contains comprehensive summaries of the WebRTC Rust library modules. These summaries provide an overview of the library's architecture, key components, and their interactions.

Table of Contents

Foundation Protocols

  • STUN - Session Traversal Utilities for NAT for network discovery
  • TURN - Traversal Using Relays around NAT for NAT traversal
  • RTP - Real-time Transport Protocol for media delivery
  • RTCP - RTP Control Protocol for QoS feedback
  • SDP - Session Description Protocol for session negotiation
  • Signal - Signaling helper functions

WebRTC Protocol Stack

  • WebRTC ICE - Interactive Connectivity Establishment for NAT traversal
  • WebRTC DTLS - Datagram Transport Layer Security for encryption
  • WebRTC SRTP - Secure Real-time Transport Protocol for media
  • WebRTC SCTP - Stream Control Transmission Protocol for data channels
  • WebRTC mDNS - Multicast DNS for ICE candidates

Media and Data Processing

Higher-level Components

Architecture Overview

The WebRTC Rust library implements the Web Real-Time Communication API following the W3C and IETF standards. It enables browser-compatible peer-to-peer connections for exchanging audio, video, and arbitrary data.

Key Components Interaction

┌─────────────────────────────────────────────────────────────────────────┐
│                              Application                                │
└───────────────────────────────┬─────────────────────────────────────────┘
                                │
┌───────────────────────────────▼─────────────────────────────────────────┐
│                       webrtc::RTCPeerConnection                         │
└┬────────────────┬─────────────┬───────────────────┬─────────────────────┘
 │                │             │                   │
┌▼────────────┐ ┌─▼───────────┐┌▼───────────┐  ┌────▼─────────┐
│ webrtc_data │ │   Hub       ││  Signal    │  │ Interceptor  │
│(DataChannel)│ │(Multi-peer) ││(Signaling) │  │(Media Pipeline)
└┬────────────┘ └─────────────┘└────────────┘  └┬────────────┬┘
 │                                              │            │
┌▼────────────┐                              ┌──▼─────────┐ │
│ webrtc_sctp │                              │webrtc_media│ │
└┬────────────┘                              └┬───────────┘ │
 │                                            │             │
┌▼────────────┐                              ┌▼───────────┐┌▼─────────┐
│ webrtc_dtls │                              │webrtc_rtp  ││webrtc_rtcp│
└┬────────────┘                              └┬───────────┘└┬─────────┘
 │                                            │             │
 │                                           ┌▼─────────────▼──────────┐
 │                                           │     webrtc_srtp         │
 │                                           └┬────────────────────────┘
 │                                            │
┌▼────────────────────────────────────────────▼──────────────────────────┐
│                              webrtc_ice                                │
└┬─────────────────┬───────────────────┬──────────────────┬──────────────┘
 │                 │                   │                  │
┌▼────────────┐  ┌─▼──────────┐     ┌─▼───────────┐   ┌──▼───────────┐
│    stun     │  │   turn     │     │webrtc_mdns  │   │  webrtc_util │
└─────────────┘  └────────────┘     └─────────────┘   └──────────────┘

Protocol Flow

  1. Signaling: Exchange of session information (using custom implementation or signal module)
  2. ICE: Establishes connectivity by finding and exchanging network candidates (including mDNS)
  3. DTLS: Secures the connection using certificate-based authentication
  4. SCTP/SRTP: Facilitates reliable data channel communication and secure media transport
  5. Media Pipeline: Processes media through interceptors for functionality like NACK and stats

Using This Documentation

Each summary page provides:

  1. Overview of the module's purpose
  2. Key structs, enums, and traits with their signatures
  3. Important functions and methods
  4. Example usage patterns
  5. Implementation notes

For complete API details, refer to the Rust documentation in the library.

Common Usage Pattern

// Create WebRTC API
let api = API::new()?;

// Configure and create peer connection
let config = RTCConfiguration {
    ice_servers: vec![
        RTCIceServer {
            urls: vec!["stun:stun.l.google.com:19302".to_string()],
            ..Default::default()
        },
    ],
    ..Default::default()
};
let peer_connection = api.new_peer_connection(config).await?;

// Create data channel
let dc = peer_connection.create_data_channel("channel", None).await?;

// Set up handlers
dc.on_open(Box::new(|| {
    println!("Data channel open");
    Box::pin(async {})
}));

dc.on_message(Box::new(|msg| {
    println!("Message received");
    Box::pin(async {})
}));

// Create and set local description
let offer = peer_connection.create_offer(None).await?;
peer_connection.set_local_description(offer.clone()).await?;

// Exchange offer/answer and ICE candidates via signaling
// ...

// When remote description is received
peer_connection.set_remote_description(remote_sdp).await?;

// When remote ICE candidates are received
peer_connection.add_ice_candidate(remote_candidate).await?;

Media Pipeline Configuration

For applications that need custom media processing:

// Create a MediaEngine
let mut m = MediaEngine::default();
m.register_default_codecs()?;

// Create an interceptor registry and add interceptors
let mut registry = Registry::new();
registry.add(Box::new(NoOp::builder()));
registry.add(Box::new(stats::StatsBuilder::default()));
registry.add(Box::new(nack::NackBuilder::default()));

// Create the API with media engine and interceptor registry
let api = APIBuilder::new()
    .with_media_engine(m)
    .with_interceptor_registry(registry)
    .build();

This documentation summary was automatically generated to provide a comprehensive overview of the WebRTC Rust library.

WebRTC.rs Examples

This document provides a comprehensive overview of the examples available in the WebRTC.rs stack. The examples serve as practical demonstrations of various WebRTC functionalities and are organized into categories based on their primary API focus.

Overview

WebRTC.rs examples are Rust implementations of the examples originally created for the Pion WebRTC library in Go. These examples provide practical demonstrations of how to use various WebRTC functionalities in Rust applications.

Media API Examples

These examples demonstrate audio and video streaming capabilities:

Video Streaming

  • Reflect: Demonstrates how to have WebRTC.rs send back to the user exactly what it receives using the same PeerConnection.

  • Play from Disk (VPx): Shows how to send VP8/VP9 video to a browser from a file saved to disk.

  • Play from Disk (H264): Demonstrates sending H264 video to a browser from a file saved to disk.

  • Play from Disk (HEVC): Shows how to stream HEVC/H.265 video from a disk file to a browser.

  • Play from Disk (Renegotiation): Extends the play-from-disk example, demonstrating how to add/remove video tracks from an already negotiated PeerConnection.

  • Insertable Streams: Shows how WebRTC.rs can be used to send E2E encrypted video and decrypt via insertable streams in the browser.

Recording

  • Save to Disk (VPx): Demonstrates how to record webcam footage (VP8/VP9 for video, Opus for audio) and save it to disk on the server side.

  • Save to Disk (H264): Shows how to record webcam footage (H264 for video, Opus for audio) and save it to disk on the server side.

Advanced Media Handling

  • Broadcast: Demonstrates how to broadcast a video to multiple peers where a broadcaster uploads the video once and the server forwards it to all other peers.

  • RTP Forwarder: Shows how to forward audio/video streams using RTP.

  • RTP to WebRTC: Demonstrates how to take RTP packets sent to a WebRTC.rs process and display them in a browser.

  • Simulcast: Shows how to accept and demux one Track that contains three Simulcast streams, returning the media as three independent Tracks back to the sender.

  • Swap Tracks: Demonstrates how to swap multiple incoming tracks on a single outgoing track.

Data Channel API Examples

These examples focus on the data channel capabilities of WebRTC:

Basic Data Channel Operations

  • Data Channels: Demonstrates sending and receiving DataChannel messages from a web browser.

  • Data Channels Create: Similar to the data-channels example, but with the data channel initialized from the server side.

  • Data Channels Close: A variant of data-channels that demonstrates the life cycle of data channels.

Advanced Data Channel Operations

  • Data Channels Detach: Shows how to send/receive DataChannel messages using the underlying DataChannel implementation directly, providing a more idiomatic way of interacting with Data Channels.

  • Data Channels Detach Create: Similar to data-channels-detach, but with the data channel initialized in the example.

  • Data Channels Flow Control: Demonstrates how to use flow control in data channels.

Connection Establishment Examples

  • ORTC: Shows how to use the ORTC API for DataChannel communication.

  • Offer Answer: Demonstrates two WebRTC.rs or Pion instances communicating directly.

  • ICE Restart: Demonstrates WebRTC.rs ICE restart capabilities.

Helper Example

  • RC Cycle: A utility example related to reference counting cycles.

Usage

Each example is structured as a standalone application and can be run using Cargo:

cargo run --example <example-name>

For instance, to run the data-channels example:

cargo run --example data-channels

Most examples include a web-based client interface, typically served at http://localhost:8080 when the example is running.

Dependencies

The examples rely on several dependencies:

  • webrtc: The main WebRTC.rs library
  • tokio: For asynchronous programming
  • env_logger: For logging
  • clap: For command-line argument parsing
  • hyper: For HTTP server functionality
  • signal: A custom crate for signaling
  • Various other utilities for serialization, random number generation, etc.

Notes

  • These examples are designed for educational purposes and may not represent production-ready code.
  • Each example demonstrates specific WebRTC concepts and capabilities.
  • The examples serve as a practical complement to the WebRTC.rs API documentation.

Hub Module Documentation

Overview

The hub module provides a helper utility for handling one-to-many chat communication in WebRTC applications. It facilitates managing multiple connections and broadcasting messages between them in a centralized manner.

Core Components

Hub Struct

The Hub struct is the main component of this module. It manages connections and provides methods for registering, unregistering, and broadcasting messages.

pub struct Hub {
    conns: Arc<Mutex<HashMap<String, Arc<dyn Conn + Send + Sync>>>>
}

Key Methods

  • new() -> Self: Creates a new Hub instance with an empty connections map.
  • async register(&self, conn: Arc<dyn Conn + Send + Sync>): Adds a new connection to the Hub. Takes an Arc<dyn Conn + Send + Sync> representing a connection and stores it in the internal map using the remote address as the key. It also starts a read loop for the connection.
  • async chat(&self): Starts a stdin read loop to dispatch messages to the hub. This allows sending messages from the console to all connected clients.

Internal Methods

  • async read_loop(conns: Arc<Mutex<HashMap<String, Arc<dyn Conn + Send + Sync>>>>, conn: Arc<dyn Conn + Send + Sync>): A background task that continuously reads messages from a connection. When a connection closes, it calls unregister.
  • async unregister(conns: Arc<Mutex<HashMap<String, Arc<dyn Conn + Send + Sync>>>>, conn: Arc<dyn Conn + Send + Sync>): Removes a connection from the Hub and closes it properly.
  • async broadcast(conns: &HashMap<String, Arc<dyn Conn + Send + Sync>>, msg: &str) -> Result<(), Error>: Sends a message to all connected clients.

Utilities Module

The Hub module includes a utilities submodule that provides helper functions for working with certificates and keys, which are necessary for secure WebRTC communication.

Key Functions

  • async chat(conn: Arc<dyn Conn + Send + Sync>) -> Result<(), Error>: Simulates a simple text chat session over a single connection. Takes an Arc<dyn Conn + Send + Sync> and sets up bidirectional communication.
  • load_key_and_certificate(key_path: PathBuf, certificate_path: PathBuf) -> Result<Certificate, Error>: Reads a certificate and its corresponding private key from files.
  • load_key(path: PathBuf) -> Result<CryptoPrivateKey, Error>: Loads a cryptographic private key from a PEM file.
  • load_certificate(path: PathBuf) -> Result<Certificate, Error>: Loads certificate(s) from a PEM file.

Error Handling

The utilities module defines its own error type (Error enum) for handling various error cases that can occur when working with certificates and keys:

  • ErrBlockIsNotPrivateKey
  • ErrUnknownKeyTime
  • ErrNoPrivateKeyFound
  • ErrBlockIsNotCertificate
  • ErrNoCertificateFound
  • Other(String)

Usage Pattern

The Hub is designed to be used in a WebRTC server application where multiple clients can connect and communicate. The typical usage pattern is:

  1. Create a new Hub instance.
  2. For each new connection, call hub.register(conn) to add it to the Hub.
  3. To enable console input to be broadcast to all clients, call hub.chat().

The Hub automatically handles:

  • Tracking all active connections
  • Broadcasting messages to all clients
  • Cleaning up connections when they are closed

Example

// Create a new hub
let hub = Hub::new();

// When a new connection is established
hub.register(conn).await;

// To start the console chat interface that broadcasts to all clients
hub.chat().await;

Implementation Details

  • The Hub uses a thread-safe HashMap wrapped in an Arc<Mutex<...>> to store connections.
  • Each connection is identified by its remote address (IP:port).
  • The module uses asynchronous Rust with tokio for handling concurrent connections.
  • When a connection is registered, a background task is spawned to continuously read messages from it.
  • When a message is received from a connection, it's displayed on the console.
  • When a message is typed on the console, it's broadcast to all connected clients.
  • Typing "exit" terminates the chat session.

Security Considerations

The utilities module provides functions for loading certificates and private keys, which are essential for establishing secure DTLS connections in WebRTC applications. The proper use of these utilities ensures that communication is encrypted.

WebRTC Interceptor Module

Overview

The Interceptor module provides a flexible and extensible architecture for modifying or monitoring RTP and RTCP packets as they flow through a WebRTC connection. Interceptors can be used to add functionality to PeerConnections by modifying any incoming/outgoing packets or generating new packets as needed.

Core Components

Interceptor Trait

The Interceptor trait enables packet processing in the media pipeline. Implementers can:

  • Intercept and modify RTP/RTCP packets through binding to streams
  • Access stream metadata through the StreamInfo structure
  • Manage resource lifecycle with explicit unbind and close operations
  • Chain with other interceptors to create processing pipelines
pub trait Interceptor {
    // Modifies incoming RTCP packets
    fn bind_rtcp_reader<'life0, 'async_trait>(
        &'life0 self,
        reader: Arc<dyn RTCPReader + Send + Sync>,
    ) -> Pin<Box<dyn Future<Output = Arc<dyn RTCPReader + Send + Sync>> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait;

    // Modifies outgoing RTCP packets
    fn bind_rtcp_writer<'life0, 'async_trait>(
        &'life0 self,
        writer: Arc<dyn RTCPWriter + Send + Sync>,
    ) -> Pin<Box<dyn Future<Output = Arc<dyn RTCPWriter + Send + Sync>> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait;

    // Modifies outgoing RTP packets
    fn bind_local_stream<'life0, 'life1, 'async_trait>(
        &'life0 self,
        info: &'life1 StreamInfo,
        writer: Arc<dyn RTPWriter + Send + Sync>,
    ) -> Pin<Box<dyn Future<Output = Arc<dyn RTPWriter + Send + Sync>> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait,
        'life1: 'async_trait;

    // Cleans up resources for a local stream
    fn unbind_local_stream<'life0, 'life1, 'async_trait>(
        &'life0 self,
        info: &'life1 StreamInfo,
    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait,
        'life1: 'async_trait;

    // Modifies incoming RTP packets
    fn bind_remote_stream<'life0, 'life1, 'async_trait>(
        &'life0 self,
        info: &'life1 StreamInfo,
        reader: Arc<dyn RTPReader + Send + Sync>,
    ) -> Pin<Box<dyn Future<Output = Arc<dyn RTPReader + Send + Sync>> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait,
        'life1: 'async_trait;

    // Cleans up resources for a remote stream
    fn unbind_remote_stream<'life0, 'life1, 'async_trait>(
        &'life0 self,
        info: &'life1 StreamInfo,
    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait,
        'life1: 'async_trait;

    // Closes the interceptor and cleans up resources
    fn close<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait;
}

InterceptorBuilder Trait

The InterceptorBuilder trait allows for the construction of interceptors:

pub trait InterceptorBuilder {
    // Required method
    fn build(
        &self,
        id: &str,
    ) -> Result<Arc<dyn Interceptor + Send + Sync>, Error>;
}

Registry

The Registry struct acts as a collector for interceptors:

pub struct Registry { /* private fields */ }

Key Methods:

impl Registry {
    // Creates a new registry
    pub fn new() -> Self { ... }
    
    // Adds a new interceptor builder to the registry
    pub fn add(&mut self, builder: Box<dyn InterceptorBuilder + Send + Sync>) { ... }
    
    // Constructs a single interceptor from an InterceptorRegistry
    pub fn build(
        &self,
        id: &str,
    ) -> Result<Arc<dyn Interceptor + Send + Sync>, Error> { ... }
    
    // Constructs a non-type erased Chain from an Interceptor registry
    pub fn build_chain(&self, id: &str) -> Result<Chain, Error> { ... }
}

Chain

The Chain struct is an interceptor that runs all child interceptors in sequence. It allows for composing multiple interceptors together in a pipeline:

pub struct Chain { /* private fields */ }

impl Chain {
    // Creates a new Chain with the given interceptors
    pub fn new(interceptors: Vec<Arc<dyn Interceptor + Send + Sync>>) -> Self { ... }
    
    // Adds a new interceptor to the chain
    pub fn add(&mut self, interceptor: Arc<dyn Interceptor + Send + Sync>) { ... }
}

impl Interceptor for Chain { ... }

Available Interceptors

NoOp

A simple pass-through interceptor that doesn't modify any packets:

pub struct NoOp { /* private fields */ }

impl NoOp {
    pub fn builder() -> impl InterceptorBuilder + Send + Sync { ... }
}

impl Interceptor for NoOp { ... }

NACK (Negative Acknowledgment)

Contains two components:

  1. Generator: Detects packet loss and generates NACK messages for retransmission

    pub struct Generator { /* private fields */ }
    
    pub struct GeneratorBuilder { /* private fields */ }
    
    impl Generator {
        // Creates a new Generator
        pub fn new(...) -> Self { ... }
    }
    
    impl Interceptor for Generator { ... }
  2. Responder: Handles incoming NACK messages by resending lost packets

    pub struct Responder { /* private fields */ }
    
    pub struct ResponderBuilder { /* private fields */ }
    
    impl Responder {
        // Creates a new Responder
        pub fn new(...) -> Self { ... }
    }
    
    impl Interceptor for Responder { ... }

Report

Handles RTP and RTCP reporting:

pub struct ReportBuilder { /* private fields */ }

// ReceiverReport: Generates RTCP receiver reports
pub struct ReceiverReport { /* private fields */ }
impl Interceptor for ReceiverReport { ... }

// SenderReport: Generates RTCP sender reports
pub struct SenderReport { /* private fields */ }
impl Interceptor for SenderReport { ... }

Stats

The stats interceptor collects RTP and RTCP statistics:

// StatsInterceptor: Tracks metrics like packet counts, bytes, loss, jitter, etc.
pub struct StatsInterceptor { /* private fields */ }

// RTPStats: Holds RTP-specific statistics
pub struct RTPStats {
    pub packets: AtomicUsize,
    pub header_bytes: AtomicUsize,
    pub payload_bytes: AtomicUsize,
    pub last_sequence_number: AtomicU16,
    pub jitter: AtomicU32,
}

// RTCPStats: Holds RTCP-specific statistics
pub struct RTCPStats {
    pub packets: AtomicUsize,
    pub bytes: AtomicUsize,
}

impl Interceptor for StatsInterceptor { ... }

TWCC (Transport-Wide Congestion Control)

Implements the TWCC RTP extension:

  1. Sender: Adds TWCC headers to outgoing RTP packets

    pub struct Sender { /* private fields */ }
    pub struct SenderBuilder { /* private fields */ }
    impl Interceptor for Sender { ... }
  2. Receiver: Processes incoming packets with TWCC headers and generates feedback

    pub struct Receiver { /* private fields */ }
    pub struct ReceiverBuilder { /* private fields */ }
    impl Interceptor for Receiver { ... }
  3. Recorder: Records timestamps for TWCC packets

    pub struct Recorder { /* private fields */ }

Mock

Contains utilities for testing interceptor implementations:

// MockInterceptor: Implements the Interceptor trait for testing
pub struct MockInterceptor { /* private fields */ }

// MockBuilder: Builds mock interceptors
pub struct MockBuilder { /* private fields */ }

// MockStream: Simulates RTP streams for testing
pub struct MockStream { /* private fields */ }

impl Interceptor for MockInterceptor { ... }

Data Structures

StreamInfo

Contains information about RTP streams:

pub struct StreamInfo {
    pub id: String,
    pub attributes: Attributes,
    pub ssrc: u32,
    pub payload_type: u8,
    pub rtp_header_extensions: Vec<RTPHeaderExtension>,
    pub mime_type: String,
    pub clock_rate: u32,
    pub channels: u16,
    pub sdp_fmtp_line: String,
    pub rtcp_feedback: Vec<RTCPFeedback>,
    pub associated_stream: Option<AssociatedStreamInfo>,
}

Attributes

A generic key/value store used by interceptors to communicate additional metadata:

pub type Attributes = Arc<Mutex<HashMap<String, Arc<dyn Any + Send + Sync>>>>;

Usage Patterns

  1. Creating a single interceptor:

    let interceptor = generator_builder.build("nack_generator")?;
  2. Composing multiple interceptors:

    let registry = Registry::new();
    registry.add(Box::new(nack_generator_builder));
    registry.add(Box::new(nack_responder_builder));
    registry.add(Box::new(stats_builder));
    
    let chain = registry.build_chain("my_interceptors")?;
  3. Building a custom interceptor:

    struct MyInterceptor {
        // fields
    }
    
    impl Interceptor for MyInterceptor {
        // implement methods
    }
    
    struct MyInterceptorBuilder {
        // fields
    }
    
    impl InterceptorBuilder for MyInterceptorBuilder {
        fn build(&self, id: &str) -> Result<Arc<dyn Interceptor + Send + Sync>, Error> {
            // build and return interceptor
        }
    }

Common Workflows

  1. Packet Monitoring: Interceptors can monitor RTP/RTCP packets without modifying them, useful for logging or debugging.

  2. Packet Modification: Interceptors can modify packets in transit, such as adding headers or changing payload data.

  3. Packet Generation: Interceptors can generate new packets, such as RTCP feedback reports based on observed traffic.

  4. Statistics Collection: Interceptors can collect statistics about the media traffic for reporting or analysis.

Best Practices

  1. Chain Order: The order of interceptors in a chain matters. For example, statistics collection should typically come after packet modification interceptors.

  2. Performance Considerations: Interceptors are in the critical path of media processing, so they should be efficient.

  3. Thread Safety: Interceptors must be thread-safe as they may be accessed from multiple threads.

  4. Error Handling: Interceptors should handle errors gracefully to avoid disrupting the media flow.

Conclusion

The interceptor architecture provides a powerful mechanism for extending WebRTC functionality. By implementing the Interceptor trait, developers can create custom packet processing logic that integrates seamlessly with the WebRTC pipeline.

WebRTC RTCP Module API Documentation

The RTCP (RTP Control Protocol) module implements encoding and decoding of RTCP packets according to RFCs 3550 and 5506. RTCP is a sister protocol of the Real-time Transport Protocol (RTP), providing out-of-band statistics and control information for RTP sessions.

Overview

RTCP provides feedback on the quality of service (QoS) in media distribution by periodically sending statistics such as:

  • Transmitted octet and packet counts
  • Packet loss
  • Packet delay variation
  • Round-trip delay time

Applications can use this information to control quality of service parameters, adjust flow, or switch codecs.

Core Components

Packet Trait

pub trait Packet: Marshal + Unmarshal + Display + Debug {
    fn header(&self) -> Header;
    fn destination_ssrc(&self) -> Vec<u32>;
    fn raw_size(&self) -> usize;
    fn as_any(&self) -> &(dyn Any + Send + Sync);
    fn equal(&self, other: &(dyn Packet + Send + Sync)) -> bool;
    fn cloned(&self) -> Box<dyn Packet + Send + Sync>;
}

The Packet trait represents an RTCP packet and is implemented by all packet types in the module. It provides essential methods for packet handling and introspection:

  • header(): Returns the Header associated with this packet
  • destination_ssrc(): Returns an array of SSRC values the packet refers to
  • raw_size(): Returns the size of the packet in bytes
  • as_any(): Converts the packet to an Any type for downcasting
  • equal(): Compares with another packet
  • cloned(): Creates a deep copy of the packet

Marshal/Unmarshal Functions

pub fn marshal(packets: &[Box<dyn Packet + Send + Sync>]) -> Result<Bytes, Error>
  • Serializes an array of RTCP packets into a single buffer.
pub fn unmarshal<B>(raw_data: &mut B) -> Result<Vec<Box<dyn Packet + Send + Sync>>, Error> 
where B: Buf
  • Deserializes a buffer containing one or more RTCP packets.
  • Handles both compound packets and individual feedback packets.

Packet Types

Header

pub struct Header {
    pub version: u8,
    pub padding: bool,
    pub count: u8,
    pub packet_type: PacketType,
    pub length: u16,
}

The Header struct defines the common header for all RTCP packets with fields for:

  • RTCP version
  • Padding flag
  • Count field (varies by packet type)
  • Packet type
  • Length of the packet

Sender Report (SR)

pub struct SenderReport {
    pub ssrc: u32,
    pub ntp_time: u64,
    pub rtp_time: u32,
    pub packet_count: u32,
    pub octet_count: u32,
    pub reports: Vec<ReceptionReport>,
    pub profile_extensions: Bytes,
}

Sender Reports provide reception quality feedback and include:

  • Sender's SSRC identifier
  • NTP timestamp for timing synchronization
  • RTP timestamp corresponding to the NTP timestamp
  • Sender statistics (packet and octet counts)
  • Reception reports for sources this sender has received from
  • Optional profile-specific extensions

Receiver Report (RR)

pub struct ReceiverReport {
    pub ssrc: u32,
    pub reports: Vec<ReceptionReport>,
    pub profile_extensions: Bytes,
}

Receiver Reports contain reception statistics from participants that are not active senders:

  • Reporter's SSRC identifier
  • List of reception reports
  • Optional profile-specific extensions

Reception Report

pub struct ReceptionReport {
    pub ssrc: u32,
    pub fraction_lost: u8, 
    pub total_lost: u32,
    pub last_sequence_number: u32,
    pub jitter: u32,
    pub last_sender_report: u32,
    pub delay: u32,
}

Reception Reports contain statistics for a specific SSRC source:

  • SSRC of the source
  • Fraction of packets lost since last report
  • Cumulative number of packets lost
  • Extended highest sequence number received
  • Interarrival jitter
  • Last SR (LSR) timestamp
  • Delay since last SR (DLSR)

Feedback Packets

Picture Loss Indication (PLI)

pub struct PictureLossIndication {
    pub sender_ssrc: u32,
    pub media_ssrc: u32,
}

PLI informs the encoder about the loss of coded video data:

  • SSRC of sender
  • SSRC of media source affected by the loss

Receiver Estimated Maximum Bitrate (REMB)

pub struct ReceiverEstimatedMaximumBitrate {
    pub sender_ssrc: u32,
    pub ssrcs: Vec<u32>,
    pub bitrate: u64,
}

REMB provides the sender with the receiver's estimated maximum bitrate:

  • SSRC of sender generating the report
  • List of SSRCs this feedback applies to
  • Maximum bitrate in bits per second

Source Description (SDES)

pub struct SourceDescription {
    pub chunks: Vec<SourceDescriptionChunk>
}

pub struct SourceDescriptionChunk {
    pub source: u32,
    pub items: Vec<SourceDescriptionItem>
}

pub struct SourceDescriptionItem {
    pub sdes_type: SdesType,
    pub text: String
}

SDES packets contain source description items like:

  • CNAME (Canonical End-Point Identifier)
  • NAME (User name)
  • EMAIL (User email)
  • PHONE (User phone number)
  • And other identification and description fields

Extended Report (XR)

pub struct ExtendedReport {
    pub sender_ssrc: u32,
    pub reports: Vec<Box<dyn Packet + Send + Sync>>,
}

Extended Reports provide additional feedback metrics beyond standard reports:

  • Supports various report block types
  • Includes VoIP metrics, reception times, statistics summaries

Compound Packet

pub struct CompoundPacket {
    pub packets: Vec<Box<dyn Packet + Send + Sync>>
}

Compound Packets bundle multiple RTCP packets together:

  • Must start with SR or RR packet
  • Must include SDES packet with CNAME
  • Can contain additional packet types

Error Handling

pub enum Error {
    WrongMarshalSize,
    InvalidTotalLost,
    InvalidHeader,
    EmptyCompound,
    BadFirstPacket,
    MissingCname,
    // ... many more error variants
}

The Error enum provides comprehensive error types for RTCP operations, including:

  • Packet validation errors
  • Format and padding errors
  • Size and structure errors
  • Missing required fields
  • Invalid values

Example Usage

Decoding RTCP packets

let pkt = rtcp::unmarshal(&rtcp_data).unwrap();

if let Some(e) = pkt
     .as_any()
     .downcast_ref::<PictureLossIndication>() {
    // Handle PLI packet
}
else if let Some(e) = packet
     .as_any()
     .downcast_ref::<Goodbye>() {
    // Handle Goodbye packet
}

Encoding RTCP packets

let pkt = PictureLossIndication{
    sender_ssrc: sender_ssrc,
    media_ssrc: media_ssrc
};

let pli_data = pkt.marshal().unwrap();
// Send pli_data over the network

Constants and Header Values

The module defines various constants for RTCP header fields:

  • VERSION_MASK, VERSION_SHIFT for handling version fields
  • PADDING_MASK, PADDING_SHIFT for padding fields
  • COUNT_MASK, COUNT_SHIFT for count fields
  • Format constants (FORMAT_PLI, FORMAT_FIR, etc.) for feedback message types
  • HEADER_LENGTH, SSRC_LENGTH for field sizes

Implementation Notes

  • The module follows RFC 3550 (RTP/RTCP) and RFC 5506 (Reduced-Size RTCP)
  • Packets are validated during unmarshal operations
  • The module supports both compound and reduced-size RTCP packets
  • All packet types implement the Packet trait, Marshal, Unmarshal, Display, and Debug traits
  • The API uses Rust's type system for type safety and proper error handling

RTP Module API Documentation

The RTP (Real-time Transport Protocol) module provides a comprehensive implementation of the RTP protocol as defined in RFC 3550. This module enables applications to send and receive real-time data such as audio and video over packet-switched networks.

Core Components

Header (rtp::header::Header)

pub struct Header {
    pub version: u8,
    pub padding: bool,
    pub extension: bool,
    pub marker: bool,
    pub payload_type: u8,
    pub sequence_number: u16,
    pub timestamp: u32,
    pub ssrc: u32,
    pub csrc: Vec<u32>,
    pub extension_profile: u16,
    pub extensions: Vec<Extension>,
    pub extensions_padding: usize,
}

Represents an RTP packet header that contains the metadata required for RTP packet transmission and sequencing.

Key Methods:

  • get_extension_payload_len(&self) -> usize: Gets the length of extensions payload
  • set_extension(&mut self, id: u8, payload: Bytes) -> Result<(), Error>: Adds or updates an RTP header extension
  • get_extension_ids(&self) -> Vec<u8>: Returns all extension IDs present in the header
  • get_extension(&self, id: u8) -> Option<Bytes>: Retrieves a specific extension by ID
  • del_extension(&mut self, id: u8) -> Result<(), Error>: Removes an extension by ID

Packet (rtp::packet::Packet)

pub struct Packet {
    pub header: Header,
    pub payload: Bytes,
}

Represents a complete RTP packet, containing both the header metadata and payload data.

Key Methods:

  • marshal_to(&self, buf: &mut [u8]) -> Result<usize, Error>: Serializes the packet into the provided buffer
  • marshal(&self) -> Result<Bytes, Error>: Serializes the packet and returns as Bytes
  • marshal_size(&self) -> usize: Determines the total size of the marshaled packet
  • unmarshal<B>(raw_packet: &mut B) -> Result<Self, Error>: Deserializes from raw bytes

Packetization

Packetizer (rtp::packetizer::Packetizer)

pub trait Packetizer: Debug {
    fn enable_abs_send_time(&mut self, value: u8);
    fn packetize(
        &mut self, 
        payload: &Bytes, 
        samples: u32
    ) -> Result<Vec<Packet>, Error>;
    fn skip_samples(&mut self, skipped_samples: u32);
    fn clone_to(&self) -> Box<dyn Packetizer + Send + Sync>;
}

Packetizes payload data into appropriate RTP packets, handling fragmentation and other codec-specific requirements.

Payloader (rtp::packetizer::Payloader)

pub trait Payloader: Debug {
    fn payload(
        &mut self, 
        mtu: usize, 
        b: &Bytes
    ) -> Result<Vec<Bytes>, Error>;
    fn clone_to(&self) -> Box<dyn Payloader + Send + Sync>;
}

Handles the codec-specific segmentation of media payloads to fit within MTU size limits.

Implementations include:

  • Av1Payloader: For AV1 video codec
  • G7xxPayloader: For G.711 and G.722 audio codecs
  • H264Payloader: For H.264 video codec
  • HevcPayloader: For H.265/HEVC video codec
  • OpusPayloader: For Opus audio codec
  • Vp8Payloader: For VP8 video codec
  • Vp9Payloader: For VP9 video codec

Depacketizer (rtp::packetizer::Depacketizer)

pub trait Depacketizer {
    fn depacketize(&mut self, b: &Bytes) -> Result<Bytes, Error>;
    fn is_partition_head(&self, payload: &Bytes) -> bool;
    fn is_partition_tail(&self, marker: bool, payload: &Bytes) -> bool;
}

Handles unpacking of RTP payloads, removing RTP-specific framing to extract the original media data.

Implementations include:

  • H264Packet: For H.264 video codec
  • H265Packet: For H.265/HEVC video codec
  • OpusPacket: For Opus audio codec
  • Vp8Packet: For VP8 video codec
  • Vp9Packet: For VP9 video codec

Sequencer (rtp::sequence::Sequencer)

pub trait Sequencer: Debug {
    fn next_sequence_number(&self) -> u16;
    fn roll_over_count(&self) -> u64;
    fn clone_to(&self) -> Box<dyn Sequencer + Send + Sync>;
}

Generates sequential sequence numbers for RTP packets, handling roll-over conditions when the 16-bit sequence counter wraps.

Factory Functions:

  • new_random_sequencer() -> Box<dyn Sequencer + Send + Sync>: Creates a sequencer starting at a random sequence number
  • new_fixed_sequencer(s: u16) -> Box<dyn Sequencer + Send + Sync>: Creates a sequencer starting at a specified sequence number

Extensions

The RTP module supports various header extensions as defined in RFCs:

AbsSendTimeExtension (rtp::extension::abs_send_time_extension::AbsSendTimeExtension)

pub struct AbsSendTimeExtension;

Implements the Absolute Send Time extension (RFC 5285) that allows for more precise synchronization and timing measurements.

AudioLevelExtension (rtp::extension::audio_level_extension::AudioLevelExtension)

pub struct AudioLevelExtension;

Implements the client-to-mixer audio level extension as specified in RFC 6464.

TransportCcExtension (rtp::extension::transport_cc_extension::TransportCcExtension)

pub struct TransportCcExtension;

Implements the transport-wide congestion control extension for RTP.

VideoOrientationExtension (rtp::extension::video_orientation_extension::VideoOrientationExtension)

pub struct VideoOrientationExtension;

Implements Coordination of Video Orientation (CVO) as defined in 3GPP TS 26.114.

Error Handling

pub enum Error {
    PacketTooShort,
    InvalidExtensionLength,
    InvalidHeader,
    HeaderSizeInsufficient,
    TooManyExtensions,
    RtpVersionUnsupported,
    EmptyPayloadWithMarker,
    ReservedException,
    ReservededExtensionByte,
    InvalidExtensionValues,
    PacketizerError,
    InvalidNalUnitType,
    InvalidPayloadType,
}

Comprehensive error handling for the various failure modes during RTP processing.

Usage Example

// Create a new RTP packet
let mut header = Header::default();
header.payload_type = 96; // Common for H.264
header.sequence_number = 1234;
header.timestamp = 5678;
header.ssrc = 12345678;

let payload = Bytes::from(vec![0, 1, 2, 3, 4]); // Example payload
let packet = Packet {
    header,
    payload,
};

// Serialize the packet
let serialized = packet.marshal().expect("Failed to marshal packet");

// Deserialize the packet
let mut buf = serialized.clone();
let deserialized = Packet::unmarshal(&mut buf).expect("Failed to unmarshal packet");

// Example of using a packetizer for H.264
let payloader = H264Payloader::default();
let mtu = 1500;
let video_frame = Bytes::from(/* H.264 NAL units */);
let payloads = payloader.payload(mtu, &video_frame).expect("Failed to payload");

// Packetize the payloads into RTP packets
let sequencer = new_random_sequencer();
let packetizer = new_packetizer(
    1500, // MTU
    96,    // Payload type
    12345678, // SSRC
    payloader,
    sequencer,
    90000, // Clock rate for H.264
);

let packets = packetizer.packetize(&video_frame, 90000).expect("Failed to packetize");

References

  1. RFC 3550: RTP: A Transport Protocol for Real-Time Applications
  2. RFC 5285: A General Mechanism for RTP Header Extensions
  3. RFC 6184: RTP Payload Format for H.264 Video
  4. RFC 6464: A Real-time Transport Protocol (RTP) Header Extension for Client-to-Mixer Audio Level Indication

This RTP module is designed for high-performance real-time media communications, supporting a wide range of codecs and extensions required for modern audio/video applications.

WebRTC SDP Module API Documentation

This markdown document provides a comprehensive overview of the Session Description Protocol (SDP) module in the WebRTC Rust implementation. SDP is a format for describing multimedia communication sessions for the purposes of session announcement, session invitation, and parameter negotiation.

Core Types

SessionDescription

pub struct SessionDescription {
    pub version: Version,
    pub origin: Origin,
    pub session_name: SessionName,
    pub session_information: Option<Information>,
    pub uri: Option<Url>,
    pub email_address: Option<EmailAddress>,
    pub phone_number: Option<PhoneNumber>,
    pub connection_information: Option<ConnectionInformation>,
    pub bandwidth: Vec<Bandwidth>,
    pub time_descriptions: Vec<TimeDescription>,
    pub time_zones: Vec<TimeZone>,
    pub encryption_key: Option<EncryptionKey>,
    pub attributes: Vec<Attribute>,
    pub media_descriptions: Vec<MediaDescription>,
}

The SessionDescription is the primary structure representing a complete SDP document. It provides a well-defined format for conveying sufficient information to discover and participate in a multimedia session.

Key Methods

  • new_jsep_session_description(identity: bool) -> Self: Creates a new SessionDescription with JSEP requirements
  • with_property_attribute(self, key: String) -> Self: Adds a property attribute 'a=key'
  • with_value_attribute(self, key: String, value: String) -> Self: Adds a value attribute 'a=key:value'
  • with_fingerprint(self, algorithm: String, value: String) -> Self: Adds a fingerprint
  • with_media(self, md: MediaDescription) -> Self: Adds a media description
  • get_codec_for_payload_type(&self, payload_type: u8) -> Result<Codec, Error>: Scans for a codec with the given payload type
  • get_payload_type_for_codec(&self, wanted: &Codec) -> Result<u8, Error>: Scans for the payload type of a given codec
  • has_attribute(&self, key: &str) -> bool: Checks if an attribute exists
  • attribute(&self, key: &str) -> Option<&String>: Returns the value of an attribute if it exists
  • marshal(&self) -> String: Serializes the SDP struct to text
  • unmarshal<R: BufRead + Seek>(reader: &mut R) -> Result<Self, Error>: Deserializes text into a SessionDescription

MediaDescription

pub struct MediaDescription {
    pub media_name: MediaName,
    pub media_title: Option<Information>,
    pub connection_information: Option<ConnectionInformation>,
    pub bandwidth: Vec<Bandwidth>,
    pub encryption_key: Option<EncryptionKey>,
    pub attributes: Vec<Attribute>,
}

MediaDescription represents a media type within a session (e.g., audio, video, application data).

Key Methods

  • new_jsep_media_description(codec_type: String, _codec_prefs: Vec<&str>) -> Self: Creates a new MediaDescription with JSEP settings
  • with_property_attribute(self, key: String) -> Self: Adds a property attribute
  • with_value_attribute(self, key: String, value: String) -> Self: Adds a value attribute
  • with_fingerprint(self, algorithm: String, value: String) -> Self: Adds a fingerprint
  • with_ice_credentials(self, username: String, password: String) -> Self: Adds ICE credentials
  • with_codec(self, payload_type: u8, name: String, clockrate: u32, channels: u16, fmtp: String) -> Self: Adds codec information
  • with_media_source(self, ssrc: u32, cname: String, stream_label: String, label: String) -> Self: Adds media source info
  • with_candidate(self, value: String) -> Self: Adds an ICE candidate (deprecated)
  • with_extmap(self, e: ExtMap) -> Self: Adds an extension map
  • with_transport_cc_extmap(self) -> Self: Adds a transport control extension map

Direction

pub enum Direction {
    Unspecified = 0,
    SendRecv = 1,    // For bidirectional communication
    SendOnly = 2,    // For outgoing communication
    RecvOnly = 3,    // For incoming communication
    Inactive = 4,    // For no communication
}

The Direction enum is a marker for the transmission direction of an endpoint.

Key Methods

  • new(raw: &str) -> Self: Creates a Direction from a raw string

ExtMap

pub struct ExtMap {
    pub value: isize,
    pub direction: Direction,
    pub uri: Option<Url>,
    pub ext_attr: Option<String>,
}

ExtMap represents the activation of a single RTP header extension.

Key Methods

  • convert(&self) -> Attribute: Converts to an Attribute
  • unmarshal<R: BufRead>(reader: &mut R) -> Result<Self, Error>: Creates an ExtMap from a string
  • marshal(&self) -> String: Creates a string from an ExtMap

Constants

Extension Map URIs

pub const TRANSPORT_CC_URI: &str = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
pub const ABS_SEND_TIME_URI: &str = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
pub const SDES_MID_URI: &str = "urn:ietf:params:rtp-hdrext:sdes:mid";
pub const SDES_RTP_STREAM_ID_URI: &str = "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
pub const AUDIO_LEVEL_URI: &str = "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
pub const VIDEO_ORIENTATION_URI: &str = "urn:3gpp:video-orientation";
pub const SDES_REPAIR_RTP_STREAM_ID_URI: &str = "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";

Default Extension Map Values

pub const DEF_EXT_MAP_VALUE_ABS_SEND_TIME: isize = 1;
pub const DEF_EXT_MAP_VALUE_TRANSPORT_CC: isize = 2;
pub const DEF_EXT_MAP_VALUE_SDES_MID: isize = 3;
pub const DEF_EXT_MAP_VALUE_SDES_RTP_STREAM_ID: isize = 4;

Session Attribute Keys

pub const ATTR_KEY_END_OF_CANDIDATES: &str = "end-of-candidates";
pub const ATTR_KEY_CANDIDATE: &str = "candidate";
pub const ATTR_KEY_GROUP: &str = "group";
pub const ATTR_KEY_SSRC: &str = "ssrc";
pub const ATTR_KEY_SSRCGROUP: &str = "ssrc-group";
pub const ATTR_KEY_MSID: &str = "msid";
pub const ATTR_KEY_MSID_SEMANTIC: &str = "msid-semantic";
pub const ATTR_KEY_CONNECTION_SETUP: &str = "setup";
pub const ATTR_KEY_MID: &str = "mid";
pub const ATTR_KEY_RTCPMUX: &str = "rtcp-mux";
pub const ATTR_KEY_ICELITE: &str = "ice-lite";
pub const ATTR_KEY_RTCPRSIZE: &str = "rtcp-rsize";
pub const ATTR_KEY_RECV_ONLY: &str = "recvonly";
pub const ATTR_KEY_SEND_ONLY: &str = "sendonly";
pub const ATTR_KEY_INACTIVE: &str = "inactive";
pub const ATTR_KEY_SEND_RECV: &str = "sendrecv";
pub const ATTR_KEY_EXT_MAP: &str = "extmap";
pub const ATTR_KEY_EXTMAP_ALLOW_MIXED: &str = "extmap-allow-mixed";
pub const ATTR_KEY_IDENTITY: &str = "identity";

Semantic Tokens

pub const SEMANTIC_TOKEN_LIP_SYNCHRONIZATION: &str = "LS";
pub const SEMANTIC_TOKEN_FLOW_IDENTIFICATION: &str = "FID";
pub const SEMANTIC_TOKEN_FORWARD_ERROR_CORRECTION: &str = "FEC";
pub const SEMANTIC_TOKEN_WEBRTC_MEDIA_STREAMS: &str = "WMS";

Error Handling

#[non_exhaustive]
pub enum Error {
    CodecNotFound,
    MissingWhitespace,
    MissingColon,
    PayloadTypeNotFound,
    Io(IoError),
    Utf8(FromUtf8Error),
    SdpInvalidSyntax(String),
    SdpInvalidValue(String),
    SdpEmptyTimeDescription,
    ParseInt(ParseIntError),
    ParseUrl(ParseError),
    ParseExtMap(String),
    SyntaxError {
        s: String,
        p: usize,
    },
}

The Error enum defines various error types that can occur when working with SDP data, including parsing errors, invalid syntax, and missing required fields.

Utility Types

ConnectionRole

pub enum ConnectionRole {
    Active,
    Passive,
    Actpass,
    Holdconn,
}

Represents the role of a connection in a session.

Codec

pub struct Codec {
    pub payload_type: u8,
    pub name: String,
    pub clock_rate: u32,
    pub encoding_parameters: String,
    pub fmtp: String,
}

Represents an audio or video codec with its parameters.

Usage Examples

Creating a basic SDP offer

// Create a new JSEP Session Description
let mut sd = SessionDescription::new_jsep_session_description(false);

// Add a media description for audio
let audio = MediaDescription::new_jsep_media_description("audio".to_string(), vec![])
    .with_codec(111, "opus".to_string(), 48000, 2, "minptime=10;useinbandfec=1".to_string())
    .with_ice_credentials("username".to_string(), "password".to_string())
    .with_fingerprint("sha-256".to_string(), "fingerprint".to_string());

// Add a media description for video
let video = MediaDescription::new_jsep_media_description("video".to_string(), vec![])
    .with_codec(96, "VP8".to_string(), 90000, 0, "".to_string())
    .with_ice_credentials("username".to_string(), "password".to_string())
    .with_fingerprint("sha-256".to_string(), "fingerprint".to_string());

// Add media descriptions to session
sd = sd.with_media(audio).with_media(video);

// Marshal to SDP string
let sdp_string = sd.marshal();

Parsing an SDP answer

// Parse SDP from string
let sdp_answer = String::try_from(sdp_string_received_from_peer)?;

// Convert to SessionDescription
let session_desc = SessionDescription::try_from(sdp_answer)?;

// Get payload type for a specific codec
let codec = Codec {
    payload_type: 0, // Will be filled by function
    name: "opus".to_string(),
    clock_rate: 48000,
    encoding_parameters: "2".to_string(),
    fmtp: "".to_string(),
};

let payload_type = session_desc.get_payload_type_for_codec(&codec)?;

Core Concepts

The SDP module implements RFC 4566 (Session Description Protocol) with extensions for WebRTC. It provides:

  1. Session Description: The top-level structure containing all session information
  2. Media Descriptions: Descriptions of media streams within a session (audio, video, application)
  3. Attributes: Key-value pairs providing additional information about the session or media
  4. Directions: Indicating whether endpoints can send, receive, both, or neither
  5. Extensions: RTP header extensions for additional functionality

The module supports both serialization (marshal) and deserialization (unmarshal) between Rust structures and the text-based SDP format, allowing for creating, parsing, and manipulating SDP documents for WebRTC applications.

Signal Module Documentation

Overview

The signal module in the WebRTC Rust implementation provides essential functionality for WebRTC signaling. Signaling is the process of coordinating communication between peers before establishing a direct WebRTC connection. This module offers utilities for encoding and decoding Session Description Protocol (SDP) messages, reading input data, and setting up a simple HTTP server for receiving SDP information.

Components

The signal module consists of four main functions:

1. HTTP SDP Server

use tokio::sync::mpsc;

pub async fn http_sdp_server(port: u16) -> tokio::sync::mpsc::Receiver<String>

This function starts an HTTP server that consumes Session Description Protocol (SDP) messages. The server listens on the specified port and processes incoming SDP messages received via HTTP POST requests to the /sdp endpoint.

Parameters:

  • port: A u16 value specifying which port the HTTP server should listen on.

Returns:

  • A tokio::sync::mpsc::Receiver<String> that allows the caller to receive SDP messages when they arrive.

Usage Pattern:

  1. Call http_sdp_server with a port number.
  2. Receive a channel receiver that will provide incoming SDP messages.
  3. The server runs in the background and forwards any SDP messages received via HTTP POST to the /sdp endpoint.

2. Standard Input Reading

use anyhow::Result;

pub fn must_read_stdin() -> anyhow::Result<String>

This function blocks until input is received from standard input (stdin). It is useful for interactive applications where user input is required.

Returns:

  • An anyhow::Result<String> containing the input line as a trimmed string or an error.

Usage Pattern:

  1. Call must_read_stdin() when you need to wait for user input.
  2. The function will block until a line is entered in the terminal.
  3. The input is trimmed and returned as a String.

3. Encoding

use base64::prelude::BASE64_STANDARD;
use base64::Engine;

pub fn encode(b: &str) -> String

This function encodes input text in base64 format. It is designed to handle SDP messages which may need to be transmitted through text-based protocols or user interfaces.

Parameters:

  • b: A string slice containing the text to encode.

Returns:

  • A String containing the base64-encoded version of the input.

Note:

  • The implementation includes commented code for optional compression before encoding, but this is currently disabled.

4. Decoding

use anyhow::Result;
use base64::prelude::BASE64_STANDARD;
use base64::Engine;

pub fn decode(s: &str) -> anyhow::Result<String>

This function decodes base64-encoded input back to its original text form. It is the counterpart to the encode function.

Parameters:

  • s: A string slice containing the base64-encoded text to decode.

Returns:

  • An anyhow::Result<String> containing the decoded text as a string, or an error if decoding fails.

Note:

  • Like the encode function, there is commented code for optional decompression after decoding.

Internal Implementation

Internally, the module uses:

  • The hyper crate for HTTP server functionality
  • Tokio for asynchronous programming
  • base64 for encoding and decoding
  • lazy_static for static variable initialization
  • Mutex-protected channels for thread-safe communication

The HTTP server implementation includes a handler that processes incoming SDP messages and forwards them through a channel. The server is designed to run indefinitely in a separate task.

Usage Patterns

The signal module is typically used in WebRTC applications as follows:

  1. Setting up signaling:

    • Start an HTTP server using http_sdp_server to receive SDP offers/answers.
    • Use the returned channel to process incoming messages.
  2. Exchanging SDP information:

    • Encode local SDP data using encode before transmitting it.
    • Decode received SDP data using decode before processing it.
  3. Interactive applications:

    • Use must_read_stdin to wait for user input, such as pasting an SDP offer.

Example Use Case

In a typical WebRTC application, this module would be used to:

  1. Generate a local SDP offer
  2. Encode it with encode
  3. Have the user share the encoded offer with a peer
  4. Start an HTTP server with http_sdp_server to receive the answer
  5. When the peer responds, their encoded answer would be received via HTTP
  6. The answer would be decoded with decode
  7. The decoded answer would be used to establish the WebRTC connection

This signaling process is essential for WebRTC as it handles the initial coordination between peers before direct peer-to-peer communication can be established.

STUN Module API Documentation

Overview

The STUN (Session Traversal Utilities for NAT) module implements the STUN protocol as specified in RFC 5389. STUN is a protocol that serves as a tool for other protocols in dealing with Network Address Translator (NAT) traversal.

Core Components

Message

pub struct Message {
    pub typ: MessageType,
    pub length: u32,
    pub transaction_id: TransactionId,
    pub attributes: Attributes,
    pub raw: Vec<u8>,
}

The Message struct is the fundamental unit in STUN communication. It represents a STUN message with the following components:

  • typ: The message type (request, response, etc.)
  • length: The message length in bytes
  • transaction_id: Unique identifier for the transaction
  • attributes: Collection of STUN attributes in the message
  • raw: Raw binary representation of the message

Key Methods:

  • new() -> Self: Creates a new empty message
  • marshal_binary() -> Result<Vec<u8>, Error>: Converts message to binary format
  • unmarshal_binary(&mut self, data: &[u8]) -> Result<(), Error>: Parses binary data into message
  • add(&mut self, t: AttrType, v: &[u8]): Adds attribute to message
  • build(&mut self, setters: &[Box<dyn Setter>]) -> Result<(), Error>: Builds message using setters
  • parse(&self, getters: &mut [G]) -> Result<(), Error>: Extracts data from message into getters
  • get(&self, t: AttrType) -> Result<Vec<u8>, Error>: Gets attribute by type
  • contains(&self, t: AttrType) -> bool: Checks if message contains attribute

Agent

pub struct Agent { /* private fields */ }

The Agent handles STUN transactions, providing thread-safe concurrency management and timeout handling.

Key Methods:

  • new(handler: Handler) -> Self: Creates a new agent with callback handler
  • start(&mut self, id: TransactionId, deadline: Instant) -> Result<(), Error>: Registers a transaction
  • stop(&mut self, id: TransactionId) -> Result<(), Error>: Stops a transaction with ErrTransactionStopped
  • process(&mut self, message: Message) -> Result<(), Error>: Processes incoming messages
  • collect(&mut self, deadline: Instant) -> Result<(), Error>: Terminates expired transactions
  • close(&mut self) -> Result<(), Error>: Terminates all transactions and closes the agent

Client

pub struct Client { /* private fields */ }

The Client simulates a connection to a STUN server.

Key Methods:

  • send(&self, m: &Message, handler: Handler) -> Result<(), Error>: Sends a message asynchronously
  • close(&mut self) -> Result<(), Error>: Closes the client connection

XorMappedAddress

pub struct XorMappedAddress {
    pub ip: IpAddr,
    pub port: u16,
}

XorMappedAddress implements the XOR-MAPPED-ADDRESS attribute as defined in RFC 5389 Section 15.2.

Key Methods:

  • add_to_as(&self, m: &mut Message, t: AttrType) -> Result<(), Error>: Adds XOR address as specified attribute
  • get_from_as(&mut self, m: &Message, t: AttrType) -> Result<(), Error>: Extracts XOR address from message

Error Handling

pub enum Error {
    ErrAttributeNotFound,
    ErrTransactionStopped,
    ErrTransactionNotExists,
    ErrTransactionExists,
    ErrAgentClosed,
    ErrTransactionTimeOut,
    // ... many other variants
}

The Error enum provides detailed error types for STUN operations, allowing precise error handling and reporting. Common errors include attribute not found, transaction timeout, integrity mismatches, and connection issues.

Traits and Interfaces

Setter

pub trait Setter {
    fn add_to(&self, b: &mut Message) -> Result<(), Error>;
}

The Setter trait defines how objects add attributes to STUN messages.

Getter

pub trait Getter {
    fn get_from(&mut self, m: &Message) -> Result<(), Error>;
}

The Getter trait defines how objects extract attributes from STUN messages.

Checker

pub trait Checker {
    fn check(&self, m: &Message) -> Result<(), Error>;
}

The Checker trait validates STUN messages against specific requirements.

Constants

The module defines numerous constants for STUN protocol elements:

  • DEFAULT_PORT: Default STUN port (3478)
  • DEFAULT_TLS_PORT: Default STUN-over-TLS port (5349)
  • Message types: BINDING_REQUEST, BINDING_SUCCESS, etc.
  • Attribute types: ATTR_MAPPED_ADDRESS, ATTR_USERNAME, etc.
  • Error codes: CODE_BAD_REQUEST, CODE_UNAUTHORIZED, etc.

Key Attributes

MappedAddress

Represents a MAPPED-ADDRESS attribute containing an IP address and port.

TextAttributes

Implements text-based attributes like Username, Realm, Software, and Nonce.

Fingerprint

Implements the FINGERPRINT attribute for integrity checking.

MessageIntegrity

Implements the MESSAGE-INTEGRITY attribute for cryptographic authentication.

Usage Example

// Create a new STUN binding request
let mut msg = Message::new();
msg.set_type(MessageType::BINDING_REQUEST);
msg.new_transaction_id()?;

// Add attributes like USERNAME
let username = Username::new("user".to_string());
username.add_to(&mut msg)?;

// Send message via client
let client = Client::default();
client.send(&msg, my_handler).await?;

Conclusion

This STUN implementation provides a comprehensive API for STUN message handling, attribute management, and client-server communication. It follows RFC 5389 and includes support for message integrity, address handling, and robust error reporting.

TURN Module API Documentation

Overview

The TURN (Traversal Using Relays around NAT) module provides an implementation of the TURN protocol as defined in RFC 5766. It enables clients to request a server to act as a relay for their communications with peers that might be unreachable due to NAT/firewall restrictions.

Core Components

Error Handling

pub enum Error {
    // Over 70 specific error variants for various TURN operations
    ErrRelayAddressInvalid,
    ErrNoAvailableConns,
    // ... more variants
    
    // Error wrapper variants
    ParseInt(ParseIntError),
    ParseIp(AddrParseError),
    Io(IoError),
    Util(Error),
    Stun(Error),
    Other(String),
}

Description: Comprehensive error type used throughout the TURN module to handle various error conditions that may occur during TURN operations.

Client

pub struct Client { /* private fields */ }

Description: A STUN/TURN client that can communicate with a TURN server.

Key Methods:

  • pub async fn new(config: ClientConfig) -> Result<Self, Error>: Creates a new TURN client with the specified configuration.
  • pub async fn listen(&self) -> Result<(), Error>: Starts listening for incoming packets.
  • pub async fn allocate(&self) -> Result<impl Conn, Error>: Sends an Allocation request to the TURN server.
  • pub async fn close(&self) -> Result<(), Error>: Closes the client's connection.
  • pub async fn send_binding_request_to(&self, to: &str) -> Result<SocketAddr, Error>: Sends a STUN binding request to a specific address.
  • pub async fn send_binding_request(&self) -> Result<SocketAddr, Error>: Sends a STUN binding request to the STUN server.

Server

pub struct Server { /* private fields */ }

Description: An instance of a TURN server that handles client requests and manages allocations.

Key Methods:

  • pub async fn new(config: ServerConfig) -> Result<Self, Error>: Creates a new TURN server with the specified configuration.
  • pub async fn delete_allocations_by_username(&self, username: String) -> Result<(), Error>: Deletes all allocations for a specific username.
  • pub async fn get_allocations_info(&self, five_tuples: Option<Vec<FiveTuple>>) -> Result<HashMap<FiveTuple, AllocationInfo>, Error>: Retrieves information about active allocations.
  • pub async fn close(&self) -> Result<(), Error>: Shuts down the TURN server and cleans up resources.

Allocation

pub struct Allocation { /* private fields */ }

Description: Represents a TURN allocation tied to a five-tuple that relays traffic between clients and peers.

Key Methods:

  • pub fn new(...) -> Self: Creates a new allocation.
  • pub async fn has_permission(&self, addr: &SocketAddr) -> bool: Checks if a peer address has permission to communicate through this allocation.
  • pub async fn add_permission(&self, p: Permission): Adds a permission for a peer.
  • pub async fn remove_permission(&self, addr: &SocketAddr) -> bool: Removes a permission for a peer.
  • pub async fn add_channel_bind(&self, c: ChannelBind, lifetime: Duration) -> Result<(), Error>: Creates a channel binding for optimized communication.
  • pub async fn remove_channel_bind(&self, number: ChannelNumber) -> bool: Removes a channel binding.
  • pub async fn close(&self) -> Result<(), Error>: Closes the allocation and associated resources.
  • pub async fn refresh(&self, lifetime: Duration): Updates the allocation's lifetime.

Authentication

pub trait AuthHandler {
    fn auth_handle(
        &self,
        username: &str,
        realm: &str,
        src_addr: SocketAddr,
    ) -> Result<Vec<u8>, Error>;
}

Description: Interface for handling TURN authentication via the STUN long-term credential mechanism.

Implementations:

  • LongTermAuthHandler: Implements the AuthHandler trait using the long-term credential mechanism as specified in the TURN RFC.

Relay Address Generation

pub trait RelayAddressGenerator {
    fn validate(&self) -> Result<(), Error>;
    
    fn allocate_conn<'life0, 'async_trait>(
        &'life0 self,
        use_ipv4: bool,
        requested_port: u16,
    ) -> Pin<Box<dyn Future<Output = Result<(Arc<dyn Conn + Send + Sync>, SocketAddr), Error>> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait;
}

Description: Interface for generating relay addresses and connections for handling TURN allocations.

Implementations:

  • RelayAddressGeneratorNone: A no-op implementation that always fails, used for testing.
  • RelayAddressGeneratorStatic: Uses a fixed IP and allocates ports for relaying.
  • RelayAddressGeneratorRanges: Dynamically allocates addresses from configured IP ranges.

Protocol Components

FiveTuple

pub struct FiveTuple {
    // Private fields
}

Description: Represents the 5-tuple (client IP, client port, server IP, server port, transport protocol) that uniquely identifies a TURN allocation.

Permission

pub struct Permission {
    // Private fields
}

Description: Represents a permission for a peer to send data through a TURN allocation.

ChannelBind

pub struct ChannelBind {
    // Private fields
}

Description: Represents a channel binding that provides an optimized way to communicate through a TURN allocation.

Protocol Constants

// Protocol ports
pub const DEFAULT_PORT: u16 = 3478;
pub const DEFAULT_TLS_PORT: u16 = 5349;

// Protocol identifiers
pub const PROTO_UDP: u8 = 17;
pub const PROTO_TCP: u8 = 6;

// Channel number constraints
pub const MIN_CHANNEL_NUMBER: u16 = 0x4000;
pub const MAX_CHANNEL_NUMBER: u16 = 0x7FFF;

// Default allocation lifetime
pub const DEFAULT_LIFETIME: Duration = Duration::from_secs(600); // 10 minutes

Helper Functions

// Request creation
pub fn allocate_request() -> Result<Message, Error>
pub fn refresh_request(lifetime: Duration) -> Result<Message, Error>
pub fn create_permission_request(xorAddr: &XorPeerAddress) -> Result<Message, Error>
pub fn send_indication(xorAddr: &XorPeerAddress, data: &Data) -> Result<Message, Error>

// Authentication
pub fn generate_auth_key(username: &str, realm: &str, password: &str) -> Vec<u8>
pub fn generate_long_term_credentials() -> (String, String) // (username, password)

Usage Example

Setting up a basic TURN server:

async fn run_turn_server() -> Result<(), Error> {
    // Create server config
    let server_config = ServerConfig {
        realm: "example.org".to_string(),
        auth_handler: Arc::new(LongTermAuthHandler::new(
            "username".to_string(),
            "password".to_string(),
        )),
        relay_addr_generator: Box::new(RelayAddressGeneratorStatic::new(
            "127.0.0.1".parse().unwrap(),
            0,
            0,
        )),
        channel_bind_timeout: Duration::from_secs(600),
        allocation_lifetime: Duration::from_secs(600),
        // more config options...
    };

    // Create and start server
    let server = Server::new(server_config).await?;
    
    // Server runs until explicitly closed
    
    // Shut down server
    server.close().await?;
    
    Ok(())
}

Setting up a TURN client:

async fn run_turn_client() -> Result<(), Error> {
    // Create client config
    let client_config = ClientConfig {
        stun_server_addr: "turn-server.example.org:3478".to_string(),
        username: "username".to_string(),
        password: "password".to_string(),
        realm: "example.org".to_string(),
        // more config options...
    };

    // Create client
    let client = Client::new(client_config).await?;
    
    // Start listening
    client.listen().await?;
    
    // Allocate relay address
    let conn = client.allocate().await?;
    
    // Use conn to send/receive data through the TURN server
    
    // Close client
    client.close().await?;
    
    Ok(())
}

Implementation Notes

  1. The TURN module implements RFC 5766 (TURN) protocol for NAT traversal.
  2. It supports both IPv4 and IPv6.
  3. The implementation is async and built with Rust's async/await features.
  4. It provides comprehensive error handling for all protocol operations.
  5. The architecture allows for customizable components like authentication and relay address generation.
  6. Both client and server implementations are provided.

This implementation enables WebRTC applications to traverse NATs and firewalls even when direct peer-to-peer communication is impossible.

WebRTC Module

Overview

The webrtc module is the main entry point for WebRTC functionality in Rust, providing a complete implementation of the WebRTC API. It enables peer-to-peer communication of audio, video, and arbitrary data by orchestrating ICE, DTLS, SRTP, and SCTP protocols.

Core Components

API

The API struct serves as a factory for WebRTC objects, with configuration for all underlying protocols:

pub struct API { /* private fields */ }

Key Methods:

  • fn new() -> Result<Self, Error>: Creates a new API with default settings
  • fn new_with_engine(media_engine: MediaEngine, registry: Registry) -> Result<Self, Error>: Creates an API with specific media engine and interceptors
  • fn new_with_options(options: APIBuilder) -> Result<Self, Error>: Creates with customized options
  • fn new_peer_connection(config: RTCConfiguration) -> Result<Arc<RTCPeerConnection>, Error>: Creates a new peer connection
  • fn connection_state(&self) -> RTCPeerConnectionState: Returns current connection state

RTCPeerConnection

The RTCPeerConnection is the central point for managing WebRTC connections:

pub struct RTCPeerConnection { /* private fields */ }

Key Methods:

Connection Management:

  • fn create_offer(options: Option<RTCOfferOptions>) -> Result<RTCSessionDescription, Error>: Creates an SDP offer
  • fn create_answer(options: Option<RTCAnswerOptions>) -> Result<RTCSessionDescription, Error>: Creates an SDP answer
  • fn set_local_description(desc: RTCSessionDescription) -> Result<(), Error>: Sets local description
  • fn set_remote_description(desc: RTCSessionDescription) -> Result<(), Error>: Sets remote description
  • fn add_ice_candidate(candidate: RTCIceCandidateInit) -> Result<(), Error>: Adds remote ICE candidate
  • fn close() -> Result<(), Error>: Closes the peer connection

Data Channel:

  • fn create_data_channel(label: &str, options: Option<RTCDataChannelInit>) -> Result<Arc<RTCDataChannel>, Error>: Creates data channel
  • fn on_data_channel(f: OnDataChannelHdlrFn) -> (): Sets handler for incoming data channels

Media:

  • fn add_track(track: Arc<dyn TrackLocal + Send + Sync>) -> Result<Arc<RTCRtpSender>, Error>: Adds media track
  • fn add_transceiver_from_track(track: Arc<dyn TrackLocal + Send + Sync>, init: Option<RTCRtpTransceiverInit>) -> Result<Arc<RTCRtpTransceiver>, Error>: Creates transceiver from track
  • fn add_transceiver_from_kind(kind: RTPCodecType, init: Option<RTCRtpTransceiverInit>) -> Result<Arc<RTCRtpTransceiver>, Error>: Creates transceiver for media type
  • fn on_track(f: OnTrackHdlrFn) -> (): Sets handler for incoming tracks

Events:

  • fn on_ice_candidate(f: OnICECandidateHdlrFn) -> (): Sets ICE candidate handler
  • fn on_ice_connection_state_change(f: OnICEConnectionStateChangeHdlrFn) -> (): Sets ICE state change handler
  • fn on_peer_connection_state_change(f: OnPeerConnectionStateChangeHdlrFn) -> (): Sets connection state handler
  • fn on_signaling_state_change(f: OnSignalingStateChangeHdlrFn) -> (): Sets signaling state handler
  • fn on_negotiation_needed(f: OnNegotiationNeededHdlrFn) -> (): Sets negotiation needed handler

RTCDataChannel

Represents a data channel for sending arbitrary data:

pub struct RTCDataChannel { /* private fields */ }

Key Methods:

  • fn send_text(text: &str) -> Result<(), Error>: Sends text data
  • fn send(data: &Bytes) -> Result<(), Error>: Sends binary data
  • fn close() -> Result<(), Error>: Closes the data channel
  • fn on_open(f: OnOpenHdlrFn) -> (): Sets open event handler
  • fn on_close(f: OnCloseHdlrFn) -> (): Sets close event handler
  • fn on_message(f: OnMessageHdlrFn) -> (): Sets message event handler
  • fn on_error(f: OnErrorHdlrFn) -> (): Sets error event handler

Configuration Types

RTCConfiguration

Configuration for creating a peer connection:

pub struct RTCConfiguration {
    pub ice_servers: Vec<RTCIceServer>,
    pub ice_transport_policy: RTCIceTransportPolicy,
    pub bundle_policy: RTCBundlePolicy,
    pub rtcp_mux_policy: RTCRtcpMuxPolicy,
    pub peer_identity: String,
    pub certificates: Vec<Arc<dyn Certificate + Send + Sync>>,
    pub icecandidatepoolsize: u8,
    // ... other fields
}

RTCIceServer

Defines STUN/TURN servers for connectivity:

pub struct RTCIceServer {
    pub urls: Vec<String>,
    pub username: String,
    pub credential: String,
    pub credential_type: RTCIceCredentialType,
}

Session Description Types

RTCSessionDescription

Represents an SDP session description:

pub struct RTCSessionDescription {
    pub sdp_type: RTCSdpType,
    pub sdp: String,
}

RTCSdpType

Type of SDP in session negotiation:

pub enum RTCSdpType {
    Unspecified,
    Offer,      // Initiating offer
    Pranswer,   // Provisional answer
    Answer,     // Final answer
    Rollback,   // Rollback to previous state
}

State Enumerations

RTCPeerConnectionState

Overall connection state:

pub enum RTCPeerConnectionState {
    Unspecified,
    New,
    Connecting,
    Connected,
    Disconnected,
    Failed,
    Closed,
}

RTCSignalingState

Signaling process state:

pub enum RTCSignalingState {
    Unspecified,
    Stable,
    HaveLocalOffer,
    HaveRemoteOffer,
    HaveLocalPranswer,
    HaveRemotePranswer,
    Closed,
}

RTCICEConnectionState

ICE connectivity state:

pub enum RTCICEConnectionState {
    Unspecified,
    New,
    Checking,
    Connected,
    Completed,
    Failed,
    Disconnected,
    Closed,
}

Usage Example

async fn webrtc_example() -> Result<(), Error> {
    // Create API
    let api = API::new()?;
    
    // Configure and create peer connection
    let config = RTCConfiguration {
        ice_servers: vec![
            RTCIceServer {
                urls: vec!["stun:stun.l.google.com:19302".to_string()],
                ..Default::default()
            },
        ],
        ..Default::default()
    };
    let peer_connection = api.new_peer_connection(config).await?;
    
    // Create data channel
    let dc = peer_connection.create_data_channel(
        "my-data-channel",
        Some(RTCDataChannelInit::default())
    ).await?;
    
    // Set up handlers
    dc.on_open(Box::new(|| {
        println!("Data channel opened");
        Box::pin(async {})
    }));
    
    dc.on_message(Box::new(|msg| {
        println!("Message received: {:?}", msg);
        Box::pin(async {})
    }));
    
    // Handle ICE candidates
    peer_connection.on_ice_candidate(Box::new(|candidate| {
        if let Some(c) = candidate {
            println!("New ICE candidate: {}", c.to_json().unwrap());
            // Send to remote peer via signaling
        }
        Box::pin(async {})
    }));
    
    // Create offer
    let offer = peer_connection.create_offer(None).await?;
    peer_connection.set_local_description(offer.clone()).await?;
    
    // Send offer to remote peer via signaling
    // ...
    
    // When answer is received from remote
    // peer_connection.set_remote_description(answer).await?;
    
    Ok(())
}

Implementation Notes

  1. The WebRTC implementation follows the W3C and IETF specifications
  2. It provides a complete stack from ICE and DTLS to SRTP and SCTP
  3. The design uses Rust's async/await for efficient I/O operations
  4. The API is similar to browser WebRTC APIs but adapted to Rust idioms
  5. The implementation supports both reliable and unreliable data transport
  6. Media handling includes audio and video with various codecs
  7. RTP header extensions and RTCP feedback mechanisms are supported
  8. The peer connection can be used with custom signaling solutions

webrtc_data Module

Overview

The webrtc_data module implements the WebRTC Data Channel functionality, providing APIs for sending and receiving arbitrary data between peers. It operates on top of the SCTP transport protocol, enabling peer-to-peer data exchange with configurable reliability modes.

Key Components

DataChannel

The DataChannel struct is the central component, representing a single data channel within an SCTP association:

pub struct DataChannel {
    // Private fields
}

Key Methods

Constructor Methods:

// Creates a new data channel
pub fn new(stream: Arc<Stream>, config: Config) -> Self

// Opens a data channel with the specified configuration
pub async fn dial(
    association: &Arc<Association>,
    identifier: u16,
    config: Config,
) -> Result<Self, Error>

// Accepts an incoming data channel
pub async fn accept<T>(
    association: &Arc<Association>,
    config: Config,
    existing_channels: &[T],
) -> Result<Self, Error>
where
    T: Borrow<Self>

// Creates a client-side data channel
pub async fn client(stream: Arc<Stream>, config: Config) -> Result<Self, Error>

// Creates a server-side data channel
pub async fn server(stream: Arc<Stream>, config: Config) -> Result<Self, Error>

Send/Receive Methods:

// Reads raw data from the channel
pub async fn read(&self, buf: &mut [u8]) -> Result<usize, Error>

// Reads data with channel metadata
pub async fn read_data_channel(
    &self,
    buf: &mut [u8],
) -> Result<(usize, bool), Error>

// Writes data to the channel
pub async fn write(&self, data: &Bytes) -> Result<usize, Error>

// Writes data with channel metadata
pub async fn write_data_channel(
    &self,
    data: &Bytes,
    is_string: bool,
) -> Result<usize, Error>

// Sends formatted message (text or binary)
pub async fn send(&self, data: &Bytes) -> Result<(), Error>

Event Handlers:

// Sets the callback for when the channel opens
pub async fn on_open(&self, f: OnOpenHdlrFn) -> Result<(), Error>
// where OnOpenHdlrFn = Box<dyn FnOnce() -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> + Send + Sync>

// Sets the callback for when messages arrive
pub async fn on_message(&self, f: OnMessageHdlrFn) -> Result<(), Error>
// where OnMessageHdlrFn = Box<dyn FnMut(Message) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> + Send + Sync>

// Sets the callback for when the channel closes
pub async fn on_close(&self, f: OnCloseHdlrFn) -> Result<(), Error>
// where OnCloseHdlrFn = Box<dyn FnOnce() -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> + Send + Sync>

// Sets the callback for errors
pub async fn on_error(&self, f: OnErrorHdlrFn) -> Result<(), Error>
// where OnErrorHdlrFn = Box<dyn FnMut(Error) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> + Send + Sync>

Buffer Management:

// Returns current size of the outgoing buffer
pub fn buffered_amount(&self) -> usize

// Returns the threshold for the buffered amount low event
pub fn buffered_amount_low_threshold(&self) -> usize

// Sets the threshold for buffer drain notification
pub fn set_buffered_amount_low_threshold(&self, threshold: usize)

// Sets handler for buffer drain events
pub fn on_buffered_amount_low(&self, f: OnBufferedAmountLowFn)
// where OnBufferedAmountLowFn = Box<dyn FnMut() -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> + Send + Sync>

Lifecycle Methods:

// Closes the data channel
pub async fn close(&self) -> Result<(), Error>

Stats and Metrics:

// Returns the number of messages sent
pub fn messages_sent(&self) -> usize

// Returns the number of messages received
pub fn messages_received(&self) -> usize

// Returns the number of bytes sent
pub fn bytes_sent(&self) -> usize

// Returns the number of bytes received
pub fn bytes_received(&self) -> usize

// Returns the stream identifier
pub fn stream_identifier(&self) -> u16

Config

The Config struct defines the properties and behavior of a data channel:

pub struct Config {
    pub label: String,
    pub ordered: bool,
    pub max_packet_life_time: Option<u16>,
    pub max_retransmits: Option<u16>,
    pub protocol: String,
    pub negotiated: bool,
    pub id: Option<u16>,
    pub priority: Option<u16>,
}

Key fields:

  • label: Identifies the channel for applications
  • ordered: If true, messages are delivered in order (reliable)
  • max_packet_life_time: Maximum time to attempt retransmission
  • max_retransmits: Maximum number of retransmission attempts
  • negotiated: If true, channel ID is negotiated out-of-band
  • id: Channel ID when negotiated out-of-band

Message

The Message enum represents data exchanged over data channels:

// The DataChannelMessage enum (from webrtc crate)
pub enum DataChannelMessage {
    Binary(Bytes),
    Text(String),
}

// The internal Message enum (from webrtc_data crate)
pub enum Message {
    DataChannelAck(DataChannelAck),
    DataChannelOpen(DataChannelOpen),
}

The DataChannelMessage enum represents application data:

  • Binary: Raw binary data
  • Text: UTF-8 text data

The internal Message enum represents protocol-level messages:

  • DataChannelAck: Acknowledgment message for channel establishment
  • DataChannelOpen: Channel establishment message

PollDataChannel

A non-async variant of DataChannel that works with synchronous code:

pub struct PollDataChannel {
    // Private fields
}

Key Methods:

// Creates a new polling data channel from an async data channel
pub fn new(data_channel: DataChannel) -> Self

// Detects if messages might be available
pub fn poll_read(&self) -> bool

// Reads a message from the channel (non-blocking)
pub fn read(&self) -> Option<Result<DataChannelMessage, Error>>

// Writes a message to the channel
pub fn write(&self, msg: DataChannelMessage) -> Result<(), Error>

// Gets the label of the data channel
pub fn label(&self) -> String

// Gets the ordered flag of the data channel
pub fn ordered(&self) -> bool

// Gets the max_packet_life_time setting
pub fn max_packet_life_time(&self) -> Option<u16>

// Gets the max_retransmits setting
pub fn max_retransmits(&self) -> Option<u16>

// Gets the protocol of the data channel
pub fn protocol(&self) -> String

// Gets the negotiated flag
pub fn negotiated(&self) -> bool

// Gets the ID of the data channel
pub fn id(&self) -> Option<u16>

// Checks if the channel is ready to use
pub fn ready(&self) -> bool

// Closes the data channel
pub fn close(&self) -> Result<(), Error>

Offers polling-based API for environments where async/await is not available. This is useful for integration with synchronous frameworks or legacy code that can't use Rust's async/await features.

Error Handling

#[non_exhaustive]
pub enum Error {
    UnexpectedEndOfBuffer {
        expected: usize,
        actual: usize,
    },
    InvalidMessageType(u8),
    InvalidChannelType(u8),
    InvalidPayloadProtocolIdentifier(u8),
    ErrStreamClosed,
    Util(webrtc_util::error::Error),
    Sctp(Error),
    Utf8(FromUtf8Error),
    new(String),
}

This enum provides comprehensive error handling for all data channel operations. The #[non_exhaustive] attribute indicates that additional error variants may be added in future library versions, so code matching on this enum should include a wildcard arm.

Usage Example

Establishing a Data Channel

// Creating a data channel
let config = Config {
    label: "chat".to_string(),
    ordered: true,
    max_retransmits: Some(3),
    ..Default::default()
};

let dc = DataChannel::new(config).await?;

// Set handlers
dc.on_open(Box::new(|| {
    println!("Data channel open");
    Box::pin(async {}) // Return a future that resolves immediately
})).await?;

dc.on_message(Box::new(|msg| {
    match msg {
        Message::Text(text) => println!("Received text: {}", text),
        Message::Binary(data) => println!("Received binary: {} bytes", data.len()),
    }
    Box::pin(async {}) // Return a future that resolves immediately
})).await?;

// Sending data
dc.send(&Bytes::from("Hello WebRTC!")).await?;

// Close when done
dc.close().await?;

Accepting a Data Channel

// Accept incoming data channel from an SCTP stream
let dc = DataChannel::accept(sctp_stream).await?;

// Set up handlers and use as above

Reliability Modes

  1. Reliable, Ordered: Default WebRTC behavior (TCP-like)

    let config = Config {
        ordered: true,
        max_packet_life_time: None,
        max_retransmits: None,
        ..Default::default()
    };
  2. Reliable, Unordered: All data arrives but order may change

    let config = Config {
        ordered: false,
        max_packet_life_time: None,
        max_retransmits: None,
        ..Default::default()
    };
  3. Partially Reliable (Timed): May drop packets after time limit

    let config = Config {
        ordered: true, // or false
        max_packet_life_time: Some(100), // milliseconds
        max_retransmits: None,
        ..Default::default()
    };
  4. Partially Reliable (Limited retransmissions): May drop after retries

    let config = Config {
        ordered: true, // or false
        max_packet_life_time: None,
        max_retransmits: Some(3),
        ..Default::default()
    };

These different modes allow applications to balance reliability against latency based on their specific needs.

webrtc_dtls Module

Overview

The webrtc_dtls module implements Datagram Transport Layer Security (DTLS) for WebRTC, enabling secure communication over unreliable transports like UDP. It provides encryption, authentication, and integrity for data exchanged in WebRTC connections.

Key Components

Config

The Config struct configures DTLS connections with options for security and performance:

pub struct Config {
    pub certificates: Vec<Certificate>,
    pub cipher_suites: Vec<CipherSuiteId>,
    pub signature_schemes: Vec<SignatureScheme>,
    pub srtp_protection_profiles: Vec<SrtpProtectionProfile>,
    pub client_auth: ClientAuthType,
    pub extended_master_secret: ExtendedMasterSecretType,
    pub flight_interval: Duration,
    pub psk: Option<PskCallback>, // where PskCallback = Arc<dyn (Fn(&[u8]) -> Result<Vec<u8>>) + Send + Sync>
    pub psk_identity_hint: Option<Vec<u8>>,
    pub insecure_skip_verify: bool,
    pub insecure_hashes: bool,
    pub insecure_verification: bool,
    pub verify_peer_certificate: Option<VerifyPeerCertificateFn>,
    pub roots_cas: rustls::RootCertStore,
    pub client_cas: rustls::RootCertStore,
    pub server_name: String,
    pub mtu: usize,
    pub replay_protection_window: usize,
}

Key fields:

  • certificates: Certificates for authentication
  • cipher_suites: Supported encryption algorithms
  • client_auth: Controls client certificate authentication
  • extended_master_secret: Enhances security against man-in-the-middle attacks
  • insecure_skip_verify: Option to bypass certificate verification (for testing only)

DTLSConn

The DTLSConn struct represents a DTLS connection that wraps an underlying network connection:

pub struct DTLSConn { /* private fields */ }

Key methods:

// Creates a new DTLS connection
pub async fn new(
    conn: Arc<dyn Conn + Send + Sync>,
    config: Config,
    is_client: bool,
    initial_state: Option<State>,
) -> Result<Self, Error>

// Reads data from the encrypted connection
pub async fn read(
    &self,
    p: &mut [u8],
    duration: Option<Duration>,
) -> Result<usize, Error>

// Writes data to the encrypted connection
pub async fn write(
    &self,
    p: &[u8],
    duration: Option<Duration>,
) -> Result<usize, Error>

// Gracefully terminates the connection
pub async fn close(&self) -> Result<(), Error>

// Returns state information
pub async fn connection_state(&self) -> State

// Returns the selected SRTP protection profile
pub fn selected_srtpprotection_profile(&self) -> SrtpProtectionProfile

Implements KeyingMaterialExporter trait:

// Exports cryptographic material for use with other protocols (e.g., SRTP)
pub trait KeyingMaterialExporter {
    fn export_keying_material<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        label: &'life1 str,
        context: &'life2 [u8],
        length: usize,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyingMaterialExporterError>> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait,
        'life1: 'async_trait,
        'life2: 'async_trait;
}

Handshaker

The DTLS handshaker manages the DTLS handshake process, negotiating security parameters between peers.

Key functions:

  • handshake(ctx, cfg, conn, is_client): Performs the DTLS handshake
  • gen_self_signed_root_cert(name): Generates a self-signed certificate for testing

State

The State struct tracks the state of a DTLS connection:

pub struct State {
    // Session details
    pub local_epoch: u16,
    pub remote_epoch: u16,
    pub cipher_suite: Option<Box<dyn CipherSuite + Send + Sync>>,
    pub is_client: bool,
    pub peer_certificates: Vec<Vec<u8>>,
    pub identity_hint: Vec<u8>,
    // ... other private fields
}

The State struct implements the KeyingMaterialExporter trait to export keys for other protocols like SRTP.

CipherSuite

The CipherSuite trait defines encryption algorithms used in DTLS:

pub trait CipherSuite: Debug {
    fn id(&self) -> CipherSuiteId;
    fn certificate_type(&self) -> ClientCertificateType;
    fn hash_func(&self) -> CipherSuiteHash;
    fn is_psk(&self) -> bool;
    fn is_initialized(&self) -> bool;
    
    // Encryption/decryption methods
    fn encrypt(&self, pkt_rlh: &RecordLayerHeader, raw: &[u8]) -> Result<Vec<u8>, Error>;
    fn decrypt(&self, record_layer_header: &RecordLayerHeader, raw: &[u8]) -> Result<Vec<u8>, Error>;
    
    // Key generation methods
    fn init(
        &mut self,
        master_secret: &[u8],
        client_random: &[u8],
        server_random: &[u8],
        is_client: bool,
    ) -> Result<(), Error>;
}

Supported cipher suites include:

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_PSK_WITH_AES_128_CCM
  • And others

Core Types

KeyingMaterialExporterError

Error type for key material export operations:

#[non_exhaustive]
pub enum KeyingMaterialExporterError {
    HandshakeInProgress,
    ContextUnsupported,
    ReservedExportKeyingMaterial,
    CipherSuiteUnset,
    Io(IoError),
    Hash(String),
}

ClientAuthType

Controls how the server handles client certificates:

pub enum ClientAuthType {
    NoClientCert,              // No client certificate is requested
    RequestClientCert,         // Client certificate is requested but optional
    RequireAnyClientCert,      // Client must provide a certificate
    VerifyClientCertIfGiven,   // Verify client certificate if provided
    RequireAndVerifyClientCert // Client must provide a valid certificate
}

ExtendedMasterSecretType

Controls the "Extended Master Secret" extension (RFC 7627):

pub enum ExtendedMasterSecretType {
    Request,  // Request but don't require
    Require,  // Require extension
    Disable   // Disable extension
}

DTLSListener

The DTLSListener accepts incoming DTLS connections:

pub struct DTLSListener { /* private fields */ }

Key functions:

// Creates a new DTLS listener
pub fn listen(
    network: &str, 
    addr: &str, 
    config: Config,
) -> Result<Self, Error>

// Accepts incoming DTLS connections
pub async fn accept(&self) -> Result<(DTLSConn, SocketAddr), Error>

// Closes the listener
pub async fn close(&self) -> Result<(), Error>

Usage Example

// Create a configuration
let mut config = Config::default();

// Generate or load certificates
let cert = gen_self_signed_root_cert("example.com")?;
config.certificates = vec![cert];

// Client mode
let conn = UdpSocket::bind("0.0.0.0:0")?;
conn.connect("example.com:443")?;
let dtls_conn = DTLSConn::new(
    Arc::new(conn),
    config,
    true, // is_client
    None  // initial_state
).await?;

// Use the connection
dtls_conn.write(b"hello", None).await?;
let mut buf = [0u8; 1024];
let n = dtls_conn.read(&mut buf, None).await?;
println!("Read: {}", std::str::from_utf8(&buf[..n])?);  

// Export keying material for SRTP
let key_material = dtls_conn.export_keying_material(
    "EXTRACTOR-dtls_srtp",  // label
    &[],                    // context
    key_length               // length
)?;

// Close the connection
dtls_conn.close().await?;

Security Features

  1. Authentication via certificates or pre-shared keys
  2. Confidentiality through strong encryption algorithms
  3. Integrity ensuring data cannot be tampered with
  4. Forward secrecy with ECDHE key exchange
  5. Key export for securing other protocols like SRTP

The module provides a complete implementation of DTLS 1.2 suitable for WebRTC applications, with a focus on security and interoperability with other WebRTC implementations.

WebRTC ICE Module API Summary

This document provides a concise technical summary of the webrtc_ice module, which implements the Interactive Connectivity Establishment (ICE) protocol for WebRTC.

Core Components

Agent

The Agent struct is central to the ICE implementation, handling candidate gathering, connectivity checks, and connection maintenance.

struct Agent { /* private fields */ }

Key Methods

  • Creation

    • async fn new(config: AgentConfig) -> Result<Self, Error>: Creates a new ICE agent with specified configuration
  • Connection Establishment

    • async fn dial(cancel_rx: Receiver<()>, remote_ufrag: String, remote_pwd: String) -> Result<Arc<impl Conn>, Error>: Initiates connection as controlling agent
    • async fn accept(cancel_rx: Receiver<()>, remote_ufrag: String, remote_pwd: String) -> Result<Arc<impl Conn>, Error>: Accepts connection as controlled agent
    • fn gather_candidates() -> Result<(), Error>: Initiates the trickle-based gathering process for ICE candidates
    • fn add_remote_candidate(c: &Arc<dyn Candidate + Send + Sync>) -> Result<(), Error>: Adds a remote candidate for connection establishment
  • State Management

    • fn on_connection_state_change(f: OnConnectionStateChangeHdlrFn): Sets a handler for connection state changes
    • fn on_candidate(f: OnCandidateHdlrFn): Sets a handler for newly gathered candidates
    • fn on_selected_candidate_pair_change(f: OnSelectedCandidatePairChangeHdlrFn): Sets a handler for when the final candidate pair is selected
    • async fn restart(ufrag: String, pwd: String) -> Result<(), Error>: Restarts the ICE agent with new credentials
  • Queries

    • async fn get_local_candidates() -> Result<Vec<Arc<dyn Candidate + Send + Sync>>, Error>: Returns local candidates
    • fn get_selected_candidate_pair() -> Option<Arc<CandidatePair>>: Returns the selected candidate pair if one exists
    • async fn get_local_user_credentials() -> (String, String): Returns the local ufrag/pwd
    • async fn get_remote_user_credentials() -> (String, String): Returns the remote ufrag/pwd
    • fn get_bytes_sent() -> usize: Returns bytes sent
    • fn get_bytes_received() -> usize: Returns bytes received
  • Statistics

    • async fn get_candidate_pairs_stats() -> Vec<CandidatePairStats>: Returns stats about candidate pairs
    • async fn get_local_candidates_stats() -> Vec<CandidateStats>: Returns stats about local candidates
    • async fn get_remote_candidates_stats() -> Vec<CandidateStats>: Returns stats about remote candidates
  • Cleanup

    • async fn close() -> Result<(), Error>: Cleans up and shuts down the agent

Candidate

The Candidate trait represents an ICE candidate, providing methods to handle network addresses for connection establishment.

trait Candidate: Display {
    fn foundation(&self) -> String;
    fn id(&self) -> String;
    fn component(&self) -> u16;
    fn set_component(&self, c: u16);
    fn last_received(&self) -> SystemTime;
    fn last_sent(&self) -> SystemTime;
    fn network_type(&self) -> NetworkType;
    fn address(&self) -> String;
    fn port(&self) -> u16;
    fn priority(&self) -> u32;
    fn related_address(&self) -> Option<CandidateRelatedAddress>;
    fn candidate_type(&self) -> CandidateType;
    fn tcp_type(&self) -> TcpType;
    fn marshal(&self) -> String;
    fn addr(&self) -> SocketAddr;
    fn close(&self) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + '_>>;
    fn seen(&self, outbound: bool);
    fn write_to(&self, raw: &[u8], dst: &(dyn Candidate + Send + Sync)) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + '_>>;
    fn equal(&self, other: &dyn Candidate) -> bool;
    fn set_ip(&self, ip: &IpAddr) -> Result<(), Error>;
    fn get_conn(&self) -> Option<&Arc<dyn Conn + Send + Sync>>;
    fn get_closed_ch(&self) -> Arc<Mutex<Option<Sender<()>>>>;
}

CandidateType

CandidateType enumerates possible types of candidates in the ICE protocol.

enum CandidateType {
    Host,           // Local candidate
    ServerReflexive, // Candidate from STUN server
    PeerReflexive,   // Candidate from remote peer
    Relay,          // Candidate from TURN server
    Unspecified,
}

ConnectionState

ConnectionState represents the current state of an ICE connection.

enum ConnectionState {
    Unspecified,
    New,            // ICE agent is gathering addresses
    Checking,       // Agent has been given candidates and is attempting to find a match
    Connected,      // Agent has a pairing but is still checking other pairs
    Completed,      // Agent has finished
    Failed,         // Agent never could successfully connect
    Disconnected,   // Agent connected but has entered a failed state
    Closed,         // Agent has finished and is no longer handling requests
}

GatheringState

GatheringState indicates the current state of candidate gathering.

enum GatheringState {
    Unspecified,
    New,            // No gathering activity performed yet
    Gathering,      // Gathering is in progress
    Complete,       // Gathering has been completed
}

UDPMux

The UDP multiplexer interfaces for allowing multiple connections via a single UDP socket.

trait UDPMux {
    fn close(&self) -> Result<(), Error>;
    fn get_conn(&self, params: &UDPMuxConnParams) -> Result<Arc<dyn UDPMuxWriter + Send + Sync>, Error>;
    fn remove_conn(&self, conn: &Arc<dyn UDPMuxWriter + Send + Sync>) -> Result<(), Error>;
    fn addr(&self) -> SocketAddr;
}

trait UDPMuxWriter {
    fn write_to(&self, buf: &[u8], target: &SocketAddr) -> Result<usize, Error>;
    fn local_addr(&self) -> Result<SocketAddr, Error>;
    fn set_callback(&self, func: Box<dyn FnMut(&[u8], SocketAddr) + Send + Sync>) -> Result<(), Error>;
}

Key Types and Configurations

AgentConfig

Configuration options for creating an ICE Agent.

struct AgentConfig {
    pub urls: Vec<Url>,                  // STUN/TURN server URLs
    pub network_types: Vec<NetworkType>, // Allowed network types
    pub udp_network: Arc<dyn UDPNetwork>, // Network implementation
    pub disconnected_timeout: Duration,  // Time until Disconnected
    pub failed_timeout: Duration,        // Time until Failed
    pub keepalive_interval: Duration,    // Interval for keepalive packets
    pub check_interval: Duration,        // Interval between connectivity checks
    pub max_binding_requests: u16,       // Max number of binding requests
    pub candidate_types: Vec<CandidateType>, // Allowed candidate types
    pub role: Role,                      // Controlling or controlled role
    pub trickle: bool,                   // Enable candidate trickling
    pub lite: bool,                      // Enable ICE-Lite mode
    pub udp_mux: Option<Arc<dyn UDPMux + Send + Sync>>, // Custom UDP multiplexer
    pub interface_filter: Option<InterfaceFilterFn>, // Filter for network interfaces
    pub ip_filter: Option<IpFilterFn>,   // Filter for IP addresses
    pub nat_1to1_ips: Vec<String>,       // 1:1 NAT IP mappings
    pub nat_1to1_ip_candidate_type: CandidateType, // Candidate type for NAT 1:1
    pub mdns_mode: MulticastDnsMode,     // mDNS discovery mode
    pub accepting_min_wait: Duration,    // Min wait before connecting when accepting
    pub accepting_max_wait: Duration,    // Max wait before connecting when accepting
}

NetworkType

Different types of networks that ICE can use for connectivity.

enum NetworkType {
    Unspecified,
    Udp4,    // IPv4 UDP
    Udp6,    // IPv6 UDP
    Tcp4,    // IPv4 TCP
    Tcp6,    // IPv6 TCP
    Unixgram, // Unix datagram socket
}

Role

Defines the role of the ICE agent in the connection.

enum Role {
    Unspecified,
    Controlling, // Agent controls negotiation
    Controlled,  // Agent is controlled in negotiation
}

MulticastDnsMode

Options for mDNS candidate discovery.

enum MulticastDnsMode {
    Unspecified,
    QueryOnly,    // Only query mDNS
    QueryAndGather, // Query and gather mDNS candidates
    Disabled,     // Disable mDNS
}

Major Sub-modules

  • candidate: Implements various candidate types (host, server reflexive, peer reflexive, relay)
  • control: Handles control attributes and role conflict resolution
  • external_ip_mapper: Maps internal to external IP addresses
  • mdns: Multicast DNS implementation for local candidate discovery
  • network_type: Network type handling and filtering
  • priority: Candidate priority calculation
  • rand: Random generation of ICE attributes and IDs
  • state: Connection and gathering state enumerations
  • stats: Statistics collection and reporting
  • tcp_type: TCP specific candidate types
  • udp_mux: UDP multiplexer implementation
  • url: STUN/TURN URL handling
  • util: ICE utility functions

Error Handling

The module uses a uniform error type webrtc_ice::Error with variants for different failure scenarios:

enum Error {
    // Various error types
    ErrUnknownType,
    ErrSchemeType,
    ErrSTUNQuery,
    ErrInvalidICECredentials,
    ErrNoMatchingCandidatePair,
    ErrClosed,
    ErrTimeout,
    // ... (other errors)
}

Example Usage

Basic usage pattern:

// Create a configuration
let config = AgentConfig {
    urls: vec![Url::parse("stun:stun.l.google.com:19302").unwrap()],
    network_types: supported_network_types(),
    ..Default::default()
};

// Create the agent
let agent = Agent::new(config).await?;

// Set up callbacks
agent.on_candidate(Box::new(|candidate| {
    if let Some(c) = candidate {
        println!("Gathered candidate: {}", c.marshal());
    }
}));

agent.on_connection_state_change(Box::new(|state| {
    println!("Connection state changed: {}", state);
}));

// Gather candidates
agent.gather_candidates()?;

// Get local credentials for signaling
let (local_ufrag, local_pwd) = agent.get_local_user_credentials().await;

// Exchange credentials with remote peer via signaling
// ...

// Set remote credentials
agent.set_remote_credentials(remote_ufrag, remote_pwd).await?;

// For controlling side (initiator)
let conn = agent.dial(cancel_rx, remote_ufrag, remote_pwd).await?;

// For controlled side (answerer)
let conn = agent.accept(cancel_rx, remote_ufrag, remote_pwd).await?;

// Use the connection
conn.write(data).await?;

Implementation Notes

  1. The ICE agent supports both standard ICE and ICE-Lite modes
  2. Candidates can be gathered via trickle ICE (incremental) or all at once
  3. The agent handles NAT traversal using STUN and TURN servers
  4. IPv4, IPv6, UDP, and TCP transports are supported
  5. Multiplexing for sharing a single network port is supported
  6. The agent implements ICE restarts for connection recovery
  7. Statistics collection provides insights into connection quality

WebRTC mDNS Module (webrtc_mdns)

The webrtc_mdns module provides an implementation of Multicast DNS (mDNS) for WebRTC applications, primarily used for local network service discovery and hostname resolution.

Overview

Multicast DNS (mDNS) is a zero-configuration networking protocol that allows devices on a local network to discover and communicate with each other without relying on a centralized DNS server. In WebRTC contexts, mDNS is particularly useful for ICE candidates gathering, where it helps preserve privacy by replacing local IP addresses with randomly generated mDNS hostnames.

Core Components

Configuration (config module)

The Config struct provides configuration options for mDNS:

pub struct Config {
    pub query_interval: Duration,
    pub local_names: Vec<String>,
}
  • query_interval: Defines how frequently to repeat queries
  • local_names: List of local mDNS names to respond to

The Config struct implements Default for easy initialization.

Connection (conn module)

The DnsConn struct provides the core functionality for maintaining an mDNS server and performing queries:

pub struct DnsConn { /* private fields */ }

Key methods:

  • server(addr: SocketAddr, config: Config) -> Result<Self, Error>: Establishes an mDNS server on the specified socket address with the given configuration.
  • close(&self) -> Result<(), Error>: Closes the mDNS connection.
  • query(&self, name: &str, close_query_signal: Receiver<()>) -> Result<(ResourceHeader, SocketAddr), Error>: Performs mDNS queries for a specified name until either receiving a result or a close signal.

Messages (message module)

The Message struct represents an mDNS message with fields for various DNS components:

pub struct Message {
    pub header: Header,
    pub questions: Vec<Question>,
    pub answers: Vec<Resource>,
    pub authorities: Vec<Resource>,
    pub additionals: Vec<Resource>,
}

Methods for encoding and decoding messages:

  • unpack(&mut self, msg: &[u8]) -> Result<(), Error>: Parses a raw byte message into the structured Message format.
  • pack(&mut self) -> Result<Vec<u8>, Error>: Serializes a Message into a byte vector.
  • append_pack(&mut self, b: Vec<u8>) -> Result<Vec<u8>, Error>: Extends an existing packed message.

Message Components

  • Header: Contains metadata about the message (ID, flags, counts)
  • Question: Represents a DNS query with name, type, and class
  • Resource: Represents DNS resource records like A, AAAA, PTR, etc.

DNS Resource Types

The module supports various DNS resource types:

  • A (IPv4 address records)
  • AAAA (IPv6 address records)
  • CNAME (Canonical name records)
  • MX (Mail exchange records)
  • NS (Name server records)
  • OPT (Option records)
  • PTR (Pointer records)
  • SOA (Start of authority records)
  • SRV (Service records)
  • TXT (Text records)

Error Handling

The module uses a unified Error enum that includes variants for various mDNS-specific issues:

pub enum Error {
    ErrJoiningMulticastGroup,
    ErrConnectionClosed,
    ErrContextElapsed,
    // ... and many other variants
}

Error variants cover various failure modes, including:

  • Network-related errors (joining multicast groups, connection issues)
  • DNS message parsing and formatting errors
  • Resource limit exceedances
  • Configuration issues

Usage Pattern

A typical usage pattern involves:

  1. Creating a configuration with appropriate settings
  2. Establishing an mDNS server on a UDP socket
  3. Performing queries as needed
  4. Closing the connection when done
// Example usage (conceptual)
let config = Config::default();
let conn = DnsConn::server(socket_addr, config)?;

// Create a channel for cancellation
let (tx, rx) = tokio::sync::mpsc::channel(1);

// Query for a hostname
let (resource, addr) = conn.query("example.local", rx).await?;

// Process results...

// Close when done
conn.close().await?;

Integration with WebRTC

In WebRTC applications, mDNS is typically used within the ICE (Interactive Connectivity Establishment) framework to:

  1. Replace local IP addresses with random mDNS hostnames in ICE candidates
  2. Resolve mDNS hostnames to IP addresses when receiving candidates
  3. Enhance privacy by preventing exposure of private network information

This functionality is most relevant when gathering and processing ICE candidates during the connection establishment phase of WebRTC peer connections.

Thread Safety

The DnsConn struct implements Send and Sync, making it safe to share across threads, while the Message struct does not implement these traits and should be handled within a single thread.

Limitations

  • The implementation primarily focuses on local network usage
  • Some resource types might have limited support
  • Error handling is comprehensive but might require application-specific strategies

WebRTC Media Module

The webrtc_media module provides foundational structures and utilities for handling multimedia data in WebRTC applications. It focuses on media sample processing, audio/video format handling, and media I/O operations.

Core Components

Media Sample

At the heart of this module is the Sample struct, which contains encoded media and timing information:

pub struct Sample {
    pub data: Bytes,                     // The actual media bitstream data (not packetized format)
    pub timestamp: SystemTime,           // Wall clock time when the sample was generated
    pub duration: Duration,              // Duration of the sample
    pub packet_timestamp: u32,           // RTP packet timestamp for the sample
    pub prev_dropped_packets: u16,       // Count of packets dropped before building this sample
    pub prev_padding_packets: u16,       // Count of padding packets detected before building this sample
}

The Sample struct implements several traits including Clone, Debug, and others to facilitate media handling operations.

Module Structure

The webrtc_media module consists of three main sub-modules:

  1. audio: Audio-specific functionality
  2. io: Media I/O operations
  3. video: Video-specific functionality

Audio Module

The audio module provides structures for handling audio data:

Audio Sample

The audio::Sample struct serves as a specialized sample structure for audio media:

pub struct Sample<Raw> {
    // Private fields
}

// Implements conversions between different audio formats
impl From<i16> for Sample<i16> { /* ... */ }
impl From<f32> for Sample<f32> { /* ... */ }
impl From<Sample<i16>> for i16 { /* ... */ }
impl From<Sample<f32>> for f32 { /* ... */ }
impl From<Sample<i16>> for Sample<f32> { /* ... */ }
impl From<Sample<f32>> for Sample<i16> { /* ... */ }

// Standard traits
impl<Raw> Copy for Sample<Raw> where Raw: Copy { /* ... */ }
impl<Raw> Clone for Sample<Raw> where Raw: Clone { /* ... */ }
impl<Raw> Debug for Sample<Raw> where Raw: Debug { /* ... */ }
impl<Raw> Default for Sample<Raw> where Raw: Default { /* ... */ }
impl<Raw> PartialEq for Sample<Raw> where Raw: PartialEq { /* ... */ }
impl<Raw> Eq for Sample<Raw> where Raw: Eq { /* ... */ }

Audio Buffer

The audio::buffer::Buffer provides functionality for multi-channel audio handling:

// Generic over both sample type (T) and layout (L)
pub struct Buffer<T, L> {
    // Private fields
}

// Two primary layouts
pub struct Interleaved;
pub struct Deinterleaved;

// Layout conversion traits
impl<T: Copy> From<Buffer<T, Interleaved>> for Buffer<T, Deinterleaved> { /* ... */ }
impl<T: Copy> From<Buffer<T, Deinterleaved>> for Buffer<T, Interleaved> { /* ... */ }

// Byte manipulation trait
pub trait FromBytes<T, L, E: ByteOrder> {
    fn from_bytes(bytes: &[u8], channels: usize) -> Result<Self, Error> where Self: Sized;
}

Features:

  • Buffer format conversions (interleaved ↔ deinterleaved)
  • Byte-level manipulation with FromBytes trait
  • Buffer reference handling with BufferRef

I/O Module

The I/O module provides tools for reading and writing media streams in various formats:

Writer Trait

The Writer trait defines a common interface for media writers:

pub trait Writer {
    fn write_rtp(&mut self, pkt: &Packet) -> Result<(), Error>;
    fn close(&mut self) -> Result<(), Error>;
}

The trait is implemented by various media format writers, allowing for a unified interface across different container formats.

Media Format Handlers

Multiple format-specific readers and writers:

H.264

// Reader for H.264 format
pub struct H264Reader<R: Read> {
    // Private fields
}

impl<R: Read> H264Reader<R> {
    pub fn new(reader: R, capacity: usize) -> H264Reader<R>;
    pub fn next_nal(&mut self) -> Result<NAL, Error>;
}

// Writer for H.264 format
pub struct H264Writer<W: Write + Seek> {
    // Private fields
}

impl<W: Write + Seek> Writer for H264Writer<W> {
    fn write_rtp(&mut self, pkt: &Packet) -> Result<(), Error>;
    fn close(&mut self) -> Result<(), Error>;
}

IVF (VP8/VP9)

// Reader for IVF format
pub struct IVFReader<R: Read> {
    // Private fields
}

impl<R: Read> IVFReader<R> {
    pub fn new(reader: R) -> Result<(IVFReader<R>, IVFFileHeader), Error>;
    pub fn reset_reader(&mut self, reset: ResetFn<R>);
    pub fn parse_next_frame(&mut self) -> Result<(BytesMut, IVFFrameHeader), Error>;
}

// Writer for IVF format
pub struct IVFWriter<W: Write + Seek> {
    // Private fields
}

impl<W: Write + Seek> Writer for IVFWriter<W> {
    fn write_rtp(&mut self, pkt: &Packet) -> Result<(), Error>;
    fn close(&mut self) -> Result<(), Error>;
}

OGG (Audio)

// Writer for OGG format
pub struct OggWriter<W: Write + Seek> {
    // Private fields
}

impl<W: Write + Seek> Writer for OggWriter<W> {
    fn write_rtp(&mut self, pkt: &Packet) -> Result<(), Error>;
    fn close(&mut self) -> Result<(), Error>;
}

Sample Builder

The SampleBuilder is a crucial component that buffers packets until media frames are complete:

pub struct SampleBuilder<T: Depacketizer> {
    // Private fields
}

impl<T: Depacketizer> SampleBuilder<T> {
    // Create a new SampleBuilder with specified parameters
    pub fn new(max_late: u16, depacketizer: T, sample_rate: u32) -> Self;
    
    // Configure maximum time delay for packet processing
    pub fn with_max_time_delay(self, max_late_duration: Duration) -> Self;
    
    // Add an RTP packet to the builder
    pub fn push(&mut self, p: Packet);
    
    // Get the next complete sample, if available
    pub fn pop(&mut self) -> Option<Sample>;
    
    // Get the next complete sample with its RTP timestamp
    pub fn pop_with_timestamp(&mut self) -> Option<(Sample, u32)>;
}

SampleBuilder functionality:

  • Maintains a buffer of received RTP packets
  • Reconstructs complete media samples from potentially out-of-order packets
  • Handles packet loss and timing information
  • Configurable through parameters like maximum lateness tolerance

Video Module

The video module contains specialized structures for video processing, although it appears to be less developed than the audio module at this time.

Usage Patterns

Media Sample Processing

  1. Creating a SampleBuilder:

    let sample_builder = SampleBuilder::new(
        100,               // Maximum packet lateness
        h264_depacketizer, // Codec-specific depacketizer
        90000              // RTP clock rate
    );
  2. Handling incoming RTP packets:

    // For each incoming RTP packet
    sample_builder.push(packet);
    
    // Check for completed samples
    while let Some(sample) = sample_builder.pop() {
        // Process the complete media sample
        process_media_sample(sample);
    }

Media File I/O

  1. Reading H.264 video:

    let mut reader = H264Reader::new(file, 1024);
    while let Ok(nal) = reader.next_nal() {
        // Process NAL unit
    }
  2. Writing to container formats:

    let writer = IVFWriter::new(file, width, height, 90000);
    writer.write_rtp(&packet)?;
    // ...
    writer.close()?;

Audio Processing

  1. Working with audio buffers:

    // Create a new interleaved audio buffer
    let buffer = Buffer::<i16, Interleaved>::new(samples, 2); // Stereo
    
    // Convert to deinterleaved format
    let deinterleaved: Buffer<i16, Deinterleaved> = buffer.into();
    
    // Access a sub-range
    let segment = buffer.sub_range(0..480);
  2. Converting between audio formats:

    // From byte stream to audio buffer
    let buffer = Buffer::<i16, Interleaved>::from_bytes::<LittleEndian>(bytes, channels)?;

Integration with WebRTC

The webrtc_media module provides the foundation for handling media in WebRTC applications:

  1. Media packet flow:

    • RTP packets are received via WebRTC data channels
    • The SampleBuilder reconstructs complete media samples
    • Samples are passed to decoders or saved to files
  2. Container format support:

    • Media can be saved to standard container formats (H.264, IVF, OGG)
    • Files can be read from these formats for streaming over WebRTC

Error Handling

The module provides a unified Error enum for error handling across all operations:

#[non_exhaustive]
pub enum Error {
    ErrBufferTooSmall,                        // Buffer too small to fit data
    ErrDataIsEmpty,                           // Data is empty
    ErrInvalidNALUHeader,                     // Invalid NAL unit header
    ErrInvalidNALUHeaderLength,               // Invalid NAL unit header length
    ErrInvalidSPS,                            // Invalid sequence parameter set
    ErrShortRead,                             // Incomplete read of expected data
    ErrIoError(IoError),                      // I/O error
    ErrUnimplemented,                         // Feature not implemented
    ErrRTPInvalidH264PacketType,              // Invalid H.264 packet type
    ErrFailedToOpenFile,                      // Failed to open file
    ErrDataOwnership,                         // Data ownership error
    ErrInvalidFileFormat,                     // Invalid file format
    // ... additional error variants
}

The Error enum ensures consistency in error reporting throughout the media processing pipeline. It is marked as #[non_exhaustive] to allow for future extensions without breaking compatibility.

WebRTC RTCPeerConnection

Overview

The RTCPeerConnection is the central component of the WebRTC API, providing methods to connect to a remote peer, maintain and monitor the connection, and establish sessions for communication. It orchestrates multiple underlying technologies (ICE, DTLS, SRTP, SCTP) to enable secure, peer-to-peer exchange of audio, video, and data.

Structure

pub struct RTCPeerConnection {
    // Private fields
}

Creation

Peer connections are created through the WebRTC API factory:

let api = API::new()?;
let peer_connection = api.new_peer_connection(config).await?;

The configuration options are provided via the RTCConfiguration struct:

pub struct RTCConfiguration {
    pub ice_servers: Vec<RTCIceServer>,
    pub ice_transport_policy: RTCIceTransportPolicy,
    pub bundle_policy: RTCBundlePolicy,
    pub rtcp_mux_policy: RTCRtcpMuxPolicy,
    pub peer_identity: String,
    pub certificates: Vec<Arc<dyn Certificate + Send + Sync>>,
    pub icecandidatepoolsize: u8,
    // Additional fields
}

Common configuration options include:

  • ice_servers: STUN/TURN servers for NAT traversal
  • ice_transport_policy: Controls which ICE candidates to use
  • bundle_policy: Controls media bundling behavior
  • certificates: Custom certificates for DTLS

Key Methods

Connection Lifecycle

// Create an offer to initiate connection
fn create_offer(&self, options: Option<RTCOfferOptions>) -> Result<RTCSessionDescription, Error>;

// Create an answer to respond to offer
fn create_answer(&self, options: Option<RTCAnswerOptions>) -> Result<RTCSessionDescription, Error>;

// Set local description (offer or answer)
fn set_local_description(&self, desc: RTCSessionDescription) -> Result<(), Error>;

// Set remote description from peer
fn set_remote_description(&self, desc: RTCSessionDescription) -> Result<(), Error>;

// Add remote ICE candidate
fn add_ice_candidate(&self, candidate: RTCIceCandidateInit) -> Result<(), Error>;

// Gracefully terminate connection
fn close(&self) -> Result<(), Error>;

Connection Monitoring

// Current connection state
fn connection_state(&self) -> RTCPeerConnectionState;

// Current ICE gathering state
fn ice_gathering_state(&self) -> RTCIceGatheringState;

// Current ICE connection state
fn ice_connection_state(&self) -> RTCIceConnectionState;

// Current signaling state
fn signaling_state(&self) -> RTCSignalingState;

Data Channel Operations

// Create data channel
fn create_data_channel(
    &self,
    label: &str,
    options: Option<RTCDataChannelInit>
) -> Result<Arc<RTCDataChannel>, Error>;

// Detect incoming data channels
fn on_data_channel(&self, f: OnDataChannelHdlrFn) -> ();

Media Operations

// Add media track
fn add_track(
    &self,
    track: Arc<dyn TrackLocal + Send + Sync>
) -> Result<Arc<RTCRtpSender>, Error>;

// Remove media track
fn remove_track(
    &self,
    sender: Arc<RTCRtpSender>
) -> Result<(), Error>;

// Add transceiver for media
fn add_transceiver_from_track(
    &self,
    track: Arc<dyn TrackLocal + Send + Sync>,
    init: Option<RTCRtpTransceiverInit>
) -> Result<Arc<RTCRtpTransceiver>, Error>;

// Add transceiver by type (audio/video)
fn add_transceiver_from_kind(
    &self,
    kind: RTPCodecType,
    init: Option<RTCRtpTransceiverInit>
) -> Result<Arc<RTCRtpTransceiver>, Error>;

// Get transceivers
fn get_transceivers(&self) -> Vec<Arc<RTCRtpTransceiver>>;

// Handle incoming tracks
fn on_track(&self, f: OnTrackHdlrFn) -> ();

Event Handlers

// ICE candidate generation
fn on_ice_candidate(&self, f: OnICECandidateHdlrFn) -> ();

// ICE connection state changes
fn on_ice_connection_state_change(&self, f: OnICEConnectionStateChangeHdlrFn) -> ();

// ICE gathering state changes
fn on_ice_gathering_state_change(&self, f: OnICEGatheringStateChangeHdlrFn) -> ();

// Negotiation needed
fn on_negotiation_needed(&self, f: OnNegotiationNeededHdlrFn) -> ();

// Connection state changes
fn on_peer_connection_state_change(&self, f: OnPeerConnectionStateChangeHdlrFn) -> ();

// Signaling state changes
fn on_signaling_state_change(&self, f: OnSignalingStateChangeHdlrFn) -> ();

State Enumerations

RTCPeerConnectionState

pub enum RTCPeerConnectionState {
    Unspecified,
    New,         // Initial state, connection created
    Connecting,  // ICE agent checking for connectivity
    Connected,   // ICE agent found viable connection
    Disconnected, // ICE connection lost temporarily
    Failed,      // ICE connection failed permanently
    Closed,      // Connection closed intentionally
}

RTCSignalingState

pub enum RTCSignalingState {
    Unspecified,
    Stable,             // No SDP exchange in progress
    HaveLocalOffer,     // Local offer set, remote not yet
    HaveRemoteOffer,    // Remote offer set, local not yet
    HaveLocalPranswer,  // Remote offer and local provisional answer
    HaveRemotePranswer, // Local offer and remote provisional answer
    Closed,             // Connection closed
}

RTCIceGatheringState

pub enum RTCIceGatheringState {
    Unspecified,
    New,       // No gathering performed yet
    Gathering, // Currently gathering candidates
    Complete,  // Gathering finished
}

RTCIceConnectionState

pub enum RTCIceConnectionState {
    Unspecified,
    New,         // ICE agent created but not gathering
    Checking,    // ICE agent checking candidates
    Connected,   // ICE agent found usable connection
    Completed,   // ICE agent finished checking
    Failed,      // ICE agent tried all candidates and failed
    Disconnected, // ICE connection lost
    Closed,      // ICE agent shut down
}

Connection Establishment Workflow

Offerer (Initiator)

// Create peer connection
let peer_connection = api.new_peer_connection(config).await?;

// Set up event handlers
peer_connection.on_ice_candidate(Box::new(|c| {
    if let Some(candidate) = c {
        // Send candidate to remote peer via signaling
    }
    Box::pin(async {})
}));

// Add tracks or create data channels if needed
let data_channel = peer_connection.create_data_channel("example", None).await?;

// Create offer
let offer = peer_connection.create_offer(None).await?;

// Set local description
peer_connection.set_local_description(offer.clone()).await?;

// Send offer to remote peer via signaling
// ...

// When ICE candidates are received from remote peer
peer_connection.add_ice_candidate(remote_candidate).await?;

// When answer is received from remote peer
peer_connection.set_remote_description(remote_answer).await?;

// Connection will establish automatically once compatible
// candidates are found and exchanged

Answerer

// Create peer connection
let peer_connection = api.new_peer_connection(config).await?;

// Set up event handlers
peer_connection.on_ice_candidate(Box::new(|c| {
    if let Some(candidate) = c {
        // Send candidate to remote peer via signaling
    }
    Box::pin(async {})
}));

// When offer is received from remote peer
peer_connection.set_remote_description(remote_offer).await?;

// Create answer
let answer = peer_connection.create_answer(None).await?;

// Set local description
peer_connection.set_local_description(answer.clone()).await?;

// Send answer to remote peer via signaling
// ...

// When ICE candidates are received from remote peer
peer_connection.add_ice_candidate(remote_candidate).await?;

// Connection will establish automatically once compatible
// candidates are found and exchanged

Optimizations and Best Practices

  1. ICE Candidate Trickling: Send ICE candidates as they're discovered rather than waiting for all

  2. BUNDLE and rtcp-mux: Use bundling to reduce the number of transport connections

  3. ICE Candidate Filtering: Use ICE transport policy to limit candidates for specific topologies

  4. SDP Munging: Avoid manual SDP modification when possible; use the API's abstractions

  5. Handling Reconnection: Monitor connection state and implement reconnection logic when needed

  6. Media Constraints: Properly configure media constraints based on network conditions

  7. Candidate Pair Selection: Understand how candidates are selected and prioritized

The RTCPeerConnection provides a robust, standards-compliant interface for WebRTC communications, abstracting the complex underlying technologies while giving developers control over the connection process.

webrtc_sctp Module

Overview

The webrtc_sctp module provides Rust implementation of the Stream Control Transmission Protocol (SCTP) for WebRTC. It enables reliable, message-oriented data transport with features like congestion control, message fragmentation, and multiple streams over a single connection.

Key Components

Association

The Association represents an SCTP association (connection) between endpoints:

pub struct Association { /* private fields */ }

Creating an Association

Two methods for establishing an association:

  • Association::server(config) - Accept an SCTP connection
  • Association::client(config) - Open an SCTP connection

An Association is configured using the Config struct:

pub struct Config {
    pub net_conn: Arc<dyn Conn + Send + Sync>,
    pub max_receive_buffer_size: u32,
    pub max_message_size: u32,
    pub name: String,
}

Key Methods

  • open_stream(stream_identifier, default_payload_type) - Creates a new stream
  • accept_stream() - Accepts incoming stream
  • shutdown() - Initiates graceful shutdown
  • close() - Ends association and cleans up resources
  • bytes_sent() / bytes_received() - Get byte count statistics

Stream

The Stream represents a bi-directional channel for sending/receiving data within an association:

pub struct Stream { /* private fields */ }

Key Methods

  • read(p) / read_sctp(p) - Read data from stream
  • write(p) / write_sctp(p, ppi) - Write data to stream
  • shutdown(how) - Shutdown read, write or both halves
  • stream_identifier() - Get the stream's identifier
  • set_reliability_params(unordered, rel_type, rel_val) - Configure reliability

Stream Reliability

SCTP streams can have different reliability modes:

pub enum ReliabilityType {
    Reliable = 0,    // Reliable transmission
    Rexmit = 1,      // Partial reliability by retransmission count
    Timed = 2,       // Partial reliability by retransmission duration
}

Usage Example

// Create an association
let config = Config {
    net_conn: /* a connection implementation */,
    max_receive_buffer_size: 65536,
    max_message_size: 65536,
    name: "example-sctp".to_string(),
};

// Server mode
let association = Association::server(config).await?;

// Client mode
let association = Association::client(config).await?;

// Open a stream
let stream = association.open_stream(
    1, // stream ID
    PayloadProtocolIdentifier::Binary
).await?;

// Configure reliability
stream.set_reliability_params(
    false, // ordered
    ReliabilityType::Reliable,
    0 // reliability value
);

// Write data
stream.write(&bytes).await?;

// Read data
let bytes_read = stream.read(&mut buffer).await?;

// Shutdown the stream
stream.shutdown(std::net::Shutdown::Both).await?;

// Close the association
association.close().await?;

Important Concepts

  1. Associations: SCTP connections between endpoints
  2. Streams: Independent bi-directional channels within an association
  3. Reliability Types: Different reliability guarantees for message delivery
  4. Payload Protocol Identifiers: Indicate the type of data being transferred

This implementation provides a comprehensive Rust API for SCTP communication in WebRTC applications, supporting both reliable and partially reliable data transmission modes.

webrtc_srtp Module

Overview

The webrtc_srtp module implements the Secure Real-time Transport Protocol (SRTP), which provides encryption, message authentication, and replay protection for RTP and RTCP packets. It enables secure media transport in WebRTC applications.

Key Components

ProtectionProfile

Specifies cipher and authentication tag details, similar to TLS cipher suites:

#[repr(u8)]
pub enum ProtectionProfile {
    Aes128CmHmacSha1_80 = 1,  // AES-CM with 80-bit HMAC-SHA1
    Aes128CmHmacSha1_32 = 2,  // AES-CM with 32-bit HMAC-SHA1
    AeadAes128Gcm = 7,        // AEAD AES-128 GCM
    AeadAes256Gcm = 8,        // AEAD AES-256 GCM
}

impl ProtectionProfile {
    pub fn key_len(&self) -> usize
    pub fn salt_len(&self) -> usize
    pub fn rtp_auth_tag_len(&self) -> usize
    pub fn rtcp_auth_tag_len(&self) -> usize
    pub fn aead_auth_tag_len(&self) -> usize
    pub fn auth_key_len(&self) -> usize
}

Each profile provides methods to determine key length, salt length, and authentication tag lengths for both RTP and RTCP.

Config

Used to configure an SRTP session:

pub struct Config {
    pub keys: SessionKeys,                        // Session keys for encryption/decryption
    pub profile: ProtectionProfile,               // Selected protection profile
    pub local_rtp_options: Option<ContextOption>, // Options for local RTP context
    pub remote_rtp_options: Option<ContextOption>, // Options for remote RTP context
    pub local_rtcp_options: Option<ContextOption>, // Options for local RTCP context
    pub remote_rtcp_options: Option<ContextOption>, // Options for remote RTCP context
}

impl Config {
    // Extract session keys from DTLS connection (RFC5764)
    pub async fn extract_session_keys_from_dtls(
        &mut self,
        exporter: impl KeyingMaterialExporter,
        is_client: bool,
    ) -> Result<(), Error>
}

impl Default for Config {}

Session

Provides a bidirectional SRTP session implementing I/O operations:

pub struct Session { /* private fields */ }

impl Session {
    // Create a new SRTP session
    pub async fn new(
        conn: Arc<dyn Conn + Send + Sync>,  // Network connection
        config: Config,                     // SRTP configuration
        is_rtp: bool,                       // Whether this is an RTP (true) or RTCP (false) session
    ) -> Result<Self, Error>

    // Open a stream for a specific SSRC
    pub async fn open(&self, ssrc: u32) -> Arc<Stream>

    // Accept incoming packets and create a stream
    pub async fn accept(&self) -> Result<(Arc<Stream>, Option<Header>), Error>

    // Close the session and clean up resources
    pub async fn close(&self) -> Result<(), Error>

    // Write a raw buffer as either RTP or RTCP
    pub async fn write(&self, buf: &Bytes, is_rtp: bool) -> Result<usize, Error>

    // Encrypt and send an RTP packet
    pub async fn write_rtp(&self, pkt: &Packet) -> Result<usize, Error>

    // Encrypt and send an RTCP packet
    pub async fn write_rtcp(
        &self,
        pkt: &(dyn Packet + Send + Sync),
    ) -> Result<usize, Error>
}

Stream

Handles encryption/decryption for a single RTP/RTCP stream identified by SSRC:

pub struct Stream { /* private fields */ }

impl Stream {
    // Create a new stream with specified SSRC
    pub fn new(ssrc: u32, tx: Sender<u32>, is_rtp: bool) -> Self

    // Get the SSRC associated with this stream
    pub fn get_ssrc(&self) -> u32

    // Check if this is an RTP stream (as opposed to RTCP)
    pub fn is_rtp_stream(&self) -> bool

    // Read and decrypt a raw packet
    pub async fn read(&self, buf: &mut [u8]) -> Result<usize, Error>

    // Read and decrypt an RTP packet
    pub async fn read_rtp(&self, buf: &mut [u8]) -> Result<Packet, Error>

    // Read and decrypt RTCP packet(s)
    pub async fn read_rtcp(
        &self,
        buf: &mut [u8],
    ) -> Result<Vec<Box<dyn Packet + Send + Sync>>, Error>

    // Close the stream and clean up resources
    pub async fn close(&self) -> Result<(), Error>
}

impl Debug for Stream {}

Usage Flow

  1. Create a Config with appropriate protection profile and keys
    • Either provide keys directly or extract from DTLS with extract_session_keys_from_dtls
  2. Create a Session using the config and network connection
  3. Either:
    • Call open to create a stream for sending/receiving with specific SSRC
    • Use accept to accept incoming packets and create streams dynamically
  4. Use the resulting Stream objects to read/write encrypted RTP/RTCP data

Security Features

  • Multiple cipher suite options with varying security levels
  • Replay protection with configurable window size
  • Authentication tag validation
  • Secure key derivation from DTLS

The module integrates with WebRTC's transport layers to provide secure media communication with minimal overhead.

WebRTC Util Module

The webrtc_util module provides a collection of utility components and abstractions that support the WebRTC implementation in Rust. This module includes network connection abstractions, buffer handling, marshaling/unmarshaling utilities, replay protection, synchronization primitives, and virtual networking capabilities.

Core Components

Buffer (buffer module)

The Buffer struct provides a thread-safe, size-limited buffer for handling binary data in WebRTC applications:

  • Manages packet data with configurable limits for both count and size
  • Thread-safe for concurrent read/write operations
  • Supports asynchronous read and write operations with optional timeouts
  • Handles buffer overflow and closure conditions
  • Provides methods for monitoring buffer state (count, size, closed status)

Example usage:

// Create a buffer with max 100 packets and 1MB size limit
let buffer = Buffer::new(100, 1024 * 1024);

// Write data to the buffer
buffer.write(&packet_data).await?;

// Read data with a timeout
let mut buf = vec![0; 1500];
let bytes_read = buffer.read(&mut buf, Some(Duration::from_secs(1))).await?;

// Close the buffer
buffer.close().await;

Connection (conn module)

The conn module provides abstractions for network connections with an async-friendly API:

  • Conn trait defines the common interface for network connections
  • Supports both connected and connection-less UDP operations
  • Native implementation for the standard library's UdpSocket
  • Custom implementations like DisconnectedPacketConn for specific use cases
  • Helper functions like lookup_host for DNS resolution

Key components:

  • Conn trait: Defines a common interface for network connections with methods:

    • async connect(&self, addr: SocketAddr) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    • async recv(&self, buf: &mut [u8]) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + 'async_trait>>
    • async recv_from(&self, buf: &mut [u8]) -> Pin<Box<dyn Future<Output = Result<(usize, SocketAddr)>> + Send + 'async_trait>>
    • async send(&self, buf: &[u8]) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + 'async_trait>>
    • async send_to(&self, buf: &[u8], target: SocketAddr) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + 'async_trait>>
    • local_addr(&self) -> Result<SocketAddr>
    • remote_addr(&self) -> Option<SocketAddr>
    • async close(&self) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    • as_any(&self) -> &(dyn Any + Send + Sync)
  • Listener trait: Abstracts connection listening and accepting with methods:

    • async accept(&self) -> Pin<Box<dyn Future<Output = Result<(Arc<dyn Conn + Send + Sync>, SocketAddr)>> + Send + 'async_trait>>
    • addr(&self) -> Result<SocketAddr>
    • async close(&self) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>

Marshal (marshal module)

The marshal module provides traits for serializing and deserializing data structures:

  • Marshal: For serializing data structures to binary format

    • marshal_to(&self, buf: &mut [u8]) -> Result<usize>
    • marshal(&self) -> Result<Vec<u8>>
  • Unmarshal: For deserializing binary data into structured types

    • unmarshal<T>(data: &[u8]) -> Result<T>
  • MarshalSize: For determining the binary size of data structures

    • marshal_size(&self) -> usize
  • ExactSizeBuf: Helper trait for exact-size binary buffers

These traits are used throughout the WebRTC stack for encoding and decoding protocol messages.

Replay Detection (replay_detector module)

The replay_detector module provides mechanisms to detect and prevent replay attacks:

  • ReplayDetector trait: Common interface for replay protection

    • check(&mut self, seq: u64) -> bool
    • fail(&mut self, seq: u64)
  • NoOpReplayDetector: A no-operation implementation for testing

  • SlidingWindowDetector: A sliding window algorithm implementation

  • WrappedSlidingWindowDetector: Handles sequence number wrapping

These components are essential for securing media streams and preventing attackers from replaying previously captured packets.

Synchronization (sync module)

The sync module provides thread synchronization primitives that are tailored for WebRTC's needs:

  • Mutex: A mutual exclusion primitive for protecting shared data
  • RwLock: A reader-writer lock for efficient concurrent access patterns
  • Associated guard types for RAII-style locking

These primitives provide abstractions over platform-specific synchronization mechanisms.

Virtual Network (vnet module)

The vnet module provides a virtual network implementation for testing WebRTC components without using actual network interfaces:

  • net: Virtual network implementation
  • router: Virtual router for packet routing
  • interface: Network interface abstractions
  • nat: NAT traversal simulations
  • chunk: Data chunking utilities

This module is particularly useful for testing WebRTC applications in controlled environments and simulating various network conditions.

Keying Material Export

The KeyingMaterialExporter trait provides functionality for extracting keying material from cryptographic contexts:

  • async export_keying_material<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, label: &'life1 str, context: &'life2 [u8], length: usize) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, KeyingMaterialExporterError>> + Send + 'async_trait>>

This trait is used for:

  • Generating symmetric keys for SRTP and other secure protocols
  • Decoupling DTLS and SRTP components to avoid direct dependencies

Error Handling

The module uses a comprehensive error type (Error) that covers various failure scenarios:

  • Network-related errors (connection, addressing)
  • Buffer-related errors (full, closed, too short)
  • Parsing errors (IP addresses, integers)
  • Virtual network errors
  • I/O errors

Integration with WebRTC Stack

The webrtc_util module serves as foundation for other WebRTC components:

  • Provides network abstractions used by ICE, DTLS, and other transport protocols
  • Offers buffering mechanisms used in media transport
  • Implements serialization/deserialization for protocol messages
  • Enables secure key derivation for encrypted communications
  • Facilitates testing through virtual network components

Usage Patterns

The utilities in this module are typically used in these scenarios:

  1. Network communication in WebRTC stacks
  2. Protocol message serialization and deserialization
  3. Media packet buffering and flow control
  4. Security key derivation and management
  5. Thread-safe state management
  6. Testing and simulation

Asynchronous Support

Most of the APIs in this module are designed with asynchronous programming in mind:

  • Async/await support for network operations
  • Future-based APIs that integrate with async runtimes like Tokio
  • Thread-safe primitives for concurrent access

Thread Safety

Components in this module are generally designed to be thread-safe:

  • Buffer uses internal synchronization for thread-safe operations
  • Mutex and RwLock provide explicit synchronization primitives
  • Connection implementations are typically shareable across threads
  • Thread-safe error handling

Conclusion

The webrtc_util module provides essential utilities that form the foundation of the WebRTC implementation in Rust. By abstracting common operations like network communication, serialization, buffering, and synchronization, it enables other WebRTC components to focus on their specific protocol implementations rather than reinventing these fundamental building blocks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment