Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發學習之使用百度語音識別SDK實現語音識別(中)

Android開發學習之使用百度語音識別SDK實現語音識別(中)

編輯:關於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();
	}

在這裡為了讓大家更好的關注於語音識別SDK,我將界面元素初始化的過程寫到了InitView()方法中,大家可以參照最後給出的代碼。其中的mHandler僅僅是為了配合進度條刷新界面,即非必需。接下來我們來寫整個程序中最為重要的一個類,即VoiceClientStatusChangeListener接口,我們一起來看代碼:

	/** 語音識別回調接口  **/
	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();
	}
    

到目前為止,百度語音識別SDK的所有API我們都已經研究完了,大家可以自己梳理下思路,最後我給出全部的代碼:

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());
                }
            }
        }
    }

	
}

當然,和上一篇文章一樣,我們需要加入必要的權限,否則程序會報錯的:

    
    
    
    

這樣,今天的內容就學習完了,在下一篇文章中,我們會以前面兩篇文章所介紹的技術為基礎,來實現一個較為實際的應用,並對當下主流的語音識別軟件進行一個對比,再次謝謝大家的關注!

源代碼下載

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved