Add wave for the recording mic + unify web cameras#1329
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Here's a visual recap of what changed: |
There was a problem hiding this comment.
Builder reviewed your changes and found 3 potential issues 🔴
Review Details
This PR removes the bubble’s dedicated local-camera path and consolidates preview rendering onto the popover-owned WebRTC/canvas relay, while also replacing the fake mic bars with a live analyser-driven waveform. The simplification makes stream ownership easier to follow overall, and the updated comments/cleanup logic keep the popover as the long-lived owner of preview media, which is the right architectural direction for WebKit/Tauri.
Risk assessment: Standard (medium). The main risk here is cross-webview media-capture behavior on macOS, where small lifecycle changes can blank preview or reopen devices unexpectedly.
Key findings:
- 🔴 The new mic meter is allowed to call
getUserMediawhile the camera bubble is live, reintroducing the WebKit capture-exclusion bug this PR is otherwise trying to avoid. - 🟡 The meter falls back to
audio: truefor the pseudo/default mic path, so opening the popover can activate the OS default microphone just to animate the waveform. - 🟡 The meter only disables after recorder installation, leaving a startup window where its mic stream overlaps the recorder’s own mic acquisition.
🧪 Browser testing: Will run after this review (PR touches UI code)
| onToggle={setMicOn} | ||
| systemAudio={systemAudioOn} | ||
| onSystemAudioToggle={setSystemAudioOn} | ||
| meterActive={popoverVisible && !isRecording} |
There was a problem hiding this comment.
🔴 Mic meter can blank the camera bubble on macOS
meterActive={popoverVisible && !isRecording} lets the new waveform open its own getUserMedia({ audio… }) session while the camera bubble is already live. This codebase explicitly documents that, in Tauri/WebKit, a sibling webview doing that mutes the bubble’s camera stream, so turning the mic meter on here can black out preview again.
There was a problem hiding this comment.
This was a problem before, when different windows called getUserMedia. This PR changes that, and now all the getUserMedia calls are owned by the popover
| stream = await navigator.mediaDevices.getUserMedia({ | ||
| audio: deviceId ? { deviceId: { exact: deviceId } } : true, |
There was a problem hiding this comment.
🟡 Default-mic waveform opens the OS input just by opening the popover
When deviceId is empty this falls back to audio: true, and selectedMicId is intentionally empty for the default/pseudo-device path. That means simply opening the popover with mic enabled now grabs the system default microphone, regressing the existing safeguard against unexpected permission prompts and Bluetooth hands-free mode flips.
| onToggle={setMicOn} | ||
| systemAudio={systemAudioOn} | ||
| onSystemAudioToggle={setSystemAudioOn} | ||
| meterActive={popoverVisible && !isRecording} |
There was a problem hiding this comment.
🟡 Waveform stays active during recorder startup
This guard only turns the meter off after isRecording flips true, but startRecording() starts its own mic getUserMedia before the recorder handle is installed. That leaves a startup window where the waveform stream overlaps the recorder’s real capture stream, which this codebase already calls out as a source of flaky mic acquisition on macOS.
1. Removed the "local camera" path in the bubble
The camera bubble previously had two ways to show your face: the normal WebRTC relay from the popover, and a special "local camera" mode that kicked in during native full-screen recording. In local mode, the bubble owned the camera directly and had to relay device lists back to the popover, because WebKit blocks a second page from accessing the camera without muting the first one.
That entire local camera path is gone. The bubble now always receives video through WebRTC or the canvas relay, regardless of recording mode. This removes a large amount of coordination code — no more device list relay events, no more fallback camera/mic state in the popover, no more separate startup and teardown flow for the full-screen case. The recorder also no longer needs to choose between two different "hide chrome" commands based on who owns the camera.
2. Mic wave is now driven by real audio
The mic wave indicator was previously a CSS animation — four bars that pulsed on a loop with no connection to what the microphone was actually picking up.
It has been replaced with a real-time SVG wave line. A new
useMicMeterhook opens an audio analyser on the selected mic, samples it 20 times per second, and draws an oscillating wave that reacts to actual sound — it moves when you speak and flattens when silent. The meter only runs while the popover is open and you are not recording.The visual design also changed: from bars positioned at the bottom of the row to an inline wave line between the device name and the dropdown arrow, with a soft fade at both ends.
