How Push-to-Talk Microphone Gating Works in Gods-Eye-View

The push-to-talk feature in Gods-Eye-View gates the microphone using a dual-flag system that only enables audio transmission when the Space key is held, preventing accidental hot-mic scenarios.

The bilawalsidhu/gods-eye-view repository implements a robust push-to-talk (PTT) mechanism that keeps the microphone physically muted unless the user explicitly holds the Space key or activates the on-screen mic button. This microphone gating strategy ensures voice data never transmits unintentionally, protecting user privacy while maintaining low-latency WebRTC connections. The core logic resides in src/voice/gevRealtime.js, where state flags coordinate between user input, audio hardware, and the realtime voice session.

Core Architecture of Push-to-Talk Microphone Gating

The implementation relies on two boolean flags that track distinct aspects of the PTT state. Understanding their interaction is essential to grasping how the microphone gate operates.

The Dual-Flag State Machine

According to the source code in src/voice/gevRealtime.js, the system maintains:

  • pushToTalkMode – Indicates whether the session operates in push-to-talk mode (global preference flag)
  • pushToTalkKeyHeld – Tracks whether the Space key is currently depressed (real-time input state)

These flags work in concert at line 413, where the actual gating decision occurs:

// src/voice/gevRealtime.js, line 413
this.setMicrophoneEnabled(!this.pushToTalkMode || this.pushToTalkKeyHeld);

When pushToTalkMode is false, the microphone follows standard toggle behavior. When true, the logical OR ensures the mic only activates while pushToTalkKeyHeld evaluates to true.

Session Initialization and PTT Mode

When creating a realtime voice session, the start method accepts a pushToTalk option that establishes the gating behavior for the entire session duration. The method initializes both flags and computes the initial key-hold state:

// src/voice/gevRealtime.js, lines 336-343
async start({ pushToTalk = false } = {}) {
  const pushToTalkKeyHeld = pushToTalk && this.pushToTalkKeyHeld;
  this.pushToTalkMode = pushToTalk;
  this.pushToTalkKeyHeld = pushToTalkKeyHeld;
  // ... session initialization continues
}

This initialization pattern ensures that if a user starts a session with PTT enabled while already holding Space, the microphone opens immediately without requiring a key release and re-press.

Real-Time Microphone Gating Logic

The actual audio gate operates through continuous evaluation of the PTT state during keyboard events and UI updates.

The Gating Decision

The setMicrophoneEnabled call at line 413 serves as the single point of truth for microphone status. This line executes whenever the UI state refreshes or input events occur, ensuring the hardware mic state stays synchronized with user intent:

  • PTT Off: !this.pushToTalkMode evaluates to true, so the mic enables regardless of key state
  • PTT On: The mic enables only when this.pushToTalkKeyHeld is true (Space is held)

Key Hold Detection and Debouncing

The Space key handlers implement guards to prevent interference with normal typing and to ignore auto-repeat events from the operating system. When the user presses Space:

// src/voice/gevRealtime.js, lines 587-595
if (this.pushToTalkKeyHeld) return;      // ignore repeat events
if (this.isActive() && !this.pushToTalkMode) return;
this.pushToTalkKeyHeld = true;
this.ui.root.dataset.pushToTalk = 'held';

On key release, the system clears the hold state and removes the visual indicator:

// src/voice/gevRealtime.js, lines 630-637
if (!this.pushToTalkKeyHeld) return;
this.pushToTalkKeyHeld = false;
delete this.ui.root.dataset.pushToTalk;
if (!this.pushToTalkMode) return;

The early return at line 637 prevents unnecessary processing when PTT is disabled, while the flag clearing at line 634 ensures the microphone gates closed even if the UI update cycle delays.

UI Feedback and Visual States

The gating mechanism provides immediate visual feedback through data attributes on the root UI element. The code sets data-push-to-talk="held" when the Space key is active (line 593) and removes it on release. Additionally, line 645 toggles data-microphone between "active" and "muted" to reflect actual transmission state.

The mic button displays instructional text derived from lines 2513-2610: "Hold Space to speak · click mic to toggle voice", ensuring users understand the dual control scheme.

Error Handling and Safety Guarantees

If the underlying WebRTC connection fails or the user revokes microphone permissions, the session cleanup code at lines 849-851 explicitly clears the dataset attributes and resets the gating flags. This guarantees no "ghost" microphone remains active during error states, preventing hot-mic leaks even during exceptional conditions.

The src/voice/voiceCost.js file tracks microphone usage duration and includes additional guards against hot-mic sessions, providing a secondary safety layer beyond the primary gating logic in gevRealtime.js.

Summary

  • Dual-flag architecture: pushToTalkMode controls global behavior while pushToTalkKeyHeld tracks real-time input, creating a reliable microphone gate
  • Single-point gating: Line 413 in gevRealtime.js evaluates !this.pushToTalkMode || this.pushToTalkKeyHeld to determine mic state
  • Safe initialization: The start method accepts pushToTalk: true to enable gating without disrupting existing key-hold states
  • Visual synchronization: Data attributes data-push-to-talk and data-microphone provide immediate UI feedback
  • Fail-safe cleanup: Error handlers explicitly clear gating flags and UI indicators to prevent accidental transmission during connection failures

Frequently Asked Questions

How do I programmatically enable push-to-talk microphone gating?

Pass pushToTalk: true when calling the start method on the realtime voice controller:

gevRealtime.start({ pushToTalk: true });

This sets the internal pushToTalkMode flag to true, causing setMicrophoneEnabled to check pushToTalkKeyHeld before opening the microphone.

What happens if I hold Space before starting a PTT session?

The initialization logic at lines 336-343 checks this.pushToTalkKeyHeld during session startup. If the Space key is already held when start({ pushToTalk: true }) executes, pushToTalkKeyHeld initializes to true, immediately enabling the microphone without requiring a key release and re-press.

Why does the microphone stay muted when I click the mic button in PTT mode?

When pushToTalkMode is active, the microphone ignores the toggle button state and only responds to the Space key hold status. To speak, you must hold the Space key continuously. Clicking the mic button only changes the mute state when operating in standard (non-PTT) mode, as indicated by the UI text "Hold Space to speak · click mic to toggle voice" implemented in the UI glue code.

How does the system prevent keyboard repeat events from breaking the microphone gate?

The keydown handler at lines 587-595 includes an early return: if (this.pushToTalkKeyHeld) return;. This prevents the operating system's auto-repeat feature from triggering multiple state changes while the key remains physically depressed, ensuring the microphone gate remains stable and open until the actual key release event occurs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →