Skip to content

fix(chrome-extension): keep camera preview alive across tab hand-offs and retry failed connects - #2022

Open
ManthanNimodiya wants to merge 3 commits into
CapSoftware:mainfrom
ManthanNimodiya:fix/extension-camera-preview-handoff
Open

fix(chrome-extension): keep camera preview alive across tab hand-offs and retry failed connects#2022
ManthanNimodiya wants to merge 3 commits into
CapSoftware:mainfrom
ManthanNimodiya:fix/extension-camera-preview-handoff

Conversation

@ManthanNimodiya

@ManthanNimodiya ManthanNimodiya commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Fixes the "front camera never loads again after switching tabs" report from Discord.

Two problems combined: switching tabs stopped and reopened the physical camera with no synchronization, and the preview iframe had no retry, one failure left the tile dead until camera settings changed, which is why deselect/reselect fixed it.

  • Offscreen doc keeps the shared camera stream warm for 2s across hand-offs, registers new sessions before the stream await, and dedups concurrent getUserMedia calls
  • Preview iframe retries failed connects with capped backoff (skipping permission errors) and reconnects when the remote track ends, stays muted, or the peer fails

Repro: with the preview live, seize the camera with another app and switch tabs, previously the tile stayed dead after freeing the camera; now it recovers on its own.

Greptile Summary

This PR improves camera-preview recovery across tab hand-offs.

  • Keeps the shared camera stream warm briefly and deduplicates concurrent camera acquisition.
  • Registers preview sessions before awaiting camera access.
  • Retries recoverable connection failures with capped backoff.
  • Reconnects after sustained peer disconnection, track mute, or track termination.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previous transient-disconnection issue is addressed by waiting through a bounded grace period, cancelling reconnection when the peer recovers, and reconnecting only when disconnection persists.

Important Files Changed

Filename Overview
apps/chrome-extension/src/offscreen/recorder.ts Adds synchronized camera acquisition and delayed stream release to preserve the shared preview during tab hand-offs.
apps/chrome-extension/src/preview/camera-preview.tsx Adds retry and liveness handling, including the grace period that resolves the previously reported transient-disconnection teardown.

Reviews (2): Last reviewed commit: "fix(chrome-extension): cancel pending mu..." | Re-trigger Greptile

Comment on lines +505 to +509
if (
peer.connectionState === "failed" ||
peer.connectionState === "disconnected" ||
peer.connectionState === "closed"
) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Transient Disconnect Tears Down Preview

A peer can enter disconnected briefly and recover to connected, but this branch immediately closes it and starts another camera hand-off. A temporary connection interruption therefore causes an avoidable black frame and camera restart instead of allowing the active peer to recover.

Suggested change
if (
peer.connectionState === "failed" ||
peer.connectionState === "disconnected" ||
peer.connectionState === "closed"
) {
if (
peer.connectionState === "failed" ||
peer.connectionState === "closed"
) {
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/chrome-extension/src/preview/camera-preview.tsx
Line: 505-509

Comment:
**Transient Disconnect Tears Down Preview**

A peer can enter `disconnected` briefly and recover to `connected`, but this branch immediately closes it and starts another camera hand-off. A temporary connection interruption therefore causes an avoidable black frame and camera restart instead of allowing the active peer to recover.

```suggestion
				if (
					peer.connectionState === "failed" ||
					peer.connectionState === "closed"
				) {
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +487 to +491
const reconnect = () => {
if (disposed || peerRef.current !== peer) return;
stopPreview();
void startPreview(0);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: when reconnect() runs, it might leave retryTimer / muteTimer pending (they’ll no-op due to peerRef guard, but still keep closures alive). Clearing them here avoids stray timers and makes the reconnect path a bit tighter.

Suggested change
const reconnect = () => {
if (disposed || peerRef.current !== peer) return;
stopPreview();
void startPreview(0);
};
const reconnect = () => {
if (disposed || peerRef.current !== peer) return;
clearRetryTimer();
clearMuteTimer();
stopPreview();
void startPreview(0);
};

@ManthanNimodiya

Copy link
Copy Markdown
Contributor Author

@greptileai

@ManthanNimodiya
ManthanNimodiya force-pushed the fix/extension-camera-preview-handoff branch from 13421c8 to 59f7a7c Compare August 6, 2026 05:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant