目前比較厲害的國內免費開源的語音識別庫主要就是:訊飛和百度,本篇博客也是關於這兩家SDK的使用。
訊飛語音開放平臺:http://doc.xfyun.cn/msc_android/299547
訊飛平臺下載的sdk有doc文件夾,其中有html結尾的API文件,需要的去官網可以下載
本篇博客Demo地址:http://download.csdn.net/download/g_ying_jie/9895905
訊飛語音聽寫功能:
第一步、集成SDK,配置權限文檔已經介紹的很清楚了,Demo也可以下下來直接運行。類似於以下目錄結構
第二步、實例化語音聽寫對象和UI。該dialog資源需要用到assets的資源
// 語音聽寫對象
private SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(VoiToTxtActivity.this, mInitListener);
// 語音聽寫UI
private RecognizerDialog mIatDialog = new RecognizerDialog(VoiToTxtActivity.this, mInitListener);
/**
* 初始化監聽器。
*/
private InitListener mInitListener = new InitListener() {
@Override
public void onInit(int code) {
Log.d(TAG, "SpeechRecognizer init() code = " + code);
if (code != ErrorCode.SUCCESS) {
showTip("初始化失敗,錯誤碼:" + code);
}
}
};
/**
* 參數設置
*/
public void setParam() {
// 清空參數
mIat.setParameter(SpeechConstant.PARAMS, null);
// 設置聽寫引擎
mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
// 設置返回結果格式
mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");
// 設置語言
mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
// 設置語言區域
mIat.setParameter(SpeechConstant.ACCENT, "mandarin");
// 設置語音前端點:靜音超時時間,即用戶多長時間不說話則當做超時處理
mIat.setParameter(SpeechConstant.VAD_BOS, "5000");
// 設置語音後端點:後端點靜音檢測時間,即用戶停止說話多長時間內即認爲不再輸入, 自動停止錄音
mIat.setParameter(SpeechConstant.VAD_EOS, "1800");
// 設置標點符號,設置爲"0"返回結果無標點,設置爲"1"返回結果有標點
mIat.setParameter(SpeechConstant.ASR_PTT, "1");
// 設置音頻保存路徑,保存音頻格式支持pcm、wav,設置路徑爲sd卡請注意WRITE_EXTERNAL_STORAGE權限
//mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
//mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
}
第四步、開始聽寫識別
// 顯示聽寫對話框
mIatDialog.setListener(mRecognizerDialogListener);
mIatDialog.show();
/**
* 聽寫UI監聽器
*/
private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
public void onResult(RecognizerResult results, boolean isLast) {
printResult(results);
}
/**
* 識別回調錯誤.
*/
public void onError(SpeechError error) {
showTip(error.getPlainDescription(true));
}
};
//解析返回的識別結果
private void printResult(RecognizerResult results) {
String text = JsonParser.parseIatResult(results.getResultString());
String sn = null;
// 讀取json結果中的sn字段
try {
JSONObject resultJson = new JSONObject(results.getResultString());
sn = resultJson.optString("sn");
} catch (JSONException e) {
e.printStackTrace();
}
mIatResults.put(sn, text);
StringBuffer resultBuffer = new StringBuffer();
for (String key : mIatResults.keySet()) {
resultBuffer.append(mIatResults.get(key));
}
mResultText.setText(resultBuffer.toString());
mResultText.setSelection(mResultText.length());
}
注意:這裏用HashMap來存儲聽寫結果
// 用HashMap存儲聽寫結果
private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mIat) {
// 退出時釋放連接
mIat.cancel();
mIat.destroy();
}
}
訊飛針對詞組優化提供了上傳聯繫人和詞表的方法
①上傳聯繫人並使用mResultText展示給用戶
ContactManager mgr = ContactManager.createManager(VoiToTxtActivity.this, mContactListener);
mgr.asyncQueryAllContactsName();
/**
* 獲取聯繫人監聽器。
*/
private ContactListener mContactListener = new ContactListener() {
@Override
public void onContactQueryFinish(final String contactInfos, boolean changeFlag) {
// 注:實際應用中除第一次上傳之外,之後應該通過changeFlag判斷是否需要上傳,否則會造成不必要的流量.
// 每當聯繫人發生變化,該接口都將會被回調,可通過ContactManager.destroy()銷燬對象,解除回調。
// if(changeFlag) {
// 指定引擎類型
runOnUiThread(new Runnable() {
public void run() {
mResultText.setText(contactInfos);
}
});
mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
mIat.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
ret = mIat.updateLexicon("contact", contactInfos, mLexiconListener);
if (ret != ErrorCode.SUCCESS) {
showTip("上傳聯繫人失敗:" + ret);
}
}
};
②上傳用戶詞組
String contents = FucUtil.readFile(VoiToTxtActivity.this, "userwords","utf-8");
mResultText.setText(contents);
// 指定引擎類型
mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
mIat.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
ret = mIat.updateLexicon("userword", contents, mLexiconListener);
if (ret != ErrorCode.SUCCESS)
showTip("上傳熱詞失敗,錯誤碼:" + ret);
/**
* 上傳聯繫人/詞表監聽器。
*/
private LexiconListener mLexiconListener = new LexiconListener() {
@Override
public void onLexiconUpdated(String lexiconId, SpeechError error) {
if (error != null) {
showTip(error.toString());
} else {
showTip("上傳成功");
}
}
};
訊飛語音合成:
第一步,實例化語音合成對象和雲端發音人列表
// 語音合成對象
private SpeechSynthesizer mTts = SpeechSynthesizer.createSynthesizer(TxtToVoiActivity.this, mTtsInitListener);
// 默認發音人
private String voicer = "xiaoyan";
private String[] mCloudVoicersEntries = getResources().getStringArray(R.array.voicer_cloud_entries);
private String[] mCloudVoicersValue = getResources().getStringArray(R.array.voicer_cloud_values);
/**
* 初始化監聽。
*/
private InitListener mTtsInitListener = new InitListener() {
@Override
public void onInit(int code) {
if (code != ErrorCode.SUCCESS) {
showTip("初始化失敗,錯誤碼:" + code);
} else {
// 初始化成功,之後可以調用startSpeaking方法
// 注:有的開發者在onCreate方法中創建完合成對象之後馬上就調用startSpeaking進行合成,
// 正確的做法是將onCreate中的startSpeaking調用移至這裏
}
}
};
res文件夾下的Strings配置如下
<string-array name="voicer_cloud_entries">
<item>小燕—女青、中英、普通話</item>
<item>小宇—男青、中英、普通話</item>
<item>小研—女青、中英、普通話</item>
<item>小琪—女青、中英、普通話</item>
<item>小峯—男青、中英、普通話</item>
<item>小梅—女青、中英、粵語</item>
<item>小莉—女青、中英、臺灣普通話</item>
</string-array>
<string-array name="voicer_cloud_values">
<item>xiaoyan</item>
<item>xiaoyu</item>
<item>vixy</item>
<item>xiaoqi</item>
<item>vixf</item>
<item>vixm</item>
<item>vixl</item>
</string-array>
第二步,設置識別參數
private int selectedNum = 0;
/**
* 發音人選擇。
*/
private void showPersonSelectDialog() {
new AlertDialog.Builder(this)
.setTitle("在線合成發音人選項")
/*
* CharSequence[] 單選框有幾項,各是什麼名字
* checkedItem 默認的選項
* listener 點擊單選框後的回調
* */
.setSingleChoiceItems(mCloudVoicersEntries, selectedNum, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 點擊了哪一項
voicer = mCloudVoicersValue[which];
selectedNum = which;
dialog.dismiss();
}
}).show();
}
/**
* 參數設置
*/
private void setParam() {
// 清空參數
mTts.setParameter(SpeechConstant.PARAMS, null);
// 根據合成引擎設置相應參數
mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
// 設置在線合成發音人
mTts.setParameter(SpeechConstant.VOICE_NAME, voicer);
//設置合成語速
mTts.setParameter(SpeechConstant.SPEED, "50");
//設置合成音調
mTts.setParameter(SpeechConstant.PITCH, "50");
//設置合成音量
mTts.setParameter(SpeechConstant.VOLUME, "50");
//設置播放器音頻流類型 值範圍:android.media.AudioManager支持的流類型值
mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");
// 設置播放合成音頻打斷音樂播放,默認爲true
mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");
// 設置音頻保存路徑,保存音頻格式支持pcm、wav,設置路徑爲sd卡請注意WRITE_EXTERNAL_STORAGE權限
// 注:AUDIO_FORMAT參數語記需要更新版本才能生效
mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/tts.wav");
}
第三步,獲取待合成的文字內容,開始合成語音
String text = ((EditText) findViewById(R.id.tts_text)).getText().toString();
/*
* 只保存音頻不調用播放接口時請註釋startSpeaking接口
* text:要合成的文本
* listener:回調接口
* uri:需要保存的音頻全路徑
*/
//String path = Environment.getExternalStorageDirectory()+"/tts.pcm";
//int code = mTts.synthesizeToUri(text, path, mTtsListener);
int code = mTts.startSpeaking(text, mTtsListener);
if (code != ErrorCode.SUCCESS) {
showTip("語音合成失敗,錯誤碼: " + code);
}
/**
* 合成回調監聽。
*/
private SynthesizerListener mTtsListener = new SynthesizerListener() {
@Override
public void onSpeakBegin() {
showTip("開始播放");
}
@Override
public void onSpeakPaused() {
showTip("暫停播放");
}
@Override
public void onSpeakResumed() {
showTip("繼續播放");
}
@Override
public void onBufferProgress(int percent, int beginPos, int endPos, String info) {
// 合成進度
mPercentForBuffering = percent;
showTip(String.format("緩衝進度爲%d%%,播放進度爲%d%%", mPercentForBuffering, mPercentForPlaying));
}
@Override
public void onSpeakProgress(int percent, int beginPos, int endPos) {
// 播放進度
mPercentForPlaying = percent;
showTip(String.format("緩衝進度爲%d%%,播放進度爲%d%%", mPercentForBuffering, mPercentForPlaying));
}
@Override
public void onCompleted(SpeechError error) {
if (error == null) {
showTip("播放完成");
} else if (error != null) {
showTip(error.getPlainDescription(true));
}
}
@Override
public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
// 以下代碼用於獲取與雲端的會話id,當業務出錯時將會話id提供給技術支持人員,可用於查詢會話日誌,定位出錯原因
// 若使用本地能力,會話id爲null
// if (SpeechEvent.EVENT_SESSION_ID == eventType) {
// String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
// Log.d(TAG, "session id =" + sid);
// }
}
};
其他的比較有用的方法:
// 取消合成
mTts.stopSpeaking();
// 暫停播放
mTts.pauseSpeaking();
// 繼續播放
mTts.resumeSpeaking();
好了到此訊飛在線語音就介紹完了,詳細的使用可以下載我上傳的Demo。這裏爲什麼強調在線呢?因爲訊飛的離線語音識別服務需要下載語記APP以及對應的離線數據包,而且離線識別只能適用於安卓平臺,因此只是嘗試了沒有深入研究就不貼出來了。
百度語音篇
百度語音基礎視頻介紹:https://chuanke.baidu.com/v7867982-208144-1278714.html
百度語音識別API對接視頻:https://chuanke.baidu.com/v7867982-209753-1294636.html
百度語音文檔中心:http://ai.baidu.com/docs#/ASR-Android-SDK/top
本篇博客Demo:http://download.csdn.net/detail/g_ying_jie/9890613
百度的SDK是離在線融合的(可是沒研究出來離線識別,需要開通離線授權,巴拉巴拉。。。。如果有哪位大神弄出來了,希望也能夠共享出來)
百度自定義了一個語音識別組件,所以基本一句話就可以實現語音識別的流程
第一步、開始識別
private void start() {
Intent recognizerIntent = new Intent(MainActivity.this, BaiduASRDigitalDialog.class);
//採樣率
recognizerIntent.putExtra(Constant.EXTRA_SAMPLE, 16000);
//識別語種
recognizerIntent.putExtra(Constant.EXTRA_LANGUAGE, "cmn-Hans-CN");
//設置語言活動模式 input輸入模式search搜索模式
recognizerIntent.putExtra(Constant.EXTRA_VAD, "input");
/*//說話開始的提示音
recognizerIntent.putExtra(Constant.EXTRA_SOUND_START, R.raw.bdspeech_recognition_start);
//說話結束的提示音
recognizerIntent.putExtra(Constant.EXTRA_SOUND_END, R.raw.bdspeech_speech_end);
//識別成功的提示音
recognizerIntent.putExtra(Constant.EXTRA_SOUND_SUCCESS, R.raw.bdspeech_recognition_success);
//識別出錯的提示音
recognizerIntent.putExtra(Constant.EXTRA_SOUND_ERROR, R.raw.bdspeech_recognition_error);
//識別取消的提示音
recognizerIntent.putExtra(Constant.EXTRA_SOUND_CANCEL, R.raw.bdspeech_recognition_cancel);
//語義識別
recognizerIntent.putExtra(Constant.EXTRA_NLU, "enable");*/
startActivityForResult(recognizerIntent, 1);
}
第二步、處理識別結果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
textView.setText(data.getExtras().getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).get(0));
}
}
注意:BaiduASRDigitalDialog需要與之配套的res資源,而且該資源都是放於drawable文件夾下,不能粗暴的將圖片資源複製到mipmap中,使用Android studio的開發者一定要注意(樓主已經入坑)
Demo都上傳到了csdn上面,有需要的可以下載運行,不需要積分。有問題或者建議歡迎在評論區留言