在工作中遇到了语音播报的需求,在收到 push 后,用语音播报 push 携带的播报内容。类似于微信支付宝的收款信息一样。调研后主要的语音播报方案有一下几种:
基于第三方的 TTS SDK,如百度、思必驰、讯飞等;
自研 Native 的 TTS 引擎+模型;
基于云端的 TTS 方案;
使用手机自带的 TTS 引擎。
无外乎就是自研或者采购,本地或者云端。
先来点废话,介绍下 TTS 的发展。
TTS 现状及发展
语音合成又称文语转换(Text to Speech,TTS)技术,是语音处理领域的一个重要的研究方向,旨在让机器生成自然动听的人类语音。
TTS 技术主要分为两种:
语音合成模型经过长时间的发展,由最初的基于拼接合成,到参数合成,逐渐达到了现阶段感情充沛的基于端到端合成,最新一代端到端合成降低了对语言学知识的要求,可批量实现多语种的合成系统,语音自然程度高。
语音合成技术内部分为前端和后端。
TTS 在语音交互场景里的应用:
基于拼接合成
为了更好的拟合人声,拼接合成技术需要一个大规模的真人音库,音库内容按照音素和不同特征进行标注,合成时根据语言学特征寻找符合的音素,拼接起来完成合成。
基于参数合成
通过深度学习构建文本特征和音库之间的映射关系,构建参数合成模型,当输入一个语言学特征时,基于神经网络给出音频特征,后通过声码器合成语音波形。
基于端到端(Tactron 为例)
端到端语音合成一定程度上解决了拼接合成和参数合成存在的缺陷。端到端合成系统直接输入文本或者注音字符,通过文本或者文本特征和语音直接建模,跳过声码器阶段,减少对声码器的依赖,弱化前端概念。
方案选择
做这个功能的时候公司已经有团队在自研 TTS 引擎了,而且云端 TTS 服务已经跑起来了,并且之前也在外部采购了些云端 TTS 服务。但是由于我们的 Push 推送量级很大,不管是外采还是自研云端引擎的成本都很高,出于成本考虑,我们选择只能考虑使用端上的方案。
客户端实现有三种方案:
外采:出于成本考虑,淘汰;
自研引擎:语音团队基于参数的合成引擎已完成开发,但是没有人力支撑后续的调试,而播报的话术比较固定,并且对合成声音的音质要求不是特别高,所以选择了一种基于拼接的合成方案作为备选,语句的前部分和后部分使用完整的语音,中间变换部分通过逐字方式合成;
手机自带 TTS 引擎:Android 系统已自带了 TTS 引擎,但是并不是所有的手机都带了中文引擎。
Android TTS 引擎使用
初始化 TTS 引擎
class TTSListener implements TextToSpeech.OnInitListener {
@Override
public void onInit(int status) {
if (mSpeech != null) {
int isSupportChinese = mSpeech.isLanguageAvailable(Locale.CHINESE);//是否支持中文
mSpeech.getMaxSpeechInputLength();//最大播报文本长度
if (isSupportChinese == TextToSpeech.LANG_AVAILABLE) {
int setLanRet = mSpeech.setLanguage(Locale.CHINESE);//设置语言
int setSpeechRateRet = mSpeech.setSpeechRate(1.0f);//设置语
int setPitchRet = mSpeech.setPitch(1.0f);//设置音量
String defaultEngine = mSpeech.getDefaultEngine();//默认引擎
if (status == TextToSpeech.SUCCESS) {
//初始化TextToSpeech引擎成功,初始化成功后才可以play等
}
}
} else {
//初始化TextToSpeech引擎失败
}
}
}
TextToSpeech mSpeech = new TextToSpeech(ContextHolder.appContext(), new TTSListener());
复制代码
设置播报状态回调
mSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override
public void onStart(String utteranceId) {
//播报开始
}
@Override
public void onDone(String utteranceId) {
//播报结束
}
@Override
public void onError(String utteranceId) {
//播报出错
}
});
复制代码
开始播报
long utteranceId = System.currentTimeMillis();
HashMap ttsOptions = new HashMap<String, String>();
ttsOptions.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,
String.valueOf(utteranceId));//utterance,这个参数随便写,用于监听播报完成的回调中
ttsOptions.put(TextToSpeech.Engine.KEY_PARAM_VOLUME, String.valueOf(1));//音量
ttsOptions.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
String.valueOf(AudioManager.STREAM_NOTIFICATION));//播放类型
int ret = mSpeech.speak(tts, TextToSpeech.QUEUE_FLUSH, ttsOptions);
if (ret == TextToSpeech.SUCCESS) {
//播报成功
}
复制代码
文本转换为语音文件
long utteranceId = System.currentTimeMillis();
File file = new File("/sdcard/audio_" + utteranceId + ".wav");
int ret = synthesizeToFile("xxxxx", null, file, String.valueOf(utteranceId));
if (ret == TextToSpeech.SUCCESS) {
//合成文件成功
}
复制代码
停止播放
调用mSpeech.stop();
此时会触发 UtteranceProgressListener 的 onDone 回调。
销毁引擎
Android11 适配
为兼容 Android11 系统手机,我们需要在应用程序 AndroidManifest.xml 文件中增加如下声明:
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE"/>
</intent>
</queries>
复制代码
3.5.x 版本 Gradle 需要使用 3.5.4 以上版本才能识别 queries 属性。
TextToSpeech 手机兼容性问题
系统自带 TextToSpeech API 使用很方便,但是有些不支持中文引擎的手机就很头疼,而且市面上哪些手机支持哪些手机不支持我们没有底,所以线上跑了一波以后拿到了目前市面手机 TextToSpeech 中文引擎的支持情况。有九十款不支持的手机如下:
+--------------------------------------+
| Xiaomi MI+9+Transparent+Edition |
| Xiaomi MI+8 |
| OnePlus GM1900 |
| OnePlus GM1910 |
| Redmi M2006C3LC |
| OnePlus IN2020 |
| meizu 16T |
| Xiaomi MI+MAX+3 |
| OnePlus ONEPLUS+A6010 |
| OnePlus ONEPLUS+A5010 |
| meizu meizu+17 |
| Redmi Redmi+K30 |
| OnePlus KB2000 |
| OnePlus HD1900 |
| OnePlus ONEPLUS+A6000 |
| meizu 16s |
| Xiaomi M2102K1C |
| Xiaomi M2002J9E |
| Redmi M2007J17C |
| OnePlus IN2010 |
| meizu meizu+17+Pro |
| nubia NX659J |
| meizu 16s+Pro |
| meizu meizu+16Xs |
| Xiaomi Mi+10 |
| Lenovo Lenovo+L78051 |
| meizu MEIZU+18 |
| OnePlus HD1910 |
| Hisense HLTE226T |
| xiaomi Redmi+Note+8 |
| Redmi Redmi+K30i+5G |
| Redmi M2007J3SC |
| Redmi M2004J19C |
| Redmi Redmi+Note+8+Pro |
| Redmi M2104K10AC |
| xiaomi Redmi+Note+7 |
| Redmi M2003J15SC |
| Xiaomi MIX+2S |
| Redmi Redmi+K30+Pro |
| nubia NX627J |
| Xiaomi MI+CC9+Pro |
| Redmi Redmi+K30+5G |
| meizu MEIZU+18+Pro |
| Xiaomi MI+9 |
| Xiaomi M2102K1AC |
| Xiaomi MI+8+UD |
| blackshark AWM-A0 |
| Xiaomi M2011K2C |
| Xiaomi MI+8+Lite |
| Sony XQ-AT72 |
| Xiaomi Mi+10+Pro |
| Xiaomi M2102J2SC |
| OnePlus ONEPLUS+A5000 |
| Xiaomi M2101K9C |
| Redmi M2103K19C |
| xiaomi Redmi+Note+7+Pro |
| nubia NX616J |
| Redmi M2012K10C |
| Xiaomi MIX+3 |
| Redmi M2004J7AC |
| Xiaomi MI+CC9+Pro+Premium+Edition |
| nubia NX619J |
| Xiaomi M2007J1SC |
| koobee X60+Pro |
| Xiaomi Redmi+K20+Pro |
| SMARTISAN DT1901A |
| Redmi M2004J7BC |
| asus ASUS_I001DA |
| HONOR HLK-AL00a |
| Redmi M2006J10C |
| Redmi M2012K11AC |
| blackshark SHARK+PRS-A0 |
| HONOR BKL-AL20 |
| SMARTISAN DT1902A |
| ZTE ZTE+A2322 |
| Redmi M2007J22C |
| blackshark SKW-A0 |
| Nokia Nokia+X7 |
| Redmi M2012K11C |
| HUAWEI MAR-AL00 |
| Redmi Redmi+K30+Pro+Zoom+Edition |
| nubia NX669J |
| Meizu 16+X |
| Xiaomi Redmi+K20+Pro+Premium+Edition |
| asus ASUS_I005DA |
| blackshark SHARK+KLE-A0 |
| Xiaomi MI+6 |
| motorola XT2125-4 |
| GIONEE 20190619G |
| HUAWEI ART-AL00m |
+--------------------------------------+
复制代码
有些支持比较好的,如华为,可以在设置中选择发音音色。在系统设置---辅助功能---无障碍---文本转语音路径下可以选择引擎,调节语速音调:
并且点击引擎选项可以安装引擎提供的发音人语音包,并选择发音人:
总结
本文总结了 TTS 的现状及发展,并介绍了移动端实现 TTS 的几种方式以及如何系统提供的 TextToSpeech API、系统 API 的局限、如何做兼容性等。
评论