Android平台使用VIA创建语音交互应用
概述
在 Android 平台上开发一款语音助手应用需要整合多种技术,包括语音识别(ASR)、文字转语音(TTS)、以及热词检测(Hotword Detection)。这些技术共同构成了语音助手应用的核心交互方式,使用户能够通过语音命令与设备进行无缝交流。
首先,语音识别(ASR, Automatic Speech Recognition) 是语音助手的基础功能,它将用户的语音转换为文本输入。在 Android 中,语音识别功能可以通过 AOSP 提供的 SpeechRecognizer
API 来实现。开发者可以使用该 API 捕捉用户的语音输入,并将其转换为结构化的数据,进而执行相应的命令。ASR 是一个关键的组件,能够理解自然语言并执行复杂指令。
接着,文字转语音(TTS, Text-to-Speech) 则提供了语音助手回应用户的方式。通过 TextToSpeech
类,应用可以将生成的文本以语音形式输出,支持多种语言和个性化设置。TTS 技术用于语音助手提供反馈,播报信息或执行通知,使交互更加人性化和直观。
VoiceInteractor 是 Android 提供的一个接口,用于处理复杂的语音交互请求。它允许应用程序与用户进行更自然的对话,例如多轮交互、确认、选择等操作。通过 VoiceInteractor,开发者可以实现更加智能和复杂的语音命令处理,例如在用户语音输入后提供进一步的选项或请求确认,提升语音助手的交互能力。
此外,热词检测(Hotword Detection) 是语音助手的重要功能之一。热词检测允许设备通过指定的唤醒词(如“Hey Google”)启动语音助手,即使设备处于待机状态。通过 Android 的 HotwordDetector
或其他硬件支持,应用可以始终在线监听用户的唤醒词,实现即时交互。这使得语音助手能够在不显著增加电量消耗的情况下,随时为用户提供服务。
通过结合语音识别、文字转语音和热词检测,Android 语音助手能够实现完整的语音交互流程,为用户提供更自然流畅的使用体验。在构建这类应用时,开发者需要灵活运用 Android 提供的 API 和框架,并确保高效的资源管理与用户隐私的保护。
术语
在本指南中涉及以下术语:
• 辅助数据:启动语音交互会话后,系统可以截取当前屏幕和视图的内容,并将这些信息传递给会话。应用可以通过实现
Activity#onProvideAssistData()
和Activity#onProvideAssistContent()
方法提供更多细节。• 按住开始讲话 (PTT):指实体的语音控制按钮,Auto通常位于方向盘等设备上,手机设备通常会复用电源键或者音量按键,用户按下后可以进行语音指令。
• RecognitionService (RS):由应用通过
SpeechRecognizer
API 使用的语音识别服务。VIA 必须包含VoiceInteractionService
和RecognitionService
。• 点按后说话 (TTT):软件的语音控制按钮,通常位于系统界面中。在 Android 中,也称为“辅助手势”。
• VoiceInteractionService:VIA 开发者实现的轻量级系统服务。系统服务会在设备启动时绑定选定服务,并使其始终处于运行状态。
• VoiceInteractionSession (VIS):封装用户交互逻辑的类,显示语音交互状态,并处理
VoiceInteractor
请求,还能接收辅助数据和屏幕截图。• VoiceInteractionSessionService (VSS):VIA 中用于处理语音交互会话的服务。系统在用户语音交互期间会绑定此服务,所有会话逻辑均由
VoiceSession
类实现。系统仅保证此服务在单个用户会话期间活跃。• 语音交互应用 (VIA):提供语音控制功能的 Android 应用,通常称为“助理”。通过在应用清单中声明
VoiceInteractionService
进行标识。系统中每次只能有一个默认的 VIA 应用,它会接收按住开始讲话 (PTT) 和点按后说话 (TTT) 事件,并与系统服务绑定。
职责
下表介绍基于AOSP语音识别框架各方在 Android 设备中的职责划分。
角色 | 责任描述 |
设备制造商 (OEM) | 构建与 AOSP 兼容的设备系统。 实现音频输入输出功能,可选择性地添加 DSP 进行启动指令检测支持。 为语音交互服务授予系统特权。 遵守与应用设置屏幕访问权限相关的 VoiceInteractionService 要求。 |
AOSP | 定义并优化 VoiceInteractionService 及相关 API。为 VIA 开发者提供 API 文档、示例代码及其他支持材料。 提供包含要求和建议的用户体验设计指南。 |
应用开发者 | 实现 VoiceInteractionService API、RecognitionService API 和 NotificationListenerService API。提供可自定义的用户界面,以便 OEM 能根据不同设备设计进行调整。 |
该职责分工确保设备、系统服务和应用之间的紧密集成,从而为 Android 通用设备中的语音交互提供更优质的用户体验。
功能要求
一个完整的语音助手App应包含以下功能点:
• [Must] 响应由系统处理的语音交互触发器(如按住讲话按钮 PTT、点击讲话按钮 TTT)。
• [Must] 直观地显示触发器的状态和进度(例如正在监听、处理或执行)。
• [Must] 通过语音或提示音反馈用户请求的理解与处理结果。
• [Must] 作为其他应用的语音识别服务提供程序(参见
SpeechRecognizer API
)。• [Need] 响应设备启动指令的语音触发。
• [Option] 显示“设置”界面,允许用户配置 VIA(如权限管理、启动指令配置、登录等)。
• [Option] 处理辅助数据(例如
Intent#ACTION_ASSIST
提供的内容)。• [Option] 支持在锁屏状态下进行语音交互操作。
组件构成
大体上讲,语音交互应用会与以下操作方进行交互:
• VoiceInteractionManagerService:该系统服务负责管理默认的语音交互应用(VIA),并将其功能扩展至系统的其他部分。
• RecognitionService:为系统中的其他应用提供语音识别功能的服务。
• SoundTrigger:用于管理启动指令,VIA 可通过
AlwaysOnHotwordDetector
使用该功能。• MediaRecorder:用于访问音频输入,执行启动指令检测(当 CPU 参与时)和语音识别任务。
• PhoneWindowManager/CarInputService:这些服务负责将按住讲话按钮 (PTT) 路由至 VIA,以处理关键事件,此外还承担其他职责。
• User:用户通过触发器(PTT、TTT、启动指令)或语音控制面板界面与 VIA 进行交互。
• CarService、Notifications、Media、Telephony、ContactsProvider:这些系统服务和应用由 VoiceInteractionSession 用于执行用户的语音指令。
激活与关闭
安装到设备的语音助手默认是不激活的,需要通过默认应用设置来激活或关闭
作者使用的荣耀X50的设备,基于Android13, 设置默认语音助手的步骤设置> 应用> 默认应用> 辅助应用和语音输入> 辅助应用。选择你想要使用的助手应用。
设置完成后,会有屏幕文字及截图权限设置界面,如上图所示。
激活后,Yoyo助理就可以使用了,短按键电源键就你能启动交互界面,后面想要切换其他助手应用,如科大讯飞、天猫精灵等也通过这里设置,如果想要关闭助手功能,可以设置为无, 这样所有助手应用进程都会退出。
选定的 VIA 会通过两种方式提供给系统:
1. 作为
RolesManager
系统服务的一部分提供2. 由
VoiceInteractionManagerService
通过AssistUtils
内部 API 提供。可以使用RolesManager
和角色名称android.app.role.ASSISTANT
来获取候选 VIA 列表。
启动会话
启动会话也就是触发语音输入及识别的过程,这里可通过3种方式启动语音交互:
1. 启动指令触发 Android 提供 AlwaysOnHotwordDetector 作为硬件 DSP 之上的一种抽象。这提供了一种便捷的方式,供您将 VoiceInteractionService 与语音模型关联起来,从而实现始终开启的低功耗语音识别。这是最常见、最广为人知的交互流程,在此流程中,用户会请求与语音应用 (VA) 进行交互,以发起新的对话。以这种方式启动的语音会话使用 SHOW_SOURCE_ASSIST_GESTURE flag 进行标识。AlwaysOnHotwordDetector 依赖于启动指令注册、SoundTrigger HAL 和硬件支持。这些可能不是在所有设备上都有。在这种情况下,如果需要支持启动指令检测,这些应用可能需要使用原生库来捕获并处理音频输入流。Android框架提供了HotwordDetectionService
来使用原生库方式实现热词唤醒,我们可以在HotwordDetectionService#onDetect
方法中实现相关唤醒处理流程。当VoiceInteractionService
启动后,我们便可以在该服务下创建HotwordDetector
启动热词探测,对于有DSP芯片支持的设备,我们使用createAlwaysOnHotwordDetector
系列接口,对于不支持DSP芯片的设备,我们使用createHotwordDetector
,使用AudioRecoder提供的音频数据进行热词识别, 热词探测还要结合KeyphraseModelManager
相关接口完成工作。
VoiceInteractionService启动后启动热词探测服务示例代码
```java
package com.android.test.voiceinteraction;
import android.content.Intent;
import android.service.voice.AlwaysOnHotwordDetector;
import android.service.voice.VoiceInteractionService;
import android.util.Log;
import java.util.Locale;
public class MainInteractionService extends VoiceInteractionService {
private static final String TAG = "MainInteractionService";
private AlwaysOnHotwordDetector mHotwordDetector;
// Callback to handle hotword detection events
private final AlwaysOnHotwordDetector.Callback mHotwordCallback = new AlwaysOnHotwordDetector.Callback() {
@Override
public void onAvailabilityChanged(int status) {
Log.i(TAG, "Hotword availability changed: " + status);
handleHotwordAvailability(status);
}
@Override
public void onDetected(AlwaysOnHotwordDetector.EventPayload eventPayload) {
Log.i(TAG, "Hotword detected");
}
@Override
public void onError() {
Log.i(TAG, "Hotword detection error");
}
.......
};
@Override
public void onReady() {
super.onReady();
Log.i(TAG, "Service ready. Initializing Hotword Detector.");
// Create Hotword Detector with specified keyphrase and locale
mHotwordDetector = createAlwaysOnHotwordDetector(
"Hello There", Locale.forLanguageTag("en-US"), mHotwordCallback);
}
// Handle the hotword availability status
private void handleHotwordAvailability(int availability) {
switch (availability) {
.......
case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNENROLLED:
Log.i(TAG, "Keyphrase not enrolled, prompting for enrollment");
Intent enrollIntent = mHotwordDetector.createEnrollIntent();
startActivity(enrollIntent); // Start enrollment activity
break;
case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED:
Log.i(TAG, "Keyphrase enrolled, starting recognition");
if (mHotwordDetector.startRecognition(AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE)) {
Log.i(TAG, "Hotword recognition started successfully");
} else {
Log.i(TAG, "Failed to start hotword recognition");
}
break;
}
}
}
代码说明:
1. 初始化
AlwaysOnHotwordDetector
:在onReady()
中,通过createAlwaysOnHotwordDetector()
创建热词探测器,指定了关键字(“Hello There”)和语言(英语)。2. 热词探测回调:定义了回调
mHotwordCallback
来处理热词可用性、探测事件和错误。3. 热词可用性处理:
handleHotwordAvailability()
根据探测器的状态执行不同的操作,比如提示用户进行关键字注册或启动热词识别。4. 启动识别:当关键字已注册时,尝试启动热词识别并记录结果。
对于使用HotwordDetectionService
方式实现的热词探测,特别适用于通过第三方热词探测库实现的助手应用,我们可以在HotwordDetectionService
中启动识别引擎,如果热词被识别到,然后通过回调onDetect方法
传递过来的Callback
将探测结果回调给客户端, 然后客户端便可以启动后续的识别流程。
2. PTT 触发
这适用于长按或短按硬件按钮。在 AAOS 中,PTT 由 CarInputService 处理。在默认实现中,此服务会处理通过车载 HAL 收到的输入事件,并在语音交互这一特殊情境中对关键事件采用以下逻辑:
• 短按 PTT 事件 (KeyEvent.KEYCODE_VOICE_ASSIST) 将被定向到
VoiceInteractionManagerService
,以启动新的语音会话。• 长按 PTT 事件将首先传递到投射接收器(如 Android Auto 或 CarPlay),然后再传递到已通过蓝牙连接的设备,最后传递到本地 VIA 应用。按照此流程启动的会话使用
SHOW_SOURCE_PUSH_TO_TALK
进行标识。
3. “点按后说话”触发(或软件按钮) 这种方式是Android手机、平板等手持设备上常用的触发方式,比如当我使用语音搜索时,我需要先通过按钮触发一个输入交互窗口,然后说话,说完话后系统就开始开始执行语义理解、关键字搜索等后续流程。
权限及分发
权限及分发问题
在开发三方语音助手(VIA)时,权限管理和分发机制至关重要。
1. 权限管理:
• 用户无法直接授予特许权限,OEM需将需要的APK预加载到系统映像中,并在构建中明确授予这些权限。
• 在
Android.bp
文件中设置依赖项,并在vendor/…/data/etc/car/
文件夹中添加特权许可名单。
android_app {
...
required: ["privapp_allowlist_com.example.myvoicecontrol"],
...
}
prebuilt_etc {
name: "privapp_allowlist_com.example.myvoicecontrol",
sub_dir: "permissions",
src: "com.example.myvoicecontrol.xml",
filename_from_src: true,
}
• 部分危险权限可预先授予默认的
VoiceInteractionService
,而非默认VIA需在首次使用时请求权限。具体权限可在 DefaultPermissionGrantPolicy.java 中查看。可以使用 default-permissions.xml 配置文件来预先授予权限,但需遵循Android兼容性定义文档(CDD)第9节的相关限制。
1. 分发机制:
• 预安装的VIA必须位于
/product/priv-apps
或/vendor/priv-apps
分区。•
vendor
分区的应用可能无法访问某些系统API,更新可通过OTA或应用商店进行。
有效管理权限和分发机制能够确保三方语音助手在Android设备上的稳定性和可靠性。
推荐阅读
如何打造车机语音交互:Google Voice Interaction 给你答案