Network Analysis & Protocols
Open Source

Phone-Server: Real-Time Full-Duplex Voice Router & Jitter Buffer

RustDockerfileTokioTungsteniteCPALWebSocketsMPSC ChannelsJitter Buffer

A low-latency raw PCM audio streaming engine built on Tokio and Tungstenite. Features server-side echo mitigation and a client-side Jitter Buffer.

Tech Stack

RustDockerfileTokioTungsteniteCPALWebSocketsMPSC ChannelsJitter Buffer

System Metrics

Unbounded MPSC channels prevent lock contention and dropped packets in the critical audio threads
The Jitter Buffer actively absorbs network underruns, stopping audio stutter during latency spikes
Multi-stage Docker builds with `--no-default-features` keep heavy C/C++ audio libs (`libasound2`) out of the Debian runtime, heavily shrinking the image size

Why Did I Build This?

"Standard protocols like WebRTC are often overkill for simple audio streaming. I built this to have a lightweight, memory-safe Rust setup that strictly transmits raw PCM audio (`f32` LE bytes) over WebSockets. The goal was to kill feedback loops (echo) by filtering source addresses at the routing layer and to manually sync hardware sample-rate disparities right on the client."

Architecture & Decisions

The core bridges CPAL's synchronous hardware threads with Tokio's asynchronous network I/O. The client downmixes stereo microphone input to mono to save bandwidth, then pipes the bytes to the async WebSocket writer via unbounded MPSC channels. On the playback side, a `Mutex`-wrapped `VecDeque` acts as a Jitter Buffer (triggering at 1000 samples) to smooth out network spikes. The server just uses a `tokio::sync::broadcast` channel mapped with `(SocketAddr, Message)` tuples, broadcasting packets to everyone except the original sender to prevent echo.

Key Features

  • 01.Low-latency audio capture and playback using CPAL
  • 02.`VecDeque`-based concurrent Jitter Buffer to handle network instability
  • 03.Server-side echo suppression using `SocketAddr` packet mapping
  • 04.Cargo feature flags to drop hardware audio dependencies (like ALSA/PulseAudio) from the server build
  • 05.On-the-fly Mono/Stereo downmixing and upmixing to keep bandwidth usage low
This project highlights how to cleanly manage the boundary between synchronous hardware interrupts and async event loops. Forcing `in_config.sample_rate = out_config.sample_rate;` on the client is a straightforward, low-level fix for hardware clock mismatches. Also, hiding the `cpal` dependency behind a Cargo feature flag keeps the server binary incredibly lean, cutting down the Docker footprint and reducing the attack surface in production.