From a8217e56cb12a858e85fd1a2333506330d660abd Mon Sep 17 00:00:00 2001 From: Gareth Morgan Date: Wed, 4 Nov 2026 22:31:47 -0800 Subject: [PATCH 01/37] egocap: preview Orin cameras directly from LiveKit in the browser Add an optional livekit_preview station section, GET /api/livekit-preview (room, publisher, tracks and a subscribe-only viewer token), and browser video tiles that subscribe to the configured publisher's tracks. The backend never decodes or relays video, and these cameras are preview-only: they are not requested from CaptureServer and are not recorded. Not exercised against a real LiveKit server or the Orin publisher. Co-Authored-By: Claude Sonnet 5.5 Signed-off-by: Gareth Morgan --- examples/egocap/LIVEKIT_PREVIEW.md | 86 +++++ examples/egocap/backend/README.md | 2 + examples/egocap/backend/egocap_web/app.py | 5 + .../backend/egocap_web/livekit_preview.py | 114 ++++++ .../backend/egocap_web/station_config.py | 56 +++ examples/egocap/frontend/package-lock.json | 120 +++++++ examples/egocap/frontend/package.json | 1 + .../src/App.liveRecordingWire.test.tsx | 2 + .../frontend/src/App.operatorLayout.test.tsx | 8 +- examples/egocap/frontend/src/App.test.tsx | 8 +- .../frontend/src/CameraGrid.livekit.test.tsx | 109 ++++++ .../egocap/frontend/src/CameraGrid.test.tsx | 8 +- examples/egocap/frontend/src/CameraGrid.tsx | 24 +- .../frontend/src/LiveKitCameraTile.test.tsx | 129 +++++++ .../egocap/frontend/src/LiveKitCameraTile.tsx | 100 ++++++ .../frontend/src/livekitPreview.test.ts | 87 +++++ .../egocap/frontend/src/livekitPreview.ts | 77 ++++ .../egocap/frontend/src/livekitTestDoubles.ts | 70 ++++ examples/egocap/frontend/src/styles.css | 27 ++ .../frontend/src/useLiveKitPreview.test.ts | 339 ++++++++++++++++++ .../egocap/frontend/src/useLiveKitPreview.ts | 166 +++++++++ .../tests/backend/test_livekit_preview.py | 180 ++++++++++ .../backend/test_station_config_livekit.py | 145 ++++++++ 23 files changed, 1858 insertions(+), 5 deletions(-) create mode 100644 examples/egocap/LIVEKIT_PREVIEW.md create mode 100644 examples/egocap/backend/egocap_web/livekit_preview.py create mode 100644 examples/egocap/frontend/src/CameraGrid.livekit.test.tsx create mode 100644 examples/egocap/frontend/src/LiveKitCameraTile.test.tsx create mode 100644 examples/egocap/frontend/src/LiveKitCameraTile.tsx create mode 100644 examples/egocap/frontend/src/livekitPreview.test.ts create mode 100644 examples/egocap/frontend/src/livekitPreview.ts create mode 100644 examples/egocap/frontend/src/livekitTestDoubles.ts create mode 100644 examples/egocap/frontend/src/useLiveKitPreview.test.ts create mode 100644 examples/egocap/frontend/src/useLiveKitPreview.ts create mode 100644 examples/egocap/tests/backend/test_livekit_preview.py create mode 100644 examples/egocap/tests/backend/test_station_config_livekit.py diff --git a/examples/egocap/LIVEKIT_PREVIEW.md b/examples/egocap/LIVEKIT_PREVIEW.md new file mode 100644 index 0000000000..d287358b5c --- /dev/null +++ b/examples/egocap/LIVEKIT_PREVIEW.md @@ -0,0 +1,86 @@ + + +# Live camera preview over LiveKit + +The camera host (an Orin running the SENSING publisher) publishes hardware-encoded H.264 into a LiveKit room. The +browser subscribes to those tracks itself and decodes them, so the egocap backend only tells it where the room is and +hands it a subscribe-only token. CaptureServer keeps doing tracking and control. + +```text +Orin: SIPL -> hardware H.264 -> LiveKit publisher --> LiveKit server --> browser