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

> Learn how Gods-Eye-View push-to-talk microphone gating uses a dual-flag system to transmit audio only when the Space key is held, preventing hot-mic issues.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: how-to-guide
- Published: 2026-08-29

---

**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`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/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`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/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:

```javascript
// 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:

```javascript
// 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:

```javascript
// 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:

```javascript
// 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`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/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`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/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`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/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:

```javascript
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.