← Back to top

Technical Documentation

Architecture and design of Hush Meet

Architecture Overview

┌─────────────────────────────────────────────────────┐
│  Chrome Extension (Manifest V3)                     │
│                                                     │
│  ┌──────────────┐     ┌───────────────────────────┐ │
│  │   Popup UI   │     │     Content Script         │ │
│  │  (React)     │     │   (meet.google.com)        │ │
│  │              │     │                            │ │
│  │  - Toggle    │     │  ┌────────────────────┐   │ │
│  │  - Meter     │◄───►│  │  Audio Analyser    │   │ │
│  │  - Settings  │     │  │  (Web Audio API)   │   │ │
│  │              │     │  └────────┬───────────┘   │ │
│  └──────────────┘     │           │               │ │
│         ▲             │  ┌────────▼───────────┐   │ │
│         │             │  │  State Machine     │   │ │
│         │             │  │  IDLE → MUTED →    │   │ │
│         │             │  │  SPEAKING → GRACE  │   │ │
│         │             │  └────────┬───────────┘   │ │
│         │             │           │               │ │
│         │             │  ┌────────▼───────────┐   │ │
│         │             │  │  Mute Controller   │   │ │
│         │             │  │  (DOM manipulation)│   │ │
│         │             │  └────────────────────┘   │ │
│         │             └───────────────────────────┘ │
│         │                                           │
│         └─── Chrome Storage API (config/state sync)─┘
│                                                     │
└─────────────────────────────────────────────────────┘

Project Structure

src/
├── constants.ts          # Constants, modes, thresholds, storage keys
├── messages.ts           # i18n messages (EN/JA)
├── i18n.ts               # Locale management
├── manifest.ts           # Chrome extension manifest definition
├── background/
│   └── service-worker.ts # Service Worker (game launcher, etc.)
├── content/
│   └── index.ts          # Content Script (state machine, mode control, shortcuts)
└── popup/
    ├── index.html        # Popup entry HTML
    ├── main.tsx          # React mount
    ├── Popup.tsx         # Popup UI component
    ├── popup.css         # Styles
    ├── Equalizer.tsx     # Spectrum analyser
    ├── ThemeSwitcher.tsx # Theme switcher
    ├── LocaleSwitcher.tsx# Language switcher
    └── GameLauncher.tsx  # Mini-game launcher

Component Details

1. Content Script (src/content/index.ts)

This script is injected into the Google Meet page. Its main responsibilities are:

1.1 Audio Analysis Engine

Uses the Web Audio API AnalyserNode to measure microphone input volume in real time.

getUserMedia() → AudioContext → MediaStreamSource → AnalyserNode
                                                          │
                                                    getFloatTimeDomainData()
                                                          │
                                                    RMS (Root Mean Square) calculation

Configuration parameters:

Parameter Value Description
fftSize 512 FFT window size
smoothingTimeConstant 0.3 Temporal smoothing coefficient
echoCancellation true Enable echo cancellation
noiseSuppression false Noise suppression off (for VAD accuracy)

1.2 State Machine

A finite state machine with 5 states manages the speech state.

IDLE ──(mode other than Off selected)──► MUTED ──(volume > speechThreshold)──► UNMUTING ──► SPEAKING
                     ▲                                                │
                     │                              (volume < silenceThreshold)
                     │                                                │
                     └──(graceTimer expired)── GRACE ◄────────────────┘
                                                │
                                         (volume > silenceThreshold)
                                                │
                                                ▼
                                            SPEAKING

* If the user manually toggles the Meet microphone, the mode stays the same and only the state follows.
State Description Meet Action
IDLE Off mode or uninitialized None
MUTED Silence detected → muted Mute
UNMUTING Speech detected → unmuting Unmute
SPEAKING Currently speaking None
GRACE Speech ended → grace period None

1.3 Operating Modes

Four modes control how state transitions behave. Off is the control-disabled mode.

Mode Unmute Mute Shortcut
Off None None Disabled
Auto Automatic on voice detection Automatic on silence Toggle
Auto-Off Manual / shortcut Automatic on silence Toggle
Push-to-Talk While key is held down Key released → Grace → Mute Hold

1.4 Shortcut Key

Provides a customizable keyboard shortcut (default: Ctrl+Shift+M).

The shortcut key can be freely changed from the popup settings.

1.5 Asymmetric Threshold Design

Different thresholds for unmuting and muting prevent chattering (frequent toggling).

speechThreshold (speech start)  = 0.025  (default)
silenceThreshold (silence)      = speechThreshold × 0.5 = 0.0125

  Volume
   ▲
   │  ┄┄┄┄┄┄┄┄┄ speechThreshold (0.025) ┄┄┄┄  ← Unmute when exceeded
   │
   │  ┄┄┄┄┄┄┄┄┄ silenceThreshold (0.0125) ┄┄  ← Grace period starts when below
   │
   └──────────────────────────────────────────► Time

1.6 Mute Button Detection

Detects the Google Meet mute button using multiple strategies:

  1. Search by aria-label attribute (supports Japanese/English)
  2. Search by data-tooltip attribute
  3. Fallback: simulate Ctrl+D keyboard shortcut

Mute state is determined from the data-is-muted attribute or the aria-label text content.

2. Popup UI (src/popup/)

A settings UI built with React 19. Synchronizes state with the Content Script in real time via the Chrome Storage API.

Data Flow

Popup → Chrome Storage → Content Script
  │                            │
  │  hushMeetConfig: object    │  (sensitivity/grace period settings)
  │  hushMeetMode: string      │  (operating mode)
  │  hushMeetShortcutKey: str  │  (shortcut key)
  │                            │
  │                            ▼
  │                      Content Script → Chrome Storage → Popup
  │                            │
  │                            │  hushMeetState: string  (current state)
  │                            │  hushMeetLevel: number  (volume level)
  │                            │  hushMeetSpectrum: array (spectrum)
  └────────────────────────────┘

The Popup and Content Script do not communicate directly; they communicate bidirectionally via Chrome Storage API change events.

Build System

Tool Version Purpose
Vite+ toolchain Dependency management, build, test, validation
Vite 8.x Internal build infrastructure
CRXJS Vite Plugin 2.x Chrome extension HMR & manifest generation
React 19.x Popup UI
TypeScript 5.9.x Type safety

Commands

Command Description
vp install Install dependencies
vp build Production build
vp test Run tests
vp check format / lint / typecheck

Known Limitations

Future Improvements