Files
rutster/docs/QUICKSTART.md
Aaron D. Lee 0eb20b729a
Some checks failed
CI / fmt (push) Successful in 1m32s
CI / clippy (push) Successful in 1m31s
CI / test (1.85) (push) Successful in 3m57s
CI / deny (push) Has been cancelled
CI / test (stable) (push) Has been cancelled
docs(reviews/2026-07-03): P4 fix — sweep status staleness + re-aim fuzz/README (#11)
Co-authored-by: Aaron D. Lee <himself@adlee.work>
Co-committed-by: Aaron D. Lee <himself@adlee.work>
2026-07-04 01:44:27 +00:00

4.0 KiB
Raw Blame History

Quickstart

Get Rutster running and hear your own voice echoed back in under 5 minutes.

Status: Slices 13 are merged to main. Slice 4 (barge-in / VAD-driven playout kill) is the active build target, in flight on the slice-4-dev-a-reflex + slice-4-dev-b-tap branches. This quickstart exercises the slice-1 WebRTC media loopback, which remains the simplest end-to-end demo on main. See docs/superpowers/specs/2026-07-01-slice-4-barge-in-design.md for the active build target's design.


Prerequisites

1. Rust toolchain

Install via rustup:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

The repo pins a specific stable channel in rust-toolchain.tomlrustup will pick it up automatically on first cargo invocation. No manual toolchain selection needed.

2. libopus (FFI dependency)

The opus crate links system libopus via FFI (per PORT_PLAN §7's "🦀 Core (FFI)" disposition — Opus is the codec surface Rust doesn't need to re-implement). Install the dev headers:

Platform Command
Debian/Ubuntu sudo apt-get install -y libopus-dev
Fedora sudo dnf install -y opus-devel
Arch sudo pacman -S opus
macOS (Homebrew) brew install opus

Verify: pkg-config --cflags opus should print a path with no error.

That's the only system dependency in slice 1. Everything else is pure Rust from crates.io.


Run the server

cargo run
# listening on http://0.0.0.0:8080

First build takes ~2 minutes (str0m + axum + tokio compile fresh). Subsequent builds are incremental.


Hear the echo

  1. Open a browser to http://localhost:8080/.
  2. Click Start call.
  3. Grant microphone permission when the browser prompts.
  4. Speak — you should hear yourself back within ~200 ms (no perceptible delay).
  5. Click Hang up to tear down. The server logs Closing → Closed for the session.

Verbose tracing for debugging:

RUST_LOG=rutster=debug cargo run

Troubleshooting

Symptom Likely cause / fix
error: linking with cc failed / could not find opus libopus dev headers not installed. Re-run the install command above.
Browser shows no mic prompt Another tab/app holding the mic, or mic permissions disabled for localhost. Check browser settings.
ICE connection failed in the browser Shouldn't happen on loopback (host candidates only). If it does, check the server console for the str0m error.
Click Start call, nothing happens Open the browser console (F12). The page logs ICE state + connection state to a <pre> element. Look for the failure there.
Port 8080 already in use Another process holding the port. Either stop it or edit crates/rutster/src/main.rs to bind a different port.

The browser test page at GET / is a single self-contained HTML file with inline JS — no build step. View source to see exactly what the client side is doing.


What's happening

When you click "Start call":

  1. Browser captures microphone audio via getUserMedia.
  2. Browser creates an RTCPeerConnection and generates an SDP offer (audio-only, Opus codec).
  3. Browser POSTs the offer to POST /v1/sessions/:id/offer.
  4. The Rutster core (built on str0m, a sans-IO WebRTC implementation) accepts the offer, generates an SDP answer with its DTLS fingerprint + ICE credentials.
  5. Browser sets the answer as remote description; ICE + DTLS handshake completes.
  6. RTP starts flowing: browser → core terminates DTLS-SRTP → decodes Opus to 16-bit PCM @ 24 kHz mono → echoes PCM back → re-encodes to Opus → DTLS-SRTP → browser plays it.

The "codec-to-PCM boundary" is the canonical point where, in a future slice, the audio tap for an external AI brain splices in. Slice 1 just echoes; step 2 of the spearhead swaps the echo for a real tap.

For the why, see ARCHITECTURE.md. For the dev loop, see DEVELOPMENT.md.