Voice Wake & Push-to-Talk

Các chế độ

  • Chế độ Wake-word (mặc định): Bộ nhận dạng giọng nói luôn bật, chờ các từ kích hoạt (swabbleTriggerWords). Khi khớp, nó bắt đầu ghi âm, hiển thị overlay với văn bản tạm thời, và tự động gửi sau khi im lặng.
  • Push-to-talk (giữ phím Right Option): Giữ phím Option bên phải để ghi âm ngay lập tức—không cần từ kích hoạt. Overlay xuất hiện khi đang giữ; thả ra sẽ hoàn tất và chuyển tiếp sau một khoảng delay ngắn để các bạn có thể chỉnh sửa văn bản.

Hành vi Runtime (wake-word)

  • Bộ nhận dạng giọng nói nằm trong VoiceWakeRuntime.
  • Trigger chỉ kích hoạt khi có khoảng dừng có ý nghĩa giữa wake word và từ tiếp theo (~0.55s). Overlay/chime có thể bắt đầu ngay khi có khoảng dừng, ngay cả trước khi lệnh bắt đầu.
  • Cửa sổ im lặng: 2.0s khi đang nói, 5.0s nếu chỉ nghe thấy trigger.
  • Hard stop: 120s để tránh session chạy mãi.
  • Debounce giữa các session: 350ms.
  • Overlay được điều khiển qua VoiceWakeOverlayController với màu sắc committed/volatile.
  • Sau khi gửi, recognizer khởi động lại sạch sẽ để lắng nghe trigger tiếp theo.

Lifecycle invariants

  • Nếu Voice Wake được bật và quyền đã được cấp, wake-word recognizer phải đang lắng nghe (trừ khi đang trong quá trình push-to-talk capture).
  • Overlay visibility (bao gồm cả việc đóng thủ công qua nút X) không bao giờ được ngăn recognizer khởi động lại.

Sticky overlay failure mode (trước đây)

Trước đây, nếu overlay bị kẹt hiển thị và các bạn đóng nó thủ công, Voice Wake có thể trông như “chết” vì nỗ lực restart của runtime có thể bị chặn bởi overlay visibility và không có restart nào được lên lịch tiếp theo.

Cải thiện:

  • Wake runtime restart không còn bị chặn bởi overlay visibility nữa.
  • Overlay dismiss completion kích hoạt VoiceWakeRuntime.refresh(...) qua VoiceSessionCoordinator, nên việc đóng X thủ công luôn tiếp tục lắng nghe.

Chi tiết Push-to-talk

  • Hotkey detection dùng global .flagsChanged monitor cho right Option (keyCode 61 + .option). Mình chỉ quan sát events (không nuốt chúng).
  • Capture pipeline nằm trong VoicePushToTalk: bắt đầu Speech ngay lập tức, stream các phần tạm thời đến overlay, và gọi VoiceWakeForwarder khi thả ra.
  • Khi push-to-talk bắt đầu, mình tạm dừng wake-word runtime để tránh audio taps xung đột; nó tự động restart sau khi thả ra.
  • Permissions: cần Microphone + Speech; để thấy events cần Accessibility/Input Monitoring approval.
  • Bàn phím ngoài: một số có thể không expose right Option như mong đợi—cung cấp shortcut dự phòng nếu người dùng báo cáo bị miss.

Cài đặt người dùng

  • Voice Wake toggle: bật wake-word runtime.
  • Hold Cmd+Fn to talk: bật push-to-talk monitor. Bị tắt trên macOS < 26.
  • Language & mic pickers, live level meter, trigger-word table, tester (chỉ local; không forward).
  • Mic picker giữ lựa chọn cuối cùng nếu thiết bị ngắt kết nối, hiển thị gợi ý disconnected, và tạm thời fallback về system default cho đến khi nó quay lại.
  • Sounds: chimes khi phát hiện trigger và khi gửi; mặc định là âm thanh hệ thống “Glass” của macOS. Các bạn có thể chọn bất kỳ file nào NSSound load được (ví dụ MP3/WAV/AIFF) cho mỗi sự kiện hoặc chọn No Sound.

Hành vi Forwarding

  • Khi Voice Wake được bật, transcripts được forward đến gateway/agent đang hoạt động (cùng chế độ local vs remote được dùng bởi phần còn lại của mac app).
  • Replies được gửi đến last-used main provider (WhatsApp/Telegram/Discord/WebChat). Nếu delivery thất bại, lỗi được log và run vẫn hiển thị qua WebChat/session logs.

Forwarding payload

  • VoiceWakeForwarder.prefixedTranscript(_:) thêm machine hint vào trước khi gửi. Được chia sẻ giữa wake-word và push-to-talk paths.

Kiểm tra nhanh

  • Bật push-to-talk, giữ Cmd+Fn, nói, thả ra: overlay sẽ hiển thị các phần tạm thời rồi gửi.
  • Khi đang giữ, menu-bar ears sẽ to ra (dùng triggerVoiceEars(ttl:nil)); chúng thu nhỏ lại sau khi thả ra.