---
title: "Voltip：Rust + Tauri 2 写的开源语音输入，记一下用到的 crate 和几处取舍 - Angryecho"
description: "Voltip 是我做的一个开源语音输入工具，能替代 Typeless 的日常听写：在任意软件里按住 Ctrl+Alt+Space 说话，松开以后，口头禅去掉、说错又改口的地方只留最后的说法，整理好的文字直接出现在光标处。 支持 Windows、macOS、Linux 和 Android，AGPL-3.0。"
canonical_url: "https://www.angryecho.com/c/rustcc/p/P2TBBnr2zj19YdphAcjfx"
meta:
  "og:description": "Voltip 是我做的一个开源语音输入工具，能替代 Typeless 的日常听写：在任意软件里按住 Ctrl+Alt+Space 说话，松开以后，口头禅去掉、说错又改口的地方只留最后的说法，整理好的文字直接出现在光标处。 支持 Windows、macOS、Linux 和 Android，AGPL-3.0。"
  "og:image": "https://www.angryecho.com/_og/d/c_Post%2Ctitle_~5ZCQ5qe9572R%2Cdescription_~5ZCQ5qe95LiA5LiL77yM5bCx5LiK5ZCQ5qe9572R44CC%2CpostId_P2TBBnr2zj19YdphAcjfx%2Crevision_~MjAyNi0xMC0yOVQwMjo1NTo1OS41MDEzMzFa%2Cp_Ii9jL3J1c3RjYy9wL1AyVEJCbnIyemoxOVlkcGhBY2pmeCI%2Cs_ieeXS2QJkK54-7Kc.png"
  "og:image:height": "630"
  "og:image:type": image/png
  "og:image:width": "1200"
  "og:title": "Voltip：Rust + Tauri 2 写的开源语音输入，记一下用到的 crate 和几处取舍"
---

