Show HN: webrtc-rs/rtc – A Sans-I/O WebRTC Stack for Rust

We're excited to share rtc (https://github.com/webrtc-rs/rtc), a pure Rust WebRTC implementation built on the sans-I/O architecture. With the recent release of rtc v0.7.0, we've achieved feature parity with our async-based webrtc crate while offering complete runtime independence.

## What is Sans-I/O?

Sans-I/O separates protocol logic from I/O operations. Instead of the library performing network reads/writes, YOU control all I/O. The library acts as a pure state machine.

Core API (8 methods):

- poll_write() / poll_event() / poll_read() / poll_timeout() - Get outputs

- handle_read() / handle_timeout() / handle_write() / handle_event() - Feed inputs

## Why Sans-I/O for WebRTC?

WebRTC is a STACK of protocols (ICE, DTLS, SRTP, SCTP, RTP/RTCP). Traditional implementations tightly couple protocol logic with async runtimes, making them runtime-locked, difficult to test without network I/O, and hard to integrate into existing event loops.

Sans-I/O solves this by modeling WebRTC as a composable protocol pipeline where each layer implements the same sansio::Protocol trait.

## Feature Parity

- Full WebRTC 1.0 API (PeerConnection, Media, DataChannel)

- Complete protocol stack (ICE, DTLS, SRTP/SRTCP, SCTP, RTP/RTCP)

- Simulcast with multiple spatial layers

- RTCP Interceptors (NACK, Sender/Receiver Reports, TWCC)

- mDNS support for IP privacy

- W3C and RFC compliant

## Architecture Highlights

- Pure Protocol Pipeline: WebRTC as composable handlers implementing sansio::Protocol. Read: Raw Bytes → Demuxer → ICE → DTLS → SCTP/SRTP → Interceptor → Endpoint. Write path reverses this.

- Zero-Cost Abstractions: Interceptors use generic composition instead of async trait objects. No heap allocations in the hot path.

- Multi-Socket I/O: Handle multiple sockets (mDNS multicast + WebRTC traffic) in one event loop - difficult with async designs.

- Testable: Protocol logic tested without network I/O. Feed synthetic packets, verify state transitions.

## Relationship with async webrtc

rtc (sans-I/O) and webrtc (async) are COMPLEMENTARY:

- Use webrtc for async/await, Tokio integration, quick start

- Use rtc for runtime independence, custom I/O, maximum control, embedded systems

Both actively maintained.

## Recent Milestones

v0.7.0 (Jan 10) - mDNS support for IP privacy with .local hostnames

v0.6.0 (Jan 9) - Complete interceptor framework (NACK, RTCP Reports, TWCC)

v0.5.0 (Jan 5) - Enhanced simulcast support

v0.3.0 (Jan 4) - Initial public release

## Use Cases

Sans-I/O shines for: custom networking, embedded systems, game engines, high performance applications, testing infrastructure, WebAssembly.

## Links

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

- Crates.io: https://crates.io/crates/rtc (v0.7.0)

- Docs: https://docs.rs/rtc

- Blog: https://webrtc.rs/blog

- Discord: https://discord.gg/4Ju8UHdXMs

Technical deep dives available on our blog exploring the protocol pipeline architecture and interceptor design principles.

We'd love feedback from the Rust and WebRTC communities!

3 points | by rainliu 10 hours ago

2 comments

  • agentifysh 10 hours ago
    Great work I have some extra questions if you could help a noob like me:

    Since I have to bring my own I/O, do you have a reference implementation or 'glue' code examples for tokio, Bevy ,std::net so I don't have to write the event loop from scratch?

    How does this integrate with the existing webrtc-rs media crates? Can I still use the media crate for packetizing H.264/Opus, or do I need to handle payload processing manually too?

    encryption (DTLS/SRTP) layer interface with the Sans-I/O model? Does it rely on ring or openssl does that introduce blocking or heap allocations?

    benchmarks comparing CPU usage between the async webrtc crate and rtc under high load?

    Is API stable or should I expect breaking changes to the poll_ or handle_ methods in the near future?

    are theer plan to support web transport, or is the focus strictly on webrtc 1.0?

    since the library doesn't control the socket directly, how does it accurately estimate bandwidth to tell the video encoder to scale down?

    • rainliu 8 hours ago
      https://github.com/webrtc-rs/rtc/blob/master/examples/exampl... lists examples how to write the event loop with sansio::Protocol interface.

      sansio::Protocol API is stable, since crate sansio is stable v1.0.

      The mdns-query-and-gather example shows how to control multiple I/O sockets to use and how to multiplex them with sansio::Protocol API.

      For bandwidth estimation, you can register your own Interceptor with callback or event message to tell the video encoder.

  • Sean-Der 10 hours ago
    Congrats! Big project to go Sans-I/O :)