前幾篇都是介紹一些輔助功能殉挽,如新聞、H5游戲裳擎、段子趣圖涎永、原生小游戲,手電筒應(yīng)用等,現(xiàn)在再來聊聊機(jī)器人陪聊主體功能--語音功能及其實(shí)現(xiàn)土辩。
【小萌伴】中的語音功能使用的是百度語音sdk支救,包含語音輸入抢野、語音播放拷淘、語音轉(zhuǎn)文字、文字轉(zhuǎn)語音指孤、聲音變換启涯、離線語音語義識別、語音喚醒等恃轩。
其中功能的主要可分為三部分:語音識別结洼、語音合成、語音喚醒叉跛。(我用的sdk比較老了松忍,下面代碼也許已經(jīng)不兼容新sdk,具體請參考 百度語音 官網(wǎng))
ChatActivity實(shí)現(xiàn)了RecognitionListener及SpeechSynthesizerListener接口筷厘,這兩個(gè)接口是語音識別與合成的監(jiān)聽鸣峭。
初始化
語音識別和語音合成需要在進(jìn)入Activity后執(zhí)行初始化,在銷毀時(shí)進(jìn)行銷毀酥艳。初始化如下摊溶,語音識別初始化沒有封裝,語音合成則用TtsUtils封裝了一下充石。
mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(ChatActivity.this, new ComponentName(ChatActivity.this, VoiceRecognitionService.class));
// 注冊監(jiān)聽器
mSpeechRecognizer.setRecognitionListener(ChatActivity.this);
mSpeechSynthesizer = TtsUtils.getSpeechSynthesizer(ChatActivity.this, ChatActivity.this, getVoice(mRobot));
語音輸入及識別
對這一塊莫换,通過BdVoiceUtil類進(jìn)行了封裝,通過調(diào)用如下方法即可開啟語音識別:
BdVoiceUtil.startASR(mSpeechRecognizer, mSpeechSynthesizer, true);
在RecognitionListener的回調(diào)中獲取語音識別的結(jié)果骤铃,包括實(shí)時(shí)(部分)轉(zhuǎn)換及全量(整句話)轉(zhuǎn)換為文字拉岁,在onResults或者onPartialResults中將轉(zhuǎn)換的文字發(fā)送到機(jī)器人api,之后邏輯與正常機(jī)器人陪聊一致惰爬。
語音合成
將機(jī)器人返回的語音轉(zhuǎn)換為文字喊暖,這一塊也在BdVoiceUtil進(jìn)行了一下封裝:
BdVoiceUtil.startTTS(mSpeechSynthesizer, msg.getContent());
通過以上代碼即可以開始轉(zhuǎn)換,將msg.getContent()轉(zhuǎn)換為語音补鼻,可以通過SpeechSynthesizerListener監(jiān)聽轉(zhuǎn)換是否成功哄啄,語音播放的進(jìn)度等。
語音合成后风范,也可以通過setParam控制聲音(0 (普通女聲), 1 (普通男聲), 2 (特別男聲), 3 (情感男聲), 4 (童聲))等
mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, String.valueOf(getVoice(robot)));
語音喚醒
語音喚醒功能在這里沒有用到咨跌,主要是在后續(xù)介紹的“找手機(jī)”功能用到;包括語音喚醒硼婿、通過語音識別達(dá)到喚醒的目的锌半、與微信等的語音輸入沖突問題等,這些留到后續(xù)介紹“找手機(jī)”時(shí)再說寇漫。
BdVoiceUtil
對語音相關(guān)的簡單封裝刊殉,其實(shí)還有TtsUtils等殉摔,總的代碼太多,這里就不貼了...
public class BdVoiceUtil {
/**
* 開始識別(會先停止SpeechSynthesizer)
* @param speechRecognizer
* @param mSpeechSynthesizer
* @param bindParams 是否需要提示音
*/
public static void startASR(SpeechRecognizer speechRecognizer, SpeechSynthesizer mSpeechSynthesizer, boolean bindParams) {
stopTTS(mSpeechSynthesizer);
Intent intent = new Intent();
bindParams(intent, bindParams);
if(speechRecognizer != null) {
speechRecognizer.startListening(intent);
}
}
public static void stopASR(SpeechRecognizer speechRecognizer) {
// 說完了
if(speechRecognizer != null) {
speechRecognizer.stopListening();
}
}
public static void cancelASR(SpeechRecognizer speechRecognizer) {
// 取消
if(speechRecognizer != null) {
speechRecognizer.cancel();
}
}
public static void destroyASR(SpeechRecognizer speechRecognizer) {
cancelASR(speechRecognizer);
if(speechRecognizer != null) {
speechRecognizer.destroy();
}
}
public static void bindParams(Intent intent, boolean hintSound) {
if(hintSound) {
// 設(shè)置識別參數(shù)
intent.putExtra(TtsUtils.EXTRA_SOUND_START, R.raw.bdspeech_recognition_start);
intent.putExtra(TtsUtils.EXTRA_SOUND_END, R.raw.bdspeech_speech_end);
intent.putExtra(TtsUtils.EXTRA_SOUND_SUCCESS, R.raw.bdspeech_recognition_success);
intent.putExtra(TtsUtils.EXTRA_SOUND_ERROR, R.raw.bdspeech_recognition_error);
intent.putExtra(TtsUtils.EXTRA_SOUND_CANCEL, R.raw.bdspeech_recognition_cancel);
}
intent.putExtra("sample", 16000); // 離線僅支持16000采樣率
intent.putExtra("language", "cmn-Hans-CN"); // 離線僅支持中文普通話
intent.putExtra("prop", 20000); // 輸入
// 語音輸入附加資源记焊,value替換為資源文件實(shí)際路徑
// 離線包過大逸月,暫不考慮支持 intent.putExtra("lm-res-file-path", "/path/to/s_2_InputMethod");
}
public static EventManager initEventWakeUp(final Activity context) {
// 喚醒功能打開步驟
// 1) 創(chuàng)建喚醒事件管理器
EventManager mWpEventManager = EventManagerFactory.create(context, "wp");
// 2) 注冊喚醒事件監(jiān)聽器
mWpEventManager.registerListener(new EventListener() {
@Override
public void onEvent(String name, String params, byte[] data, int offset, int length) {
try {
if(params == null) {
return;
}
JSONObject json = new JSONObject(params);
if ("wp.data".equals(name)) { // 每次喚醒成功, 將會回調(diào)name=wp.data的時(shí)間, 被激活的喚醒詞在params的word字段
String word = json.getString("word"); // 喚醒詞
WpEventManagerUtil.doEvent(context, word);
if(Logs.isDebug()) {
Logs.logI(BdVoiceUtil.class.getSimpleName(), "百度語音喚醒" + word);
}
} else if ("wp.exit".equals(name)) {
// 喚醒已經(jīng)停止
}
} catch (JSONException e) {
throw new AndroidRuntimeException(e);
}
}
});
return mWpEventManager;
}
public static EventManager eventWakeUp(final Activity context, EventManager mWpEventManager) {
if(mWpEventManager == null) {
mWpEventManager = initEventWakeUp(context);
}
// 3) 通知喚醒管理器, 啟動喚醒功能
HashMap params = new HashMap();
params.put("kws-file", "assets:///WakeUp.bin"); // 設(shè)置喚醒資源, 喚醒資源請到 http://yuyin.baidu.com/wake#m4 來評估和導(dǎo)出
mWpEventManager.send("wp.start", new JSONObject(params).toString(), null, 0, 0);
return mWpEventManager;
}
public static void eventWekeUpStop(EventManager mWpEventManager) {
if(mWpEventManager != null) {
// 停止喚醒監(jiān)聽
mWpEventManager.send("wp.stop", null, null, 0, 0);
}
}
public static void stopTTS(SpeechSynthesizer mSpeechSynthesizer) {
if(mSpeechSynthesizer != null) {
mSpeechSynthesizer.stop();
}
}
public static void releaseTTS(SpeechSynthesizer mSpeechSynthesizer) {
stopTTS(mSpeechSynthesizer);
if(mSpeechSynthesizer != null) {
mSpeechSynthesizer.release();
}
}
public static void startTTS(SpeechSynthesizer mSpeechSynthesizer, String text) {
stopTTS(mSpeechSynthesizer);
if(mSpeechSynthesizer != null) {
mSpeechSynthesizer.speak(text);
}
}
}
頁面布局與一般輸入框沒大差別,這里就不多說了~~~
個(gè)人博客: IT老五
微信公眾號:IT老五(it-lao5)遍膜,一起源創(chuàng)碗硬,一起學(xué)習(xí)!
相關(guān)內(nèi)容:
【小萌伴Android】相關(guān)文章目錄
1.【小萌伴Android】思量再三瓢颅,終于鼓起勇氣開源~
2.【小萌伴Android】機(jī)器人陪聊模塊分享
3.【小萌伴Android】新聞/H5游戲模塊及廣告過濾
4.【小萌伴Android】段子趣圖模塊及其實(shí)現(xiàn) 及 段子趣圖數(shù)據(jù)爬取
5.【小萌伴Android】原生小游戲及其實(shí)現(xiàn)(一)2048
6.【小萌伴Android】原生小游戲及其實(shí)現(xiàn)(二)小鳥
7.【小萌伴Android】原生小游戲及其實(shí)現(xiàn)(三)飛機(jī)
8.【小萌伴Android】手電筒功能及其實(shí)現(xiàn)
9.【小萌伴Android】機(jī)器人陪聊--語音功能及其實(shí)現(xiàn)