diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-05 01:16:12 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-05 01:16:12 +0200 |
| commit | 243bcf017b4957237b3ddf556bd0a37296eb8798 (patch) | |
| tree | 7d0820796737aad4dcfb89de7bec1e7271759af6 /docs/MESHBAY_DESIGN.md | |
| parent | ac8ed437659d765120d1b0cc9f83e942549b479f (diff) | |
| download | meshbay-243bcf017b4957237b3ddf556bd0a37296eb8798.tar.gz | |
feat(cast): photos on the TV, and a television chosen once for the session
A cast button in Videos' toolbar, at the top of Photos, in an album's bar and
in the lightbox, in a group and in Search alike. A television chosen there is
kept for the session: a film opened plays on it with the player as its remote
from the start, and a photo opened in the lightbox is shown on it, scaled to
1920x1080, upright, as JPEG. The lightbox gains a slideshow.
The relay serves one photo at /image behind the stream's token, on the desktop
and on Android; the shell, not the page, decides that the receiver loads it as
a picture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs/MESHBAY_DESIGN.md')
| -rw-r--r-- | docs/MESHBAY_DESIGN.md | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md index 525c5c3..64364b0 100644 --- a/docs/MESHBAY_DESIGN.md +++ b/docs/MESHBAY_DESIGN.md @@ -3422,6 +3422,36 @@ lands the target is shown, not the old stream's position. Pausing the receiver pauses the local element too, which otherwise goes on fetching for nobody. The copy-URL cast has no receiver to read and keeps the ordinary player. +**A television is chosen for the session, not for one film** +(`cast-session.js`). Any cast button — Videos' toolbar, the Photos toolbar, a +photo album's bar, the lightbox, the player — sets it, and it is held in memory +only. A film opened +while one is set starts its cast as a restart does: pending until the first +segment, then the relay and `connect` (or `reload`, when the receiver is already +connected), with the player drawn as the remote from the start. *Stop casting* +clears it, from the player's remote or from any button. + +**A photo is served at `/image`, one at a time** (`cast:image`). The page scales +it to fit 1920×1080, applies its EXIF orientation and re-encodes it as JPEG +before it leaves: a camera original is too large for a receiver to decode in good +time, and some formats it does not decode at all. The relay starts for it if +nothing else has, serves it behind the stream's token with a versioned address +(a receiver handed the same URL twice shows what it already has), and accepts +only `image/jpeg`, `image/png` or `image/webp`. **The shell, not the page, says +what the receiver loads:** the relay's photo URL is loaded as a picture +(`streamType: NONE`, photo metadata, no subtitles), any other relay URL as the +stream, and on Android no URL but the relay's own is accepted at all. A photo +does not start the foreground service, and its load answers as soon as the +receiver accepts it: a photo never reaches PLAYING. Only the newest photo asked +for is sent; paging quickly shows where the reader stopped. + +**The interface itself is not cast.** The default media receiver plays what it +is given and renders nothing of its own, and a rendered interface sent to it as +live video does not work: it starts a progressive stream that arrives at real +time only when the stream carries audio and its first seconds arrive faster than +real time, and then holds that lead as latency — five seconds, measured. Showing +the application on a television needs a registered receiver of our own. + **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 = |