22、语音交互:Google Assistant 集成,自定义语音引擎(VHAL 语音控制)
语音交互在车载系统里,说实话,已经不只是“锦上添花”的功能了。用户坐进车里,第一件事可能就是喊“Hey Google,导航去公司”。如果这个链路没打通,整个座舱体验会大打折扣。
今天我们来聊聊 Android Automotive OS 里的语音交互。重点有两个:一是怎么把 Google Assistant 集成进来,二是如果车厂想用自己的语音引擎,怎么通过 VHAL 做语音控制。
Google Assistant 的集成方式
Google Assistant 在 AAOS 里不是随便一个 App,它是系统级服务。集成它,说白了就是走 Google 的 GMS 认证流程。
我当年在项目里第一次接 Assistant,以为加个 APK 就行。结果发现,事情没那么简单。
核心要点:Google Assistant 需要 Automotive GMS 包,并且要配置好对应的权限和 Service。
集成步骤大致如下:
- 获取 GMS 认证——车厂需要和 Google 签协议,拿到 Automotive GMS 包。
- 配置 Assistant Service——在
AndroidManifest.xml里声明 Assistant 服务。 - 绑定麦克风输入——语音数据要从车载麦克风走 Audio HAL 传到 Assistant。
- 处理响应——Assistant 返回的结果,要么播报,要么执行动作。
这里有个坑。我记得有一次,麦克风数据一直传不过去。查了半天,发现是 Audio Policy 配置里没把麦克风设备设为“语音识别”的默认源。嗯,这种细节很容易漏掉。
自定义语音引擎:为什么需要?
有些车厂不想用 Google Assistant。原因很多:数据隐私、本地化需求、或者单纯想打造自己的品牌语音助手。
这时候就需要自定义语音引擎。说白了,就是自己写一个语音识别 + 语义理解的 Service,然后把它注册成系统默认的 Assistant。
怎么做?核心就两步:
- 实现一个
VoiceInteractionService的子类。 - 在 Manifest 里声明
BIND_VOICE_INTERACTION权限。
代码大概长这样:
public class MyCarVoiceService extends VoiceInteractionService {
@Override
public void onReady() {
super.onReady();
// 初始化语音引擎
initVoiceEngine();
}
private void initVoiceEngine() {
// 加载本地语音模型
// 或者连接云端语音服务
}
}
然后在 Manifest 里:
<service
android:name=".MyCarVoiceService"
android:permission="android.permission.BIND_VOICE_INTERACTION">
<intent-filter>
<action android:name="android.service.voice.VoiceInteractionService" />
</intent-filter>
</service>
提示:注册完 Service 后,还要在 Settings 里把默认 Assistant 改成你的 Service。否则系统不会调用它。
VHAL 语音控制:让语音真正“开车”
语音控制不只是“打开音乐”这种 App 层面的操作。真正有价值的是控制车辆硬件——比如调空调、开窗户、调座椅。
这些操作怎么通过语音实现?答案就是 VHAL。
VHAL(Vehicle Hardware Abstraction Layer)是 AAOS 里访问车辆硬件的标准接口。语音引擎识别到用户的意图后,通过 VHAL 下发指令,车就能动起来。
举个例子,用户说“把空调调到 24 度”。流程是这样的:
- 语音引擎识别出“空调”和“24度”。
- 引擎调用 VHAL 的
setProperty方法,设置 HVAC 温度属性。 - VHAL 把指令传给 MCU,空调开始工作。
代码示例:
public void setHvacTemperature(int zone, float temp) {
VehiclePropValue prop = new VehiclePropValue();
prop.prop = VehicleProperty.HVAC_TEMPERATURE_SET;
prop.areaId = zone;
prop.value.floatValue = temp;
prop.status = VehiclePropertyStatus.AVAILABLE;
try {
mVehicle.setProperty(prop);
} catch (RemoteException e) {
Log.e("VoiceControl", "设置空调温度失败", e);
}
}
警告:VHAL 的 setProperty 是异步的。不要在主线程里调用,也不要做同步等待。我曾经见过一个项目,因为同步等待 VHAL 返回,导致 UI 线程卡死,整个系统都冻住了。
语音控制的权限与安全
语音控制车辆硬件,涉及安全问题。你不能让语音随便控制刹车、油门吧?
AAOS 里,VHAL 的每个属性都有访问权限控制。语音引擎需要申请对应的权限,才能在 VHAL 里操作。
常见的权限分级:
| 权限级别 | 示例操作 | 是否需要用户确认 |
|---|---|---|
| 低风险 | 调音量、切歌 | 不需要 |
| 中风险 | 调空调、开窗户 | 建议确认 |
| 高风险 | 开车门、启动引擎 | 必须确认 |
我建议,中风险以上的操作,语音执行前最好弹个确认框。或者要求用户说“确认”才能执行。否则误触发会很麻烦。
SVG 流程图:语音控制 VHAL 的完整链路
这张图展示了从用户说出指令到车辆硬件执行的完整链路。你想想看,中间任何一个环节出问题,语音控制就废了。所以每个节点都要做好异常处理。
实际项目中的避坑指南
我在几个项目里踩过不少坑,挑几个典型的说说:
- 麦克风唤醒延迟——用户喊了“Hey Google”,但系统要等两三秒才响应。原因是麦克风没做低功耗唤醒。后来我们改成了 DSP 硬件唤醒,延迟降到 0.5 秒以内。
- VHAL 属性冲突——语音引擎和 HMI 同时操作同一个 VHAL 属性,导致状态不一致。解决办法是加一个锁机制,同一时间只允许一个模块写属性。
- 多音区处理——车里四个座位,每个座位的人都能喊语音。但空调温度只能调一个区的。我们后来做了“焦点座位”策略,谁先唤醒,语音就优先处理谁的命令。
小技巧:调试语音控制 VHAL 时,可以用 dumpsys vehicle_hal 查看当前所有属性的值。这样能快速定位是语音引擎没发指令,还是 VHAL 没执行。
总结一下
语音交互在 AAOS 里,核心就是两件事:集成 Google Assistant 或者自建语音引擎,然后通过 VHAL 控制车辆硬件。
集成 Assistant 走 GMS 认证流程,自建引擎则要实现 VoiceInteractionService。VHAL 语音控制要注意权限分级和安全确认,别让语音随便动刹车油门。
嗯,语音这块其实还有很多细节,比如多语言支持、离线识别、降噪处理。但今天先把主链路讲清楚,剩下的后面再聊。
公众号:蓝海资料掘金营,微信deep3321