WebRTC API Compliance: Sans-I/O rtc vs W3C Spec
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 |
Implementation Highlights
✅ Strengths
- Complete Core WebRTC - Full peer connection, data channels, RTP/RTCP
- Perfect Negotiation Support - Rollback transitions implemented correctly
- Statistics - Complete W3C stats specification
- Transports - Full ICE/DTLS/SCTP stack
- Sans-I/O Flexibility - Application controls all I/O and threading
- Interceptor Architecture - NACK, TWCC, PLI, custom interceptors
- Raw RTP Access -
write_rtp(),write_rtcp()for manual control
⚠️ Minor Gaps
- Transport References - Not exposed (transports managed internally)
- ICE Candidate Lists - No accessor (candidates available via events)
- Dedicated Transport Events - State changes via connection state events
❌ Notable Missing Features
- DTMF Sending - Can be implemented at app level with RFC 4733
- Identity Assertions - IdP integration not implemented
- 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
- Full interface-by-interface Comparison and Analysis: Full WebRTC API Compliance Analysis
- W3C WebRTC Spec: https://www.w3.org/TR/webrtc/
- MDN Reference: https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API