` + `LocalVadReflex`) is **reused
verbatim** from slice 4 — barge-in fires on PSTN caller speech the same way it
fires on WebRTC caller speech. The only difference is the ingress: str0m's RTP
decode (WebRTC) vs the Media Streams WSS pump + G.711 codec (trunk).
---
## 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 `` element. Look for the failure there. |
| Port 8080 already in use | Set `RUTSTER_HTTP_BIND`, e.g. `RUTSTER_HTTP_BIND=0.0.0.0:8090 cargo run -p rutster` |
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).