环境:Android Studio , Mac
开通百度语音服务按提示操作即可
环境配置
下载SDK和NDK库
1.com.baidu.tts_x.x.x.xxxxx_xxxxx.jar 位于 app/libs 目录下。(引入jar包)
2.armeabi,armeabi-v7a,arm64-v8a,x86,x86_64 5个架构目录位于app\src\main\jniLibs 目录下,如果为了节省安装包体积,可以只使用armeabi目录,性能损失微小。(我只保留了armeabi目录)。
实现监听器SpeechSynthesizerListener
package com.demo.tts.listener;
import android.util.Log;
import com.baidu.tts.client.SpeechError;
import com.baidu.tts.client.SpeechSynthesizerListener;
/**
* SpeechSynthesizerListener 简单地实现,仅仅记录日志
* Created by xiaowen on 2017/5/19.
*/
public class MessageListener implements SpeechSynthesizerListener{
private static final String TAG = "MessageListener";
/**
* 播放开始,每句播放开始都会回调
*
* @param utteranceId
*/
@Override
public void onSynthesizeStart(String utteranceId) {
sendMessage("准备开始合成,序列号:" + utteranceId);
}
/**
* 语音流 16K采样率 16bits编码 单声道 。
*
* @param utteranceId
* @param bytes 二进制语音 ,注意可能有空data的情况,可以忽略
* @param progress 如合成“百度语音问题”这6个字, progress肯定是从0开始,到6结束。 但progress无法和合成到第几个字对应。
*/
@Override
public void onSynthesizeDataArrived(String utteranceId, byte[] bytes, int progress) {
// Log.i(TAG, "合成进度回调, progress:" + progress + ";序列号:" + utteranceId );
}
/**
* 合成正常结束,每句合成正常结束都会回调,如果过程中出错,则回调onError,不再回调此接口
*
* @param utteranceId
*/
@Override
public void onSynthesizeFinish(String utteranceId) {
sendMessage("合成结束回调, 序列号:" + utteranceId);
}
@Override
public void onSpeechStart(String utteranceId) {
sendMessage("播放开始回调, 序列号:" + utteranceId);
}
/**
* 播放进度回调接口,分多次回调
*
* @param utteranceId
* @param progress 如合成“百度语音问题”这6个字, progress肯定是从0开始,到6结束。 但progress无法保证和合成到第几个字对应。
*/
@Override
public void onSpeechProgressChanged(String utteranceId, int progress) {
// Log.i(TAG, "播放进度回调, progress:" + progress + ";序列号:" + utteranceId );
}
/**
* 播放正常结束,每句播放正常结束都会回调,如果过程中出错,则回调onError,不再回调此接口
*
* @param utteranceId
*/
@Override
public void onSpeechFinish(String utteranceId) {
sendMessage("播放结束回调, 序列号:" + utteranceId);
}
/**
* 当合成或者播放过程中出错时回调此接口
*
* @param utteranceId
* @param speechError 包含错误码和错误信息
*/
@Override
public void onError(String utteranceId, SpeechError speechError) {
sendErrorMessage("错误发生:" + speechError.description + ",错误编码:"
+ speechError.code + ",序列号:" + utteranceId);
}
private void sendMessage(String message) {
sendMessage(message, false);
}
private void sendErrorMessage(String message) {
sendMessage(message, true);
}
protected void sendMessage(String message, boolean isError) {
if (isError) {
Log.e(TAG, message);
} else {
Log.i(TAG, message);
}
}
}
封装SpeechSynthesizer的操作
package com.demo.tts;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.os.Build;
import android.util.Log;
import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.SpeechSynthesizerListener;
import com.baidu.tts.client.TtsMode;
import com.demo.tts.listener.MessageListener;
import java.util.ArrayList;
/**
* Created by xiaowen on 2017/11/3.
*/
public class Speek {
// ================== 初始化参数设置开始 ==========================
/**
* 发布时请替换成自己申请的appId appKey 和 secretKey。注意如果需要离线合成功能,请在您申请的应用中填写包名。
*/
private String appId = "10318618";
private String appKey = "cOvGbUOyDr0gVyML07543vnY";
private String secretKey = "5280e6434339c695eee267ff373567a4";
// TtsMode.MIX; 离在线融合,在线优先; TtsMode.ONLINE 纯在线; 没有纯离线
private TtsMode ttsMode = TtsMode.ONLINE;
protected SpeechSynthesizer mSpeechSynthesizer;
private static final String TAG = "Speek";
private Activity activity;
private static boolean isPermissionRequested = false;
public Speek(Activity activity){
this.activity=activity;
Permission();
initTTs();
}
public void Speeking(String text){
int result = mSpeechSynthesizer.speak(text);
checkResult(result, "speak");
}
/**
* 初始化TTS
*/
private void initTTs() {
SpeechSynthesizerListener listener=new MessageListener();
//获取 SpeechSynthesizer 实例
mSpeechSynthesizer = SpeechSynthesizer.getInstance();
//设置使用环境
mSpeechSynthesizer.setContext(activity);
//注册监听其
mSpeechSynthesizer.setSpeechSynthesizerListener(listener);
/**
* 授权检验接口
* 测试AppId,AppKey AppSecret填写正确,语音合成服务是否开通。
* 在线合成模式下,验证权限。首次验证时比较耗时,第一次调用成功,之后可以不必调用。
*/
mSpeechSynthesizer.auth(TtsMode.ONLINE); // 纯在线
/**
* 设置 App Id和 App Key 及 App Secret
* 用户在语音官网或者百度云网站上申请语音合成的应用后,会有appId appKey及appSecret
*/
int result = mSpeechSynthesizer.setAppId(appId);
checkResult(result, "setAppId");
result = mSpeechSynthesizer.setApiKey(appKey, secretKey);
checkResult(result, "setApiKey");
//设置合成参数
// 以下setParam 参数选填。不填写则默认值生效
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0"); // 设置在线发声音人: 0 普通女声(默认) 1 普通男声 2 特别男声 3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "9"); // 设置合成的音量,0-9 ,默认 5
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5");// 设置合成的语速,0-9 ,默认 5
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5");// 设置合成的语调,0-9 ,默认 5
//mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);
// 该参数设置为TtsMode.MIX生效。即纯在线模式不生效。
// MIX_MODE_DEFAULT 默认 ,wifi状态下使用在线,非wifi离线。在线状态下,请求超时6s自动转离线
// MIX_MODE_HIGH_SPEED_SYNTHESIZE_WIFI wifi状态下使用在线,非wifi离线。在线状态下, 请求超时1.2s自动转离线
// MIX_MODE_HIGH_SPEED_NETWORK , 3G 4G wifi状态下使用在线,其它状态离线。在线状态下,请求超时1.2s自动转离线
// MIX_MODE_HIGH_SPEED_SYNTHESIZE, 2G 3G 4G wifi状态下使用在线,其它状态离线。在线状态下,请求超时1.2s自动转离线
/**
* 初始化合成引擎
* 设置合成的参数后,需要调用此方法初始化
*/
result = mSpeechSynthesizer.initTts(ttsMode);
checkResult(result, "initTts");
//设置音频流类型
mSpeechSynthesizer.setAudioStreamType(AudioManager.MODE_IN_CALL);
}
/**
* 获取权限(Android6.0 以上需要动态获取权限)
*/
private void Permission() {
if (Build.VERSION.SDK_INT >= 23 && !isPermissionRequested) {
String permissions[] = {
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.MODIFY_AUDIO_SETTINGS,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.WRITE_SETTINGS,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.ACCESS_WIFI_STATE,
Manifest.permission.CHANGE_WIFI_STATE
};
ArrayList toApplyList = new ArrayList();
for (String perm : permissions) {
if (PackageManager.PERMISSION_GRANTED != activity.checkSelfPermission(perm)) {
toApplyList.add(perm);
//进入到这里代表没有权限.
}
}
if(toApplyList.size()==0)
{
return;
}
else
{
activity.requestPermissions(toApplyList.toArray(new String[toApplyList.size()]), 0);
}
}
}
private void print(String message) {
Log.i(TAG, message);
}
private void checkResult(int result, String method) {
if (result != 0) {
print("error code :" + result + " method:" + method + ", 错误码文档:http://yuyin.baidu.com/docs/tts/122 ");
}
}
public void Destory(){
if (mSpeechSynthesizer != null){
mSpeechSynthesizer.stop();
mSpeechSynthesizer.release();
mSpeechSynthesizer = null;
print("释放资源成功");
}
}
}
package com.demo.map;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.demo.tts.Speek;
/**
* Created by xiaowen on 2017/11/5.
*/
public class TTsActivity extends Activity {
private Button mBtnPlay;
private EditText mEdtWords;
private Speek speek;
private String words;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tts);
speek=new Speek(this);
initView();
}
private void initView(){
mBtnPlay= (Button) findViewById(R.id.play);
mEdtWords= (EditText) findViewById(R.id.words);
mBtnPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
words=mEdtWords.getText().toString();
if(!words.equals(""))
{
speek.Speeking(words);
}
else
{
speek.Speeking("请告诉我,您需要我说些什么");
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//释放资源
speek.Destory();
}
}