官網:http://yuyin.baidu.com/ 或 http://ai.baidu.com/sdk#tts(建議)
第一步:下載SDK,將demo運行起來,沒問題的話在應用管理 | 控制台創建新的應用,綁定包名,開通語音識別和語音合成的服務。
第二步:在工程中添加jar以及so庫,raw,assets(有的話)等,記得這個有個坑,就是在上傳svn或者其他什么操作時,授權失敗,不識別語音了,看下是不是so庫丟失了,重新添加下。
這里因為已經用過了語音識別封裝了方法,只要在onCreate方法調用該方法即可進行語音識別,這里是沒有百度語音識別的UI界面的,結果在onResult方法里,可以自己直接處理或eventbus post出去操作。
下面是方法:
// 語音識別客戶端
private SpeechRecognizer speechRecognizer;
private void initRecognizer() {
speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this, new ComponentName(this, VoiceRecognitionService.class));
speechRecognizer.setRecognitionListener(new RecognitionListener() {
@Override
public void onReadyForSpeech(Bundle params) {
progressView.start();
status = STATUS_Ready;
print("准備就緒,可以開始說話");
}
@Override
public void onBeginningOfSpeech() {
time = System.currentTimeMillis();
status = STATUS_Speaking;
print("檢測到用戶的已經開始說話");
Log.e("555555555", "onBeginningOfSpeech: ");
}
@Override
public void onRmsChanged(float rmsdB) {
if (rmsdB < 100) {
rmsdB = 0;
}
if (rmsdB > 900) {
rmsdB = 900;
}
progressView.setVolume((int) (rmsdB / 42f));
Log.e(TAG, "onRmsChanged: " + rmsdB);
}
@Override
public void onBufferReceived(byte[] buffer) {
}
@Override
public void onEndOfSpeech() {
speechEndTime = System.currentTimeMillis();
status = STATUS_Recognition;
print("檢測到用戶的已經停止說話");
Log.e("555555555", "onEndOfSpeech: ");
}
@Override
public void onError(int error) {
time = 0;
status = STATUS_None;
StringBuilder sb = new StringBuilder();
switch (error) {
case SpeechRecognizer.ERROR_AUDIO:
sb.append("音頻問題");
break;
case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
sb.append("沒有語音輸入");
break;
case SpeechRecognizer.ERROR_CLIENT:
sb.append("其它客戶端錯誤");
break;
case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
sb.append("權限不足");
break;
case SpeechRecognizer.ERROR_NETWORK:
sb.append("網絡問題");
break;
case SpeechRecognizer.ERROR_NO_MATCH:
sb.append("沒有匹配的識別結果");
break;
case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
sb.append("引擎忙");
break;
case SpeechRecognizer.ERROR_SERVER:
sb.append("服務端錯誤");
break;
case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
sb.append("連接超時");
break;
}
sb.append(":" + error);
print("識別失敗:" + sb.toString());
handlerRecognizer.sendEmptyMessage(0);
}
@Override
public void onResults(Bundle results) {
long end2finish = System.currentTimeMillis() - speechEndTime;
status = STATUS_None;
ArrayList<String> nbest = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
print("識別成功:" + Arrays.toString(nbest.toArray(new String[nbest.size()])));
String json_res = results.getString("origin_result");
try {
print("origin_result=\n" + new JSONObject(json_res).toString(4));
} catch (Exception e) {
print("origin_result=[warning: bad json]\n" + json_res);
}
String strEnd2Finish = "";
if (end2finish < 60 * 1000) {
strEnd2Finish = "(waited " + end2finish + "ms)";
}
//最終結果
// txtResult.setText(nbest.get(0) + strEnd2Finish);
Log.e("111111111111", "onResults: " + nbest.get(0) + strEnd2Finish);
EventBus.getDefault().post(new EventAction(1002, nbest.get(0)));
time = 0;
}
@Override
public void onPartialResults(Bundle partialResults) {
ArrayList<String> nbest = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
if (nbest.size() > 0) {
print("~臨時識別結果:" + Arrays.toString(nbest.toArray(new String[0])));
// txtResult.setText(nbest.get(0));
Log.e("111111111111", "onPartialResults: " + nbest.get(0));
}
}
@Override
public void onEvent(int eventType, Bundle params) {
switch (eventType) {
case EVENT_ERROR:
String reason = params.get("reason") + "";
print("EVENT_ERROR, " + reason);
break;
case VoiceRecognitionService.EVENT_ENGINE_SWITCH:
int type = params.getInt("engine_type");
print("*引擎切換至" + (type == 0 ? "在線" : "離線"));
break;
}
}
});
}
第三步:語音合成:和語音識別同樣的操作,開通服務,在工程中添加jar和其他so庫等,添加完了后,這里也進行了方法封裝,只要在onCreate方法里調用該方法就可以開啟語音合成。
下面是語音合成的方法:
// 語音合成客戶端
private SpeechSynthesizer mSpeechSynthesizer;
// 初始化語音合成客戶端並啟動
private void initTTS() {
// 獲取語音合成對象實例
mSpeechSynthesizer = SpeechSynthesizer.getInstance();
// 設置context
mSpeechSynthesizer.setContext(this);
// 設置語音合成狀態監聽器
mSpeechSynthesizer.setSpeechSynthesizerListener(new SpeechSynthesizerListener() {
@Override
public void onSynthesizeStart(String s) {
Log.e("444444444", "onSynthesizeStart: ");
}
@Override
public void onSynthesizeDataArrived(String s, byte[] bytes, int i) {
Log.e("444444444", "onSynthesizeDataArrived: ");
}
@Override
public void onSynthesizeFinish(String s) {
Log.e("444444444", "onSynthesizeFinish: ");
}
@Override
public void onSpeechStart(String s) {
Log.e("444444444", "onSpeechStart: ");
}
@Override
public void onSpeechProgressChanged(String s, int i) {
}
@Override
public void onSpeechFinish(String s) {//監聽到播放結束
Log.e("444444444", "onSpeechFinish: ");
if ("我暫時停止接受您的指令,需要恢復,請按恢復按鈕。".equals(message)) {
} else {
handlerRecognizer.sendEmptyMessage(0);//由於項目需求在監聽到語音播放結束的時候重新開啟語音識別,但是語音識別只能在主線程中執行,所以這里用handler起了一個線程,方法在下面賦
}
}
@Override
public void onError(String s, SpeechError speechError) {
Log.e("444444444", "onError: ");
}
});
// 設置在線語音合成授權,需要填入從百度語音官網申請的api_key和secret_key
mSpeechSynthesizer.setApiKey("Uod13Hd6rURLvDLRlVP5PgSB", "cba32e2cc5189a886bd127715dcafabe");
// 設置離線語音合成授權,需要填入從百度語音官網申請的app_id
mSpeechSynthesizer.setAppId("9942218");
// 文本模型文件路徑 (離線引擎使用)
this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, mSampleDirPath + "/"
+ TEXT_MODEL_NAME);
// 聲學模型文件路徑 (離線引擎使用)
this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, mSampleDirPath + "/"
+ SPEECH_FEMALE_MODEL_NAME);
// 本地授權文件路徑,如未設置將使用默認路徑.設置臨時授權文件路徑,
// LICENCE_FILE_NAME請替換成臨時授權文件的實際路徑,僅在使用臨時license文件時需要進行設置,
// 如果在[應用管理]中開通了正式離線授權,不需要設置該參數,建議將該行代碼刪除(離線引擎)
// 如果合成結果出現臨時授權文件將要到期的提示,說明使用了臨時授權文件,請刪除臨時授權即可。
// this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_LICENCE_FILE, mSampleDirPath + "/"
// + LICENSE_FILE_NAME);
// 獲取語音合成授權信息---有兩種模式:僅在線;混合(離在線)
//初始化合成引擎,可以指定使用online在線,或者mix離在線混合引擎. mix混合引擎會在online在線不能用的情況下自動使用offline離線引擎。
AuthInfo authInfo = mSpeechSynthesizer.auth(TtsMode.MIX);
// 判斷授權信息是否正確,如果正確則初始化語音合成器並開始語音合成,如果失敗則做錯誤處理
if (authInfo.isSuccess()) {
mSpeechSynthesizer.initTts(TtsMode.MIX);
} else {
// 授權失敗
Toast.makeText(this, "授權失敗", Toast.LENGTH_SHORT).show();
}
}
第四步:重新開啟語音識別,用handler起了一個線程
Handler handlerRecognizer = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
startRecognizer();
}
};
第五步:需要控制語音識別的開始和停止的方法,這里也做了封裝,在需要的時候調用即可。
下面是語音識別開始和停止的方法:
/**
* 開始識別語音
*/
private void startRecognizer() {
Intent intent = new Intent();
intent.putExtra("language", "cmn-Hans-CN");
intent.putExtra("prop", 10005);
speechEndTime = -1;
speechRecognizer.startListening(intent);
}
//暫停語音識別
private void stopRecognizer() {
speechRecognizer.stopListening();
print("點擊了“說完了”");
}
//停止語音識別
private void cancelRecognizer() {
speechRecognizer.cancel();
status = STATUS_None;
print("點擊了“取消”");
}
這里需要注意的是,我遇到的一個問題:
在需要停止監聽語音的時候,剛開始我調用的是stop方法,但是並不能真正的停止語音監聽,在和百度的技術人員溝通后才知道要調用cancle方法才可以,兩個方法同時調用也不可取。
第六步:百度語音合成的方法:
//語音開始播報
mSpeechSynthesizer.speak(“text”);
//語音停止播報mSpeechSynthesizer.stop();
第七步:
當然語音合成和識別都要在activity或fragment的生命周期中做相應的操作:
@Override
protected void onResume() {
if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {//橫屏操作
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
mSpeechSynthesizer.resume();
super.onResume();
}
@Override
protected void onPause() {
cancelRecognizer();
if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {//橫屏操作
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
mSpeechSynthesizer.pause();
super.onPause();
}
@Override
protected void onDestroy() {
if (null != mSpeechSynthesizer) {
mSpeechSynthesizer.release();
}
if (null != speechRecognizer) {
// 退出時釋放連接
speechRecognizer.destroy();
}
super.onDestroy();
}