feat(desktop): hold announcements while another app uses the microphone - #646
charleslpan wants to merge 2 commits into
Conversation
The only quiet Luke had was a calendar interval, which misses unscheduled calls, calls that run over, and everyone with no calendar connected. macOS already knows: CoreAudio says whether any process is capturing from an input device, one boolean, no permission, no audio. A new native helper reports that boolean and nothing else, watching every input device rather than only the default, and reading a Bluetooth output's drop to its call codec because a Bluetooth microphone does not set the running flag while in use. A pure gate turns it into a hold: a foreign capture — Luke's own exchange excluded — holds after a short onset and releases a grace after it stops. The hold pools with the meetings under the one flag the renderer already draws the sleeping face from, so the face, the announcer, and their tests are unchanged, and the same setting governs both. A released backlog now speaks its newest three rather than eight. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4bd8d34. Configure here.
| this.#release = undefined; | ||
| this.#set(false); | ||
| }, CALL_QUIET_RELEASE_MS); | ||
| } |
There was a problem hiding this comment.
Exchange releases hold during active calls
High Severity
#apply treats any live exchange as if capture stopped, so a hold already won by a foreign capture starts the release grace the moment the developer talks or types to Luke. After CALL_QUIET_RELEASE_MS the quiet lifts even though the microphone is still taken, and announcements can speak into the call until onset runs again.
Reviewed by Cursor Bugbot for commit 4bd8d34. Configure here.
| return | ||
| } | ||
| let running = live.contains(where: isRunningSomewhere) || headsetOnCallCodec() | ||
| say("capture running=\(running ? 1 : 0)") |
There was a problem hiding this comment.
Duplex playback reported as microphone capture
High Severity
report treats kAudioDevicePropertyDeviceIsRunningSomewhere on every device that merely has input streams as a capture. That flag is device-wide, so playback on a USB headset, audio interface, or other duplex device counts as a call and holds announcements for the whole time audio is playing, plus the release grace.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 4bd8d34. Configure here.
The desktop caps released notices after filtering them by current status, so the helper's own limit branch had no caller and duplicated the cap. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>


Summary
InputCapture.swift) that reports one boolean, whether any process is capturing from an input device, read from CoreAudio's running flag or a Bluetooth output's drop to its call codec, with no audio, device name, or process name.call-quiet.ts) turns a foreign capture, Luke's own exchange excluded, into a hold after a short onset that releases a fixed grace after capture stops.AGENTS.md,PRIVACY.md, and the README to disclose the new read.Evidence
not run./scripts/verify.sh):not runAutomated visual evidence
Download the deterministic macOS evidence · workflow run
4bd8d349becb7065bb704b4fdff2c07e925c1a86smokePhysical-device evidence
not attachednot performednot recordedNotes
🤖 Generated with Claude Code
Open in Alchemize
Open workspace in Conductor