语音合成初始化问题
舍_1991 发布于2019-04 浏览:3516 回复:3
0
收藏

Android开发,我在应用Application类中,初始化百度语音,写了个工具类用来进行语音的方法,日志也显示初始化成功,请问我再一个activity中想调用【.speak()】等方法,还需要重新初始化一遍吗?能不能直接获取到工具类中的变量?

收藏
点赞
0
个赞
共3条回复 最后由用户已被禁言回复于2022-04
#4缺水的鱼的老巢回复于2019-04

不用,你写个管理类,里面封装出初始化方法, speak(String text)方法和release 方法,你初始化时用Application 的context,这样你应用所有地方都可以直接调speak方法传入文字去合成播放了,如:

package com.android.fisewatchlauncher.baiduspeech.tts.listener;

import android.content.Context;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.android.fisewatchlauncher.KApplication;
import com.android.fisewatchlauncher.baiduspeech.tts.control.InitConfig;
import com.android.fisewatchlauncher.baiduspeech.tts.util.AutoCheck;
import com.android.fisewatchlauncher.utils.LogUtils;
import com.baidu.speech.EventListener;
import com.baidu.speech.EventManager;
import com.baidu.speech.EventManagerFactory;
import com.baidu.speech.asr.SpeechConstant;
import com.baidu.tts.auth.AuthInfo;
import com.baidu.tts.chainofresponsibility.logger.LoggerProxy;
import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.SpeechSynthesizerListener;
import com.baidu.tts.client.TtsMode;

import org.json.JSONObject;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
* @author mare
* @Description:
* @csdnblog http://blog.csdn.net/mare_blue
* @date 2017/8/9
* @time 9:34
*/
public class BaiduAsrTTSManager {

private static final String TEXT = "亲,该吃药了! ";
// ================== 初始化参数设置开始 ==========================
/**
* 发布时请替换成自己申请的appId appKey 和 secretKey。注意如果需要离线合成功能,请在您申请的应用中填写包名。
* 本demo的包名是com.baidu.tts.sample,定义在build.gradle中。
*/
protected String appId = "xxx";

protected String appKey = "xxx";

protected String secretKey = "xxx";

// TtsMode.MIX; 离在线融合,在线优先; TtsMode.ONLINE 纯在线; 没有纯离线
private TtsMode ttsMode = TtsMode.ONLINE;
private Handler mHandler;

// ================选择TtsMode.ONLINE 不需要设置以下参数; 选择TtsMode.MIX 需要设置下面2个离线资源文件的路径
private static final String TEMP_DIR = "/sdcard/baiduTTS"; // 重要!请手动将assets目录下的3个dat 文件复制到该目录

// 请确保该PATH下有这个文件
private static final String TEXT_FILENAME = TEMP_DIR + "/" + "bd_etts_text.dat";

// 请确保该PATH下有这个文件 ,m15是离线男声
private static final String MODEL_FILENAME =
TEMP_DIR + "/" + "bd_etts_common_speech_m15_mand_eng_high_am-mix_v3.0.0_20170505.dat";

// ===============初始化参数设置完毕,更多合成参数请至getParams()方法中设置 =================

protected SpeechSynthesizer mSpeechSynthesizer;


private BaiduAsrTTSManager() {
}
private static class SingletonHolder {
private static final BaiduAsrTTSManager INSTANCE = new BaiduAsrTTSManager();
}

public static BaiduAsrTTSManager instance() {
return SingletonHolder.INSTANCE;
}

 

/**
* 注意此处为了说明流程,故意在UI线程中调用。
* 实际集成中,该方法一定在新线程中调用,并且该线程不能结束。具体可以参考NonBlockSyntherizer的写法
*/
public void initTTs(Context context,Handler handler) {
LoggerProxy.printable(true); // 日志打印在logcat中
boolean isMix = ttsMode.equals(TtsMode.MIX);
boolean isSuccess;
mHandler = handler;
if (isMix) {
// 检查2个离线资源是否可读
isSuccess = checkOfflineResources();
if (!isSuccess) {
return;
} else {
print("离线资源存在并且可读, 目录:" + TEMP_DIR);
}
}
// 日志更新在UI中,可以换成MessageListener,在logcat中查看日志
SpeechSynthesizerListener listener = new UiMessageListener(mHandler);

// 1. 获取实例
mSpeechSynthesizer = SpeechSynthesizer.getInstance();
mSpeechSynthesizer.setContext(context);

// 2. 设置listener
mSpeechSynthesizer.setSpeechSynthesizerListener(listener);

// 3. 设置appId,appKey.secretKey
int result = mSpeechSynthesizer.setAppId(appId);
checkResult(result, "setAppId");
result = mSpeechSynthesizer.setApiKey(appKey, secretKey);
checkResult(result, "setApiKey");

// 4. 支持离线的话,需要设置离线模型
if (isMix) {
// 检查离线授权文件是否下载成功,离线授权文件联网时SDK自动下载管理,有效期3年,3年后的最后一个月自动更新。
isSuccess = checkAuth();
if (!isSuccess) {
return;
}
// 文本模型文件路径 (离线引擎使用), 注意TEXT_FILENAME必须存在并且可读
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, TEXT_FILENAME);
// 声学模型文件路径 (离线引擎使用), 注意TEXT_FILENAME必须存在并且可读
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, MODEL_FILENAME);
}

