Conflict resolution: keep M3's full handler.go rewrite (per-stream
index, error matrix, PATCH, CORS, auto-cleanup) and re-apply the
swagger annotations from #7 onto the new function declarations,
including a fresh annotation for the M3-introduced Trickle endpoint.
Swagger docs regenerated to pick up all three.
Race-clean: go test -race ./app/webrtc/... green.
The WHEP routes were mounted by http/server.go via the app/webrtc
Handler.Register(), but Subscribe and Unsubscribe carried no swag
annotations. The Swagger UI at /api/swagger/index.html therefore
didn't list /api/v3/whep/* — programmatic API consumers and humans
browsing the docs couldn't discover the endpoints.
Adds the standard upstream-shaped @Summary / @Tags / @ID / @Router
annotations on Subscribe and Unsubscribe (matching the rtmp.go and
srt.go pattern) and regenerates docs/{docs.go,swagger.json,swagger.yaml}
via 'make swagger'. Verified: swagger.json now contains both paths,
swagger UI renders them under the v16.16.0 tag.
Closes#3.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Major Handler rewrite implementing the design's M3 acceptance
criteria ('5 concurrent viewers, all error paths correct, clean
teardown'):
Multi-viewer correctness:
- streamID -> resourceID -> Peer two-level index (was flat)
- per-stream peer cap alongside total cap, defaults match the
design's '5–8 viewer' target (8/stream, total from corewebrtc)
- per-peer awaitPeerClose goroutine watches Peer.Done() so ICE
failures yank the index entry + decrement the counter (no leaks)
- tearDownStreamPeers callback (registered with Subsystem in
NewHandler) drives all peer closes when the source process stops
Error matrix from design §6:
- 406 on codec mismatch (offer missing H264 or Opus rtpmap)
- 504 on ICE gathering timeout (passthrough from CreatePeerFromSources)
- 204 on DELETE unknown resource (idempotent per WHEP spec; was 404)
- 503 on per-stream cap reached (separate body from total-cap 503)
- 400 on missing/empty body (unchanged)
- 404 on unknown stream (unchanged)
WHEP spec compatibility:
- PATCH /whep/:id/:resource for trickle-ICE
- OPTIONS preflight on every WHEP path
- CORS Allow-Origin/Methods/Headers + Expose-Headers (Location, ETag)
- ETag header on Subscribe response
Defensive nil-peer guards in tearDown / Close paths so a partial
state doesn't panic.
Refactor: 134 -> 341 lines on handler.go but the surface is the
same (NewHandler/Register/Subscribe/Unsubscribe/Close); existing
callers continue to work. Pre-M3 test 'Unsubscribe_404WhenUnknown'
renamed and updated to the new 204 expectation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduces the HTTP surface the browser (or OBS WebRTC clients)
target when subscribing to a process's egress:
POST /whep/:id -> answer SDP + Location header
DELETE /whep/:id/:resource -> tear down a specific peer
The handler looks up the per-process stream pair via the Subsystem,
validates SDP offer shape, and delegates peer creation to the core
PeerFactory's CreatePeerFromSources (two-source forwarding).
WHEP routes are left unauthenticated in M2 — browsers and OBS don't
carry the Core JWT, and per-process signed-URL tokens are an M3
enhancement. Deployments should place the endpoint behind an
authenticated reverse-proxy for now.
Tests cover:
- 404 for POSTs against unregistered streams
- 400 for empty/invalid SDP offers once a stream is registered
- 404 for DELETE against unknown resource ids