返回博客

Android 离线语音输入实现方案

在移动应用开发中,语音输入已成为提升用户体验的重要交互方式。然而,传统的云端语音识别方案存在明显的痛点:网络依赖、隐私风险、延迟抖动、成本不可控。对于需要高隐私保护、弱网环境可用、或实时性要求高的场景,真正的离线语音识别成为必需。

⚠️ 注意:本文讨论的"离线语音识别"指的是完全端侧运行的方案,模型文件打包在 APK 中或下载到本地,识别过程不依赖任何网络请求。Google SpeechRecognizer 的"离线模式"并非真正的离线方案。

三大主流方案对比

方案模型大小准确率实时性推荐指数
Sherpa ONNX30MB-200MB⭐⭐⭐⭐⭐优秀⭐⭐⭐⭐⭐ 首选
Whisper39MB-155MB⭐⭐⭐⭐⭐一般⭐⭐⭐⭐ 适合转写
Vosk50MB-1GB⭐⭐⭐⭐优秀⭐⭐⭐⭐ 备选

Sherpa ONNX(强烈推荐)

Sherpa ONNX 是新一代开源语音识别工具包,基于下一代 Kaldi(k2)和 ONNX Runtime,专为嵌入式和移动设备优化。

核心优势:模型小巧、支持流式识别、延迟极低、中文效果优异、活跃社区维护。

快速集成

  1. 下载模型:从 Releases 下载中文模型(推荐 20M 版本,约 60MB)
  2. 添加依赖implementation 'com.github.k2-fsa:sherpa-onnx-android:1.10.0'
  3. 初始化识别器:加载模型并创建 OfflineRecognizer
  4. 录音识别:使用 AudioRecord 采集音频,调用 recognizer.decode()

核心代码

// 初始化识别器
val config = OfflineRecognizerConfig().apply {
    modelConfig = OfflineModelConfig().apply {
        transducer = OfflineTransducerModelConfig().apply {
            encoder = "$modelDir/encoder.onnx"
            decoder = "$modelDir/decoder.onnx"
            joiner = "$modelDir/joiner.onnx"
        }
        tokens = "$modelDir/tokens.txt"
        numThreads = 4
    }
}
val recognizer = OfflineRecognizer(config)

// 识别音频
val result = recognizer.decode(audioData, 16000f)
println(result.text)

完整实现参考官方 Android 示例项目

模型选择

场景推荐模型大小RTF*
实时语音输入Zipformer 20M~60MB0.1
低功耗设备Zipformer 14M~40MB0.05
高准确率Paraformer~200MB0.3

* RTF:处理 1 秒音频所需时间,< 1 表示实时

Whisper(适合转写)

Whisper 是 OpenAI 开源的通用语音识别模型。需要通过 whisper.cpp 移植到 Android。

局限:不支持流式识别,需要完整音频文件,延迟较高(RTF ≈ 1.0),不适合实时语音输入。

Vosk(备选)

Vosk 基于传统 Kaldi,API 设计简洁,适合快速原型开发。但模型相对老旧,Sherpa ONNX 是更好的选择。

// Vosk 简洁 API
val model = Model("/path/to/model")
val recognizer = Recognizer(model, 16000f)
recognizer.acceptWaveform(buffer)
val result = recognizer.result()

性能优化建议

总结

Android 离线语音识别技术已经相当成熟,Sherpa ONNX 凭借出色的性能、小巧的模型体积和活跃的社区,成为当前最推荐的方案。

方案推荐场景注意事项
Sherpa ONNX实时语音输入、低延迟场景首选方案,中文效果优异
Whisper语音转写、多语言支持不支持流式,延迟较高
Vosk快速原型、简单集成模型较老,建议迁移到 Sherpa