在libs和jniLibs加入对应jar包和so库
/**
* 唤醒
*/
public class WakeUpUtils {
private final String TAG = this.getClass().getSimpleName();
private static WakeUpUtils utils = null;
private EventManager eventManager;
private EventListener listener;
private boolean isInited = false;
private static Handler handler;
private final int WAKEUP = 1010;
// 是否加载离线资源
private boolean isOfflineEngineLoaded = false;
public WakeUpUtils(){
init();
}
public static WakeUpUtils getIntance(Handler mHandler){
handler = mHandler;
if (utils == null){
synchronized (WakeUpUtils.class){
if (utils == null){
utils = new WakeUpUtils();
}
}
}
return utils;
}
private void init(){
if (isInited){
LogUtils.log(TAG,"还未调用release(),请勿新建一个新类");
return;
}
isInited = true;
//创建唤醒事件管理器
eventManager = EventManagerFactory.create(MyApplication.context,"wp");
//注册唤醒事件监听器
eventManager.registerListener(new EventListener() {
@Override
public void onEvent(String name, String params1, byte[] bytes, int i, int i1) {
try{
listener = this;
if ("wp.data".equals(name)){
LogUtils.log("唤醒", params1);
TTSUtils.getInstance().speak(MyApplication.context.getString(R.string.wakeup_yes), true);
// handler.sendEmptyMessage(WAKEUP);
// RecognizerUtils.getIntance(handler).start();
}else if ("wp.exit".equals(name)){
LogUtils.log("唤醒退出", params1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
loadOfflineEngine(fetchOfflineParams());
}
/**
* 离线命令词,在线不需要调用
*
* @param params 离线命令词加载参数,见文档“ASR_KWS_LOAD_ENGINE 输入事件参数”
*/
private void loadOfflineEngine(Map<String, Object> params) {
String json = new JSONObject(params).toString();
// SDK集成步骤(可选)加载离线命令词(离线时使用)
eventManager.send(SpeechConstant.ASR_KWS_LOAD_ENGINE, json, null, 0, 0);
isOfflineEngineLoaded = true;
// 没有ASR_KWS_LOAD_ENGINE这个回调表试失败,如缺少第一次联网时下载的正式授权文件。
}
private Map<String, Object> fetchOfflineParams() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(SpeechConstant.DECODER, 2);
map.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, "assets:///baidu_speech_grammar.bsg");
map.putAll(fetchSlotDataParam());
return map;
}
private Map<String, Object> fetchSlotDataParam() {
Map<String, Object> map = new HashMap<String, Object>();
try {
JSONObject json = new JSONObject();
json.put("name", new JSONArray().put("妈妈").put("老伍"))
.put("appname", new JSONArray().put("手百").put("度秘"));
map.put(SpeechConstant.SLOT_DATA, json);
} catch (JSONException e) {
e.printStackTrace();
}
return map;
}
public void start() {
if (eventManager != null){
HashMap params = new HashMap();
params.put("kws-file","assets:///WakeUp.bin");
eventManager.send("wp.start",new JSONObject(params).toString(), null,0,0);
}
}
public void stop() {
if (eventManager != null){
eventManager.send(SpeechConstant.WAKEUP_STOP, null, null, 0, 0);
}
}
public void release() {
isInited = false;
stop();
if (eventManager != null){
if (isOfflineEngineLoaded) {
// SDK集成步骤 如果之前有调用过 加载离线命令词,这里要对应释放
eventManager.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0);
isOfflineEngineLoaded = false;
}
eventManager.unregisterListener(listener);
eventManager = null;
utils = null;
}
}
}
// 合成
public class TTSUtils {
private static TTSUtils utils = null;
private SpeechSynthesizer mSpeechSynthesizer;
private boolean isWakeUp = false;
public TTSUtils(){
new Thread(new Runnable() {
@Override
public void run() {
init();
}
}).start();
}
public static TTSUtils getInstance(){
if (utils == null){
synchronized (TTSUtils.class){
if (utils == null){
utils = new TTSUtils();
}
}
}
return utils;
}
/**
* speak 实际上是调用 synthesize后,获取音频流,然后播放。
* 获取音频流的方式见SaveFileActivity及FileSaveListener
* 需要合成的文本text的长度不能超过1024个GBK字节。
*/
public void speak(String text) {
// 需要合成的文本text的长度不能超过1024个GBK字节。
if (mSpeechSynthesizer != null){
mSpeechSynthesizer.speak(text);
}
}
/**
* speak 实际上是调用 synthesize后,获取音频流,然后播放。
* 获取音频流的方式见SaveFileActivity及FileSaveListener
* 需要合成的文本text的长度不能超过1024个GBK字节。
*/
public void speak(String text, boolean isWakeUp) {
this.isWakeUp = isWakeUp;
// 需要合成的文本text的长度不能超过1024个GBK字节。
if (mSpeechSynthesizer != null){
mSpeechSynthesizer.speak(text);
}
}
public void pause() {
// 需要合成的文本text的长度不能超过1024个GBK字节。
if (mSpeechSynthesizer != null){
mSpeechSynthesizer.pause();
}
}
public void resume() {
// 需要合成的文本text的长度不能超过1024个GBK字节。
if (mSpeechSynthesizer != null){
mSpeechSynthesizer.resume();
}
}
public void stop() {
// 需要合成的文本text的长度不能超过1024个GBK字节。
if (mSpeechSynthesizer != null){
mSpeechSynthesizer.stop();
}
}
public void release() {
// 需要合成的文本text的长度不能超过1024个GBK字节。
if (mSpeechSynthesizer != null){
mSpeechSynthesizer.release();
}
}
private void init(){
mSpeechSynthesizer = SpeechSynthesizer.getInstance();
mSpeechSynthesizer.setContext(MyApplication.context.getApplicationContext());
mSpeechSynthesizer.setSpeechSynthesizerListener(new SpeechSynthesizerListener() {
@Override
public void onSynthesizeStart(String s) {
// LogUtils.log("TTSUtils", "onSynthesizeStart" + "--" + s);
}
@Override
public void onSynthesizeDataArrived(String s, byte[] bytes, int i) {
// LogUtils.log("TTSUtils", "onSynthesizeDataArrived" + "--" + s);
}
@Override
public void onSynthesizeFinish(String s) {
// LogUtils.log("TTSUtils", "onSynthesizeFinish" + "--" + s);
}
@Override
public void onSpeechStart(String s) {
// LogUtils.log("TTSUtils", "onSpeechStart" + "--" + s);
}
@Override
public void onSpeechProgressChanged(String s, int i) {
// LogUtils.log("TTSUtils", "onSpeechProgressChanged" + "--" + s);
}
@Override
public void onSpeechFinish(String s) {
// LogUtils.log("TTSUtils", "onSpeechFinish" + "--" + s);
if (isWakeUp){
isWakeUp = false;
RecognizerUtils.getIntance().start();
}
}
@Override
public void onError(String s, SpeechError speechError) {
// LogUtils.log("TTSUtils", "onError" + "--" + s + "--" +speechError.description);
}
});
/*这里只是为了让Demo运行使用的APPID,请替换成自己的id。*/
mSpeechSynthesizer.setAppId("15692915");
/*这里只是为了让Demo正常运行使用APIKey,请替换成自己的APIKey*/
mSpeechSynthesizer.setApiKey("R2XiXKorcR75HyIejnBROSMm",
"Co85H7ZXROB0DEM4WfLgAlEojUd5GXFi");
// 授权检测接口(只是通过AuthInfo进行检验授权是否成功。选择纯在线可以不必调用auth方法。
AuthInfo authInfo = mSpeechSynthesizer.auth(TtsMode.MIX);
if (!authInfo.isSuccess()) {
// 离线授权需要网站上的应用填写包名。本demo的包名是com.baidu.tts.sample,定义在build.gradle中
String errorMsg = authInfo.getTtsError().getDetailMessage();
LogUtils.log("TTSUtils","鉴权失败 =" + errorMsg);
} else {
LogUtils.log("TTSUtils","验证通过,离线正式授权文件存在。");
}
getParams();
// 初始化tts
int result = mSpeechSynthesizer.initTts(TtsMode.MIX);
if (result != 0) {
LogUtils.log("TTSUtils","【error】initTts 初始化失败 + errorCode:" + result);
return;
}
// 此时可以调用 speak和synthesize方法
LogUtils.log("TTSUtils", "合成引擎初始化成功");
}
/**
* 合成的参数,可以初始化时填写,也可以在合成前设置。
*
* @return
*/
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
// 离线资源文件,从assets目录中复制到临时目录,需要在initTTs方法前完成
setOfflineVoiceType(VOICE_FEMALE);
// 文本模型文件路径 (离线引擎使用), 注意TEXT_FILENAME必须存在并且可读
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, textFilename);
// 声学模型文件路径 (离线引擎使用), 注意TEXT_FILENAME必须存在并且可读
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, modelFilename);
// 以下参数均为选填
// 设置在线发声音人: 0 普通女声(默认) 1 普通男声 2 特别男声 3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
params.put(SpeechSynthesizer.PARAM_SPEAKER, "0");
// 设置合成的音量,0-9 ,默认 5
params.put(SpeechSynthesizer.PARAM_VOLUME, "9");
// 设置合成的语速,0-9 ,默认 5
params.put(SpeechSynthesizer.PARAM_SPEED, "5");
// 设置合成的语调,0-9 ,默认 5
params.put(SpeechSynthesizer.PARAM_PITCH, "5");
params.put(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_HIGH_SPEED_SYNTHESIZE);
// 该参数设置为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自动转离线
// 声学模型文件路径 (离线引擎使用), 请确认下面两个文件存在
params.put(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, textFilename);
params.put(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, modelFilename);
return params;
}
private static HashMap<String, Boolean> mapInitied = new HashMap<String, Boolean>();
private final String VOICE_FEMALE = "F";//离线女声
private final String VOICE_MALE = "M";//离线男声
private final String VOICE_DUYY = "Y";//离线度逍遥
private final String VOICE_DUXY = "X";//离线度丫丫
private String textFilename = "";
private String modelFilename = "";
private void setOfflineVoiceType(String voiceType) {
String text = "bd_etts_text.dat";
String model;
if (VOICE_MALE.equals(voiceType)) {
model = "bd_etts_common_speech_m15_mand_eng_high_am-mix_v3.0.0_20170505.dat";
} else if (VOICE_FEMALE.equals(voiceType)) {
model = "bd_etts_common_speech_f7_mand_eng_high_am-mix_v3.0.0_20170512.dat";
} else if (VOICE_DUXY.equals(voiceType)) {
model = "bd_etts_common_speech_yyjw_mand_eng_high_am-mix_v3.0.0_20170512.dat";
} else if (VOICE_DUYY.equals(voiceType)) {
model = "bd_etts_common_speech_as_mand_eng_high_am_v3.0.0_20170516.dat";
} else {
throw new RuntimeException("voice type is not in list");
}
textFilename = copyAssetsFile(text);
modelFilename = copyAssetsFile(model);
}
private String copyAssetsFile(String sourceFilename) {
String destFilename = FileUtil.createTmpDir(MyApplication.context) + "/" + sourceFilename;
try {
File file = new File(destFilename);
if (file.exists()){
return destFilename;
}
boolean recover = false;
Boolean existed = mapInitied.get(sourceFilename); // 启动时完全覆盖一次
if (existed == null || !existed) {
recover = true;
}
FileUtil.copyFromAssets(MyApplication.context.getApplicationContext().getAssets(),
sourceFilename, destFilename, recover);
return destFilename;
}catch (Exception e){
e.printStackTrace();
}
return destFilename;
}