如何使用 SpeechRecognizer 实现离线语音转文字?

解读

面试官抛出这道题,核心想验证三件事:

  1. 你是否知道 Android 官方 SpeechRecognizer 默认只能“在线”调 Google 云端,而国内手机基本阉割 GMS,云端通路不可达;
  2. 你是否具备“离线”落地的工程思维——选型、模型、资源、权限、生命周期、容错、功耗;
  3. 你是否能把“离线”与“国产化合规”结合起来,比如不依赖 Google 服务、不偷传用户音频、支持信创芯片。
    因此,回答必须围绕“无 GMS、纯端侧、可商用”展开,而不是简单贴一段 RecognizerIntent 代码。

知识点

  1. Android 语音识别栈:
    • 官方 API:SpeechRecognizer / RecognizerIntent → 通过 com.google.android.googlequicksearchbox 云端识别,国内不可用。
    • 系统级 PackageManager 查询:若设备厂商内置离线引擎(如华为 HwVoiceService、小米 MiAi、OPPO HeyTapSpeech),可通过隐式 Intent 调起,但机型碎片化严重。
  2. 端侧模型方案:
    • 轻量级流式模型:WeNet、Kaldi 移植、Vosk、Sherpa-ncnn,均基于 ONNX/NCNN,体积 50–150 MB,支持中文。
    • 量化与压缩:INT8 权重 + 稀疏化,可把模型压到 30 MB 以内,首次启动解压到 /data/data/<pkg>/files/ 目录。
    • 音频前端:16 kHz/16 bit 单声道,VAD(WebRTC AGC/VAD)裁剪,MFCC 或 Fbank 特征,20 ms 帧移。
  3. 权限与隐私合规:
    • 麦克风权限:RECORD_AUDIO,Android 13 及以上需“运行时 + 前台服务”双重声明。
    • 隐私政策:在清单中声明 android:required="false" 的麦克风特性,避免商店审核被拒;T-1 天弹窗告知用户“本机离线识别,音频不出端”。
  4. 工程落地:
    • 线程模型:AudioRecord 在常驻 HandlerThread 采集,环形缓冲区 320 ms,回调到 JNI 层推理,结果通过 LiveData 回主线程。
    • 生命周期:Service + BroadcastReceiver 监听屏幕熄灭,立即 stopRecording(),防止耗电。
    • 容错:模型文件 MD5 校验,损坏时从 assets 重新拷贝;JNI 层捕获 OOM,回退到“请手动输入”模式。
  5. 性能指标:
    • 首字延迟 < 300 ms,句末延迟 < 800 ms;
    • 内存峰值 < 180 MB(32 位)/ 280 MB(64 位);
    • 连续识别 30 min,电量消耗 < 3%。

答案

“国内场景下,SpeechRecognizer 默认通道被阉割,真正的离线方案需要三步:
第一步,放弃官方 SpeechRecognizer,改用端侧轻量模型。以 Vosk 为例,把中文 1.8 GB 大模型剪枝到 80 MB,assets 分包动态下发。
第二步,自建 RecognizerService。内部用 AudioRecord 采集 16 kHz 单声道,通过 WebRTC VAD 检测语音起止,只把有效语音段送进 JNI 层推理,避免整段录音占用内存。
第三步,封装与系统 SpeechRecognizer 完全一致的接口:startListening(Bundle) → onBeginningOfSpeech() → onPartialResults() → onResults(),让业务层无感切换。
最后,权限侧在 Android 13 上必须申请 RECORD_AUDIO + FOREGROUND_SERVICE_MICROPHONE,并在代码里动态检测‘后台启动录音’权限,否则小米、华为会直接抛 SecurityException。上线前用 Battery Historian 跑 2 小时 monkey,确保离线模型不持锁、不泄漏、不耗电。”

拓展思考

  1. 如果老板要求“零安装包增量”,如何把 80 MB 模型放到系统分区?
    答:与厂商预装谈判,把模型 push 到 /system/etc/voice/model/,通过 HIDL 暴露 IVoiceRecognitionService,供多应用共享,APK 体积降为 0。
  2. 车载场景下,车机芯片是 RK3566,A35 四核 1.8 GHz,无 NPU,如何再压性能?
    答:改用 WeNet 的 CPU INT8 流式解码,单核占用 35 %,把 beam size 调到 3,字错误率仅上升 0.8 %,可接受。
  3. 合规升级:网信办要求“录音数据不出车”,但又要后台热词更新,如何解?
    答:模型权重拆分:底层声学模型固定在车机,语言模型做成 3-gram 文本文件(仅 2 MB),后台通过 TSP 通道下发差分,客户端合并后重启识别服务,全程无音频上传。