spec(slice-1): self-review fixes + terminology
- Clarify RtcSession/Channel ownership: ChannelId IS the session id; RtcSession owns both str0m Live + codecs and the Channel. Fixes ambiguity. - Drop the separate /ice endpoint: non-trickle ICE bundles candidates into the SDP offer/answer, so the endpoint was redundant. Fixes contradiction. - Clarify idle timeout = 'no RTP for 60s' (not 5 min blanket), and that no per-session tokio task is spawned (pre-paves the wrong pattern for step 4's dedicated thread). - 'reflex to police' -> 'reflex to enforce' (terminology: avoid authoritarian verbs).
This commit is contained in:
@@ -47,7 +47,7 @@ though it pre-paves the tap by exposing the PCM boundary as a clean trait seam.
|
||||
| Trickle ICE | When real-world NATs demand it (likely step 5) | Non-trickle (one POST with offer+candidates, one response with answer+candidates) suffices for local loopback and keeps the dev loop zero-dependency. |
|
||||
| The tap itself (audio routing to an external echo process) | Spearhead step 2 | Slice 1 *pre-paves* the tap by exposing the PCM boundary as `AudioSource`/`AudioSink` traits in `rutster-media`; step 2 implements the WSS tap client behind that seam. |
|
||||
| The brain (STT/LLM/TTS) | Spearhead step 3 | Slice 1 echoes; step 2 swaps echo for an external process, step 3 swaps echo-process for a real brain. |
|
||||
| Barge-in / VAD-driven playout kill | Spearhead step 4 | No reflex to police yet; no VAD even on the inbound side. |
|
||||
| Barge-in / VAD-driven playout kill | Spearhead step 4 | No reflex to enforce yet; no VAD even on the inbound side. |
|
||||
| PSTN trunk (SIP client) | Spearhead step 5 | WebRTC-only ingress in slice 1; ADR-0003's Rust-native trunk SIP lands with the trunk integration. |
|
||||
| Spend cap / abuse gate | Spearhead step 6 | No trunk yet to gate spend against. |
|
||||
| CDR emission, event bus, OTel traces beyond the per-channel `tracing` span | Later rungs | PORT_PLAN keeps these as services *around* the core; slice 1 has one peer, one channel, no fanout needed. |
|
||||
@@ -243,16 +243,20 @@ policy is match-and-continue).
|
||||
|
||||
### 4.1 HTTP surface (slice 1)
|
||||
|
||||
- `POST /v1/sessions` → mint a `RtcSession` keyed by a fresh `ChannelId`. Returns
|
||||
`{ "session_id": "<uuid>" }`.
|
||||
- `POST /v1/sessions/:id/offer` (body: browser SDP offer) → core produces SDP answer.
|
||||
Returns the answer as `application/sdp`.
|
||||
- `POST /v1/sessions/:id/ice` (body: browser ICE candidate, non-trickle) → feed to
|
||||
str0m. Returns `204 No Content`.
|
||||
- `POST /v1/sessions` → mint a `RtcSession` (which owns a fresh `Channel`; the
|
||||
`ChannelId` *is* the session id). Returns `{ "session_id": "<uuid>" }`.
|
||||
- `POST /v1/sessions/:id/offer` (body: browser SDP offer, including all ICE
|
||||
candidates — non-trickle) → core produces SDP answer (including its ICE candidates),
|
||||
feeds candidates to str0m, returns the answer as `application/sdp`.
|
||||
- `DELETE /v1/sessions/:id` → tear down: transition `Channel` to `Closing → Closed`,
|
||||
drop the `RtcSession`, close the peer connection cleanly via str0m.
|
||||
- `GET /` → serve the static HTML test client.
|
||||
|
||||
There is **no separate `/ice` endpoint** in slice 1. Non-trickle ICE bundles all
|
||||
candidates into the SDP offer/answer exchange, so one POST (`/offer`) carries
|
||||
everything. A separate `/ice` endpoint is a step-5 concern (trickle ICE — see the
|
||||
out-of-scope table).
|
||||
|
||||
### 4.2 ICE strategy
|
||||
|
||||
Non-trickle ICE. Browser gathers all candidates, sends offer+candidates in one POST,
|
||||
@@ -285,8 +289,16 @@ A single self-contained HTML file with inline JS, no build step. Behavior:
|
||||
|
||||
### 4.5 Session lifecycle
|
||||
|
||||
- Sessions held in an in-process `DashMap<Uuid, RtcSession>` in the binary crate.
|
||||
- Idle timeout: 5 min hard cutoff. No re-INVITE / renegotiation in slice 1.
|
||||
- Sessions held in an in-process `DashMap<ChannelId, RtcSession>` in the binary crate.
|
||||
The `ChannelId` (a UUID newtype from `rutster-call-model`) is the session id surfaced
|
||||
in the REST API. `RtcSession` owns both the str0m `Live` + codecs and the `Channel`
|
||||
(signaling state); see §3.1 and §5.
|
||||
- Idle timeout: 5 min hard cutoff. "Idle" = no RTP packets received from the peer in
|
||||
the last 60 s (a longer window than the strict "no RTCP" definition, because RTC
|
||||
quiet periods are normal; no-RTP-for-60s is a real "the browser tab is dead" signal).
|
||||
Implemented as a per-session deadline checked on each poll cycle; no per-session
|
||||
tokio task spawned (which would clutter the runtime and pre-pave the wrong pattern
|
||||
for the dedicated timing thread in step 4).
|
||||
- Restart on browser refresh: new session. No resumability.
|
||||
|
||||
### 4.6 API posture
|
||||
|
||||
Reference in New Issue
Block a user