From 1d56517f07426a9f6691f531a6b43b8574e43f63 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Fri, 21 Aug 2026 19:41:32 +0200 Subject: [PATCH] docs(specs): add backend-owned stream selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rust becomes the single owner of which stream to play — direct play or transcode, at what ceiling, over what transport — and hands every player backend a self-describing StreamSelection instead of a bare URL. mpv, ExoPlayer and the HTML5/hls.js path all consume one decision rather than three places re-deriving it. The motivating leak is concrete. VideoPlayer.svelte determines transport with `currentStreamUrl.includes(".m3u8")`, in two places, for a URL Rust constructed and therefore already knows the shape of. That is the boundary rule in miniature: not item-type taxonomy, but the same error of reconstructing a domain fact in the presentation layer because the wire shape did not carry it. A tagged Transport enum deletes it. The design line, which ExoPlayer forces: Rust decides *what stream*, the player decides *how to deliver it*. ExoPlayer has genuine adaptive track selection; this spec must not reimplement or fight it. Rust only adapts where the player cannot (mpv) and the server actually offers a ladder. Six phases, and phase 1 stands alone as pure ownership movement with no behaviour change. Phase 4 (direct-play negotiation) is what removes the transcode and unblocks the Linux native-video work. Phase 5 (adaptation) is gated on counting EXT-X-STREAM-INF entries in a real playlist — the acceptance criteria require that count be recorded before it is either started or dropped. Takes DR-121 from read-through-media-cache.md, which specced Rust-owned quality reporting but never built it; that spec keeps its capture half. --- docs-site/SUMMARY.md | 1 + docs/specs/README.md | 1 + docs/specs/backend-owned-stream-selection.md | 242 +++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 docs/specs/backend-owned-stream-selection.md diff --git a/docs-site/SUMMARY.md b/docs-site/SUMMARY.md index ce86b824..45a207be 100644 --- a/docs-site/SUMMARY.md +++ b/docs-site/SUMMARY.md @@ -33,6 +33,7 @@ - [Spec Review Checklist](specs/SPEC-REVIEW-CHECKLIST.md) - [Playback Backend Unification](specs/playback-backend-unification.md) - [Linux Native Video Spike](specs/linux-native-video-spike.md) +- [Backend-Owned Stream Selection](specs/backend-owned-stream-selection.md) - [Player Facade Enforcement](specs/player-facade-enforcement.md) - [Windows Native Audio Backend](specs/windows-native-audio-backend.md) - [libmpv2 Migration](specs/libmpv2-migration.md) diff --git a/docs/specs/README.md b/docs/specs/README.md index 4ac015a9..9c4eac56 100644 --- a/docs/specs/README.md +++ b/docs/specs/README.md @@ -44,6 +44,7 @@ taken by other work; each carries a ⚠️ note at the top. | Spec | Blocked on / note | |---|---| +| [backend-owned-stream-selection.md](backend-owned-stream-selection.md) | Rust owns direct-play-vs-transcode, transport and quality; players consume one `StreamSelection`. Phase 1 (delete the `.m3u8` sniff) stands alone. Unblocks Linux native video. | | [build-provenance.md](build-provenance.md) | `build.rs` is still bare. ⚠️ suggested id DR-093 is taken. | | [player-facade-enforcement.md](player-facade-enforcement.md) | ~60 `commands.player*` sites still outside the facade; no lint rule. ⚠️ suggested id DR-095 is taken. | | [windows-native-audio-backend.md](windows-native-audio-backend.md) | Blocked on the libmpv2 swap. ⚠️ suggested id IR-030 is taken. | diff --git a/docs/specs/backend-owned-stream-selection.md b/docs/specs/backend-owned-stream-selection.md new file mode 100644 index 00000000..a32391d8 --- /dev/null +++ b/docs/specs/backend-owned-stream-selection.md @@ -0,0 +1,242 @@ +# Spec: Backend-owned stream selection + +**Status:** Proposed +**Requirements:** UR-079 (new) → DR-219 … DR-224 (new); **implements and extends +DR-121**, currently allocated to +[read-through-media-cache.md](read-through-media-cache.md) and not started. +Re-check `requirements.md` before allocating — the ids moved twice while this was +being written (`DR` max was 215, then 218). +**UX spec:** the quality selector in `VideoPlayer.svelte` already exists; this +changes what fills it, not how it looks. +**Supersedes / revises:** takes DR-121 out of +[read-through-media-cache.md](read-through-media-cache.md), which should keep +only its capture/eviction half. Unblocks +[linux-native-video-spike.md](linux-native-video-spike.md). + +**Destination on completion:** +[01-rust-backend.md](../architecture/01-rust-backend.md) — extends the +"Streaming quality ladder" section; and +[03-data-flow.md](../architecture/03-data-flow.md) — playback initiation. The +durable half is the layer line and the `StreamSelection` contract; phases and +acceptance criteria are disposable. + +## Summary + +Make Rust the single owner of *which stream to play* — direct play or transcode, +at what ceiling, over what transport — and hand every player backend a +self-describing selection instead of a bare URL. mpv, ExoPlayer and the HTML5 +`