Skip to content

Repository files navigation

rustrtc

Crates.io Documentation

A high-performance, full-stack real-time communication library — WebRTC, RTP/SRTP, T.38 Fax, and UPnP NAT traversal — all through a unified PeerConnection API.

Features

  • High performance — ~3.3× faster than webrtc-rs and ~3.2× faster than pion (Go) in throughput, with ~52% less memory than webrtc-rs (see the benchmark below).
  • Full protocol stack — WebRTC, RTP, SRTP, and T.38 fax in a single library, plus UPnP IGD NAT traversal. Few moving parts, no missing pieces.
  • Unified PeerConnection API — one interface for every transport mode (WebRtc ICE/DTLS/SRTP, Srtp, Rtp, and T.38). No fragmented APIs.
  • WebRTC compliant — interoperable with Chrome/WebRTC and pion; offer/answer, renegotiation, rollback, and standard SDP attributes.
  • ICE restart — restart_ice() for network migration / re-INVITE flows, with automatic detection of remote-initiated restarts (RFC 8445 §9).
  • Complete media pipeline — packetizer/depacketizer (VP8, VP9, H264, Opus, G.711/G.722/G.729), jitter buffer, NACK/RTX, FIR/PLI, TWCC, and REMB for audio and video.
  • Bandwidth estimation (GCC) — generates TWCC receiver feedback, stamps transport-wide sequence numbers on outbound RTP, and exposes a live target_bitrate estimate for encoder adaptation (RtpSender::subscribe_target_bitrate).
  • Full ICE — STUN, TURN (UDP + TCP), ICE Lite, ICE TCP (RFC 6544), single-port UDP mux for SFU/WHEP deployments, and mDNS candidate obfuscation (enable_mdns).
  • NAT traversal & deployment — RTP latching, UPnP IGD port mapping, and firewall-friendly port ranges (rtp_start_port/rtp_end_port).
  • Production extras — RTP rewrite bridge (SSRC/PT/sequence remapping) and a WebRTC-compatible stats model.

Benchmark (rustrtc vs webrtc-rs & pion) in 0.3.141

CPU: Intel(R) Core(TM) i7-9700T CPU @ 2.00GHz (8 cores)
OS: Debian 13, 6.12.101+deb13-amd64
Compiler: rustc 1.97.1 (8bab26f4f 2026-07-14), go version go1.24.4 linux/amd64

cargo run -r --example benchmark

Comparison (Baseline: webrtc)
Metric               | webrtc     | rustrtc    | pion      
--------------------------------------------------------------------------------
Duration (s)         | 10.07      | 10.24      | 10.07     
Setup Latency (ms)   | 25.64      | 0.45       | 3.00      
Throughput (MB/s)    | 165.98     | 549.04     | 169.58    
Msg Rate (msg/s)     | 169967.13  | 562214.36  | 173647.96 
CPU Usage (%)        | 677.95     | 739.62     | 555.20    
Memory (MB)          | 44.00      | 21.00      | 48.00     
--------------------------------------------------------------------------------

Performance Charts
==================

Throughput (MB/s) (Higher is better)
webrtc     | ████████████                             165.98
rustrtc    | ████████████████████████████████████████ 549.04
pion       | ████████████                             169.58

Message Rate (msg/s) (Higher is better)
webrtc     | ████████████                             169967.13
rustrtc    | ████████████████████████████████████████ 562214.36
pion       | ████████████                             173647.96

Setup Latency (ms) (Lower is better)
webrtc     | ████████████████████████████████████████ 25.64
rustrtc    |                                          0.45
pion       | ████                                     3.00

CPU Usage (%) (Lower is better)
webrtc     | ████████████████████████████████████     677.95
rustrtc    | ████████████████████████████████████████ 739.62
pion       | ████████████████████████████████████████ 555.20

Memory (MB) (Lower is better)
webrtc     | ████████████████████████████████████████ 44.00
rustrtc    | █████████████████                        21.00
pion       | ████████████████████████████████████████ 48.00

Key Findings:

  • Throughput: rustrtc is ~3.3× faster than webrtc-rs and ~3.2× faster than pion.
  • Memory: rustrtc uses ~52% less memory than webrtc-rs and ~56% less than pion.
  • Setup latency: 0.45 ms — orders of magnitude faster than webrtc-rs (25.6 ms) and ~6.7× faster than pion (3.0 ms).
  • Efficiency per CPU: 0.74 MB/s per CPU-percent vs 0.31 (pion) and 0.24 (webrtc-rs) — rustrtc delivers ~2.3× more throughput per unit of CPU.

