ECM
ECM
总版主
总版主
  • 社区居民
  • 忠实会员
  • 原创写手
阅读:2074回复:0

Android开发学习之使用百度语音识别SDK实现语音识别(下)

楼主#
更多 发布于:2016-01-01 13:57
今天我们来继续学习百度语音识别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<List<Candidate>> sentences = ((List<List<Candidate>>) result);  
                    StringBuffer sb = new StringBuffer();  
                    for (List<Candidate> 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<List<Candidate>> sentences = ((List<List<Candidate>>) result);  
                    StringBuffer sb = new StringBuffer();  
                    for (List<Candidate> candidates : sentences) {  
                        if (candidates != null && candidates.size() > 0) {  
                            sb.append(candidates.get(0).getWord());  
                        }  
                    }  
                    Result.setText(sb.toString());  
                }  
            }  
        }  
    }  
   
       
}

          当然,和上一篇文章一样,我们需要加入必要的权限,否则程序会报错的:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>  
<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

         这样,今天的内容就学习完了,在下一篇文章中,我们会以前面两篇文章所介绍的技术为基础,来实现一个较为实际的应用,并对当下主流的语音识别软件进行一个对比,再次谢谢大家的关注!        

 

 

 

 

 

 

 

异常中心网是一家专门收集整理程序员编程过程中遇到的常见异常(exception)以及各种异常问答中心的网站。异常中心网旨在,减少程序员在编码遇到异常,处理各种异常时间和痛苦,让程序员能更愉快的、快速的定位异常并查找对应的异常解决方案。异常中心网诚心打造最完美的编程社区为程序员用户服务,努力成为最好的程序员乐园程序员社区程序异常中心程序bug中心异常问答中心

 

喜欢0 评分0
游客

返回顶部