編輯:關於Android編程
今天我們來繼續學習百度語音識別SDK的相關內容,今天我們以百度語音識別SDK提供的API接口為前提,來實現自己的語音識別交互界面。在正式開始今天的文章之前,我們首先來了解下百度語音識別SDK中的幾個重要的類吧。
1、VoiceRecognitionClient
VoiceRecognitionClient是整個語音識別API中的入口API,我們對於語音識別的整體控制都集中在這個類當中。VoiceRecognitionClient提供了speakFinish()、startVoiceRecognition()、stopVoiceRecognition()三個主要的方法。分別用來控制語音識別結束(指已經說完)、語音識別停止、語音識別開始。通過VoiceRecognitionClient類我們可以對整個語音識別進行宏觀上的調控(請原諒我這麼說),這是整個語音識別SDK中的入口類。
2、VoiceRecognitionConfig
VoiceRecognitionConfig是語音識別的配置類,在這個類裡我們可以對當前語音識別環境進行配置,如語音識別的模式、語音識別音效、語音識別采樣率等。
3、VoiceClientStatusChangeListener
VoiceClientStatusChangeListener是語音識別的回調接口類,我們要調用百度語音識別API就必須實現這個類,因此這個類是整個語音識別中最重要的一個類,換句話說,如果說VoiceRecognitionClient控制整個宏觀層面上的語音識別,那麼VoiceClientStatusChangeListener就是在控制整個語音識別的微觀層面,一個語音識別的過程包括語音識別開始、語音識別監聽、語音識別識別、語音識別反饋,而通過VoiceClientStatusChangeListener我們就能對語音識別的每一個過程進行控制,這個類相對復雜,我們待會會做詳細的討論。
好了,現在主要的類已經介紹完了,下面大家可以跟著我一起來學習今天的內容了。首先說一下今天想要實現的內容,在今天的程序中,我們將實現通過兩個Button來控制語音識別的開始和結束並在界面上反饋當前語音識別的狀態和最終的結果,通過一個進度條控件(程序演示需要,非必需)來顯示當前用戶說話音量的大小情況。首先,我們來初始化語音識別的入口類:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_voice); InitView(); //獲取mClent mClient=VoiceRecognitionClient.getInstance(this); //設置應用授權信息 mClient.setTokenApis(API_KEY, SECRET_KEY); //初始化主線程 mHandler=new Handler(); }
/** 語音識別回調接口 **/ private VoiceClientStatusChangeListener mListener=new VoiceClientStatusChangeListener() { public void onClientStatusChange(int status, Object obj) { switch (status) { // 語音識別實際開始,這是真正開始識別的時間點,需在界面提示用戶說話。 case VoiceRecognitionClient.CLIENT_STATUS_START_RECORDING: IsRecognition = true; mVolumeBar.setVisibility(View.VISIBLE); BtnCancel.setEnabled(true); BtnStart.setText("說完"); Status.setText("當前狀態:請說話"); mHandler.removeCallbacks(mUpdateVolume); mHandler.postDelayed(mUpdateVolume, UPDATE_INTERVAL); break; case VoiceRecognitionClient.CLIENT_STATUS_SPEECH_START: // 檢測到語音起點 Status.setText("當前狀態:說話中"); break; case VoiceRecognitionClient.CLIENT_STATUS_AUDIO_DATA: //這裡可以什麼都不用作,簡單地對傳入的數據做下記錄 break; // 已經檢測到語音終點,等待網絡返回 case VoiceRecognitionClient.CLIENT_STATUS_SPEECH_END: Status.setText("當前狀態:正在識別...."); BtnCancel.setEnabled(false); mVolumeBar.setVisibility(View.INVISIBLE); break; // 語音識別完成,顯示obj中的結果 case VoiceRecognitionClient.CLIENT_STATUS_FINISH: Status.setText(null); UpdateRecognitionResult(obj); IsRecognition = false; ReSetUI(); break; // 處理連續上屏 case VoiceRecognitionClient.CLIENT_STATUS_UPDATE_RESULTS: UpdateRecognitionResult(obj); break; // 用戶取消 case VoiceRecognitionClient.CLIENT_STATUS_USER_CANCELED: Status.setText("當前狀態:已取消"); IsRecognition = false; ReSetUI(); break; default: break; } } @Override public void onError(int errorType, int errorCode) { IsRecognition = false; Result.setText("出錯: 0x%1$s"+Integer.toHexString(errorCode)); ReSetUI(); } @Override public void onNetworkStatusChange(int status, Object obj) { // 這裡不做任何操作不影響簡單識別 } };
1、對識別結果的解析
/* *將識別結果顯示到界面上 */ private void UpdateRecognitionResult(Object result) { if (result != null && result instanceof List) { @SuppressWarnings("rawtypes") List results = (List) result; if (results.size() > 0) { if (mType==VOICE_TYPE_SEARCH) { Result.setText(results.get(0).toString()); } else if (mType == VOICE_TYPE_INPUT) { @SuppressWarnings("unchecked") List> sentences = ((List
>) result); StringBuffer sb = new StringBuffer(); for (List
candidates : sentences) { if (candidates != null && candidates.size() > 0) { sb.append(candidates.get(0).getWord()); } } Result.setText(sb.toString()); } } } }
2、識別類型
識別的類型有兩種,一種是Search、一種是Input。Search適用於較短的句子的識別,即短語的識別;Input適用於長句子的識別,即長句的識別。總體來說,百度語音識別的效果還是很不錯的
接下來,我們對語音識別進行一個控制,一起來看代碼吧:
/* * 處理Click事件 */ @Override public void onClick(View v) { switch(v.getId()) { case R.id.Start: if (IsRecognition) { // 用戶說完 mClient.speakFinish(); } else { // 用戶重試,開始新一次語音識別 Result.setText(null); // 需要開始新識別,首先設置參數 config = new VoiceRecognitionConfig(); if (mType == VOICE_TYPE_INPUT) { config.setSpeechMode(VoiceRecognitionConfig.SPEECHMODE_MULTIPLE_SENTENCE); } else { config.setSpeechMode(VoiceRecognitionConfig.SPEECHMODE_SINGLE_SENTENCE); } //開啟語義解析 config.enableNLU(); //開啟音量反饋 config.enableVoicePower(true); config.enableBeginSoundEffect(R.raw.bdspeech_recognition_start); // 設置識別開始提示音 config.enableEndSoundEffect(R.raw.bdspeech_speech_end); // 設置識別結束提示音 config.setSampleRate(VoiceRecognitionConfig.SAMPLE_RATE_8K); //設置采樣率 //使用默認的麥克風作為音頻來源 config.setUseDefaultAudioSource(true); // 下面發起識別 int code = VoiceRecognitionClient.getInstance(this).startVoiceRecognition( mListener, config); if (code == VoiceRecognitionClient.START_WORK_RESULT_WORKING) { // 能夠開始識別,改變界面 BtnStart.setEnabled(false); BtnStart.setText("說完"); BtnCancel.setEnabled(true); } else { Result.setText("啟動失敗: 0x%1$s"+code); } } break; case R.id.Cancel: mClient.stopVoiceRecognition(); break; } }
/** 音量更新時間間隔 **/ private static final int UPDATE_INTERVAL=200; /** 音量更新任務 **/ private Runnable mUpdateVolume=new Runnable() { @Override public void run() { if (IsRecognition) { long vol = VoiceRecognitionClient.getInstance(BaiduVoiceActivity.this) .getCurrentDBLevelMeter(); mVolumeBar.setProgress((int)vol); mHandler.removeCallbacks(mUpdateVolume); mHandler.postDelayed(mUpdateVolume, UPDATE_INTERVAL); } } };當然,這段代碼是可以不要的,如果我們取消了音量反饋的話;其次,在實際的語音識別應用中,我們通常會看到界面會根據用戶輸入的聲音的大小繪制一定的波形,這已經超出了本文的研究范圍,但是至少說明我們需要在實際的應用中研究這一過程,或者我們可以偷下懶,直接放個動畫了事。最後,我們需要寫一些用於釋放語音識別資源的方法:
@Override protected void onDestroy() { VoiceRecognitionClient.releaseInstance(); // 釋放識別庫 super.onDestroy(); } @Override protected void onPause() { if (IsRecognition) { mClient.stopVoiceRecognition(); // 取消識別 } super.onPause(); }
package com.Android.BaiduVoice; import java.util.List; import com.baidu.voicerecognition.android.Candidate; import com.baidu.voicerecognition.android.VoiceRecognitionClient; import com.baidu.voicerecognition.android.VoiceRecognitionConfig; import com.baidu.voicerecognition.android.VoiceRecognitionClient.VoiceClientStatusChangeListener; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; public class BaiduVoiceActivity extends Activity implements OnClickListener { /** 應用授權信息 **/ private String API_KEY="8MAxI5o7VjKSZOKeBzS4XtxO"; private String SECRET_KEY="Ge5GXVdGQpaxOmLzc8fOM8309ATCz9Ha"; /** 界面布局元素 **/ private TextView Status,Result; private ProgressBar mVolumeBar; private Button BtnStart,BtnCancel; /** 語音識別Client **/ private VoiceRecognitionClient mClient; /** 語音識別配置 **/ private VoiceRecognitionConfig config; /** 語音識別回調接口 **/ private VoiceClientStatusChangeListener mListener=new VoiceClientStatusChangeListener() { public void onClientStatusChange(int status, Object obj) { switch (status) { // 語音識別實際開始,這是真正開始識別的時間點,需在界面提示用戶說話。 case VoiceRecognitionClient.CLIENT_STATUS_START_RECORDING: IsRecognition = true; mVolumeBar.setVisibility(View.VISIBLE); BtnCancel.setEnabled(true); BtnStart.setText("說完"); Status.setText("當前狀態:請說話"); mHandler.removeCallbacks(mUpdateVolume); mHandler.postDelayed(mUpdateVolume, UPDATE_INTERVAL); break; case VoiceRecognitionClient.CLIENT_STATUS_SPEECH_START: // 檢測到語音起點 Status.setText("當前狀態:說話中"); break; case VoiceRecognitionClient.CLIENT_STATUS_AUDIO_DATA: //這裡可以什麼都不用作,簡單地對傳入的數據做下記錄 break; // 已經檢測到語音終點,等待網絡返回 case VoiceRecognitionClient.CLIENT_STATUS_SPEECH_END: Status.setText("當前狀態:正在識別...."); BtnCancel.setEnabled(false); mVolumeBar.setVisibility(View.INVISIBLE); break; // 語音識別完成,顯示obj中的結果 case VoiceRecognitionClient.CLIENT_STATUS_FINISH: Status.setText(null); UpdateRecognitionResult(obj); IsRecognition = false; ReSetUI(); break; // 處理連續上屏 case VoiceRecognitionClient.CLIENT_STATUS_UPDATE_RESULTS: UpdateRecognitionResult(obj); break; // 用戶取消 case VoiceRecognitionClient.CLIENT_STATUS_USER_CANCELED: Status.setText("當前狀態:已取消"); IsRecognition = false; ReSetUI(); break; default: break; } } @Override public void onError(int errorType, int errorCode) { IsRecognition = false; Result.setText("出錯: 0x%1$s"+Integer.toHexString(errorCode)); ReSetUI(); } @Override public void onNetworkStatusChange(int status, Object obj) { // 這裡不做任何操作不影響簡單識別 } }; /** 語音識別類型定義 **/ public static final int VOICE_TYPE_INPUT=0; public static final int VOICE_TYPE_SEARCH=1; /** 音量更新時間間隔 **/ private static final int UPDATE_INTERVAL=200; /** 音量更新任務 **/ private Runnable mUpdateVolume=new Runnable() { @Override public void run() { if (IsRecognition) { long vol = VoiceRecognitionClient.getInstance(BaiduVoiceActivity.this) .getCurrentDBLevelMeter(); mVolumeBar.setProgress((int)vol); mHandler.removeCallbacks(mUpdateVolume); mHandler.postDelayed(mUpdateVolume, UPDATE_INTERVAL); } } }; /** 主線程Handler */ private Handler mHandler; /** 正在識別中 */ private boolean IsRecognition = false; /** 當前語音識別類型 **/ private int mType=VOICE_TYPE_INPUT; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_voice); InitView(); //獲取mClent mClient=VoiceRecognitionClient.getInstance(this); //設置應用授權信息 mClient.setTokenApis(API_KEY, SECRET_KEY); //初始化主線程 mHandler=new Handler(); } /* * 界面初始化 */ private void InitView() { Status=(TextView)findViewById(R.id.Status); Result=(TextView)findViewById(R.id.Result); mVolumeBar=(ProgressBar)findViewById(R.id.VolumeProgressBar); BtnStart=(Button)findViewById(R.id.Start); BtnStart.setOnClickListener(this); BtnCancel=(Button)findViewById(R.id.Cancel); BtnCancel.setOnClickListener(this); } @Override protected void onDestroy() { VoiceRecognitionClient.releaseInstance(); // 釋放識別庫 super.onDestroy(); } @Override protected void onPause() { if (IsRecognition) { mClient.stopVoiceRecognition(); // 取消識別 } super.onPause(); } /* * 處理Click事件 */ @Override public void onClick(View v) { switch(v.getId()) { case R.id.Start: if (IsRecognition) { // 用戶說完 mClient.speakFinish(); } else { // 用戶重試,開始新一次語音識別 Result.setText(null); // 需要開始新識別,首先設置參數 config = new VoiceRecognitionConfig(); if (mType == VOICE_TYPE_INPUT) { config.setSpeechMode(VoiceRecognitionConfig.SPEECHMODE_MULTIPLE_SENTENCE); } else { config.setSpeechMode(VoiceRecognitionConfig.SPEECHMODE_SINGLE_SENTENCE); } //開啟語義解析 config.enableNLU(); //開啟音量反饋 config.enableVoicePower(true); config.enableBeginSoundEffect(R.raw.bdspeech_recognition_start); // 設置識別開始提示音 config.enableEndSoundEffect(R.raw.bdspeech_speech_end); // 設置識別結束提示音 config.setSampleRate(VoiceRecognitionConfig.SAMPLE_RATE_8K); //設置采樣率 //使用默認的麥克風作為音頻來源 config.setUseDefaultAudioSource(true); // 下面發起識別 int code = VoiceRecognitionClient.getInstance(this).startVoiceRecognition( mListener, config); if (code == VoiceRecognitionClient.START_WORK_RESULT_WORKING) { // 能夠開始識別,改變界面 BtnStart.setEnabled(false); BtnStart.setText("說完"); BtnCancel.setEnabled(true); } else { Result.setText("啟動失敗: 0x%1$s"+code); } } break; case R.id.Cancel: mClient.stopVoiceRecognition(); break; } } /* * 重置界面 */ private void ReSetUI() { BtnStart.setEnabled(true); // 可以開始重試 BtnStart.setText("重試"); BtnCancel.setEnabled(false); // 還沒開始不能取消 } /* *將識別結果顯示到界面上 */ private void UpdateRecognitionResult(Object result) { if (result != null && result instanceof List) { @SuppressWarnings("rawtypes") List results = (List) result; if (results.size() > 0) { if (mType==VOICE_TYPE_SEARCH) { Result.setText(results.get(0).toString()); } else if (mType == VOICE_TYPE_INPUT) { @SuppressWarnings("unchecked") List> sentences = ((List
>) result); StringBuffer sb = new StringBuffer(); for (List
candidates : sentences) { if (candidates != null && candidates.size() > 0) { sb.append(candidates.get(0).getWord()); } } Result.setText(sb.toString()); } } } } }
這樣,今天的內容就學習完了,在下一篇文章中,我們會以前面兩篇文章所介紹的技術為基礎,來實現一個較為實際的應用,並對當下主流的語音識別軟件進行一個對比,再次謝謝大家的關注!
源代碼下載
前言android 自定義控件之ViewGroup生命周期執行步驟。了解ViewGroup的生命周期的執行步驟對於自己自定義ViewGroup的時候十分重要,清楚了整個流
使用gradle構建android應用時,你總是需要這樣一個文件:build.gradle。你應該已經看過這個文件了,如果沒有看過的話,你現在就可以看一下,它沒有多少內容
問題現象 (該文章,引自零號路的私人博客,本人在浏覽框架的開發過程中,用該方式,規避了內存洩露的問題。) 在Android5.1系統中,會發現App存在 Web
前言:多年之前接觸過zxing實現二維碼,沒想到今日項目中再此使用竟然使用的還是zxing,百度之,竟是如此牛的玩意。當然,項目中我們也許只會用到二維碼的掃描和生成兩個功