集成Android百度语音合成功能(在线、离线、离在线融合)
转至博客http://blog.****.net/aquarius_seven/article/details/76850292
前面2篇文章分别写了在线和离线2种语音合成,分别用的是科大讯飞和云知声的SDK,那么本文就开始写离在线融合的百度语音SDK。
你们知道吗,百度语音跟百度导航SDK有冲突,因为百度导航SDK内置了百度语音,但是它并没有暴露语音合成功能出来给我们调用,所以用了百度语音就用不了百度导航,用了百度导航就用不了百度语音,就是那么坑。
没办法,项目要求一定要用百度的地图和导航,还要有语音合成功能,那么只能用百度语音的restAPI或者是选择其它的第三方SDK了,也就是我前面2篇文章的由来了,一开始我选择了讯飞的在线合成,后来发现有时候不太方便,又选择了云知声的离线合成。
好吧,废话不多说,现在就开始集成吧。
首先,打开百度语音开放平台
然后,注册、登录不啰嗦(图略)
打开应用管理,创建新应用-->选择服务(语音合成)-->下载SDK(语音合成)-->集成开发(补全包名)-->完成
下载完成,解压压缩包BaiduTtsSample
打开BaiduTtsSample-->assets,选择复制2个文件(离线语音合成模型)到你项目中的assets资源目录下
打开BaiduTtsSample-->libs,选择复制jar包和.so文件到你的项目libs目录下
注意:需要在build.gradle增加如下图所示代码(注意层级),不然调用方法时会报错(如下图左上角箭头修改项目结构为Project,然后找到在app目录下的build.gradle文件进行修改)
[html] view plain copy
- repositories {
- flatDir {
- dir 'libs'
- }
- }
-
repositories {
-
flatDir {
-
dir 'libs'
-
}
-
}
[html] view plain copy
- sourceSets {
- main {
- jniLibs.srcDir 'libs'
- }
- }
-
sourceSets {
-
main {
-
jniLibs.srcDir 'libs'
-
}
-
}
做完以上准备工作,就可以开始撸代码了
首先,AndroidManifest.xml申请权限(6.0需要动态申请权限,碍于篇幅,请自行百度)
[html] view plain copy
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_SETTINGS" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
-
<uses-permission android:name="android.permission.INTERNET" />
-
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
-
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
-
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
然后,直接封装成工具类,以供全局调用离在线语音合成功能,大家可以直接复制进去用,其中APIKEY、SECRETKEY和APPID在百度语音开放平台-->应用管理,点击你之前创建的应用可查看
[java] view plain copy
- package com.cyf.ttsdemo.utils;
- import android.content.Context;
- import android.os.Environment;
- import android.util.Log;
- import com.baidu.tts.client.SpeechError;
- import com.baidu.tts.client.SpeechSynthesizer;
- import com.baidu.tts.client.SpeechSynthesizerListener;
- import com.baidu.tts.client.TtsMode;
- import com.cyf.ttsdemo.MyApplication;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- /**
- * Created by As on 2017/8/7.
- */
- public class TTSUtils implements SpeechSynthesizerListener {
- private static final String TAG = "TTSUtils";
- private static volatile TTSUtils instance = null;
- private SpeechSynthesizer mSpeechSynthesizer;
- private static final String SAMPLE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/baiduTTS/";
- private static final String SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female.dat";
- private static final String TEXT_MODEL_NAME = "bd_etts_text.dat";
- private static final String APIKEY = "6kl3vrfNvLRo8iIWp93NRwkw";
- private static final String SECRETKEY = "ae9d2a7fb54ce8f2f80c46c22ca4acaf";
- private static final String APPID = "9978777";
- private TTSUtils() {
- }
- public static TTSUtils getInstance() {
- if (instance == null) {
- synchronized (TTSUtils.class) {
- if (instance == null) {
- instance = new TTSUtils();
- }
- }
- }
- return instance;
- }
- public void init() {
- Context context = MyApplication.getContext();
- File file = new File(SAMPLE_DIR);
- if (!file.exists()) {
- file.mkdirs();
- }
- File textModelFile = new File(SAMPLE_DIR + TEXT_MODEL_NAME);
- if (!textModelFile.exists()) {
- copyAssetsFile2SDCard(context, TEXT_MODEL_NAME, SAMPLE_DIR + TEXT_MODEL_NAME);
- }
- File speechModelFile = new File(SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);
- if (!speechModelFile.exists()) {
- copyAssetsFile2SDCard(context, SPEECH_FEMALE_MODEL_NAME, SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);
- }
- // 获取语音合成对象实例
- mSpeechSynthesizer = SpeechSynthesizer.getInstance();
- // 设置context
- mSpeechSynthesizer.setContext(context);
- // 设置语音合成状态监听器
- mSpeechSynthesizer.setSpeechSynthesizerListener(this);
- mSpeechSynthesizer.setApiKey(APIKEY, SECRETKEY);
- // 设置离线语音合成授权,需要填入从百度语音官网申请的app_id
- mSpeechSynthesizer.setAppId(APPID);
- // 设置语音合成文本模型文件
- mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, SAMPLE_DIR + TEXT_MODEL_NAME);
- // 设置语音合成声音模型文件
- mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);
- // 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。)
- mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
- // 设置Mix模式的合成策略
- mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);
- // 初始化tts
- mSpeechSynthesizer.initTts(TtsMode.MIX);
- }
- //需要合成的msg长度不能超过1024个GBK字节。
- public void speak(String msg) {
- int result = mSpeechSynthesizer.speak(msg);
- if (result < 0) {
- Log.e(TAG, "error,please look up error code = " + result + " in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");
- }
- }
- public void pause() {
- mSpeechSynthesizer.pause();
- }
- public void resume() {
- mSpeechSynthesizer.resume();
- }
- public void stop() {
- mSpeechSynthesizer.stop();
- }
- public void release() {
- if (null != mSpeechSynthesizer) {
- mSpeechSynthesizer.release();
- }
- }
- @Override
- public void onSynthesizeStart(String s) {
- // 监听到合成开始,在此添加相关操作
- }
- @Override
- public void onSynthesizeDataArrived(String s, byte[] bytes, int i) {
- // 监听到有合成数据到达,在此添加相关操作
- }
- @Override
- public void onSynthesizeFinish(String s) {
- // 监听到合成结束,在此添加相关操作
- }
- @Override
- public void onSpeechStart(String s) {
- // 监听到合成并播放开始,在此添加相关操作
- }
- @Override
- public void onSpeechProgressChanged(String s, int i) {
- // 监听到播放进度有变化,在此添加相关操作
- }
- @Override
- public void onSpeechFinish(String s) {
- // 监听到播放结束,在此添加相关操作
- }
- @Override
- public void onError(String s, SpeechError speechError) {
- // 监听到出错,在此添加相关操作
- }
- public static void copyAssetsFile2SDCard(Context context, String fileName, String path) {
- try {
- InputStream is = context.getAssets().open(fileName);
- FileOutputStream fos = new FileOutputStream(new File(path));
- byte[] buffer = new byte[1024];
- int byteCount = 0;
- while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取buffer字节
- fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流
- }
- fos.flush();// 刷新缓冲区
- is.close();
- fos.close();
- } catch (IOException e) {
- Log.e(TAG, "copyAssetsFile2SDCard: " + e.toString());
- }
- }
- }<span style="font-size: 14px; font-family: "Microsoft YaHei";">
- </span>
-
package com.cyf.ttsdemo.utils;
-
import android.content.Context;
-
import android.os.Environment;
-
import android.util.Log;
-
import com.baidu.tts.client.SpeechError;
-
import com.baidu.tts.client.SpeechSynthesizer;
-
import com.baidu.tts.client.SpeechSynthesizerListener;
-
import com.baidu.tts.client.TtsMode;
-
import com.cyf.ttsdemo.MyApplication;
-
import java.io.File;
-
import java.io.FileOutputStream;
-
import java.io.IOException;
-
import java.io.InputStream;
-
/**
-
* Created by As on 2017/8/7.
-
*/
-
public class TTSUtils implements SpeechSynthesizerListener {
-
private static final String TAG = "TTSUtils";
-
private static volatile TTSUtils instance = null;
-
private SpeechSynthesizer mSpeechSynthesizer;
-
private static final String SAMPLE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/baiduTTS/";
-
private static final String SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female.dat";
-
private static final String TEXT_MODEL_NAME = "bd_etts_text.dat";
-
private static final String APIKEY = "6kl3vrfNvLRo8iIWp93NRwkw";
-
private static final String SECRETKEY = "ae9d2a7fb54ce8f2f80c46c22ca4acaf";
-
private static final String APPID = "9978777";
-
private TTSUtils() {
-
}
-
public static TTSUtils getInstance() {
-
if (instance == null) {
-
synchronized (TTSUtils.class) {
-
if (instance == null) {
-
instance = new TTSUtils();
-
}
-
}
-
}
-
return instance;
-
}
-
public void init() {
-
Context context = MyApplication.getContext();
-
File file = new File(SAMPLE_DIR);
-
if (!file.exists()) {
-
file.mkdirs();
-
}
-
File textModelFile = new File(SAMPLE_DIR + TEXT_MODEL_NAME);
-
if (!textModelFile.exists()) {
-
copyAssetsFile2SDCard(context, TEXT_MODEL_NAME, SAMPLE_DIR + TEXT_MODEL_NAME);
-
}
-
File speechModelFile = new File(SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);
-
if (!speechModelFile.exists()) {
-
copyAssetsFile2SDCard(context, SPEECH_FEMALE_MODEL_NAME, SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);
-
}
-
// 获取语音合成对象实例
-
mSpeechSynthesizer = SpeechSynthesizer.getInstance();
-
// 设置context
-
mSpeechSynthesizer.setContext(context);
-
// 设置语音合成状态监听器
-
mSpeechSynthesizer.setSpeechSynthesizerListener(this);
-
mSpeechSynthesizer.setApiKey(APIKEY, SECRETKEY);
-
// 设置离线语音合成授权,需要填入从百度语音官网申请的app_id
-
mSpeechSynthesizer.setAppId(APPID);
-
// 设置语音合成文本模型文件
-
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, SAMPLE_DIR + TEXT_MODEL_NAME);
-
// 设置语音合成声音模型文件
-
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, SAMPLE_DIR + SPEECH_FEMALE_MODEL_NAME);
-
// 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。)
-
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
-
// 设置Mix模式的合成策略
-
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);
-
// 初始化tts
-
mSpeechSynthesizer.initTts(TtsMode.MIX);
-
}
-
//需要合成的msg长度不能超过1024个GBK字节。
-
public void speak(String msg) {
-
int result = mSpeechSynthesizer.speak(msg);
-
if (result < 0) {
-
Log.e(TAG, "error,please look up error code = " + result + " in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");
-
}
-
}
-
public void pause() {
-
mSpeechSynthesizer.pause();
-
}
-
public void resume() {
-
mSpeechSynthesizer.resume();
-
}
-
public void stop() {
-
mSpeechSynthesizer.stop();
-
}
-
public void release() {
-
if (null != mSpeechSynthesizer) {
-
mSpeechSynthesizer.release();
-
}
-
}
-
@Override
-
public void onSynthesizeStart(String s) {
-
// 监听到合成开始,在此添加相关操作
-
}
-
@Override
-
public void onSynthesizeDataArrived(String s, byte[] bytes, int i) {
-
// 监听到有合成数据到达,在此添加相关操作
-
}
-
@Override
-
public void onSynthesizeFinish(String s) {
-
// 监听到合成结束,在此添加相关操作
-
}
-
@Override
-
public void onSpeechStart(String s) {
-
// 监听到合成并播放开始,在此添加相关操作
-
}
-
@Override
-
public void onSpeechProgressChanged(String s, int i) {
-
// 监听到播放进度有变化,在此添加相关操作
-
}
-
@Override
-
public void onSpeechFinish(String s) {
-
// 监听到播放结束,在此添加相关操作
-
}
-
@Override
-
public void onError(String s, SpeechError speechError) {
-
// 监听到出错,在此添加相关操作
-
}
-
public static void copyAssetsFile2SDCard(Context context, String fileName, String path) {
-
try {
-
InputStream is = context.getAssets().open(fileName);
-
FileOutputStream fos = new FileOutputStream(new File(path));
-
byte[] buffer = new byte[1024];
-
int byteCount = 0;
-
while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取buffer字节
-
fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流
-
}
-
fos.flush();// 刷新缓冲区
-
is.close();
-
fos.close();
-
} catch (IOException e) {
-
Log.e(TAG, "copyAssetsFile2SDCard: " + e.toString());
-
}
-
}
-
}
同样的需要新建MyApplication.java进行预初始化离线语音合成功能
[java] view plain copy
- package com.cyf.ttsdemo;
- import android.app.Application;
- import android.content.Context;
- import com.cyf.ttsdemo.utils.TTSUtils;
- /**
- * Created by As on 2017/8/7.
- */
- public class MyApplication extends Application {
- private static Context context;
- @Override
- public void onCreate() {
- super.onCreate();
- context = getApplicationContext();
- TTSUtils.getInstance().init();
- }
- public static Context getContext() {
- return context;
- }
- }<span style="font-size: 14px; font-family: "Microsoft YaHei";">
- </span>
-
package com.cyf.ttsdemo;
-
import android.app.Application;
-
import android.content.Context;
-
import com.cyf.ttsdemo.utils.TTSUtils;
-
/**
-
* Created by As on 2017/8/7.
-
*/
-
public class MyApplication extends Application {
-
private static Context context;
-
@Override
-
public void onCreate() {
-
super.onCreate();
-
context = getApplicationContext();
-
TTSUtils.getInstance().init();
-
}
-
public static Context getContext() {
-
return context;
-
}
-
}
最后,别忘了在AndroidManifest.xml文件中注册该Application
好的,这样就大功告成了,在需要进行语音合成的地方调用TTSUtils.getInstance().speak("xxx")即可
最后,我们需要到百度语音开放平台进行申请提高配额,不然使用的语音合成功能每天是有次数限制的。
当应用审核通过之后,就可以免费无限制的使用离在线语音合成功能啦。