No regression with the new stack: this run has the TWCC/GCC pipeline active (enable_gcc = true: transport-cc sequence stamping on every outbound packet plus receiver-side TWCC feedback generation), and throughput still holds 3.3× / 3.2× over webrtc-rs / pion. ICE restart, mDNS candidate obfuscation, and the VP9 codec are likewise pure add-ons — the ratios above are the stable signal across releases (0.3.114: 2.95× / 2.7×; 0.3.141: 3.3× / 3.2×).

Usage

Here is a simple example of how to create a PeerConnection and handle an offer:

use rustrtc::{PeerConnection, RtcConfiguration, SessionDescription, SdpType};

#[tokio::main]
async fn main() {
    let config = RtcConfiguration::default();
    let pc = PeerConnection::new(config);

    // Create a Data Channel
    let dc = pc.create_data_channel("data", None).unwrap();

    // Handle received messages
    let dc_clone = dc.clone();
    tokio::spawn(async move {
        while let Some(event) = dc_clone.recv().await {
            if let rustrtc::DataChannelEvent::Message(data) = event {
                println!("Received: {:?}", String::from_utf8_lossy(&data));
            }
        }
    });

    // Create an offer
    let offer = pc.create_offer().unwrap();
    pc.set_local_description(offer).unwrap();

    // Wait for ICE gathering to complete
    pc.wait_for_gathering_complete().await;

    // Get the complete SDP with candidates
    let complete_offer = pc.local_description().unwrap();
    println!("Offer SDP: {}", complete_offer.to_sdp_string());
}

Configuration

All configuration goes through RtcConfiguration (or its builder RtcConfigurationBuilder):

Transport & Network

  • transport_mode — TransportMode::WebRtc (default), TransportMode::Srtp, or TransportMode::Rtp.
  • ice_servers — STUN/TURN server list.
  • ice_transport_policy — All or Relay.
  • rtp_start_port / rtp_end_port — Restrict RTP/ICE to a port range.
  • external_ip — Override the external IP for ICE candidates (NAT scenarios).
  • external_ip_candidate_type — How ICE advertises external_ip: Host (default) replaces the host candidate's address; ServerReflexive keeps the host candidate and adds external_ip as a srflx candidate on the same socket (1:1 NAT, RFC 8445 §5.1.1.2). WebRTC mode only.
  • bind_ip — Bind to a specific local IP.
  • disable_ipv6 — Disable IPv6 candidate gathering.
  • enable_ice_lite — Enable ICE Lite mode.
  • ice_tcp_policy — IceTcpPolicy::Disabled (default), IceTcpPolicy::Enabled, or IceTcpPolicy::PassiveOnly. Controls ICE TCP candidate support per RFC 6544.
  • ice_udp_mux / ice_udp_mux_port — Share a single UDP socket across many PeerConnections (single-port multiplexing for SFU/WHEP). Set ice_udp_mux = true and ice_udp_mux_port = <port>; incoming packets are demuxed by the server ufrag in the STUN Binding Request, then by remote source address.
  • enable_mdns — Advertise host candidates via mDNS (<random>.local hostnames instead of local IPs, draft-ietf-rtcweb-mdns). A built-in mDNS responder answers A/AAAA lookups; real addresses are kept internally so connectivity is unaffected. Default: false.

Bandwidth Estimation (GCC)

  • enable_gcc — TWCC + GCC loop (default: true): outbound RTP is stamped with transport-cc sequence numbers, TWCC feedback is generated for inbound streams, and each RtpSender publishes a bandwidth estimate. The library does not throttle sends itself — drive your encoder from RtpSender::subscribe_target_bitrate():
let mut rx = sender.subscribe_target_bitrate().unwrap();
while let Ok(new_bps) = rx.changed().await {
    encoder.set_bitrate(*rx.borrow());
}

ICE Restart

pc.restart_ice().await?;      // rolls fresh ICE credentials (RFC 8445 §9)
let offer = pc.create_offer().await?;  // carries the new ice-ufrag/pwd

Remote-initiated restarts (peer offers new credentials) are detected and mirrored automatically. DTLS/SRTP survive across the restart.

UPnP

  • enable_upnp — Auto-map ports via UPnP IGD.
  • upnp_lease_duration — UPnP port mapping lease duration in seconds (default: 3600).

RTP Latching

  • enable_latching — Enable dynamic remote address detection for RTP-only mode.
  • probation_max_packets — Number of packets to observe before committing a latched address.

Media Capabilities

  • media_capabilities — Configure audio/video/image (T.38) codecs and SCTP port via MediaCapabilities. Video presets: VideoCapability::default() (VP8), VideoCapability::vp9() / vp9_with_rtx(pt) (RFC 9628), VideoCapability::h264().
  • ssrc_start — Starting SSRC value for local tracks.
  • depacketizer_strategy — Pluggable per-kind depacketizer (e.g. Vp9Depacketizer for RFC 9628 VP9 reassembly).

