前言
在Android车载开发启示录|语音篇-全局在胸的博客。笔者介绍了车载语音系统的实现流程,包括语音捕捉、语音识别、自然语言处理、文本到语音等环节。其中文本到语音(TextToSpeech)这一环在整个语音系统中是非常重要,可以说是必不可少的。
本篇博客将从 TTS 的基础知识入手,详细介绍如何在Android项目中实现文本到语音转换的,揭秘TextToSpeech的声音魔法
什么是 TextToSpeech?
TextToSpeech
是 Android
提供的文本到语音转换框架,主要功能是将字符串形式的文本转化为可听的语音。在车载系统环境下,它的应用场景涵盖语音导航、消息播报、语音助手等功能:
-
语音导航
TTS 被广泛应用于车载导航系统,用于将实时的路径指引以语音形式播报。例如:
- "请在前方 500 米右转"
- 动态交通更新,如 "前方出现拥堵,正在为您重新规划路线"
-
消息通知
车载系统会通过 TTS 将短信、日程或应用通知内容读出来,减少驾驶员查看屏幕的需求,从而提高安全性。
-
语音助手
集成 TTS 的语音助手能够通过语音回答驾驶员的查询,例如天气、股票信息或系统设置。
-
无障碍功能
为驾驶员提供辅助语音功能,例如读出菜单选项或帮助信息,提高人机交互的友好性。
TextToSpeech
的核心是语音合成引擎,Android
系统通常预装 Google TTS
引擎,但开发者也可以选择第三方引擎。
TextToSpeech 的实现
架构
TextToSpeech 的架构可以划分为以下层次:
1.应用层
负责与开发者和用户交互,包括 API 调用与界面操作。
Android 提供的 android.speech.tts.TextToSpeech
类允许开发者在应用中轻松集成 TTS 功能。
2.框架层
由 Android
系统提供的 TextToSpeech
服务及其接口组成,负责连接应用与底层引擎。并提供了一套抽象接口和系统服务:
(1)TextToSpeechService
- Android 系统的 TTS 服务,通过 AIDL(Android 接口定义语言)与应用层通信。
- 负责调用 TTS 引擎,管理实例的生命周期。
- 支持多用户、多任务并发操作。
(2)TextToSpeechManager
- 系统级管理类,用于协调多个应用对 TTS 引擎的访问。
- 例如,语音导航的播报优先级可能高于音乐通知。
(3)配置与优化
- 设置默认引擎:通过系统设置界面或编程方式设置默认的 TTS 引擎。
- 调整音频属性:通过
AudioAttributes
配置音频流类型。
3.引擎层
引擎层是整个架构的核心部分,负责实际的文本到语音转换,可能由 Google TTS、第三方 TTS 引擎或设备厂商定制的引擎提供。
TTS 引擎种类
- Google TTS:Android 默认的语音合成引擎,支持在线和离线模式。
- 第三方引擎:如 Nuance、Cerence 等,提供高级语音功能和定制化能力。
- 设备厂商自研引擎:部分车厂可能提供优化后的 TTS 引擎以适配其车载系统。
4.音频输出层
通过 Audio HAL 将生成的语音音频传递到车载音响设备。
(1)AudioTrack 与 AudioFlinger TTS 引擎生成语音数据后,通过 AudioTrack
播放,AudioFlinger
负责管理音频流的混合与路由。
(2)音频 HAL(Hardware Abstraction Layer) HAL 将音频信号转换为硬件设备可识别的格式,并输出到车载扬声器。
(3)多音频流管理 在 Android Automotive 中,多个音频流(如导航、电话、媒体)可能同时存在。根据场景设置对应的音频流。
TextToSpeech 应用层的实现
1. 初始化 TTS 引擎
在使用 TTS 前,需要初始化引擎,并确保引擎加载成功。以下是基本的初始化代码:
java
private TextToSpeech textToSpeech;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textToSpeech = new TextToSpeech(this, status -> {
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e("TTS", "Language not supported");
}
} else {
Log.e("TTS", "Initialization failed");
}
});
}
2. 语音合成
使用 speak()
方法将文本转化为语音:
java
public void speakText(String text) {
textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
}
- QUEUE_FLUSH:清空当前队列并立即播放新文本。
- QUEUE_ADD:将新文本添加到播放队列中。
3. 调整语音属性
开发者可以通过以下方法调整语音的语速和音调:
java
textToSpeech.setPitch(1.0f); // 默认音调,范围 0.1 到 2.0
textToSpeech.setSpeechRate(1.0f); // 默认语速,范围 0.1 到 2.0
4. 释放资源
在不再需要使用 TTS 时,必须释放资源以避免内存泄漏:
java
@Override
protected void onDestroy() {
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
super.onDestroy();
}
TextToSpeech 系统调度
Android TextToSpeech
的系统调度是通过多层架构和组件实现的,涵盖了应用层、框架层和底层服务。以下是系统调度的详细流程解析:
系统调度流程
- 应用层调用应用开发者通过
TextToSpeech API
发起语音合成请求,例如speak()
或synthesizeToFile()
方法。 - 跨进程通信 (IPC)应用层的请求会通过 Binder 机制传递到 Android 系统服务层。
- TTS 服务调度系统中的
TextToSpeechService
会接收请求,执行语音合成调度逻辑。 - 引擎处理请求被转发至当前设置的 TTS 引擎(如 Google TTS),引擎负责具体的文本解析、语音合成。
- 音频输出合成的语音数据通过
AudioTrack
或其他音频接口播放,也可选择输出到文件。
1. 应用层请求
开发者在应用层通过 TextToSpeech
类向系统发起语音请求。例如:
csharp
textToSpeech.speak("Hello, world!", TextToSpeech.QUEUE_FLUSH, null, null)
TextToSpeech
类内部通过 ITtsCallback
接口与系统服务通信。
2. Binder 通信
TextToSpeech
的实现依赖于Binder IPC
调用,将请求转发至 TextToSpeechService
:
arduino
public void speak(String text, int queueMode, Bundle params, String utteranceId) {
try {
mService.speak(text, queueMode, params, utteranceId);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in speak()", e);
}
}
mService
是一个通过Binder
获取的远程接口实例。
3. TextToSpeechService
在系统服务层,TextToSpeechService
是 TTS 的核心调度服务,处理来自应用的请求。关键代码如下:
arduino
@Override
public void speak(String text, int queueMode, Bundle params, String utteranceId) {
synchronized (mLock) {
if (mCurrentEngine == null) {
throw new IllegalStateException("No TTS engine is bound");
}
mCurrentEngine.speak(text, queueMode, params, utteranceId);
}
}
mCurrentEngine
是当前绑定的 TTS 引擎实例。调度逻辑包括队列管理(如 QUEUE_FLUSH 和 QUEUE_ADD)以及引擎调用。
4. TTS 引擎
系统会根据用户设置加载 TTS 引擎(如 Google TTS 或其他第三方引擎)。TTS 引擎的接口定义在 TextToSpeechService.Engine
中
arduino
@Override
public int onSynthesizeText(SynthesisRequest request, SynthesisCallback callback) {
String text = request.getText();
int result = synthesize(text, callback);
return result;
}
SynthesisRequest
包含合成参数,如文本内容、语言设置。SynthesisCallback
用于将生成的音频数据回调到系统。
5. 音频输出
TTS 合成的语音数据最终通过 AudioTrack
播放
AudioTrack
是 Android 提供的低级音频接口,用于流式播放 PCM 数据。系统也支持将音频保存为文件,便于后续使用。
arduino
@Override
public void audioAvailable(byte[] buffer) {
if (mAudioTrack != null) {
mAudioTrack.write(buffer, 0, buffer.length);
}
}