Repository navigation
fix(inbox): the voice mic never stays stuck, and no tap does nothing - #2519
Merged
Merged
Conversation
- A throw from `deps.open()` (`new AudioContext()` refusing) left the take in `opening` for good: no status line, no Cancel, Send off, every tap ignored. It is now a mic that did not start (`micfailed`), and the next tap opens again. - A second tap while the mic is still opening was dropped silently. It now cancels (nothing is recorded yet), which also frees a mic that never opens. - A recorder that rejects on stop left the spinner up for good. It now ends at rest with `badclip`, the microphone released. Regression tests: voiceSession.test.ts (3 fail on main) and a phone New message e2e in inbox-voice.spec.ts (fails on main).
voice_press (each press, release, lost or toggle with the phase and mode it met), voice_phase (each change of phase, mode, prompting, slow or trouble) and voice_open (each step of opening the microphone: context, stream, worklet, ready, with ok, ms, the AudioContext's state and an error name). Written through debugNote, so nothing while debug is off. The Inbox's filter keeps only their fixed words: never audio, the words or a status line. Tests: voiceDebugLog.test.ts (DOM: off writes nothing, on writes the lines with no words, every field survives the filter) and debug-log.test.ts.
Owner
Author
|
Added in
They are written through Tests: |
The owner's report was a tap that showed nothing. Their call on the earlier fix
(a second tap while opening cancels): unseen, that is worse.
- From the press, the mic button is lit with the spinner while the mic opens.
Its words ("Opening the mic…", "Asking for the mic…") and Cancel follow
after 150 ms (was 1 s), so a mic that opens at once doesn't flash a line.
- A second tap while opening is ignored again, but the busy look stays and the
take listens once the mic opens. Cancel on the bar is the way out.
- A mic that never opens gives up after 10 s (30 s while the browser is
asking) with the "microphone didn't start" note, so the next tap works.
- Fixes 2 and 3 stay: a throw while opening is micfailed, a failed stop is
badclip.
Tests: voiceSession.test.ts (no cancel, line within 150 ms, both give-ups),
voiceComposeRenders.test.tsx (DOM: the spinner on the first tap with no wait,
kept on a second tap, gone once listening), inbox-voice.spec.ts updated.
Review of #2519: - voiceDebugLog.test.ts joins the DOM test list (the allowlist guard). - VoiceDeps.open takes an AbortSignal. Cancel, the box closing and the 10 s / 30 s give-up abort it. openVoiceRecorder then closes its AudioContext at once, not when getUserMedia settles (maybe never), and a stream that arrives later has its tracks stopped before the worklet loads. A test drives the real recorder on a stand-in AudioContext and getUserMedia: a mic answering after the give-up holds nothing. - Space or Enter while the mic opens is a tap: busy, nothing cancelled. - Every session trouble code survives the debug log's filter (VOICE_TROUBLE_CODES, the type derived from it). - inbox-compose.md: the open's abort, the keyboard, and the one press that still starts nothing (a Send on its way).
The slow line and the 10 s / 30 s give-ups are cleared when the mic opens or the take ends, so an old take's give-up can't reach a newer take that is still opening, even without the run check. The test fake's canceller now acts as clearTimeout. inbox-compose.md: 10 s is the best case; a browser that can't say whether it will ask (often iOS) waits 30 s.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The owner reported that on iPhone Safari (0.28.45, New message) the mic sometimes did nothing when tapped: "I tapped, and nothing happened, so visually it was an issue." This PR makes every tap show at once, ends every stuck path at rest, and adds voice lines to the opt-in debug log so a repeat can be diagnosed.
What changes
new AudioContext()throws as the mic opensopeningfor good: lit, no line, no Cancel, Send off, every tap ignoredmicfailednote, Send free, the next tap recordsrecorder.stop()rejectsbadclipnote, microphone releasedEvery other real-path flow I tried already returned to rest in Chromium (fake capture) and WebKit (iPhone viewport, a tone): quick re-taps, a tap while transcribing, double taps, compose closed mid-take and reopened, a suspended AudioContext, a track that ends, and a worklet that fails to load once.
A take that ends before the mic opens lets go of it
VoiceDeps.open(signal). Cancel, the box closing and the give-up abort the open.openVoiceRecorderthen closes its AudioContext at once, not whengetUserMediasettles (which may be never). A stream that arrives later has its tracks stopped before the worklet loads. The slow line and both give-up timers are cleared when the mic opens or the take ends, so an old take's give-up can't reach a newer take. Space or Enter while opening acts as a tap: busy, nothing cancelled. 10 s is the best case: a browser that can't say whether it will ask (often iOS) waits 30 s.Debug log (opt-in, off by default, no UI)
voice_press(each input with the phase and mode it met),voice_phase(each change), andvoice_open(each step of opening the mic, with ms, the AudioContext's state and an error name). They hold fixed words only, never audio or text. They are documented indocs/agent-guides/inbox-window.md.What this does not prove
The owner's exact trigger is unknown. In their debug log, the taps that did nothing made no request, which fits a mic slow to open (before this PR: no visible change for 1 s, and a second tap ignored) or a mic that never opened. The voice lines will show which next time.
Tests
packages/inbox/voiceSession.test.ts: no cancel on a second tap, by pointer or keyboard; the line within 150 ms; both give-ups; the open aborted by Cancel, close and give-up; a cancelled take's give-up never reaching the next take; the real recorder with a mic answering after the give-up (context closed at once, tracks stopped); the throw while opening and the failed stop.packages/inbox/voiceComposeRenders.test.tsx(DOM): the spinner on the first tap with no wait, kept on a second tap, gone once listening. It fails on the previous head.packages/inbox/voiceDebugLog.test.ts(DOM, now intests/dom-test-list.txt; every trouble code survives the filter) andpackages/shared/inbox/debug-log.test.ts.tests/e2e/inbox-voice.spec.ts: the phone test, updated.No new keyboard shortcuts.