官方文檔:http://ai.baidu.com/docs#/TTS-Android-SDK/6d5d6899java
官方百度語音合成控制檯:https://cloud.baidu.com/product/speech/ttsandroid
在百度語音控制檯中申請使用語音合成的受權,填入相關數據後(注意:必定要選擇Android填入正確的包名,否則可能會影響使用離線語音合成)。獲得相應的APP_ID,APP_KEY,SECRET_KEY;而後在下載語音包SDK。app
這裏有三組文件須要分別存放到指定目錄(這些文件在語音包的sdk裏都有):ide
請將這個jar導入libs文件夾裏工具
注意這5個文件在代碼裏還要進行復制操做,將這些文件複製到外部存儲的指定目錄才能正常使用。gradle
使用方法能夠參考百度,也能夠參考我這個封裝,可是請要多調試。由於百度的sdk常常變更,有時效性的。網站
/** *@content:百度語音合成的接口class *@time:2018-9-10 *@build: */ public interface SpeechListener { void onInitFinish(); void onStart(Context context,String resultValue); void onProgress(Context context,String resultValue,int current); void onFinish(Context context,String resultValue); void onError(Context context,String resultValue, SpeechError speechError); }
/** *@content:百度語音合成的數據管理class *@time:2018-9-8 *@build: */ public class VoiceConfigData { /** * 帳號組 */ public static final String APP_ID = "請輸入你的app id"; public static final String APP_KEY = "請輸入你的app key"; public static final String SECRET_KEY = "請輸入你的 secret key"; /** * 模式 TtsMode.MIX; 離在線融合,在線優先; TtsMode.ONLINE 純在線; 沒有純離線 */ public static final TtsMode TTS_MODE = TtsMode.MIX; /** *離線資源文件名稱與離線資源轉存路徑 */ public static final String TEMP_DIR = Environment.getExternalStorageDirectory() +"/"+"baiduTTS";//轉存路徑 //離線度丫丫 public static final String OFFLINE_FILE_ONE = "bd_etts_common_speech_as_mand_eng_high_am_v3.0.0_20170516.dat"; //離線女聲 public static final String OFFLINE_FILE_TWO = "bd_etts_common_speech_f7_mand_eng_high_am-mix_v3.0.0_20170512.dat"; //離線男聲 public static final String OFFLINE_FILE_THREE = "bd_etts_common_speech_m15_mand_eng_high_am-mix_v3.0.0_20170505.dat"; //yyjw 度逍遙 public static final String OFFLINE_FILE_FOUR = "bd_etts_common_speech_yyjw_mand_eng_high_am-mix_v3.0.0_20170512.dat"; //離線文字識別文件 public static final String TEXT_FILENAME = "bd_etts_text.dat"; }
package com.yt.owl.utils.BaiduVoiceUtil; import android.content.Context; import android.media.AudioManager; import android.util.Log; import android.util.Pair; import com.baidu.tts.auth.AuthInfo; import com.baidu.tts.chainofresponsibility.logger.LoggerProxy; import com.baidu.tts.client.SpeechError; import com.baidu.tts.client.SpeechSynthesizeBag; import com.baidu.tts.client.SpeechSynthesizer; import com.baidu.tts.client.SpeechSynthesizerListener; import com.yt.owl.utils.FileHandleUtil; import java.util.ArrayList; import java.util.List; /** *@content:百度語音合成工具class *@time:2018-9-10 *@build: * 使用說明:先使用getI方法獲得單例,在使用init方法初始化,初始化完成後在調用語音合成等等方法。 * 最後注意!請不要忘記了使用Destroy方法釋放資源 */ public class SpeakVoiceUtil { private static final String TAG = "SpeakVoiceUtil"; private SpeechSynthesizer mSpeechSynthesizer; private Context mContext; private static SpeakVoiceUtil mSpeakVoiceUtil; private SpeechListener mSpeechListener; private SpeechSynthesizerListener mSpeechSynthesizerListener; private SpeakVoiceUtil(){} public static SpeakVoiceUtil getI(){ if (mSpeakVoiceUtil == null){ mSpeakVoiceUtil = new SpeakVoiceUtil(); } return mSpeakVoiceUtil; } /** * 初始化 * @param context 外部上下文 */ public void init(Context context){ this.mContext = context; if (mSpeakVoiceUtil == null){ Log.e(TAG, "Error SpeakVoiceUtil is null"); return; } initFile(); initTTs(); checkAuth(); if (mSpeechListener !=null) { mSpeechListener.onInitFinish(); } } /** * 合成語音而且播放 * @param text 要合成的text文本 */ public void speak(String text){ if (mSpeechSynthesizer == null) { Log.e(TAG, "Error speak:mSpeechSynthesizer is null."); return; } int result = mSpeechSynthesizer.speak(text); checkResult(result, "speak"); Log.i(TAG, "播放語音:"+text); } /** * 中止語音合成和播放,清空列隊 */ public void stop() { if(mSpeechSynthesizer == null){ Log.e(TAG, "Error stop:mSpeechSynthesizer is null."); return; } int result = mSpeechSynthesizer.stop(); checkResult(result, "stop"); Log.i(TAG, "中止語音"); } /** * 暫停播放。僅調用speak後生效 */ public void pause() { if(mSpeechSynthesizer == null){ Log.e(TAG, "Error pause:mSpeechSynthesizer is null."); return; } int result = mSpeechSynthesizer.pause(); checkResult(result, "pause"); Log.i(TAG, "暫停語音"); } /** * 繼續播放。僅調用speak後生效,調用pause生效 */ public void resume() { if(mSpeechSynthesizer == null){ Log.e(TAG, "Error resume:mSpeechSynthesizer is null."); return; } int result = mSpeechSynthesizer.resume(); checkResult(result, "resume"); Log.i(TAG, "恢復語音"); } /** * 批量播放 * * 使用demo * List<SpeechSynthesizeBag> list = new ArrayList<>(); * SpeechSynthesizeBag s1 = new SpeechSynthesizeBag(); * s1.setText("開始批量播放"); * s1.setUtteranceId("1"); * list.add(s1); * SpeechSynthesizeBag s2 = new SpeechSynthesizeBag(); * s2.setText("批量播放成功"); * s2.setUtteranceId("2"); * list.add(s2); * SpeakVoiceUtil.getI().batchSpeak(list); */ public void batchSpeak(List<SpeechSynthesizeBag> list) { if(mSpeechSynthesizer == null){ Log.e(TAG, "Error batchSpeak:mSpeechSynthesizer is null."); return; } int result = mSpeechSynthesizer.batchSpeak(list); checkResult(result, "batchSpeak"); } /** * 釋放資源 */ public void Destroy() { if (mSpeechSynthesizer != null) { mSpeechSynthesizer.stop(); mSpeechSynthesizer.release(); mSpeechSynthesizer = null; } } public int setVoice(float leftVoice,float rightVoice){ if (mSpeechSynthesizer == null){ Log.e(TAG, "Error setVoice: mSpeechSynthesizer is null"); return -1; } int result = mSpeechSynthesizer.setStereoVolume(leftVoice,rightVoice); return result; } /** * 語音播放監聽接口回調 * @param SpeechListener 接口類 */ public void onSpeechListener(SpeechListener SpeechListener){ this.mSpeechListener = SpeechListener; } /** * 初始化語音參數 */ private void initTTs(){ LoggerProxy.printable(true); // 日誌打印在logcat中 mSpeechSynthesizer = SpeechSynthesizer.getInstance(); mSpeechSynthesizer.setContext(mContext); getSpeechSynthesizerListener(); mSpeechSynthesizer.setSpeechSynthesizerListener(mSpeechSynthesizerListener); int result = mSpeechSynthesizer.setAppId(VoiceConfigData.APP_ID); checkResult(result,"setAppId");//檢查結果 result = mSpeechSynthesizer.setApiKey(VoiceConfigData.APP_KEY,VoiceConfigData.SECRET_KEY); checkResult(result,"setApiKey"); mSpeechSynthesizer.auth(VoiceConfigData.TTS_MODE); // 文本模型文件路徑 (離線引擎使用), 注意TEXT_FILENAME必須存在而且可讀 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, VoiceConfigData.TEMP_DIR+"/"+VoiceConfigData.TEXT_FILENAME); // 聲學模型文件路徑 (離線引擎使用), 注意TEXT_FILENAME必須存在而且可讀 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, VoiceConfigData.TEMP_DIR+"/"+VoiceConfigData.OFFLINE_FILE_TWO); // 如下setParam 參數選填。不填寫則默認值生效 // 設置在線發聲音人: 0 普通女聲(默認) 1 普通男聲 2 特別男聲 3 情感男聲<度逍遙> 4 情感兒童聲<度丫丫> mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0"); // 設置合成的音量,0-9 ,默認 5 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "5"); // 設置合成的語速,0-9 ,默認 5 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5"); // 設置合成的語調,0-9 ,默認 5 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5"); // 設置參數的組合模式 // 該參數設置爲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.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT); mSpeechSynthesizer.setAudioStreamType(AudioManager.MODE_IN_CALL);//設置音頻流出口 mSpeechSynthesizer.setStereoVolume(1f,1f);//設置音量 result = mSpeechSynthesizer.initTts(VoiceConfigData.TTS_MODE);//初始化在線模式:TtsMode.MIX; 離在線融合,在線優先; TtsMode.ONLINE 純在線; 沒有純離線 checkResult(result, "initTts"); } /** * 初始化文件,將assets目錄的離線語音包複製到sd卡中 */ private void initFile(){ Log.i(TAG, "開始初始化離線文件"); String [] files = {VoiceConfigData.OFFLINE_FILE_ONE, VoiceConfigData.OFFLINE_FILE_TWO, VoiceConfigData.OFFLINE_FILE_THREE, VoiceConfigData.OFFLINE_FILE_FOUR, VoiceConfigData.TEXT_FILENAME}; if (FileHandleUtil.isCanUseSD()){//判斷sd卡是否可用 for (String file : files){ String filePath = VoiceConfigData.TEMP_DIR+"/"+file; if (!FileHandleUtil.isFileExist(filePath)){ Log.i(TAG, "initFile 準備複製文件file:"+file+" 到指定目錄:"+filePath); FileHandleUtil.copyFromAssetsToSdcard(mContext,file,VoiceConfigData.TEMP_DIR); }else { Log.i(TAG, "initFile "+file+"文件存在不須要複製"); } } }else { Log.e(TAG, "sdcard is null ..."); return; } } private void checkResult(int result, String method) { if (result != 0) { Log.e(TAG, "error code :" + result + " method:" + method + ", 錯誤碼文檔:http://yuyin.baidu.com/docs/tts/122"); } } /** * 檢查appId ak sk 是否填寫正確,另外檢查官網應用內設置的包名是否與運行時的包名一致。本demo的包名定義在build.gradle文件中 * * @return */ private boolean checkAuth() { AuthInfo authInfo = mSpeechSynthesizer.auth(VoiceConfigData.TTS_MODE); if (!authInfo.isSuccess()) { // 離線受權須要網站上的應用填寫包名。本demo的包名是com.baidu.tts.sample,定義在build.gradle中 String errorMsg = authInfo.getTtsError().getDetailMessage(); Log.e(TAG, "error 鑑權失敗 errorMsg=" + errorMsg); return false; } else { Log.e(TAG, "驗證經過,離線正式受權文件存在" ); return true; } } /** * 語音合成監聽接口回調方法 */ private void getSpeechSynthesizerListener(){ if (mSpeechSynthesizerListener == null) { Log.e(TAG, "初始化SpeechSynthesizerListener"); mSpeechSynthesizerListener = new SpeechSynthesizerListener() { @Override public void onSynthesizeStart(String s) { Log.i(TAG, "onSynthesizeStart合成啓動:返回碼=" + s); } @Override public void onSynthesizeDataArrived(String s, byte[] bytes, int i) { Log.i(TAG, "onSynthesizeDataArrived合成數據到達:" + "返回碼=" + s + "; 字節=" + bytes + "; current=" + i); } @Override public void onSynthesizeFinish(String s) { Log.i(TAG, "onSynthesizeFinish合成完成:返回碼=" + s); } @Override public void onSpeechStart(String s) { Log.i(TAG, "onSpeechStart語音開始:返回碼=" + s); if (mSpeechListener != null) { mSpeechListener.onStart(mContext, s); } } @Override public void onSpeechProgressChanged(String s, int i) { Log.i(TAG, "onSpeechProgressChanged語音播放中:返回碼=" + s + "; current=" + i); if (mSpeechListener != null) { mSpeechListener.onProgress(mContext, s, i); } } @Override public void onSpeechFinish(String s) { Log.i(TAG, "onSpeechFinish語音播放結束:返回碼=" + s); if (mSpeechListener != null) { mSpeechListener.onFinish(mContext, s); } } @Override public void onError(String s, SpeechError speechError) { Log.e(TAG, "onError異常:返回碼=" + s + "; SpeechError=" + speechError); if (mSpeechListener != null) { mSpeechListener.onError(mContext, s, speechError); } } }; } } }
另外還有一些複製文件的的簡單方法,我就不貼出來了。能夠自行編寫方法用於複製文件ui