SCTP (Data Channels)

  • sctp_rto_initial, sctp_rto_min, sctp_rto_max, sctp_max_association_retransmits, sctp_receive_window, sctp_heartbeat_interval, sctp_max_heartbeat_failures, sctp_max_burst, sctp_max_cwnd

RTP Buffer

  • rtp_buffer_capacity — Per-SSRC receive buffer capacity.
  • buffer_drop_strategy — DropNew or DropOldest when buffer is full.
use rustrtc::{
    PeerConnection, RtcConfiguration, RtcConfigurationBuilder,
    IceServer, TransportMode, config::T38Capability,
};

// Using builder
let config = RtcConfigurationBuilder::new()
    .transport_mode(TransportMode::Rtp)
    .enable_latching(true)
    .probation_max_packets(Some(5))
    .rtp_port_range(50000, 50100)
    .enable_upnp(true)
    .ice_tcp_policy(config::IceTcpPolicy::Enabled)
    .ice_server(IceServer::new(vec!["stun:stun.l.google.com:19302"]))
    .build();

let pc = PeerConnection::new(config);
// Direct field access
let mut config = RtcConfiguration::default();
config.transport_mode = TransportMode::WebRtc;
config.enable_latching = true;
config.rtp_start_port = Some(50000);
config.rtp_end_port = Some(50100);
config.enable_upnp = true;

T.38 fax

The t38 feature provides a complete T.38 v3 terminal: IFP wire codec, UDPTL transport (with redundancy and gap recovery), a T.30 session engine (CED/DIS → DCS/TCF → CFR → page → EOP/MCF → DCN, with timers and retries), and V.21/V.27ter DSP for audio-gateway use.

use rustrtc::t38::endpoint::{FaxEndpoint, ReceiveCodec};
use rustrtc::t38::t30::{T30FaxConfig, T30Role, T30Session};

let mut session = T30Session::new(T30FaxConfig::default());
session.role = T30Role::Callee;
let endpoint = FaxEndpoint::from_socket(socket, remote, session);
endpoint.set_codec(ReceiveCodec::Wire);
let events = endpoint.run_call(60_000).await; // drives the whole fax session

spandsp interop e2e

tests/t38_spandsp_interop.rs runs real fax sessions against a spandsp-based T.38 terminal (tools/t38-peer/t38_peer.py, ctypes over the system libspandsp). Both directions are covered: rustrtc-caller→spandsp-callee (pixel-exact page verification) and spandsp-caller→rustrtc-callee.

# requires: python3 + PIL, and libspandsp (brew install spandsp)
cargo test --features t38,t38-interop --test t38_spandsp_interop

Without the t38-interop feature the tests compile to nothing; with the feature but without python3/libspandsp they skip at runtime.

Examples

You can run the examples provided in the repository.

SFU (Selective Forwarding Unit)

A multi-user video conferencing server. It receives media from each participant and forwards it to others.

  1. Run the server:

    cargo run --example rustrtc_sfu
  2. Open your browser and navigate to http://127.0.0.1:8081. Open multiple tabs/windows to simulate multiple users.

rustrtcsfu

Echo Server

The echo server example demonstrates how to accept a WebRTC connection, receive data on a data channel, and echo it back. It also supports video playback if an IVF file is provided.

  1. Run the server:

    cargo run --example echo_server
  2. Open your browser and navigate to http://127.0.0.1:3000.

DataChannel Chat

A multi-user chat room using WebRTC DataChannels.

  1. Run the server:

    cargo run --example datachannel_chat
  2. Open your browser and navigate to http://127.0.0.1:3000. Open multiple tabs to chat between them.

Audio Saver

Records audio from the browser's microphone and saves it to a file (output.ulaw) on the server.

  1. Run the server:

    cargo run --example audio_saver
  2. Open your browser and navigate to http://127.0.0.1:3000. Click "Start" to begin recording.

RTP Play (FFmpeg)

Streams a video file (examples/static/output.ivf) via RTP to a UDP port, which can be played back using ffplay.

  1. Run the server:

    cargo run --example rtp_play
  2. In a separate terminal, run ffplay (requires ffmpeg installed):

    ffplay -protocol_whitelist file,udp,rtp -i examples/rtp_play.sdp

License

This project is licensed under the MIT License.

About

A high-performance implementation of WebRTC.

Topics

Resources

Stars

111 stars

Watchers

1 watching

Forks

Contributors

Languages