webrtc-rs Documentation

repository·master·Indexed 26 days ago

https://github.com/webrtc-rs/webrtc

An async-friendly WebRTC implementation in Rust, inspired by the Pion stack. It features a Sans-I/O protocol core (rtc) and a runtime-agnostic async layer (webrtc) supporting Tokio and smol. The library provides high-level APIs for PeerConnection, media tracks via TrackLocal, and TURN relaying through RTCTurnRelayer, maintaining over 95% W3C API compliance.

Tokens
4.1K
Snippets
4
Records
21
Agent score
89%

What's inside webrtc-rs

  1. Overview of webrtc-rs

    master

    webrtc-rs is an async-friendly WebRTC implementation in Rust. It is designed to be runtime-agnostic and is built upon a Sans-I/O core.

    Architecture

    • rtc: The Sans-I/O protocol core containing the complete WebRTC stack (95%+ W3C API compliance).
    • webrtc (this crate): A thin async layer over rtc providing:
      • PeerConnection: The primary user-facing async API handle for operations like creating offers/answers, adding tracks, and creating data channels.
      • PeerConnectionDriver: An internal background event loop that manages sockets, drives the rtc core, handles timeouts, and dispatches events.
      • Runtime: A trait that abstracts timers, task spawning, and sockets to ensure the crate remains runtime-agnostic.
  2. Build, test, and run webrtc-rs

    master

    To build and test the project from source, follow these steps. Ensure you have the rtc submodule initialized first.

    # Update rtc submodule first
    git submodule update --init --recursive
    
    # Build the library
    cargo build
    
    # Run tests
    cargo test
    
    # Build documentation
    cargo doc --open
    
    # Run examples
    cargo run --example data-channels
    # Update rtc submodule first
    git submodule update --init --recursive
    
    # Build the library
    cargo build
    
    # Run tests
    cargo test
    
    # Build documentation
    cargo doc --open
    
    # Run examples
    cargo run --example data-channels
  3. Choose the right version: v0.17.x vs v0.20.0

    master

    The project is currently transitioning between two major architectural approaches. Choose based on your project requirements:

    v0.17.x (Maintenance Mode)

    • Status: Receives bug fixes only (no new features).
    • Best for: Mature, Tokio-based production applications requiring stability.
    • Coupling: Tight coupling with the Tokio runtime.

    v0.20.0-rc.1 (New Architecture - Release Candidate)

    • Status: Published as a pre-release (Release Candidate).
    • Best for: Early adopters and new projects wanting a runtime-agnostic, Sans-I/O design.
    • Key Features:
      • Runtime Independence: Uses a Runtime abstraction. Supports runtime-tokio (default) and runtime-smol via feature flags. async-std and embassy are planned.
      • Clean Event Handling: Uses trait-based event handlers with async fn in trait, eliminating callback Arc cloning and complex Box::pin patterns.
      • Sans-I/O Foundation: Protocol logic is separated from I/O, allowing for deterministic testing without real network I/O.
  4. Understand the WebRTC Architecture

    master

    The crate uses a driver-based architecture to separate protocol state from I/O:

    • PeerConnection: The primary user-facing API handle. All operations (creating offers, adding tracks, creating data channels) are asynchronous and communicate with a background driver.
    • PeerConnectionDriver: An internal background event loop that coordinates network sockets (UDP/TCP), handles timeouts, drives the underlying Sans-I/O rtc core, and dispatches events.
    • Runtime: A trait that abstracts async operations (timers, spawning, sockets), allowing the crate to remain runtime-agnostic.
  5. Select an active async runtime via Cargo features

    master

    The webrtc crate is runtime-agnostic and supports different asynchronous runtimes through Cargo features. The active runtime is selected at compile time:

    • runtime-tokio (default): Uses the Tokio runtime.
    • runtime-smol: Uses the smol runtime.

    When a runtime is selected, the crate exports type aliases (e.g., Mutex, Sender, Receiver, Interval) that map to that specific runtime's primitives, providing zero-cost abstraction.

  6. Configure Async Runtime Support

    master

    The webrtc library is runtime-agnostic and supports different async runtimes via Cargo features:

    • runtime-tokio (default): Integrates with the Tokio async runtime.
    • runtime-smol: Integrates with the smol async runtime.
  7. Quick Start: Build a PeerConnection and initiate an SDP offer

    master

    To use webrtc, you must implement the PeerConnectionEventHandler trait to handle events like ICE candidate gathering. You then use RTCConfigurationBuilder to configure ICE servers and PeerConnectionBuilder to instantiate the connection. Once built, you can use the PeerConnection to create and set SDP offers.

    use webrtc::peer_connection::{
        PeerConnection, PeerConnectionBuilder, PeerConnectionEventHandler,
        RTCConfigurationBuilder, RTCIceServer, RTCPeerConnectionIceEvent,
    };
    use std::sync::Arc;
    
    // 1. Implement the PeerConnectionEventHandler trait to handle events
    #[derive(Clone)]
    struct MyHandler;
    
    #[async_trait::async_trait]
    impl PeerConnectionEventHandler for MyHandler {
        async fn on_ice_candidate(&self, event: RTCPeerConnectionIceEvent) {
            println!("New local ICE candidate gathered: {}", event.candidate);
        }
    }
    
    # #[cfg(feature = "runtime-tokio")]
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        // 2. Configure the peer connection
        let config = RTCConfigurationBuilder::default()
            .with_ice_servers(vec![RTCIceServer {
                urls: vec!["stun:stun.l.google.com:19302".to_owned()],
                ..Default::default()
            }])
            .build();
    
        // 3. Build the PeerConnection
        let pc = PeerConnectionBuilder::new()
            .with_configuration(config)
            .with_handler(Arc::new(MyHandler))
            .with_udp_addrs(vec!["0.0.0.0:0"])
            .build()
            .await?;
    
        // 4. Create an SDP offer and set it as local description
        let offer = pc.create_offer(None).await?;
        pc.set_local_description(offer).await?;
        
        println!("Local description set successfully!");
        Ok(())
    }
    # #[cfg(not(feature = "runtime-tokio"))]
    # fn main() {}
  8. Configure the shared reactor pool size

    master

    The WebRTC stack uses a shared, bounded pool of single-threaded reactors for dedicated-reactor connections. You can globally configure the number of threads in this pool.

    Precedence Order:

    1. Explicit override via set_reactor_pool_size.
    2. The WEBRTC_REACTOR_POOL_SIZE environment variable.
    3. Host parallelism (detected via available_parallelism, falling back to 4).

    Important: The pool is sized once, lazily, on its first use. You must call set_reactor_pool_size before building your first PeerConnection that uses a dedicated reactor thread. Subsequent calls will have no effect.

  9. Understand webrtc-rs Semantic Versioning

    master

    The project follows Semantic Versioning (SemVer). Note that because the current version is 0.x, minor version bumps may include breaking changes.

    Versioning Logic

    • Patch (0.x.Y): Bug fixes and internal improvements (no public API changes).
    • Minor (0.X.0): Backwards-compatible additions or deprecations. Note: In 0.x, this may include breaking changes.
    • Major (X.0.0): Breaking changes to the public API.

    Pre-release Suffixes

    Pre-releases are ordered by increasing stability:

    1. -alpha.N: Early preview, unstable API.
    2. -beta.N: Feature-complete, minor API changes possible.
    3. -rc.N: Release candidate, no further API changes expected unless critical.
  10. Initialize RTCTurnRelayer

    master

    To manage TURN server interactions and relaying events, initialize an RTCTurnRelayer. It requires a list of local socket addresses, a list of ICE servers (containing TURN URLs), and an ICE transport policy.

    Note: The relayer currently supports UDP-based TURN URLs and skips secure (TLS) TURN URLs or non-UDP protocols.

    let mut relayer = RTCTurnRelayer::new(
        vec![local_addr],
        vec![RTCIceServer {
            urls: vec![format!("turn:{}?transport=udp", turn_peer_addr)],
            username: "user".to_owned(),
            credential: "pass".to_owned(),
        }],
        RTCIceTransportPolicy::Relay,
    );
  11. Manage spawned tasks with JoinHandle

    master

    When using Runtime::spawn or Runtime::spawn_reactor, a JoinHandle is returned. This handle allows you to manage the lifecycle of the background task:

    • .abort(): Explicitly cancels the task.
    • .is_finished(): Checks if the task has completed.

    Note on Dropping: If the JoinHandle is dropped without calling .abort(), the task is detached and will continue running independently until it completes or the runtime is shut down.

  12. Start TURN candidate gathering with gather()

    master

    Call gather() to begin the process of allocating TURN resources. This method iterates through the provided ICE servers, resolves TURN server hostnames, and initiates TURN allocation requests for each valid UDP TURN URL and local address pair.

    If gathering is already in progress or complete, the method returns early. If successful, the relayer transitions to the RTCIceGatheringState::Gathering state.