diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-18 09:47:01 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-18 09:49:27 +0200 |
| commit | c03512aeab576a06f8d5026e5eb484897ec45f99 (patch) | |
| tree | 81a2f319273d01610b1851da6e3ba20b5d2c0886 /docs/MESHBAY_DESIGN.md | |
| parent | 4742aa685129cf790d3f7510238919ffde15a949 (diff) | |
| download | meshbay-c03512aeab576a06f8d5026e5eb484897ec45f99.tar.gz | |
feat(cast): carry subtitles to a Chromecast, on the relay's clock
The relay forwards the node's fragments untouched, and those begin at zero
at the seek point. The player never notices because its SourceBuffer is given
`timestampOffset = start`; a receiver has no equivalent, so the cues are
shifted by `-start` before they leave, recomputed at every restart of the
relay. Sent as they are, a subtitle would be out by the whole seek.
The document is served from the relay's own port at /subs.vtt, behind the same
token as the stream and with CORS: a receiver fetches a side-loaded track with
XHR from its own origin, and without the headers it fails as a network error
with nothing on screen to say so. The URL carries a version because a track is
cached by address — changing the cues behind a fixed URL leaves the previous
language showing.
Cues that end before the stream begins are dropped rather than clamped, so a
line from before the seek cannot appear over the first frames after it.
The relay is plain Node, so the tests start it and fetch from it rather than
reading its source.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGY17EPph5LsLzePPXhUVc
Diffstat (limited to 'docs/MESHBAY_DESIGN.md')
| -rw-r--r-- | docs/MESHBAY_DESIGN.md | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md index 8f91a87..781438a 100644 --- a/docs/MESHBAY_DESIGN.md +++ b/docs/MESHBAY_DESIGN.md @@ -2596,6 +2596,25 @@ any LAN renderer can play; the relay is device-agnostic. Chromecast discovery an control ship. DLNA/UPnP is designed and not built: it is a second device backend beside the first, not a second relay. +**Subtitles are rebased onto the relay's clock before they are sent.** The node +extracts a track whole, so its cues carry the film's timeline, and the player +can use them unchanged because its SourceBuffer is given `timestampOffset = +start`. The relay has no such offset: it forwards the node's fragments, which +begin at zero at the seek point. A receiver is therefore sent the cues shifted +by `-start`, recomputed at every restart of the relay, and cues that end before +the stream begins are dropped rather than clamped to zero. + +**The subtitle is served from the relay's own port, behind the same token as the +stream, and with CORS.** A receiver fetches a side-loaded track with XHR from +its own origin rather than handing it to a media element, so without +`Access-Control-Allow-Origin` it fails as a network error and the film plays on +with no subtitles and no message. The stream carries the same headers, because a +receiver given a side-loaded track reads the media through the same checked +path: on one and not the other, the load fails whole. They widen nothing the +token does not already govern. The subtitle URL carries a version because a +receiver caches a track by address: changing the cues behind a fixed URL leaves +the previous language on screen. + --- ## 12. Testing posture |