From f6e2b7edda355cb1afcb2c45c088db9f5ceb803e Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 25 Jun 2026 10:48:09 -0700 Subject: [PATCH] Use persistent WebTransport frame stream --- AGENTS.md | 2 ++ README.md | 6 +++--- public/app.js | 57 ++++++++++++++++++++++++++++++++++++++----------- server/index.js | 39 +++++++++++++++++++++++++-------- 4 files changed, 79 insertions(+), 25 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 17e3d65..c8f04a7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,6 +48,8 @@ Audio is the playback clock. The server sends JPEG frames over WebSocket by defa - First 8 bytes: little-endian float64 timestamp in seconds. - Remaining bytes: one complete JPEG image. +WebSocket sends one binary frame packet per message. WebTransport uses one persistent server-to-client unidirectional frame stream: the stream begins with the single byte `WT_STREAM_FRAME`, then repeats records of 4-byte little-endian uint32 packet length followed by one complete binary frame packet. Do not open one WebTransport stream per JPEG frame; that caused poor device performance at normal frame rates. + The frontend decodes JPEGs with browser image APIs, queues frames, and paints frames whose timestamps are due relative to `audio.currentTime`. This means the browser decodes only audio and still images, not video. ## Why JPEG Frames diff --git a/README.md b/README.md index a5f14f6..81fea63 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A small web app that plays a remote video stream without using browser video decoding. The server uses `ffmpeg` to decode the input URL into: - an MP3 audio stream served to a normal `