From c03512aeab576a06f8d5026e5eb484897ec45f99 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Fri, 18 Sep 2026 09:47:01 +0200 Subject: feat(cast): carry subtitles to a Chromecast, on the relay's clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_01UGY17EPph5LsLzePPXhUVc --- packages/meshbay-client/src/preload.js | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/meshbay-client/src/preload.js') diff --git a/packages/meshbay-client/src/preload.js b/packages/meshbay-client/src/preload.js index c9c9fe0..c2a2bd4 100644 --- a/packages/meshbay-client/src/preload.js +++ b/packages/meshbay-client/src/preload.js @@ -139,6 +139,7 @@ contextBridge.exposeInMainWorld('meshbay', { start: (opts) => ipcRenderer.invoke('cast:start', opts), push: (data) => ipcRenderer.invoke('cast:push', data), stop: () => ipcRenderer.invoke('cast:stop'), + subtitle: (sub) => ipcRenderer.invoke('cast:subtitle', sub), finish: () => ipcRenderer.invoke('cast:finish'), status: () => ipcRenderer.invoke('cast:status'), discover: () => ipcRenderer.invoke('cast:discover'), -- cgit v1.2.3