Hush Meet 的架构与设计
┌─────────────────────────────────────────────────────┐
│ Chrome 扩展程序 (Manifest V3) │
│ │
│ ┌──────────────┐ ┌───────────────────────────┐ │
│ │ 弹出界面 │ │ Content Script │ │
│ │ (React) │ │ (meet.google.com) │ │
│ │ │ │ │ │
│ │ - 切换 │ │ ┌────────────────────┐ │ │
│ │ - 音量表 │◄───►│ │ 音频分析器 │ │ │
│ │ - 设置 │ │ │ (Web Audio API) │ │ │
│ │ │ │ └────────┬───────────┘ │ │
│ └──────────────┘ │ │ │ │
│ ▲ │ ┌────────▼───────────┐ │ │
│ │ │ │ 状态机 │ │ │
│ │ │ │ IDLE → MUTED → │ │ │
│ │ │ │ SPEAKING → GRACE │ │ │
│ │ │ └────────┬───────────┘ │ │
│ │ │ │ │ │
│ │ │ ┌────────▼───────────┐ │ │
│ │ │ │ 静音控制器 │ │ │
│ │ │ │ (DOM 操作)│ │ │
│ │ │ └────────────────────┘ │ │
│ │ └───────────────────────────┘ │
│ │ │
│ └─── Chrome Storage API (配置/状态同步)─┘
│ │
└─────────────────────────────────────────────────────┘
src/
├── constants.ts # 常量、模式、阈值、存储键
├── messages.ts # i18n 消息 (EN/JA)
├── i18n.ts # 语言管理
├── manifest.ts # Chrome 扩展程序清单定义
├── background/
│ └── service-worker.ts # Service Worker(游戏启动器等)
├── content/
│ └── index.ts # Content Script(状态机、模式控制、快捷键)
└── popup/
├── index.html # 弹出页面入口 HTML
├── main.tsx # React 挂载
├── Popup.tsx # 弹出界面组件
├── popup.css # 样式
├── Equalizer.tsx # 频谱分析器
├── ThemeSwitcher.tsx # 主题切换器
├── LocaleSwitcher.tsx# 语言切换器
└── GameLauncher.tsx # 小游戏启动器
src/content/index.ts)此脚本被注入到 Google Meet 页面中。其主要职责包括:
使用 Web Audio API 的 AnalyserNode 实时测量麦克风输入音量。
getUserMedia() → AudioContext → MediaStreamSource → AnalyserNode
│
getFloatTimeDomainData()
│
RMS(均方根)计算
配置参数:
| 参数 | 值 | 说明 |
|---|---|---|
fftSize |
512 | FFT 窗口大小 |
smoothingTimeConstant |
0.3 | 时间平滑系数 |
echoCancellation |
true | 启用回声消除 |
noiseSuppression |
false | 关闭噪声抑制(为保证 VAD 准确性) |
一个包含 5 个状态的有限状态机管理语音状态。
IDLE ──(选择了非关闭模式)──► MUTED ──(音量 > 语音阈值)──► UNMUTING ──► SPEAKING
▲ │
│ (音量 < 静音阈值)
│ │
└──(宽限定时器到期)── GRACE ◄────────────────────┘
│
(音量 > 静音阈值)
│
▼
SPEAKING
* 如果用户手动切换 Meet 麦克风,模式保持不变,仅状态跟随变化。
| 状态 | 说明 | Meet 操作 |
|---|---|---|
| IDLE | 关闭模式或未初始化 | 无 |
| MUTED | 检测到静音 → 已静音 | 静音 |
| UNMUTING | 检测到语音 → 正在取消静音 | 取消静音 |
| SPEAKING | 正在讲话 | 无 |
| GRACE | 讲话结束 → 宽限期 | 无 |
四种模式控制状态转换的行为。关闭模式为禁用控制模式。
| 模式 | 取消静音 | 静音 | 快捷键 |
|---|---|---|---|
| 关闭 | 无 | 无 | 禁用 |
| 自动 | 检测到语音时自动取消静音 | 检测到静音时自动静音 | 切换 |
| 自动关闭 | 手动 / 快捷键 | 检测到静音时自动静音 | 切换 |
| Push-to-Talk | 按住键时取消静音 | 松开键 → 宽限期 → 静音 | 按住 |
提供可自定义的键盘快捷键(默认:Ctrl+Shift+M)。
快捷键可以在弹出窗口的设置中自由更改。
取消静音和静音使用不同的阈值,以防止抖动(频繁切换)。
语音阈值(语音开始) = 0.025(默认)
静音阈值(静音判定) = 语音阈值 × 0.5 = 0.0125
音量
▲
│ ┄┄┄┄┄┄┄┄┄ 语音阈值 (0.025) ┄┄┄┄ ← 超过时取消静音
│
│ ┄┄┄┄┄┄┄┄┄ 静音阈值 (0.0125) ┄┄ ← 低于时开始宽限期
│
└──────────────────────────────────────────► 时间
使用多种策略检测 Google Meet 的静音按钮:
aria-label 属性搜索(支持日语/英语)data-tooltip 属性搜索Ctrl+D 键盘快捷键
静音状态通过 data-is-muted 属性或 aria-label 文本内容来判定。
src/popup/)使用 React 19 构建的设置界面。通过 Chrome Storage API 与 Content Script 实时同步状态。
speechThreshold(0.005–0.25)— 按模式保存
gracePeriod(500ms–4000ms)— 按模式保存
Popup → Chrome Storage → Content Script
│ │
│ hushMeetConfig: object │ (灵敏度/宽限期设置)
│ hushMeetMode: string │ (运行模式)
│ hushMeetShortcutKey: str │ (快捷键)
│ │
│ ▼
│ Content Script → Chrome Storage → Popup
│ │
│ │ hushMeetState: string (当前状态)
│ │ hushMeetLevel: number (音量电平)
│ │ hushMeetSpectrum: array (频谱)
└────────────────────────────┘
Popup 和 Content Script 之间不直接通信;它们通过 Chrome Storage API 的变更事件进行双向通信。
| 工具 | 版本 | 用途 |
|---|---|---|
| Vite+ | toolchain | 依赖管理、构建、测试、验证 |
| Vite | 8.x | 内部构建基础设施 |
| CRXJS Vite Plugin | 2.x | Chrome 扩展程序 HMR 和清单生成 |
| React | 19.x | Popup UI |
| TypeScript | 5.9.x | 类型安全 |
| 命令 | 说明 |
|---|---|
vp install |
安装依赖 |
vp build |
生产环境构建 |
vp test |
运行测试 |
vp check |
格式化 / 代码检查 / 类型检查 |