Add microphone device selection and permission handling#212
Add microphone device selection and permission handling#212traumafactory0 wants to merge 1 commit intosohzm:masterfrom
Conversation
📝 WalkthroughWalkthroughThis change introduces audio input device selection functionality for the application. Users can now select a preferred microphone device from a dropdown in the customize view. The selected device is persisted in storage and applied as a constraint during audio capture operations in the renderer module. Changes
Sequence DiagramsequenceDiagram
participant User as User (Settings)
participant UI as CustomizeView
participant Storage as Storage
participant Browser as Browser API
participant Capture as Renderer (Capture)
User->>UI: Opens Settings
UI->>Browser: getAudioInputDevices()
Browser-->>Browser: Request mic permission
Browser-->>UI: Returns device list [{deviceId, label}]
UI->>UI: Displays dropdown with devices
User->>UI: Selects device
UI->>Storage: Save audioInputDeviceId
User->>Capture: Start Recording
Capture->>Storage: Load audioInputDeviceId
Capture->>Browser: startCapture() with<br/>audio constraints (deviceId)
Browser-->>Capture: Stream with selected device
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/components/views/CustomizeView.js`:
- Around line 489-494: The updated() hook never sees changes because
audioDeviceDropdownOpen is not declared as a reactive property; add
audioDeviceDropdownOpen to the component's static properties (with type: Boolean
and a default of false) so changedProperties.has('audioDeviceDropdownOpen')
becomes true when it toggles and the existing logic that sets
_audioDropdownListenerAdded and calls document.addEventListener('click',
this._closeAudioDropdown) will run; keep _audioDropdownListenerAdded and
_closeAudioDropdown as-is (or alternatively, if you prefer Option B, remove the
updated() logic and instead attach/detach the document click listener directly
inside the dropdown toggle handler).
| updated(changedProperties) { | ||
| if (changedProperties.has('audioDeviceDropdownOpen') && this.audioDeviceDropdownOpen && !this._audioDropdownListenerAdded) { | ||
| this._audioDropdownListenerAdded = true; | ||
| setTimeout(() => document.addEventListener('click', this._closeAudioDropdown), 0); | ||
| } | ||
| } |
There was a problem hiding this comment.
Bug: outside-click handler is never attached — audioDeviceDropdownOpen is not a reactive property.
changedProperties.has('audioDeviceDropdownOpen') will always be false because audioDeviceDropdownOpen is not declared in static properties (lines 297–315). LitElement's changedProperties map only tracks reactive properties. As a result, _closeAudioDropdown is never registered on document, and clicking outside the dropdown won't close it.
A quick fix is to add audioDeviceDropdownOpen to static properties, or attach/detach the listener directly in the toggle handler instead of relying on updated().
Option A: declare it as a reactive property (simplest)
static properties = {
selectedProfile: { type: String },
selectedLanguage: { type: String },
selectedImageQuality: { type: String },
layoutMode: { type: String },
keybinds: { type: Object },
googleSearchEnabled: { type: Boolean },
backgroundTransparency: { type: Number },
fontSize: { type: Number },
theme: { type: String },
onProfileChange: { type: Function },
onLanguageChange: { type: Function },
onImageQualityChange: { type: Function },
onLayoutModeChange: { type: Function },
isClearing: { type: Boolean },
isRestoring: { type: Boolean },
clearStatusMessage: { type: String },
clearStatusType: { type: String },
+ audioDeviceDropdownOpen: { type: Boolean },
};Option B: attach listener directly in the toggle handler
`@click`=${(e) => {
e.stopPropagation();
if (this.audioInputDevicesLoading || this.audioInputDevices.length === 0) return;
this.audioDeviceDropdownOpen = !this.audioDeviceDropdownOpen;
+ if (this.audioDeviceDropdownOpen) {
+ setTimeout(() => document.addEventListener('click', this._closeAudioDropdown), 0);
+ } else {
+ document.removeEventListener('click', this._closeAudioDropdown);
+ }
this.requestUpdate();
}}Then updated() can be removed entirely.
🤖 Prompt for AI Agents
In `@src/components/views/CustomizeView.js` around lines 489 - 494, The updated()
hook never sees changes because audioDeviceDropdownOpen is not declared as a
reactive property; add audioDeviceDropdownOpen to the component's static
properties (with type: Boolean and a default of false) so
changedProperties.has('audioDeviceDropdownOpen') becomes true when it toggles
and the existing logic that sets _audioDropdownListenerAdded and calls
document.addEventListener('click', this._closeAudioDropdown) will run; keep
_audioDropdownListenerAdded and _closeAudioDropdown as-is (or alternatively, if
you prefer Option B, remove the updated() logic and instead attach/detach the
document click listener directly inside the dropdown toggle handler).
Problem
Some mics (e.g. Logitech G733) didn’t work: the app didn’t ask for permission in a way that exposes the device list, so sessions could fail.
What changed
Summary by CodeRabbit
Release Notes