// 5. 以下setParam 参数选填。不填写则默认值生效
// 设置在线发声音人: 0 普通女声(默认) 1 普通男声 2 特别男声 3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "4");
// 设置合成的音量,0-9 ,默认 5
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "9");
// 设置合成的语速,0-9 ,默认 5
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "3");
// 设置合成的语调,0-9 ,默认 5
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "7");

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自动转离线

mSpeechSynthesizer.setAudioStreamType(AudioManager.MODE_IN_CALL);

// x. 额外 : 自动so文件是否复制正确及上面设置的参数
Map params = new HashMap<>();
// 复制下上面的 mSpeechSynthesizer.setParam参数
// 上线时请删除AutoCheck的调用
if (isMix) {
params.put(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, TEXT_FILENAME);
params.put(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, MODEL_FILENAME);
}
InitConfig initConfig = new InitConfig(appId, appKey, secretKey, ttsMode, params, listener);
AutoCheck.getInstance(context).check(initConfig,mHandler);

// 6. 初始化
result = mSpeechSynthesizer.initTts(ttsMode);
checkResult(result, "initTts");

}
/**
* 检查appId ak sk 是否填写正确,另外检查官网应用内设置的包名是否与运行时的包名一致。本demo的包名定义在build.gradle文件中
*
* @return
*/
private boolean checkAuth() {
AuthInfo authInfo = mSpeechSynthesizer.auth(ttsMode);
if (!authInfo.isSuccess()) {
// 离线授权需要网站上的应用填写包名。本demo的包名是com.baidu.tts.sample,定义在build.gradle中
String errorMsg = authInfo.getTtsError().getDetailMessage();
print("【error】鉴权失败 errorMsg=" + errorMsg);
return false;
} else {
print("验证通过,离线正式授权文件存在。");
return true;
}
}
/**
* 检查 TEXT_FILENAME, MODEL_FILENAME 这2个文件是否存在,不存在请自行从assets目录里手动复制
*
* @return
*/
private boolean checkOfflineResources() {
String[] filenames = {TEXT_FILENAME, MODEL_FILENAME};
for (String path : filenames) {
File f = new File(path);
if (!f.canRead()) {
print("[ERROR] 文件不存在或者不可读取,请从assets目录复制同名文件到:" + path);
print("[ERROR] 初始化失败!!!");
return false;
}
}
return true;
}

public void speak() {
/* 以下参数每次合成时都可以修改
* mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
* 设置在线发声音人: 0 普通女声(默认) 1 普通男声 2 特别男声 3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
* mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "5"); 设置合成的音量,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);
* 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自动转离线
*/

if (mSpeechSynthesizer == null) {
print("[ERROR], 初始化失败");
return;
}
int result = mSpeechSynthesizer.speak(TEXT);
print("合成并播放 按钮已经点击");
checkResult(result, "speak");
}

public void stop() {
print("停止合成引擎 按钮已经点击");
if(mSpeechSynthesizer != null) {
int result = mSpeechSynthesizer.stop();
checkResult(result, "stop");
}
}
public void print(String message) {
LogUtils.e("BaiduTTS " + 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 releaseTTS(){
if (mSpeechSynthesizer != null) {
mSpeechSynthesizer.stop();
mSpeechSynthesizer.release();
mSpeechSynthesizer = null;
print("释放资源成功");
}
}

}

 

0
#3用户已被禁言回复于2019-04
#2 舍_1991回复
就是想问下,加入我有多个activity要执行合成,就要在各自的类中分别进行初始化吗?
展开

您的问题工单为您解决了吗?

0
#2舍_1991回复于2019-04

就是想问下,加入我有多个activity要执行合成,就要在各自的类中分别进行初始化吗?

0
TOP
切换版块