Conversation
Adds in-call participant video: publish the local camera via WHIP and consume remote video via WHEP (H264 over SMB), with self-preview, per-tile video grid, source pinning, return-feed and fullscreen controls, plus the video-enabled toggle in production setup.
e37fafa to
e94e56f
Compare
birme
left a comment
There was a problem hiding this comment.
Automated code-reviewer verdict (daily-backlog-pr Phase 3): NEEDS CHANGES
Reviewed the full +4752/−261 diff across 69 files with the branch checked out. Feature-scoped work that mirrors the existing audio patterns well, with good coverage of the new pure logic. Two concrete media-lifecycle bugs should be fixed before shipping a camera feature:
High
- Camera capture is never stopped on call exit (privacy/hardware leak).
production-line.tsx:149destructures onlyconst [inputVideoStream] = useVideoInput({...}), discarding the third tuple element — thereset()that stops the camera tracks.useVideoInput.reset(use-video-input.ts:67-72) is the only placevideoInput.getTracks().forEach(t => t.stop())runs, and it's never called. The effect cleanup (:62-64) only setsaborted = true;REMOVE_CALL(global-state-reducer.ts:123) doesn't stopmediaStreamVideoInput; andrtcPeerConnection.close()doesn't stop local getUserMedia tracks. Net: camera stays live + recording indicator on after leaving a video line, until the tab closes. Capture and call the videoreseton exit/unmount. - Frame-monitor
setIntervals leak on unmount.attachShowWhenReady(video-element-factory.ts:470-490) starts a 500ms interval per remote video element, cleared only bystopFrameMonitor, which is called only fromremoveThisElementon trackended/removetrack.useVideoElementscleanup (use-video-elements.ts:11-24) nullssrcObjectbut doesn't callstopFrameMonitor, nor does theuseRtcConnectionteardown. On abrupt teardown/navigation the interval + rVFC loop keep running against detached elements. CallstopFrameMonitorfor every element incleanUpVideo.
Medium
checkbox.tsx:76-87— input madereadOnly+tabIndex={-1}with toggle delegated to wrapperonClick, synthesizing a fakeChangeEventviaas unknown as. Removes keyboard focus/space-to-toggle from a shared primitive (a11y regression + scope creep). Prefer a nativedisabledprop.- PC held in
useState(never recreated) but stream refs are in the effect deps — a stream-ref change wouldclose()the PC and the re-run no-ops behindsignalingState === "closed"guards, dead-ending the call. Latent today (no device-switch re-acquire); add a guard/comment. - No test asserting camera tracks stop / frame monitors clear on exit — exactly where the leaks live.
Nits
- Raw
console.warn/errorin prod paths vs the projectloggerutil;video-element-factory.tsbuilds ~540 lines of tile chrome via imperativecreateElement+inline styles vs Emotionstyled()used elsewhere.
Notes: no user-input URL construction (all via backend API_URL), no new bundle secrets, reducer ERROR change well-contained, CI green. Both High items are small localized fixes.
…n#692) Capture the useVideoInput reset() and invoke it on exit and on unmount so camera tracks (getUserMedia) are stopped, releasing the hardware/indicator. Call stopFrameMonitor for every element in useVideoElements cleanUpVideo so the 500ms frame-monitor setInterval no longer leaks on teardown. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
This PR looks like part of a multi-repo/multi-PR dependency stack together with Eyevinn/intercom-manager#315 (backend video support). Holding off on automated review/merge here — this needs a human (or the relevant implementation agent) to assess the whole stack together, not a per-PR pass. |
Adds in-call participant video: publish the local camera via WHIP and consume remote video via WHEP (H264/VP8 over SMB), with self-preview, per-tile video grid, source pinning, return-feed and fullscreen controls, plus the video-enabled toggle in production setup.
Closes #692
Companion PR (backend): Eyevinn/intercom-manager#315