Builds out the user-facing docs tree alongside the slice-1 build target. Kept the implementer's planned Task 7 'Slice 1 dev loop' README section untouched — these docs are the canonical destination for that pointer. - docs/QUICKSTART.md: 5-min path to 'hear the echo' (libopus install, cargo run, browser steps, troubleshooting, what's happening under the hood). - docs/DEVELOPMENT.md: dev loop — workspace layout, per-crate iteration, running tests, the 20 ms loop / 'drop + observe' rule, slice-1 boundaries (what NOT to add yet). - CONTRIBUTING.md (at repo root, conventional): trunk-based dev, CI gates, commit message style, atomic commits, code style + learner-facing documentation policy, terminology policy, PR workflow + review checklist, GPL-3.0-or-later license. - README.md: add a Quickstart pointer at the top, a Documentation table linking to every doc, and the slice-1 build-target status block.
116 lines
3.9 KiB
Markdown
116 lines
3.9 KiB
Markdown
# Quickstart
|
|
|
|
Get Rutster running and hear your own voice echoed back in under 5 minutes.
|
|
|
|
> **Status:** Slice 1 (WebRTC media loopback) is the active build target.
|
|
> If the workspace isn't on `main` yet, check the `slice-1-webrtc-loopback`
|
|
> branch — that's where the implementation is landing task-by-task.
|
|
> See [`docs/superpowers/specs/2026-06-28-slice-1-webrtc-loopback-design.md`](superpowers/specs/2026-06-28-slice-1-webrtc-loopback-design.md)
|
|
> for the full design.
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
### 1. Rust toolchain
|
|
|
|
Install via [rustup](https://rustup.rs/):
|
|
|
|
```bash
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
```
|
|
|
|
The repo pins a specific stable channel in `rust-toolchain.toml` — `rustup`
|
|
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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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`](https://docs.rs/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`](ARCHITECTURE.md). For the dev loop,
|
|
see [`DEVELOPMENT.md`](DEVELOPMENT.md).
|