Spaces:
Sleeping
fix(voice): KI-174 — revive on visibilitychange + window focus
Browse filesUser report: "sometimes when I go away from clicking the text box, it
seems to not input my voice anymore. I have to restart the whole voice
thing."
Root cause: Chrome's SpeechRecognition auto-stops when the document
loses visibility (tab switch, app switch, screenshot tool, OS modal,
notification overlay). The KI-173 heartbeat is throttled to ~1Hz when
the tab is hidden, so revival takes 4-8s after returning.
Fix: added two immediate-revival event listeners:
- document.visibilitychange → visible
- window.focus
When fired, both call safeStart() if wantRunningRef.current AND no
text turn is pending AND document.visibilityState === "visible".
InvalidStateError swallowed by safeStart if recognition is already
running.
Combined with KI-173 heartbeat as a safety net, the mic should stay
alive across:
- Tab switches → visibilitychange fires
- App switches → window.focus fires
- Screenshot tool grabbing focus → window.focus fires
- Notification overlays clearing → window.focus fires
- All other transient browser quirks → 4s heartbeat catches them
Verification: npx tsc --noEmit clean (exit 0).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@@ -539,6 +539,42 @@ export function useStreamingVoice(
|
|
| 539 |
return () => clearInterval(tick);
|
| 540 |
}, [enabled, isSupported, isTextRequestPendingRef, safeStart]);
|
| 541 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 542 |
// Unmount cleanup.
|
| 543 |
useEffect(() => {
|
| 544 |
return () => {
|
|
|
|
| 539 |
return () => clearInterval(tick);
|
| 540 |
}, [enabled, isSupported, isTextRequestPendingRef, safeStart]);
|
| 541 |
|
| 542 |
+
// KI-174 (2026-05-15) — immediate-revival on visibility/focus changes.
|
| 543 |
+
// User reported: "sometimes when I go away from clicking the text box,
|
| 544 |
+
// it seems to not input my voice anymore. I have to restart the whole
|
| 545 |
+
// voice thing." Root cause: Chrome's SpeechRecognition auto-stops
|
| 546 |
+
// when the tab loses visibility (tab switch, app switch, screenshot,
|
| 547 |
+
// OS modal). The KI-173 heartbeat is throttled to ~1Hz when the tab
|
| 548 |
+
// is hidden, so it takes several seconds to revive after returning.
|
| 549 |
+
// Force-revival on:
|
| 550 |
+
// - document `visibilitychange` → visible
|
| 551 |
+
// - window `focus`
|
| 552 |
+
// Both check wantRunningRef + isTextRequestPendingRef before firing.
|
| 553 |
+
useEffect(() => {
|
| 554 |
+
if (!enabled || !isSupported) return;
|
| 555 |
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
| 556 |
+
|
| 557 |
+
const tryRevive = (trigger: string) => {
|
| 558 |
+
if (
|
| 559 |
+
wantRunningRef.current
|
| 560 |
+
&& !isTextRequestPendingRef.current
|
| 561 |
+
&& document.visibilityState === "visible"
|
| 562 |
+
) {
|
| 563 |
+
console.debug("[useStreamingVoice] revival trigger=" + trigger);
|
| 564 |
+
safeStart();
|
| 565 |
+
}
|
| 566 |
+
};
|
| 567 |
+
|
| 568 |
+
const onVisible = () => tryRevive("visibilitychange");
|
| 569 |
+
const onFocus = () => tryRevive("window.focus");
|
| 570 |
+
document.addEventListener("visibilitychange", onVisible);
|
| 571 |
+
window.addEventListener("focus", onFocus);
|
| 572 |
+
return () => {
|
| 573 |
+
document.removeEventListener("visibilitychange", onVisible);
|
| 574 |
+
window.removeEventListener("focus", onFocus);
|
| 575 |
+
};
|
| 576 |
+
}, [enabled, isSupported, isTextRequestPendingRef, safeStart]);
|
| 577 |
+
|
| 578 |
// Unmount cleanup.
|
| 579 |
useEffect(() => {
|
| 580 |
return () => {
|