Skip to content

Add wave for the recording mic + unify web cameras#1329

Open
shomix wants to merge 4 commits into
mainfrom
shomix-p-camera-wave
Open

Add wave for the recording mic + unify web cameras#1329
shomix wants to merge 4 commits into
mainfrom
shomix-p-camera-wave

Conversation

@shomix

@shomix shomix commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

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 useMicMeter hook 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.
image

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Here's a visual recap of what changed:

Open the full interactive recap

@shomix shomix changed the title Shomix p camera wave Add wave for the recording mic + unify web cameras Jun 19, 2026

@builder-io-integration builder-io-integration Bot left a comment

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.

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 getUserMedia while the camera bubble is live, reintroducing the WebKit capture-exclusion bug this PR is otherwise trying to avoid.
  • 🟡 The meter falls back to audio: true for 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}

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.

🔴 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.

Fix in Builder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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

Comment on lines +98 to +99
stream = await navigator.mediaDevices.getUserMedia({
audio: deviceId ? { deviceId: { exact: deviceId } } : true,

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.

🟡 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.

Fix in Builder

onToggle={setMicOn}
systemAudio={systemAudioOn}
onSystemAudioToggle={setSystemAudioOn}
meterActive={popoverVisible && !isRecording}

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.

🟡 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.

Fix in Builder

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.

2 participants