Skip to content

Repository files navigation

WebRTC.rs

License: MIT/Apache 2.0DiscordTwitter

Sans-I/O WebRTC implementation in Rust

Sponsored with 💖 by

Gold Sponsors:
Recall.ai

Silver Sponsors:
Stream Chat
ChannelTalk
Bronze Sponsors:
AdrianEddy

Table of Content

Overview

RTC is a pure Rust implementation of WebRTC using a sans-I/O architecture. Unlike traditional WebRTC libraries, RTC separates protocol logic from I/O operations, giving you complete control over networking, threading, and async runtime integration.

What is Sans-I/O?

Sans-I/O (without I/O) is a design pattern where the library handles protocol logic but you control all I/O operations. Instead of the library performing network reads and writes directly, you feed it network data and it tells you what to send.

Benefits:

  • 🚀 Runtime Independent - Works with tokio, async-std, smol, or blocking I/O
  • 🎯 Full Control - You control threading, scheduling, and I/O multiplexing
  • 🧪 Testable - Protocol logic can be tested without real network I/O
  • 🔌 Flexible - Easy integration with existing networking code

Sans-I/O Event Loop Pattern

The sans-I/O architecture uses a simple event loop with six core methods:

Core API Methods

  1. poll_write() - Get outgoing network packets to send via UDP
  2. poll_event() - Process connection state changes and notifications
  3. poll_read() - Get incoming application messages (RTP, RTCP, Data)
  4. poll_timeout() - Get next timer deadline for retransmissions/keepalives
  5. handle_read() - Feed incoming network packets into the connection
  6. handle_timeout() - Notify about timer expiration

Additional methods for external control:

  • handle_write() - Queue application messages (RTP/RTCP/Data) for sending
  • handle_event() - Inject external events into the connection

Event Loop Example

use rtc::peer_connection::RTCPeerConnection;use rtc::peer_connection::configuration::RTCConfigurationBuilder;use rtc::peer_connection::event::{RTCPeerConnectionEvent,RTCTrackEvent};use rtc::peer_connection::state::RTCPeerConnectionState;use rtc::peer_connection::message::RTCMessage;use rtc::peer_connection::sdp::RTCSessionDescription;use rtc::shared::{TaggedBytesMut,TransportContext,TransportProtocol};use rtc::sansio::Protocol;use std::time::{Duration,Instant};use tokio::net::UdpSocket;use bytes::BytesMut;#[tokio::main]asyncfnmain() -> Result<(),Box<dyn std::error::Error>>{// Setup peer connectionlet config = RTCConfigurationBuilder::new().build();letmut pc = RTCPeerConnection::new(config)?;// Signaling: Create offer and set local descriptionlet offer = pc.create_offer(None)?;
pc.set_local_description(offer.clone())?;// TODO: Send offer.sdp to remote peer via your signaling channel// signaling_channel.send_offer(&offer.sdp).await?;// TODO: Receive answer from remote peer via your signaling channel// let answer_sdp = signaling_channel.receive_answer().await?;// let answer = RTCSessionDescription::answer(answer_sdp)?;// pc.set_remote_description(answer)?;// Bind UDP socketlet socket = UdpSocket::bind("0.0.0.0:0").await?;let local_addr = socket.local_addr()?;letmut buf = vec![0u8;2000];'EventLoop:loop{// 1. Send outgoing packetswhileletSome(msg) = pc.poll_write(){
socket.send_to(&msg.message, msg.transport.peer_addr).await?;}// 2. Handle eventswhileletSome(event) = pc.poll_event(){match event {RTCPeerConnectionEvent::OnConnectionStateChangeEvent(state) => {println!("Connection state: {state}");if state == RTCPeerConnectionState::Failed{returnOk(());}}RTCPeerConnectionEvent::OnTrack(RTCTrackEvent::OnOpen(init)) => {println!("New track: {}", init.track_id);}
_ => {}}}// 3. Handle incoming messageswhileletSome(message) = pc.poll_read(){match message {RTCMessage::RtpPacket(track_id, packet) => {println!("RTP packet on track {track_id}");}RTCMessage::DataChannelMessage(channel_id, msg) => {println!("Data channel message");}
_ => {}}}// 4. Handle timeoutslet timeout = pc.poll_timeout().unwrap_or(Instant::now() + Duration::from_secs(86400));let delay = timeout.saturating_duration_since(Instant::now());if delay.is_zero(){
pc.handle_timeout(Instant::now())?;continue;}// 5. Multiplex I/O
tokio::select! {
_ = stop_rx.recv() => {break'EventLoop,} _ = tokio::time::sleep(delay) => {
pc.handle_timeout(Instant::now())?;}Ok(message) = message_rx.recv() => {
pc.handle_write(message)?;}Ok(event) = event_rx.recv() => {
pc.handle_event(event)?;}Ok((n, peer_addr)) = socket.recv_from(&mut buf) => {
pc.handle_read(TaggedBytesMut{
now:Instant::now(),
transport:TransportContext{
local_addr,
peer_addr,
ecn:None,
transport_protocol:TransportProtocol::UDP,},
message:BytesMut::from(&buf[..n]),})?;}}}
pc.close()?;Ok(())}