> Index of every page on this site: [llms.txt](https://www.angryecho.com/llms.txt)

# **Voltip：Rust + Tauri 2 写的开源语音输入，记一下用到的 crate 和几处取舍**

Voltip 是我做的一个开源语音输入工具，能替代 Typeless 的日常听写：在任意软件里按住 Ctrl+Alt+Space 说话，松开以后，口头禅去掉、说错又改口的地方只留最后的说法，整理好的文字直接出现在光标处。

![Voltip 首页：快捷键、麦克风、正在使用的语音模型和 AI 润色模型](https://voltip.firlab.app/screens/home-zh-light.webp)

支持 Windows、macOS、Linux 和 Android，AGPL-3.0。识别可以纯本地离线跑，也能接 OpenAI、Groq、硅基流动、阿里云百炼或任意 OpenAI 兼容接口；Android 应用可以当电脑的麦克风和键盘。原生能力全在 Rust 里，这里记一下用到的 crate 和几处取舍，供做类似东西的朋友参考。

### 结构

一个 Rust workspace，加两个 Tauri 2 应用（桌面、Android），共用一套 React 界面。界面只显示状态、发命令，全局快捷键、音频、识别、文字插入、剪贴板、加密连接都在 Rust 里。依赖方向只允许向下：`apps → core → {pairing, transport, identity} → {crypto, protocol}`；中继 `voltip-relay` 只依赖 `protocol`，拿不到也不需要会话密钥。

Rust 到 webview 的通道按语义分：离散的状态变化走事件总线并折叠进一个 `UiState`；电平、进度这类连续流走 `tauri::ipc::Channel`，跟着发起它的 command 结束；事件总线不承载 30 Hz 以上的数据。

### 本地识别

- `transcribe-cpp`：跑 Qwen3-ASR 的 GGUF 模型，ggml 源码用 cmake 构建、静态链接。macOS 开 `metal` feature，Windows / Linux 的发布包开 `vulkan` feature（测试和 lint 的 gate 不开，因为要装 Vulkan SDK）。Windows 包在 Linux 上用 cargo-xwin 交叉编译到 `x86_64-pc-windows-msvc`。
- `sherpa-onnx`：跑 SenseVoice、Paraformer 和实时识别模型，用 `shared` feature 动态链接，**不用** `**static**`：那组静态库会把 espeak-ng（GPL-3.0）链进来。
- `rubato`：整段重采样到 16 kHz 再交给 transcribe.cpp（它只收 16 kHz）。
- 模型下载断点续传，每个文件用之前校验 SHA-256。

### 音频

- `cpal`：麦克风枚举和输入（WASAPI / CoreAudio / ALSA / Android AAudio），电平计算是纯 DSP，可以脱离硬件测。
- `rtrb`：录音时音频回调往无锁的单生产者单消费者环形缓冲里推 16 kHz 单声道帧，解码线程取出；音频线程上不加锁、不分配内存。
- `sonora`：WebRTC AEC3 的纯 Rust 移植，用在「麦克风 + 电脑声音」混合录音时消除扬声器回声。选它而不是 `aec3`，是按实测的消除效果和依赖比较的结果；纯 Rust 也省掉了各平台的 C 工具链。
- `opus-rs`：libopus 1.6 的纯 Rust 移植，手机当麦克风时先压缩音频再传；Android 和 Windows 交叉编译都不用 C 工具链。

### 文字处理

- `aho-corasick`：个人词典（每个词条一个正确写法，加最多 10 个常被听错的写法）和字面替换规则的多模式匹配，本来就因为 `regex` 在依赖图里。
- `ferrous-opencc`：简繁转换，字典在构建时编译进二进制，约 2.3 MB，日文表不带。
- `enigo` + `arboard`：插入文字的办法是把文字放进剪贴板、模拟一次粘贴、再把剪贴板原来的内容放回去。目标窗口以管理员身份运行等粘贴不进去的情况，文字留在剪贴板里，悬浮窗说明原因，不会丢。

### 手机和电脑之间

- `snow`： `Noise_XX_25519_ChaChaPoly_SHA256`。配对时两端显示由握手哈希推出的安全码，人工核对一致才信任；已配对设备重逢时同样用 XX。
- 配对和连接的状态机写成 sans-IO： `step(event) -> Vec<Action>`，网络和时间由调用方注入，单元测试里能把超时、重放、频道被占这些路径走一遍。
- 设备之间只经中继（ `axum` 的 WebSocket），中继只转发密文；协议帧用 `ciborium`（CBOR）编码，中继的控制帧是 JSON，方便排障。

### 其他

- `axum`：除了中继，还有 OpenAI 兼容的本机语音服务 `/v1/audio/transcriptions`（无头的 `voltip-server` 在没有桌面的 Linux 上跑同一套识别、词典和预设）。
- `rmcp`：本机 MCP 服务，让 Claude Code、Codex 读替换汇总、帮你整理词典；它新建的规则要用户确认才生效。
- `keyring`：服务商密钥和设备私钥存进系统钥匙串； `rusqlite`（bundled）存历史记录。
- 依赖全部用 `=` 锁定确切版本；Rust 行覆盖率门是 90%（ `cargo llvm-cov`）。

### 不足也先说

- 还没有 iOS 版；纯 Wayland 会话没有全局快捷键，要在系统设置里自己绑；
- Windows 安装包还没做代码签名，第一次运行 SmartScreen 会提示；
- 每次都要按键说话，没有语音唤醒。

开源免费，官网： https://voltip.firlab.app/zh/ ，源码： https://github.com/sunerpy/voltip 。目前支持 Windows/Linux/macOS/Android 版本，欢迎使用，如果觉得有用可以动动小手给个 star，也欢迎来提 issue 和 PR。

排序方式 :

### **成为第一条评论！**

Nobody's responded to this post yet. Add your thoughts and get the conversation going.

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://www.angryecho.com/c/rustcc/p/P2TBBnr2zj19YdphAcjfx#post","@type":"DiscussionForumPosting","commentCount":0,"dateModified":"2026-10-29T02:55:59.501Z","datePublished":"2026-10-26T07:54:00.000Z","description":"Voltip 是我做的一个开源语音输入工具，能替代 Typeless 的日常听写：在任意软件里按住 Ctrl+Alt+Space 说话，松开以后，口头禅去掉、说错又改口的地方只留最后的说法，整理好的文字直接出现在光标处。 支持 Windows、macOS、Linux 和 Android，AGPL-3.0。","headline":"Voltip：Rust + Tauri 2 写的开源语音输入，记一下用到的 crate 和几处取舍","isPartOf":"https://www.angryecho.com/c/rustcc","mainEntityOfPage":"https://www.angryecho.com/c/rustcc/p/P2TBBnr2zj19YdphAcjfx","text":"Voltip 是我做的一个开源语音输入工具，能替代 Typeless 的日常听写：在任意软件里按住 Ctrl+Alt+Space 说话，松开以后，口头禅去掉、说错又改口的地方只留最后的说法，整理好的文字直接出现在光标处。\n\n\n\n支持 Windows、macOS、Linux 和 Android，AGPL-3.0。识别可以纯本地离线跑，也能接 OpenAI、Groq、硅基流动、阿里云百炼或任意 OpenAI 兼容接口；Android 应用可以当电脑的麦克风和键盘。原生能力全在 Rust 里，这里记一下用到的 crate 和几处取舍，供做类似东西的朋友参考。\n\n结构\n\n一个 Rust workspace，加两个 Tauri 2 应用（桌面、Android），共用一套 React 界面。界面只显示状态、发命令，全局快捷键、音频、识别、文字插入、剪贴板、加密连接都在 Rust 里。依赖方向只允许向下：apps → core → {pairing, transport, identity} → {crypto, protocol}；中继 voltip-relay 只依赖 protocol，拿不到也不需要会话密钥。\n\nRust 到 webview 的通道按语义分：离散的状态变化走事件总线并折叠进一个 UiState；电平、进度这类连续流走 tauri::ipc::Channel，跟着发起它的 command 结束；事件总线不承载 30 Hz 以上的数据。\n\n本地识别\n\n\n\n\n\ntranscribe-cpp：跑 Qwen3-ASR 的 GGUF 模型，ggml 源码用 cmake 构建、静态链接。macOS 开 metal feature，Windows / Linux 的发布包开 vulkan feature（测试和 lint 的 gate 不开，因为要装 Vulkan SDK）。Windows 包在 Linux 上用 cargo-xwin 交叉编译到 x86_64-pc-windows-msvc。\n\n\n\nsherpa-onnx：跑 SenseVoice、Paraformer 和实时识别模型，用 shared feature 动态链接，不用 static：那组静态库会把 espeak-ng（GPL-3.0）链进来。\n\n\n\nrubato：整段重采样到 16 kHz 再交给 transcribe.cpp（它只收 16 kHz）。\n\n\n\n模型下载断点续传，每个文件用之前校验 SHA-256。\n\n音频\n\n\n\n\n\ncpal：麦克风枚举和输入（WASAPI / CoreAudio / ALSA / Android AAudio），电平计算是纯 DSP，可以脱离硬件测。\n\n\n\nrtrb：录音时音频回调往无锁的单生产者单消费者环形缓冲里推 16 kHz 单声道帧，解码线程取出；音频线程上不加锁、不分配内存。\n\n\n\nsonora：WebRTC AEC3 的纯 Rust 移植，用在「麦克风 + 电脑声音」混合录音时消除扬声器回声。选它而不是 aec3，是按实测的消除效果和依赖比较的结果；纯 Rust 也省掉了各平台的 C 工具链。\n\n\n\nopus-rs：libopus 1.6 的纯 Rust 移植，手机当麦克风时先压缩音频再传；Android 和 Windows 交叉编译都不用 C 工具链。\n\n文字处理\n\n\n\n\n\naho-corasick：个人词典（每个词条一个正确写法，加最多 10 个常被听错的写法）和字面替换规则的多模式匹配，本来就因为 regex 在依赖图里。\n\n\n\nferrous-opencc：简繁转换，字典在构建时编译进二进制，约 2.3 MB，日文表不带。\n\n\n\nenigo + arboard：插入文字的办法是把文字放进剪贴板、模拟一次粘贴、再把剪贴板原来的内容放回去。目标窗口以管理员身份运行等粘贴不进去的情况，文字留在剪贴板里，悬浮窗说明原因，不会丢。\n\n手机和电脑之间\n\n\n\n\n\nsnow：Noise_XX_25519_ChaChaPoly_SHA256。配对时两端显示由握手哈希推出的安全码，人工核对一致才信任；已配对设备重逢时同样用 XX。\n\n\n\n配对和连接的状态机写成 sans-IO：step(event) -> Vec\u003CAction>，网络和时间由调用方注入，单元测试里能把超时、重放、频道被占这些路径走一遍。\n\n\n\n设备之间只经中继（axum 的 WebSocket），中继只转发密文；协议帧用 ciborium（CBOR）编码，中继的控制帧是 JSON，方便排障。\n\n其他\n\n\n\n\n\naxum：除了中继，还有 OpenAI 兼容的本机语音服务 /v1/audio/transcriptions（无头的 voltip-server 在没有桌面的 Linux 上跑同一套识别、词典和预设）。\n\n\n\nrmcp：本机 MCP 服务，让 Claude Code、Codex 读替换汇总、帮你整理词典；它新建的规则要用户确认才生效。\n\n\n\nkeyring：服务商密钥和设备私钥存进系统钥匙串；rusqlite（bundled）存历史记录。\n\n\n\n依赖全部用 = 锁定确切版本；Rust 行覆盖率门是 90%（cargo llvm-cov）。\n\n不足也先说\n\n\n\n\n\n还没有 iOS 版；纯 Wayland 会话没有全局快捷键，要在系统设置里自己绑；\n\n\n\nWindows 安装包还没做代码签名，第一次运行 SmartScreen 会提示；\n\n\n\n每次都要按键说话，没有语音唤醒。\n\n开源免费，官网：https://voltip.firlab.app/zh/ ，源码：https://github.com/sunerpy/voltip 。目前支持 Windows/Linux/macOS/Android 版本，欢迎使用，如果觉得有用可以动动小手给个 star，也欢迎来提 issue 和 PR。","url":"https://www.angryecho.com/c/rustcc/p/P2TBBnr2zj19YdphAcjfx","author":{"@type":"Person","name":"sunerpy","url":"https://www.angryecho.com/u/R4C0984662a-9aed-4d2"},"image":["https://voltip.firlab.app/screens/home-zh-light.webp"],"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/DislikeAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":0}]}]}
```

## Sitemap

See the full [sitemap](https://www.angryecho.com/sitemap.md) for all pages.
