Repository navigation
feat(desktop): warn when the recording's microphone or camera disconnects - #4263
richiemcilroy wants to merge 2 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
Sandchest reviewed Sandchest reviews every change for vulnerabilities an attacker could use · 3 credits · Review details |
| let actor = self | ||
| .active | ||
| .as_ref() | ||
| .and_then(|active| active.switched_microphone_actor()) | ||
| .or_else(|| Feeds::global(cx).read(cx).mic_actor()); |
There was a problem hiding this comment.
Reconnect skips recording-owned fallback feeds
Medium Severity
When start_attempt_with_upload cannot lock an app feed or receives no live app actor, it opens a recording-owned _mic_feed or _camera_feed. These are distinct from the Instant-switched microphone feed. After unplug/replug, this actor selection ignores _mic_feed, so it either returns without reopening or reopens an unrelated app feed. reopen_camera likewise only restarts the app preview. The recording therefore continues without microphone audio or camera frames even if the preview recovers and clears its warning. Retain and reconnect the actual feeds locked by the active recording, including startup fallbacks.
| .is_some_and(|session| session.read(cx).disconnected_inputs().camera); | ||
| let session_subscription = session.map(|session| { | ||
| cx.observe(&session, |this: &mut Self, session, cx| { | ||
| let disconnected = session.read(cx).disconnected_inputs().camera; |
There was a problem hiding this comment.
Camera disconnect warnings persist after recording stops
Medium Severity
Disconnect the camera during recording, stop before reconnecting it, then reconnect or select a working camera in the idle preview. RecordingSession::finish leaves input_watch.disconnected.camera set, the watcher exits outside Phase::Recording, and only the next recording activation resets it. Both this subscription and the preview initializer consume the stale flag without a phase check, so the disconnect overlay remains over healthy video. Clear recording-scoped disconnect state on completion and prevent late reconnect callbacks from restoring stale state, or gate the preview flag to a live recording.
| pub fn disconnected_inputs(&self) -> DisconnectedInputs { | ||
| self.input_watch.disconnected |
There was a problem hiding this comment.
Camera warning outlives recording
disconnected_inputs() keeps returning the last recording's flags after it stops. If the camera disconnects and the user stops before reconnecting it, the watch exits without clearing the flag. The bubble reads that flag outside a recording, so selecting a working camera still leaves it covered by “Camera disconnected” until another recording starts. Clear the flags when recording ends, or return no disconnected inputs outside Phase::Recording.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/session/input_watch.rs
Line: 71-72
Comment:
**Camera warning outlives recording**
`disconnected_inputs()` keeps returning the last recording's flags after it stops. If the camera disconnects and the user stops before reconnecting it, the watch exits without clearing the flag. The bubble reads that flag outside a recording, so selecting a working camera still leaves it covered by “Camera disconnected” until another recording starts. Clear the flags when recording ends, or return no disconnected inputs outside `Phase::Recording`.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| microphone: feeds | ||
| .microphone | ||
| .clone() | ||
| .filter(|_| active.mic_mute.is_some() && switching != Some(InputKind::Microphone)), |
There was a problem hiding this comment.
Disabled microphone still warns
An Instant recording still watches the microphone after the user chooses “No Microphone.” That choice only sets mic_muted; it leaves feeds.microphone and active.mic_mute populated. This filter therefore keeps watching the disabled microphone and raises a warning if it is unplugged. Skip watching it while Instant has it muted, while preserving the ability to reopen it when enabled again.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/session/input_watch.rs
Line: 109-112
Comment:
**Disabled microphone still warns**
An Instant recording still watches the microphone after the user chooses “No Microphone.” That choice only sets `mic_muted`; it leaves `feeds.microphone` and `active.mic_mute` populated. This filter therefore keeps watching the disabled microphone and raises a warning if it is unplugged. Skip watching it while Instant has it muted, while preserving the ability to reopen it when enabled again.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| let presence = cx | ||
| .background_executor() | ||
| .spawn(async move { list_presence(&watched) }) | ||
| .await; | ||
| if this | ||
| .update(cx, |this, cx| this.apply_presence(generation, presence, cx)) |
There was a problem hiding this comment.
Old poll restarts replacement camera
The poll result is applied without checking which devices it describes. A user can switch from unplugged camera A to working camera B while enumeration runs. A's result then marks B disconnected; the next poll unnecessarily restarts B and interrupts its preview. Carry WatchedInputs back with the result and discard results for inputs that changed or now have a switch pending.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/session/input_watch.rs
Line: 88-93
Comment:
**Old poll restarts replacement camera**
The poll result is applied without checking which devices it describes. A user can switch from unplugged camera A to working camera B while enumeration runs. A's result then marks B disconnected; the next poll unnecessarily restarts B and interrupts its preview. Carry `WatchedInputs` back with the result and discard results for inputs that changed or now have a switch pending.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| /// Marks `at` in a Studio recording and returns the new marker count. | ||
| /// Instant recordings have no editor timeline to put a marker on, so | ||
| /// they take none. | ||
| /// The feed a microphone switch moved the recording onto, if any. |
There was a problem hiding this comment.
Method documentation describes another action
The new comment above switched_microphone_actor() repeats the method's name and leaves the existing marker documentation attached to the wrong method. AGENTS.md requires comments to explain non-obvious context rather than narrate the code. Remove the redundant line and move the marker documentation back to add_marker(). The new comments above WatchedInputs and disconnected_issue() also repeat their code. This repository requirement must be satisfied before merging.
Context Used: AGENTS.md (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/recording.rs
Line: 871
Comment:
**Method documentation describes another action**
The new comment above `switched_microphone_actor()` repeats the method's name and leaves the existing marker documentation attached to the wrong method. `AGENTS.md` requires comments to explain non-obvious context rather than narrate the code. Remove the redundant line and move the marker documentation back to `add_marker()`. The new comments above `WatchedInputs` and `disconnected_issue()` also repeat their code. This repository requirement must be satisfied before merging.
**Context Used:** AGENTS.md ([source](https://github.com/capsoftware/cap/blob/main/AGENTS.md))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.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!

Stacked on #4262.
When the microphone or camera disappears mid-recording, the GPUI app said nothing: the bar's issue card only covered errors, sleep pause and low storage (
controls_window.rs), and the camera bubble had no "Camera disconnected" overlay (camera_window.rslisted it as a known gap). The Tauri app warned in both places (in-progress-recording.tsx:199-208,camera.tsx:66,162) and reopened the device when it came back. This brings that back.sequenceDiagram participant W as Input watch (1 s poll) participant S as RecordingSession participant F as Feed the recording reads participant UI as Bar + bubble W->>S: selected mic / camera missing from the device list S->>UI: "Microphone disconnected. Silence will be used until it reconnects." Note over F: recording continues: mic source fills silence, camera track gets no frames W->>S: same device listed again S->>F: SetInput(same device) on the locked feed F-->>S: ready S->>UI: warning clearssession/input_watch.rs): while a recording is live (running or paused), poll the microphone names and camera device ids once a second, as Tauri'sspawn_microphone_watcher/spawn_camera_watcherdid. Only the inputs the recording uses are watched: an input switched to "None", or one with a switch in flight, is never reported missing.LockedInputReconnected), so Studio and Instant both resume on it. After an Instant mic switch (feat(desktop): recording settings menu with mid-recording microphone and camera switching #4262) that is the switched-to feed. The warning clears only once the reopen succeeds; a failed reopen retries on the next poll.Edge cases
Tests
session::input_watch::tests: a missing device warns and its return asks for a reopen while the warning stays until the reopen succeeds; an input the recording stopped using never warns.Proof
Pending (hardware unplug runs on the Mac mini are blocked on a microphone permission grant); this section will carry the unplug/replug recordings and A/V sync against
main.The behavior issues are non-blocking, but the explicit comments policy must be satisfied before merging.
Findings
Fix with agent prompt
Summary
Adds recording-time microphone and camera disconnect warnings, retries returned devices, and adds translated text for the controls bar and camera bubble.
Review used source inspection. Hardware unplug/replug behavior and native UI rendering were not run.
Reviews (1) · Last reviewed commit: "style: rustfmt" · Reviewed by Greptile