モード
- ウェイクワード モード (既定): 常時オンの Speech recognizer がトリガー語 (
swabbleTriggerWords) を待機します。一致するとキャプチャを開始し、部分テキスト付きのオーバーレイを表示し、無音後に自動送信します。 - プッシュトゥトーク (右 Option 長押し): 右 Option キーを押している間、即座にキャプチャを開始します。トリガー語は不要です。オーバーレイは押下中に表示され、キーを離すと、短い待機の後に確定して転送されるため、その間に文面を調整できます。
実行時の挙動 (ウェイクワード)
- Speech recognizer は
VoiceWakeRuntimeにあります。 - トリガーは、ウェイクワードと次の単語の間に 意味のある間 がある場合にのみ発火します (およそ 0.55 秒のギャップ)。オーバーレイや chime は、コマンド開始前でもその間で起動することがあります。
- 無音判定のウィンドウは、発話が続いている場合は 2.0 秒、トリガー語だけが聞こえた場合は 5.0 秒です。
- 暴走防止のため、120 秒で強制停止します。
- セッション間の debounce は 350 ms です。
- オーバーレイは
VoiceWakeOverlayControllerが制御し、確定済み / 未確定の色分けを行います。 - 送信後、recognizer は次のトリガーを待つために正常に再起動します。
ライフサイクル上の不変条件
- Voice Wake が有効で、必要なアクセス許可が付与されている場合、ウェイクワード recognizer は常に待機している必要があります。例外は、明示的なプッシュトゥトークのキャプチャ中だけです。
- オーバーレイの可視状態は、X ボタンによる手動 dismiss を含めて、recognizer の再開を妨げてはいけません。
Sticky overlay の障害モード (以前)
以前は、オーバーレイが表示されたまま張り付いた状態で手動クローズすると、runtime の再起動がオーバーレイ可視状態に阻まれ、その後の再起動も予約されないため、Voice Wake が停止したように見えることがありました。 現在の対策:- wake runtime の再起動は、オーバーレイの可視状態に依存しません。
- オーバーレイの dismiss 完了時に、
VoiceSessionCoordinator経由でVoiceWakeRuntime.refresh(...)を呼ぶため、手動で X を押しても必ず待機状態へ戻ります。
プッシュトゥトーク固有の仕様
- ホットキー検出では、右 Option (
keyCode 61+.option) に対するグローバル.flagsChangedmonitor を使います。イベントは監視するだけで、横取りはしません。 - キャプチャ パイプラインは
VoicePushToTalkにあり、Speech を即座に開始し、partial をオーバーレイへ流し、キーを離したらVoiceWakeForwarderを呼びます。 - プッシュトゥトーク開始時には、音声入力の競合を避けるため wake-word runtime を一時停止し、キーを離すと自動で再開します。
- 必要な権限は Microphone と Speech です。イベント監視には Accessibility / Input Monitoring の承認も必要です。
- 外付けキーボードの一部では右 Option が期待どおり取得できない場合があります。報告がある場合は代替ショートカットを用意してください。
ユーザー向け設定
- Voice Wake トグル: wake-word runtime を有効化します。
- Hold Cmd+Fn to talk: プッシュトゥトーク monitor を有効化します。macOS 26 未満では無効です。
- 言語 picker、マイク picker、ライブ レベル メーター、トリガー語テーブル、tester を提供します。tester はローカル専用で、転送は行いません。
- マイク picker は、デバイス切断時も最後の選択を保持し、切断中であることを表示したうえで、一時的にシステム既定マイクへフォールバックします。デバイスが戻れば元の選択へ復帰します。
- Sounds: トリガー検出時と送信時に chime を鳴らせます。既定値は macOS の “Glass” システム サウンドです。各イベントごとに
NSSoundで読み込めるファイル (MP3 / WAV / AIFF など) を指定するか、No Sound を選べます。
転送の挙動
- Voice Wake が有効な場合、transcript は現在アクティブなゲートウェイ / エージェントへ転送されます。転送先は macOS アプリ全体で使っている local / remote モード設定に従います。
- 応答は、最後に使った main provider (WhatsApp / Telegram / Discord / WebChat) に配信されます。配信に失敗した場合でも、エラーはログに残り、実行状況は WebChat や session log から確認できます。
転送ペイロード
VoiceWakeForwarder.prefixedTranscript(_:)は、送信前に machine hint を前置します。この処理はウェイクワード経路とプッシュトゥトーク経路で共有されます。
簡易確認
- プッシュトゥトークを有効にし、Cmd+Fn を押しながら話し、離してください。オーバーレイに partial が出て、その後送信されるはずです。
- 押下中はメニュー バーの耳が拡大状態を維持します (
triggerVoiceEars(ttl:nil)を使用)。キーを離すと元に戻ります。