Features

  • ICE (Interactive Connectivity Establishment) - NAT traversal with STUN/TURN
  • DTLS (Datagram Transport Layer Security) - Encryption for media and data
  • SCTP (Stream Control Transmission Protocol) - Reliable data channels
  • RTP/RTCP - Real-time media transport and control
  • SDP (Session Description Protocol) - Offer/answer negotiation
  • Data Channels - Bidirectional peer-to-peer data transfer
  • Media Tracks - Audio/video transmission
  • Trickle ICE - Progressive candidate gathering
  • Simulcast & SVC - Simulcast and scalable video coding

Examples

The repository includes comprehensive examples demonstrating various use cases:

Run an example:

cargo run --example data-channels-answer

Architecture

RTC is built from composable crates, each implementing a specific protocol:

RTC Crates

RTC
MediaInterceptorDataChannel
RTPRTCPSRTPSCTP
DTLS
mDNSSTUNTURNICE
SDPShared

Dependency Graph

RTC Crates Dependency Graph

Protocol Stack

RTC Protocols Stack

Common Use Cases

Data Channels

use rtc::data_channel::RTCDataChannelInit;fnexample(mutpc:RTCPeerConnection) -> Result<(),Box<dyn std::error::Error>>{// Create a data channellet init = RTCDataChannelInit{ordered:true,max_retransmits:None,
..Default::default()};letmut dc = pc.create_data_channel("my-channel",Some(init))?;// Send data
dc.send_text("Hello, WebRTC!")?;Ok(())}

Media Tracks

use rtc::media_stream::MediaStreamTrack;use rtc::rtp_transceiver::rtp_sender::{RTCRtpCodec,RtpCodecKind};fnexample(mutpc:RTCPeerConnection) -> Result<(),Box<dyn std::error::Error>>{// Create a video tracklet track = MediaStreamTrack::new("stream-id".to_string(),"track-id".to_string(),"Camera".to_string(),RtpCodecKind::Video,vec![RTCRtpEncodingParameters{
rtp_coding_parameters:RTCRtpCodingParameters{
ssrc:Some(ssrc),
..Default::default()},
codec:RTCRtpCodec::default(),
..Default::default()}],);// Add to peer connectionlet sender_id = pc.add_track(track)?;Ok(())}

Signaling

WebRTC requires an external signaling channel (e.g., WebSocket, HTTP) to exchange offers and answers:

fnexample(mutpc:RTCPeerConnection) -> Result<(),Box<dyn std::error::Error>>{// Create and send offerlet offer = pc.create_offer(None)?;
pc.set_local_description(offer.clone())?;// Send offer.sdp via your signaling channel// Receive and apply answer// let answer = receive_answer_from_signaling()?;// pc.set_remote_description(answer)?;Ok(())}

Specification Compliance

This implementation follows these specifications:

  • W3C WebRTC 1.0 - Main WebRTC API specification
  • RFC 8829 - JSEP: JavaScript Session Establishment Protocol
  • RFC 8866 - SDP: Session Description Protocol
  • RFC 8445 - ICE: Interactive Connectivity Establishment
  • RFC 6347 - DTLS: Datagram Transport Layer Security
  • RFC 9260 - SCTP: Stream Control Transmission Protocol
  • RFC 8831 - WebRTC Data Channels
  • RFC 3550 - RTP: Real-time Transport Protocol
  • RFC 3711 - SRTP: Secure Real-time Transport Protocol

Documentation

Building and Testing

# Build the library
cargo build
# Run tests
cargo test# Build documentation
cargo doc --open
# Run examples
cargo run --example data-channels-answer

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under either of:

at your option.

Acknowledgments

Special thanks to all contributors and the WebRTC-rs community for making this project possible.

About

Sans-IO OpenBubbles RTC implementation in Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages