WebRTC API Compliance: Sans-I/O rtc vs W3C Spec

January 24, 2026 views

How does a Sans-I/O WebRTC implementation in Rust compare to the browser-based W3C WebRTC API? After completing the core WebRTC feature set, we conducted a comprehensive compliance analysis against the W3C WebRTC 1.0 specification. The results might surprise you.

For the complete interface-by-interface comparison, including every method, property, and event across 15+ WebRTC interfaces, see the Full WebRTC API Compliance Analysis. The detailed reference includes:

  • Line-by-line API member comparisons with implementation notes
  • Status indicators (✅ Full / ⚠️ Partial / ❌ Missing)
  • Architectural differences explained
  • Sans-I/O specific extensions documented
  • Compliance percentages per interface

TL;DR: 95%+ Compliance

Despite fundamental architectural differences (no async/await, application-controlled I/O), the rtc library achieves 95%+ compliance with the W3C WebRTC specification. All core interfaces reach 90-100% compliance, with gaps only in niche features like DTMF tone sending and Identity Provider APIs.

Interface Compliance Status
RTCPeerConnection 100% Complete implementation
RTCSessionDescription 100% Full spec + rollback support
RTCIceCandidate 100% All properties including extensions
RTCDataChannel 100% Binary/text, buffering, flow control
RTCRtpTransceiver 100% Full direction control
RTCRtpSender 95% Missing only DTMF tone sending
RTCRtpReceiver 100% Track management, statistics
RTCIceTransport 90% Minor: missing selectedCandidatePair accessor
RTCDtlsTransport 90% Core transport, minor accessor gaps
RTCStatsReport 95% Comprehensive statistics with extensions

Architecture: Sans-I/O vs Browser WebRTC

The fundamental difference between browser WebRTC and rtc is the Sans-I/O architecture. This design choice affects API style but not functionality:

Aspect Browser WebRTC rtc (Sans-I/O)
Async Model Promises (async/await) Synchronous + explicit timeouts
Events addEventListener() poll_event() returns enum
I/O Control Hidden in browser engine Application controls sockets
Media Capture getUserMedia() API Application provides raw frames
ICE Gathering Automatic via browser stack Application adds local candidates
Key Insight: Sans-I/O requires the application to handle I/O operations (network sockets, timers, media capture), but provides identical WebRTC functionality once data reaches the library. The API surface intentionally mirrors W3C WebRTC for familiarity.

Implementation Highlights

✅ Strengths

  1. Complete Core WebRTC - Full peer connection, data channels, RTP/RTCP
  2. Perfect Negotiation Support - Rollback transitions implemented correctly
  3. Statistics - Complete W3C stats specification
  4. Transports - Full ICE/DTLS/SCTP stack
  5. Sans-I/O Flexibility - Application controls all I/O and threading
  6. Interceptor Architecture - NACK, TWCC, PLI, custom interceptors
  7. Raw RTP Access - write_rtp(), write_rtcp() for manual control

⚠️ Minor Gaps

  1. Transport References - Not exposed (transports managed internally)
  2. ICE Candidate Lists - No accessor (candidates available via events)
  3. Dedicated Transport Events - State changes via connection state events

❌ Notable Missing Features

  1. DTMF Sending - Can be implemented at app level with RFC 4733
  2. Identity Assertions - IdP integration not implemented
  3. Encoded Transforms - Use interceptor API instead

Architectural Deep Dive

Event Handling

Browser WebRTC:

pc.onnegotiationneeded = async () => {
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);
  // Send offer via signaling
};

rtc (Sans-I/O):

while let Some(event) = pc.poll_event() {
    match event {
        RTCPeerConnectionEvent::OnNegotiationNeeded => {
            let offer = pc.create_offer(None)?;
            pc.set_local_description(offer)?;
            // Send offer via signaling
        }
        // ... other events
    }
}

I/O Control

Browser WebRTC:

  • Hidden socket management
  • Automatic packet transmission
  • Browser controls network I/O

rtc (Sans-I/O):

// Application controls socket
let socket = UdpSocket::bind("0.0.0.0:0")?;

// Application polls for I/O
if let Some(data) = pc.poll_write()? {
    socket.send_to(&data.buffer, data.remote_addr)?;
}

let mut buf = [0u8; 1500];
if let Ok((len, addr)) = socket.recv_from(&mut buf) {
    pc.handle_read(&buf[..len], addr, Instant::now())?;
}

Timeouts

Browser WebRTC:

  • Automatic timeout management
  • Hidden retransmissions

rtc (Sans-I/O):

let timeout = pc.poll_timeout();
sleep(timeout);
pc.handle_timeout(Instant::now())?;

What's Missing?

The gaps are almost entirely niche features that most applications don't use:

  • DTMF Tone Sending (RTCDTMFSender): VoIP dial pad tones - rare in modern WebRTC apps
  • Identity Provider APIs (RTCIdentityProvider): Federated identity - complex, rarely used
  • Encoded Transform APIs: Experimental feature for E2E encryption in browsers - use interceptor API instead
  • Priority Hints: Network priority APIs - browser-specific optimizations

For 95%+ of WebRTC use cases—video conferencing, screen sharing, file transfer, gaming—the rtc library provides complete W3C spec compliance.

Why This Matters

Familiar APIs: Developers with browser WebRTC experience can apply their knowledge directly. The method names, state machines, and event flows match the W3C specification.

Specification Compliance: Following the W3C spec ensures correct behavior for interoperability. Edge cases like rollback, trickle ICE detection, and state transitions work as specified.

Future-Proof: As the W3C specification evolves, the library can adopt new features while maintaining its Sans-I/O architecture advantages (testability, determinism, no hidden threads).

Recommendations

For Application Developers

Use rtc for:

  • Server-side WebRTC (SFUs, gateways)
  • Embedded systems / IoT
  • Custom transport layers (e.g., QUIC)
  • Deterministic testing
  • Non-tokio async runtimes

Consider alternatives if:

  • You need DTMF (implement at app level or use webrtc crate)
  • You need identity assertions (uncommon feature)
  • You want browser-like async API (use webrtc crate instead)

For Library Contributors

High Priority:

  • ✅ Core WebRTC - COMPLETE
  • ✅ Perfect Negotiation - COMPLETE
  • ✅ Statistics - COMPLETE

Medium Priority:

  • ⚠️ Expose transport references
  • ⚠️ Add dedicated transport state change events

Low Priority:

  • ❌ DTMF sending (niche use case)
  • ❌ Identity assertions (rarely used)
  • ❌ Encoded transforms (use interceptors)

Conclusion

The rtc library demonstrates that Sans-I/O architecture does not mean sacrificing standards compliance. By separating I/O from protocol logic, we achieve both the flexibility of manual I/O control and the familiarity of W3C WebRTC APIs.

Whether you're building a server-side media router, embedded device, or testing infrastructure, you can leverage the same WebRTC APIs used in billions of browsers—just with deterministic, testable, thread-safe implementations.


References


← Back to Blog | Home