2014-05-29 14:23:07 VoiceFans 阅读数 70930
  • Android 实战开发 三方SDK 讯飞语音SDK

    Android 第三方SDK开发视频教程,给课程结合讯飞语音这个第三方SDK进行实战教学,实现在线语音合成,将文字信息转化为声音信息,给应用配上“嘴巴;语音听写,将连续语音识别为文字,给应用配上“耳朵”。

    4827 人正在学习 去看看 Frank Lee

     百度Android语音识别SDK分在线与离线两种,这篇文章介绍在线SDK的使用方法。

     在线SDK是以JAR包和动态链接库形式发布和使用,可以从百度开放云平台网站中下载SDK及使用说明文档。

http://developer.baidu.com/wiki/index.php?title=docs/cplat/media/voice

     完成语音SDK的集成分以下几步,本文将一步步介绍SDK集成方法。

      

 1、注册开放开放平台   

 点击管理控制台,选择移动应用管理


 选择创建应用,填写应用名称

      


可以看到右上角有ID、API KEY、Secret KEY,点击可以复制其内容,保存这些字符串,在使用语音SDK时会用到。


2、申请开启语音识别服务 ,选择媒体云---语音识别,点击申请开启服务,填写理由。


等待对接成功


3、使用语音识别SDK前的准备

之前准备了SDK开发包以及ID、API KEY、Secret KEY。

首先将开发包中的lib中的库添加到工程中


        声明权限

     <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /></span>

   4、语音识别

SDK有两种实现语音识别的方式,一种是直接使用SDK中的语音识别控件,一种是使用SDK中的语音识别服务。

语音识别控件方式

语音识别控件BaiduASRDigitalDialog,提供了整套语音交互、提示音、音量反馈、动效反馈。开发者初始化一个BaiduASRDigitalDialog对象,并设置相关参数及结果回调,调用Show()方法就可以弹出对话框开始识别,识别结束后会在回调中得到识别结果。

if (mDialog == null || mCurrentTheme != Config.DIALOG_THEME) {
                    mCurrentTheme = Config.DIALOG_THEME;
                    if (mDialog != null) {
                        mDialog.dismiss();
                    }
                    Bundle params = new Bundle();
                    params.putString(BaiduASRDigitalDialog.PARAM_API_KEY, Constants.API_KEY);
                    params.putString(BaiduASRDigitalDialog.PARAM_SECRET_KEY, Constants.SECRET_KEY);
                    params.putInt(BaiduASRDigitalDialog.PARAM_DIALOG_THEME, Config.DIALOG_THEME);
                    mDialog = new BaiduASRDigitalDialog(this, params);
                    mDialog.setDialogRecognitionListener(mRecognitionListener);
                }
                mDialog.getParams().putInt(BaiduASRDigitalDialog.PARAM_PROP, Config.CURRENT_PROP);
                mDialog.getParams().putString(BaiduASRDigitalDialog.PARAM_LANGUAGE,
                        Config.getCurrentLanguage());
                mDialog.show();


识别对话框支持的参数定义在BaiduASRDigitalDialog中以PARAM_前缀的常量。列表如下:

PARAM_API_KEY

string

 

开放平台认证API_key

PARAM_SECRET_KEY

string

 

开放平台认证Secret_key

PARAM_LANGUAGE

string

LANGUAGE_CHINESE

语种,取值定义在VoiceRecognitionConfig类中前缀为LANGUAGE_的常量

PARAM_PARTIAL_RESULTS

boolean

true

连续上屏

PARAM_NLU_ENABLE

boolean

false

是否语义解析。Prop为输入时暂不支持语义,请显示指定为其它领域。

PARAM_NLU_PARAMS

string

 

预留语义解析参数

PARAM_PROP

int

PROP_INPUT

领域参数,定义在VoiceRecognitionConfig类中前缀为PROP_的常量

PARAM_PORMPT_TEXT

string

“请说话”

对话框提示语

PARAM_PROMPT_SOUND_ENABLE

boolean

true

提示音,需要集成SDK包Raw文件夹的资源

PARAM_DIALOG_THEME

int

THEME_BLUE_LIGHTBG

样式。定义在前缀为THEME_的常量中

PARAM_TIPS

String[]

 

引导语列表

PARAM_SHOW_TIPS_ON_START

boolean

false

对话框弹出时首先显示引导语列表

PARAM_SHOW_TIP

boolean

false

识别启动3秒未检测到语音,随机出现一条引导语

PARAM_SHOW_HELP_ON_SILENT

boolean

false

静音超时后将“取消”按钮替换为“帮助”

设置回调方法,处理返回的结果

 mRecognitionListener = new DialogRecognitionListener() {

            @Override
            public void onResults(Bundle results) {
                ArrayList<String> rs = results != null ? results
                        .getStringArrayList(RESULTS_RECOGNITION) : null;
                if (rs != null && rs.size() > 0) {
                    mResult.setText(rs.get(0));
                }

            }
        };



API方式
首先需要配置语音识别引擎ASREngine的参数VoiceRecognitionConfig
VoiceRecognitionConfig config = new VoiceRecognitionConfig();
                config.setProp(Config.CURRENT_PROP);
                config.setLanguage(Config.getCurrentLanguage());
                config.enableVoicePower(Config.SHOW_VOL); // 音量反馈。
                if (Config.PLAY_START_SOUND) {
                    config.enableBeginSoundEffect(R.raw.bdspeech_recognition_start); // 设置识别开始提示音
                }
                if (Config.PLAY_END_SOUND) {
                    config.enableEndSoundEffect(R.raw.bdspeech_speech_end); // 设置识别结束提示音
                }
                config.setSampleRate(VoiceRecognitionConfig.SAMPLE_RATE_8K); // 设置采样率,需要与外部音频一致

然后启动识别
 int code = mASREngine.startVoiceRecognition(mListener, config);

其中mListener是识别过程的回调,需要对其中的方法进行实现
 /**
     * 重写用于处理语音识别回调的监听器
     */
    class MyVoiceRecogListener implements VoiceClientStatusChangeListener {

        @Override
        public void onClientStatusChange(int status, Object obj) {
            switch (status) {
            // 语音识别实际开始,这是真正开始识别的时间点,需在界面提示用户说话。
                case VoiceRecognitionClient.CLIENT_STATUS_START_RECORDING:
                    isRecognition = true;
                    mHandler.removeCallbacks(mUpdateVolume);
                    mHandler.postDelayed(mUpdateVolume, POWER_UPDATE_INTERVAL);
                    mControlPanel.statusChange(ControlPanelFragment.STATUS_RECORDING_START);
                    break;
                case VoiceRecognitionClient.CLIENT_STATUS_SPEECH_START: // 检测到语音起点
                    mControlPanel.statusChange(ControlPanelFragment.STATUS_SPEECH_START);
                    break;
                // 已经检测到语音终点,等待网络返回
                case VoiceRecognitionClient.CLIENT_STATUS_SPEECH_END:
                    mControlPanel.statusChange(ControlPanelFragment.STATUS_SPEECH_END);
                    break;
                // 语音识别完成,显示obj中的结果
                case VoiceRecognitionClient.CLIENT_STATUS_FINISH:
                    mControlPanel.statusChange(ControlPanelFragment.STATUS_FINISH);
                    isRecognition = false;
                    updateRecognitionResult(obj);
                    break;
                // 处理连续上屏
                case VoiceRecognitionClient.CLIENT_STATUS_UPDATE_RESULTS:
                    updateRecognitionResult(obj);
                    break;
                // 用户取消
                case VoiceRecognitionClient.CLIENT_STATUS_USER_CANCELED:
                    mControlPanel.statusChange(ControlPanelFragment.STATUS_FINISH);
                    isRecognition = false;
                    break;
                default:
                    break;
            }

        }

        @Override
        public void onError(int errorType, int errorCode) {
            isRecognition = false;
            mResult.setText(getString(R.string.error_occur, Integer.toHexString(errorCode)));
            mControlPanel.statusChange(ControlPanelFragment.STATUS_FINISH);
        }

        @Override
        public void onNetworkStatusChange(int status, Object obj) {
            // 这里不做任何操作不影响简单识别
        }
    }

获得识别BDVRClient对象

mASREngine = VoiceRecognitionClient.getInstance(this);
        mASREngine.setTokenApis(Constants.API_KEY, Constants.SECRET_KEY);

请求参数设置
每次识别需要通过通过VoiceRecognitionConfig设置参数,其中一些方法在API中有说明

方法

参数

描述

enableBeginSoundEffect

int soundResourceId 启动提示音资源Id

设置开始提示音,soundResourceId为放置在Raw文件夹的资源Id。

 

enableEndSoundEffect

int soundResourceId 说话结束提示音资源Id

检测到用户说话结束播报的提示音,非识别结束

setSampleRate

int rate 采样率

设置音频采样率,

通常建议开发者不指定采样频率,由BDVRClient自动根据当前网络环境选择采样频率。WiFi环境下将使用16kHz采样,移动网络下将使用8kHz采样,来节省流量。参考常量定义

SAMPLE_RATE_8K 8K采样率

SAMPLE_RATE_16K 16K采样率

setProp

int prop

开发者可以通过指定垂直分类来获取更精准的语音识别结果。

注:垂直分类目前支持地图,音乐,视频,APP,网址,开发者需要注意设定采样频率时只能在这五种垂直分类中选择。若指定其他分类,可能会影响识别结果的精度。参考PROP_前缀的常量定义。

setUseDefaultAudioSource

boolean useDefaultSource

设置是否使用缺省的录音。 如果不使用,用户需要调用VoiceRecognitionClient对象的feedAudioBuffer方法为识别器提供语音数据

enableNLU

 

启用语义解析,只在搜索模式起作用

getSampleRate

 

获取当前识别采样率

setLanguage

String Language

设置语种。目前支持的语种有中文普通话(LANGUAGE_CHINESE)、中文粤语(LANGUAGE_CANTONSE)、英文(LANGUAGE_ENGLISH)。


开始语音识别,BDVRClient在开始识别后,会启动录音、预处理、上传到服务器并获取识别结果。

 int code = mASREngine.startVoiceRecognition(mListener, config);
                if (code != VoiceRecognitionClient.START_WORK_RESULT_WORKING) {
                    mResult.setText(getString(R.string.error_start, code));
                } 

取消语音识别

 mASREngine.stopVoiceRecognition();

结束语音识别

mRecognitionClient.speakFinish();

读者可以结合着SDK文档与demo源代码一起来学习百度语音识别SDK的使用。


语音识别的demo下载: http://download.csdn.net/detail/voicefans/7451441


小伙伴注意: 需要按照文章开头的去申请api key和secret key, 修改Constant.java,填上自己的key就ok了。VoiceRecognitionDemoActivity.java  展示了如何使用Dialog方式识别


如果遇到问题欢迎留言交流。












2019-07-30 10:31:07 qq_24822271 阅读数 166
  • Android 实战开发 三方SDK 讯飞语音SDK

    Android 第三方SDK开发视频教程,给课程结合讯飞语音这个第三方SDK进行实战教学,实现在线语音合成,将文字信息转化为声音信息,给应用配上“嘴巴;语音听写,将连续语音识别为文字,给应用配上“耳朵”。

    4827 人正在学习 去看看 Frank Lee

科大接口调用文档:
https://www.xfyun.cn/doc/asr/voicedictation/Linux-SDK.html#_2、sdk集成指南

from ctypes import *
import time
import threading

# 调用动态链接库
dll = cdll.LoadLibrary("../Linux_iat1226_xxxxxxx/libs/x64/libmsc.so")
# 登录参数,apppid一定要和你的下载SDK对应
login_params = b"appid = xxxxxx, work_dir = ."

FRAME_LEN = 640  # Byte

MSP_SUCCESS = 0
# 返回结果状态
MSP_AUDIO_SAMPLE_FIRST = c_int(1)
MSP_AUDIO_SAMPLE_CONTINUE = c_int(2)
MSP_AUDIO_SAMPLE_LAST = c_int(4)
MSP_REC_STATUS_COMPLETE = c_int(5)
# 你的语音文件路径
filename = "./f1.wav"


class Msp:
    def __init__( self ):
        self.recogStatus = c_int(8)
        self.counter = 0
        self.laststr = ''
        self.sessionID = None
        self.epStatus = None
        self.count = 0

    def login( self ):
        ret = dll.MSPLogin(None, None, login_params)
        # print('MSPLogin =>', ret)

    def logout( self ):
        ret = dll.MSPLogout()
        # print('MSPLogout =>', ret)

    def isr( self, audiofile, session_begin_params ):
        ret = c_int()
        self.sessionID = c_voidp()
        dll.QISRSessionBegin.restype = c_char_p
        self.sessionID = dll.QISRSessionBegin(None, session_begin_params, byref(ret))
        print('QISRSessionBegin => self.sessionID:', self.sessionID, 'ret:', ret.value)

        # 每秒【1000ms】  16000 次 * 16 bit 【20B】 ,每毫秒:1.6 * 16bit 【1.6*2B】 = 32Byte
        # 1帧音频20ms【640B】 每次写入 10帧=200ms 【6400B】

        # piceLne = FRAME_LEN * 20
        piceLne = 1638 * 2
        self.epStatus = c_int(0)
        self.recogStatus = c_int(0)

        wavFile = open(audiofile, 'rb')

        while wavFile:
            wavData = wavFile.read(piceLne)

            aud_stat = MSP_AUDIO_SAMPLE_CONTINUE
            if (self.count == 0):
                aud_stat = MSP_AUDIO_SAMPLE_FIRST  # 第一句

            if len(wavData) <= 0:
                # print('最后一句话')
                ret = dll.QISRAudioWrite(self.sessionID, None, 0, MSP_AUDIO_SAMPLE_LAST, byref(self.epStatus),byref(self.recogStatus))
                #print('send last ,recogStatus:',self.recogStatus.value,'ret:',ret)
                break
            else:
                ret = dll.QISRAudioWrite(self.sessionID, wavData, len(wavData), aud_stat,
                                         byref(self.epStatus),
                                         byref(self.recogStatus))
                #print('len(wavData):', len(wavData), 'QISRAudioWrite ret:', ret, 'epStatus:', self.epStatus.value, 'recogStatus:', self.recogStatus.value)
            self.count += 1
            time.sleep(0.1)
            if self.recogStatus.value==0:
                self.get_result()
        wavFile.close()
        print("所有待识别音频已全部发送完毕")

        while self.recogStatus.value != 5:
            self.get_result()
            time.sleep(1)


    def get_result( self , ):
        #print('开始获取识别结果', self.recogStatus.value)
        ret = c_int(0)
        dll.QISRGetResult.restype = c_char_p
        retstr = dll.QISRGetResult(self.sessionID, byref(self.recogStatus), 0, byref(ret))
        #print("error code : ", ret.value, 'recogStatus:', self.recogStatus.value)

        if retstr is not None:
            self.laststr += retstr.decode()
            print(self.laststr)

        if self.recogStatus.value == 5:
            ret = dll.QISRSessionEnd(self.sessionID, 'end')
            print('语音识别结束')
        return self.laststr

        


def XF_text( filepath, audiorate ):
    msp = Msp()
    print("登录科大讯飞")
    msp.login()
    print("科大讯飞登录成功")
    session_begin_params = b"sub = iat, ptt = 0, result_encoding = utf8, result_type = plain, domain = iat"
    if 16000 == audiorate:
        session_begin_params = b"sub = iat, domain = iat, language = zh_cn, accent = mandarin, sample_rate = 16000, result_type = plain, result_encoding = utf8,vad_enable=0"
    text = msp.isr(filepath, session_begin_params)
    msp.logout()
    return text





if __name__ == '__main__':
    res = XF_text(filename, 16000)
2018-09-11 14:24:18 qq_31545245 阅读数 1065
  • Android 实战开发 三方SDK 讯飞语音SDK

    Android 第三方SDK开发视频教程,给课程结合讯飞语音这个第三方SDK进行实战教学,实现在线语音合成,将文字信息转化为声音信息,给应用配上“嘴巴;语音听写,将连续语音识别为文字,给应用配上“耳朵”。

    4827 人正在学习 去看看 Frank Lee

百度语音识别SDK嵌入开发文档

  1. 前提
    本Demo将百度语音SDK(其中一部分功能)和自定义的UI对话框封装到一个module中,便于后续的SDK版本更新以及调用。
    2.实施
    1.新建项目(获取包名)
    这里写图片描述
    2.在百度AI平台创建应该获取API Key和Secre Key
    官网地址:http://ai.baidu.com/tech/speech
    (具体过程省略,都是正常的互联网网站可视化操作很简单)
    3.下载SDK
    这里写图片描述
    这里写图片描述
    4.使用步骤
    一 项目组织结构图
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    二 导入步骤
    (1)新建module,命名为baiduspeech
    这里写图片描述
    这里写图片描述
    (2)在baiduspeech的AndroidMainfest.xml中添加以下代码
    在官方demo的AndroidMainfest.xml中找到如下信息,然后复制到您自己的同名文件中。此处需要您复制1、权限2、官网申请的应用信息3、SDK的Service。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.why.project.baiduspeech">

    <!-- ======================百度语音====================== -->
    <!-- begin: baidu speech sdk  权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- end: baidu speech sdk  权限 -->

    <application>

        <!-- ======================百度语音========================== -->
        <!-- 正式发布时,请替换成您自己的appId 本demo的appId会不定时下线 -->
        <meta-data
            android:name="com.baidu.speech.APP_ID"
            android:value="11588936" />
        <meta-data
            android:name="com.baidu.speech.API_KEY"
            android:value="XRF3IOf2tNGePzlv47cBnvF3" />
        <meta-data
            android:name="com.baidu.speech.SECRET_KEY"
            android:value="diC8lQ7XDcGBKQ6FzCpvnan54F5CnMZI" />
        <service
            android:name="com.baidu.speech.VoiceRecognitionService"
            android:exported="false" />
    </application>
</manifest>

(3)复制jar文件
将官方demo中的app\libs\bdasr_V3_20180320_9066860.jar复制进您项目的同名目录
这里写图片描述
在build.gradle中确认是否含有以下红色标记的代码
这里写图片描述
(4)复制jni库的so文件
复制官方demo中 app\src\main\jniLibs 至项目的同名目录。
这里写图片描述
(5)在官方demo中找到下面的文件复制到项目中(按照下面的包名进行查找)
这里写图片描述

package com.why.project.baiduspeech.recognization;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**
 * Created by fujiayi on 2017/6/16
 */

public class MessageStatusRecogListener extends StatusRecogListener {
    private Handler handler;

    private long speechEndTime;

    private boolean needTime = true;

    private static final String TAG = "MesStatusRecogListener";

    public MessageStatusRecogListener(Handler handler) {
        this.handler = handler;
    }


    @Override
    public void onAsrReady() {
        super.onAsrReady();
        sendStatusMessage("引擎就绪,可以开始说话。");
    }

    @Override
    public void onAsrBegin() {
        super.onAsrBegin();
        sendStatusMessage("检测到用户说话");
    }

    @Override
    public void onAsrEnd() {
        super.onAsrEnd();
        speechEndTime = System.currentTimeMillis();
        sendMessage("检测到用户说话结束");
    }

    @Override
    public void onAsrPartialResult(String[] results, RecogResult recogResult) {
        sendStatusMessage("临时识别结果,结果是“" + results[0] + "”;原始json:" + recogResult.getOrigalJson());
        super.onAsrPartialResult(results, recogResult);
    }

    @Override
    public void onAsrFinalResult(String[] results, RecogResult recogResult) {
        super.onAsrFinalResult(results, recogResult);
        //String message = "识别结束,结果是”" + results[0] + "”";//why 实际中可以去掉,不需要
        String message = recogResult.getOrigalJson();//{"results_recognition":["什么什么"],"origin_result":{"corpus_no":6522034498058113957,"err_no":0,"result":{"word":["什么什么"]},"sn":"bfa8b286-ab0e-4f86-9209-1d36d38b1224","voice_energy":16191.7705078125},"error":0,"best_result":"什么什么","result_type":"final_result"}
        sendStatusMessage(message + "“;原始json:" + recogResult.getOrigalJson());
        if (speechEndTime > 0) {
            long diffTime = System.currentTimeMillis() - speechEndTime;
            //message += ";说话结束到识别结束耗时【" + diffTime + "ms】";// why 实际中可以去掉,不需要

        }
        speechEndTime = 0;
        sendMessage(message, status, true);
    }

    @Override
    public void onAsrFinishError(int errorCode, int subErrorCode, String errorMessage, String descMessage,
                                 RecogResult recogResult) {
        super.onAsrFinishError(errorCode, subErrorCode, errorMessage, descMessage, recogResult);
        //String message = "识别错误, 错误码:" + errorCode + " ," + subErrorCode + " ; " + descMessage;// why 实际中可以去掉,不需要
        String message = recogResult.getOrigalJson();//{"origin_result":{"sn":"","error":7,"desc":"No recognition result match","sub_error":7001},"error":7,"desc":"No recognition result match","sub_error":7001}
        sendStatusMessage(message + ";错误消息:" + errorMessage + ";描述信息:" + descMessage);
        if (speechEndTime > 0) {
            long diffTime = System.currentTimeMillis() - speechEndTime;
            //message += "。说话结束到识别结束耗时【" + diffTime + "ms】";// why实际中可以去掉,不需要
        }
        speechEndTime = 0;
        sendMessage(message, status, true);
        speechEndTime = 0;
    }

    @Override
    public void onAsrOnlineNluResult(String nluResult) {
        super.onAsrOnlineNluResult(nluResult);
        if (!nluResult.isEmpty()) {
            sendStatusMessage("原始语义识别结果json:" + nluResult);
        }
    }

    @Override
    public void onAsrFinish(RecogResult recogResult) {
        super.onAsrFinish(recogResult);
        sendStatusMessage("识别一段话结束。如果是长语音的情况会继续识别下段话。");

    }

    /**
     * 长语音识别结束
     */
    @Override
    public void onAsrLongFinish() {
        super.onAsrLongFinish();
        sendStatusMessage("长语音识别结束。");
    }


    /**
     * 使用离线命令词时,有该回调说明离线语法资源加载成功
     */
    @Override
    public void onOfflineLoaded() {
        sendStatusMessage("【重要】asr.loaded:离线资源加载成功。没有此回调可能离线语法功能不能使用。");
    }

    /**
     * 使用离线命令词时,有该回调说明离线语法资源加载成功
     */
    @Override
    public void onOfflineUnLoaded() {
        sendStatusMessage(" 离线资源卸载成功。");
    }

    @Override
    public void onAsrExit() {
        super.onAsrExit();
        sendStatusMessage("识别引擎结束并空闲中");
    }

    private void sendStatusMessage(String message) {
        sendMessage(message, status);
    }

    private void sendMessage(String message) {
        sendMessage(message, WHAT_MESSAGE_STATUS);
    }

    private void sendMessage(String message, int what) {
        sendMessage(message, what, false);
    }


    private void sendMessage(String message, int what, boolean highlight) {


        if (needTime && what != STATUS_FINISHED) {
            message += "  ;time=" + System.currentTimeMillis();
        }
        if (handler == null){
            Log.i(TAG, message );
            return;
        }
        Message msg = Message.obtain();
        msg.what = what;
        msg.arg1 = status;
        if (highlight) {
            msg.arg2 = 1;
        }
        msg.obj = message + "\n";
        handler.sendMessage(msg);
    }
}

至此,百度语音SDK集成到baiduspeech中了,下一步就是在baiduspeech中创建UI对话框。
(7)创建底部对话框SpeechBottomSheetDialog
1、在baiduspeech的build.gradle中引用recyclerview【版本号和项目的appcompat保持一致】

apply plugin: 'com.android.library'

android {
    compileSdkVersion 27



    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com.android.support:appcompat-v7:27.1.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    //RecyclerView
    compile "com.android.support:recyclerview-v7:27.1.1"
}

2、对话框类、列表适配器类、布局文件xml文件、图片资源、动画style样式等复制到baiduspeech中

这里写图片描述
这里写图片描述
3、这里主要标注下SpeechBottomSheetDialog.java中百度语音的相关代码

package com.why.project.baiduspeech.dialog;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.DialogFragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.speech.asr.SpeechConstant;
import com.baidu.speech.utils.LogUtil;
import com.why.project.baiduspeech.R;
import com.why.project.baiduspeech.control.MyRecognizer;
import com.why.project.baiduspeech.recognization.IStatus;
import com.why.project.baiduspeech.recognization.MessageStatusRecogListener;
import com.why.project.baiduspeech.recognization.StatusRecogListener;
import com.why.project.baiduspeech.util.Logger;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by HaiyuKing
 * Used 语音识别底部对话框
 */

public class SpeechBottomSheetDialog extends DialogFragment {
    private static final String TAG = SpeechBottomSheetDialog.class.getSimpleName();

    private Context mContext;
    /**View实例*/
    private View myView;

    private ImageView img_close;
    private ProgressBar loadProgressBar;
    private TextView tv_tishi;
    private RecyclerView result_list;
    private Button btn_start;

    private ArrayList<String> resultWordList;
    private SpeechResultAdapter speechResultAdapter;

    private String BtnStartText = "按一下开始听音";
    private String BtnStopText = "按一下结束听音";
    private String BtnSearchingText = "正在识别";

    private String TishiNoText = "没听清,请重说一遍";

    /**识别控制器,使用MyRecognizer控制识别的流程*/
    protected MyRecognizer myRecognizer;
    /**控制UI按钮的状态*/
    protected int status;

    protected Handler handler;


    public static SpeechBottomSheetDialog getInstance(Context mContext)
    {
        SpeechBottomSheetDialog speechBottomSheetDialog = new SpeechBottomSheetDialog();
        speechBottomSheetDialog.mContext = mContext;

        return speechBottomSheetDialog;
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));//设置背景为透明,并且没有标题
        myView = inflater.inflate(R.layout.dialog_bottomsheet_speech, container, false);
        return myView;

    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);

        initHandler();//初始化handler
        initRecog();//初始化语音

        initViews();
        initDatas();
        initEvents();
    }

    /**
     * 设置宽度和高度值,以及打开的动画效果
     */
    @Override
    public void onStart() {
        super.onStart();
        //设置对话框的宽高,必须在onStart中
        DisplayMetrics metrics = new DisplayMetrics();
        this.getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
        Window window = this.getDialog().getWindow();
        window.setLayout(metrics.widthPixels, this.getDialog().getWindow().getAttributes().height);
        window.setGravity(Gravity.BOTTOM);//设置在底部
        //打开的动画效果
        //设置dialog的 进出 动画
        getDialog().getWindow().setWindowAnimations(R.style.speechbottomsheetdialog_animation);
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        LogUtil.w(TAG,"{onDismiss}");
        //当对话框消失的时候统一执行销毁语音功能
        destroyRecog();//销毁语音
    }


    private void initViews() {
        img_close = (ImageView) myView.findViewById(R.id.img_close);
        loadProgressBar = (ProgressBar) myView.findViewById(R.id.loadProgressBar);
        tv_tishi = (TextView) myView.findViewById(R.id.tv_tishi);
        result_list = (RecyclerView) myView.findViewById(R.id.result_list);
        btn_start = (Button) myView.findViewById(R.id.btn_start);
    }

    /**初始化数据*/
    private void initDatas() {
        resultWordList = new ArrayList<String>();
        speechResultAdapter = null;
        //设置布局管理器
        LinearLayoutManager linerLayoutManager = new LinearLayoutManager(getActivity());
        result_list.setLayoutManager(linerLayoutManager);

        //可以设置为打开后自动识别语音
        startRecog();
        showProgress();
    }

    private void initEvents() {
        //关闭图标的点击事件
        img_close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });

        //按钮的点击事件
        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                switch (status) {
                    case IStatus.STATUS_NONE: // 初始状态
                        startRecog();
                        status = IStatus.STATUS_WAITING_READY;
                        updateBtnTextByStatus();//更改按钮的文本
                        //显示加载区域
                        showProgress();
                        break;
                    case IStatus.STATUS_WAITING_READY: // 调用本类的start方法后,即输入START事件后,等待引擎准备完毕。
                    case IStatus.STATUS_READY: // 引擎准备完毕。
                    case IStatus.STATUS_SPEAKING:
                    case IStatus.STATUS_FINISHED: // 长语音情况
                    case IStatus.STATUS_RECOGNITION:
                        stopRecog();
                        status = IStatus.STATUS_STOPPED; // 引擎识别中
                        updateBtnTextByStatus();//更改按钮的文本
                        break;
                    case IStatus.STATUS_STOPPED: // 引擎识别中
                        cancelRecog();
                        status = IStatus.STATUS_NONE; // 识别结束,回到初始状态
                        updateBtnTextByStatus();//更改按钮的文本
                        break;
                    default:
                        break;
                }
            }
        });
    }


    /**
     * 显示加载进度区域,隐藏其他区域*/
    private void showProgress(){
        loadProgressBar.setVisibility(View.VISIBLE);
        tv_tishi.setVisibility(View.GONE);
        result_list.setVisibility(View.GONE);
    }

    /**
     * 显示文本提示区域,隐藏其他区域*/
    private void showTishi(){
        tv_tishi.setVisibility(View.VISIBLE);
        loadProgressBar.setVisibility(View.GONE);
        result_list.setVisibility(View.GONE);
    }

    /**
     * 显示语音结果区域,隐藏其他区域*/
    private void showListView(){
        result_list.setVisibility(View.VISIBLE);
        loadProgressBar.setVisibility(View.GONE);
        tv_tishi.setVisibility(View.GONE);
    }

    //======================================语音相关代码==========================================
    /**
     * 初始化handler*/
    private void initHandler(){
        handler = new Handler() {
            /*@param msg*/
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                handleMsg(msg);
            }
        };
        Logger.setHandler(handler);
    }


    /**
     * 在onCreate中调用。初始化识别控制类MyRecognizer
     */
    protected void initRecog() {

        StatusRecogListener listener = new MessageStatusRecogListener(handler);
        myRecognizer = new MyRecognizer(mContext,listener);

        status = IStatus.STATUS_NONE;//默认什么也没有做
    }

    /**
     * 销毁时需要释放识别资源。
     */
    protected void destroyRecog() {
        myRecognizer.release();
        Log.i(TAG, "destroyRecog");
    }

    /**
     * 开始录音,点击“开始”按钮后调用。
     */
    protected void startRecog() {
        Map<String, Object> params = new LinkedHashMap<String, Object>();
        params.put(SpeechConstant.ACCEPT_AUDIO_DATA, false);//是否保存音频
        params.put(SpeechConstant.DISABLE_PUNCTUATION, false);//是否禁用标点符号,在选择输入法模型的前提下生效【不禁用的话,说完一段话,就自带标点符号】
        params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);//暂时不知道什么意思
        params.put(SpeechConstant.PID, 1536); // 普通话 search搜索模型,默认,适用于短句,无逗号,可以有语义
        //params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 0); // 长语音,建议搭配input输入法模型
        myRecognizer.start(params);
    }

    /**
     * 开始录音后,手动停止录音。SDK会识别在此过程中的录音。点击“停止”按钮后调用。
     */
    private void stopRecog() {
        myRecognizer.stop();
    }

    /**
     * 开始录音后,取消这次录音。SDK会取消本次识别,回到原始状态。点击“取消”按钮后调用。
     */
    private void cancelRecog() {
        myRecognizer.cancel();
    }


    protected void handleMsg(Message msg) {
        Log.e(TAG,"msg.what="+msg.what);
        Log.e(TAG,"msg.obj.toString()="+msg.obj.toString());
        Log.e(TAG,"msg.arg2="+msg.arg2);
        switch (msg.what) { // 处理MessageStatusRecogListener中的状态回调
            case IStatus.STATUS_FINISHED:
                //识别结束时候的调用【判断显示结果列表区域还是提示区域】
                if (msg.arg2 == 1) {
                    //解析json字符串
                    try {
                        JSONObject msgObj = new JSONObject(msg.obj.toString());
                        String error = msgObj.getString("error");
                        if(error.equals("0")){
                            //解析结果集合,展现列表
                            JSONObject origin_resultObj = msgObj.getJSONObject("origin_result");
                            JSONObject resultObj = origin_resultObj.getJSONObject("result");
                            JSONArray wordList = resultObj.getJSONArray("word");

                            initList(wordList);//初始化集合数据

                            showListView();
                        }else if(error.equals("7")){
                            tv_tishi.setText(TishiNoText);
                            showTishi();
                        }else{//应该根据不同的状态值,显示不同的提示
                            tv_tishi.setText(TishiNoText);
                            showTishi();
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                        tv_tishi.setText(TishiNoText);
                        showTishi();
                    }
                }else if(msg.arg2 == 0){//无网络的情况
                    //解析json字符串{"origin_result":{"sn":"","error":2,"desc":"Network is not available","sub_error":2100},"error":2,"desc":"Network is not available","sub_error":2100}
                    try {
                        JSONObject msgObj = new JSONObject(msg.obj.toString());
                        JSONObject origin_resultObj = msgObj.getJSONObject("origin_result");
                        String error = origin_resultObj.getString("error");
                        if(error.equals("2")){
                            //解析结果集合,展现列表
                            String desc = origin_resultObj.getString("desc");
                            Toast.makeText(mContext,desc,Toast.LENGTH_SHORT).show();
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                status = msg.what;
                updateBtnTextByStatus();
                break;
            case IStatus.STATUS_NONE:
            case IStatus.STATUS_READY:
            case IStatus.STATUS_SPEAKING:
            case IStatus.STATUS_RECOGNITION:
                status = msg.what;
                updateBtnTextByStatus();
                break;
            default:
                break;
        }
    }

    /**更改按钮的文本*/
    private void updateBtnTextByStatus() {
        switch (status) {
            case IStatus.STATUS_NONE:
                btn_start.setText(BtnStartText);
                btn_start.setEnabled(true);
                break;
            case IStatus.STATUS_WAITING_READY:
            case IStatus.STATUS_READY:
            case IStatus.STATUS_SPEAKING:
            case IStatus.STATUS_RECOGNITION:
                btn_start.setText(BtnStopText);
                btn_start.setEnabled(true);
                break;
            case IStatus.STATUS_STOPPED:
                btn_start.setText(BtnSearchingText);
                btn_start.setEnabled(true);
                break;
            default:
                break;
        }
    }

    //========================================更改列表==========================
    /**获取集合数据,并显示*/
    private void initList(JSONArray wordList){
        //先清空
        if(resultWordList.size() > 0){
            resultWordList.clear();
        }
        //再赋值
        for(int i=0;i<wordList.length();i++){
            String wordItem = "";
            try {
                wordItem = wordList.getString(i);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            resultWordList.add(wordItem);
        }

        if(speechResultAdapter == null){
            //设置适配器
            speechResultAdapter = new SpeechResultAdapter(getActivity(), resultWordList);
            result_list.setAdapter(speechResultAdapter);
            //添加分割线
            //设置添加删除动画

            //调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
            result_list.setSelected(true);
        }else{
            speechResultAdapter.notifyDataSetChanged();
        }

        speechResultAdapter.setOnItemClickLitener(new SpeechResultAdapter.OnItemClickLitener() {
            @Override
            public void onItemClick(int position) {
                dismiss();
                if(mOnResultListItemClickListener != null){
                    mOnResultListItemClickListener.onItemClick(resultWordList.get(position));
                }
            }
        });
    }

    //=========================语音列表项的点击事件监听==============================
    public static abstract interface OnResultListItemClickListener
    {
        //语音结果列表项的点击事件接口
        public abstract void onItemClick(String title);
    }

    private OnResultListItemClickListener mOnResultListItemClickListener;

    public void seOnResultListItemClickListener(OnResultListItemClickListener mOnResultListItemClickListener)
    {
        this.mOnResultListItemClickListener = mOnResultListItemClickListener;
    }

}

4、如果想要使用长语音功能,请参考SpeechLongBottomSheetDialog.java文件

package com.why.project.baiduspeech.dialog;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.DialogFragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.speech.asr.SpeechConstant;
import com.baidu.speech.utils.LogUtil;
import com.why.project.baiduspeech.R;
import com.why.project.baiduspeech.control.MyRecognizer;
import com.why.project.baiduspeech.recognization.IStatus;
import com.why.project.baiduspeech.recognization.MessageStatusRecogListener;
import com.why.project.baiduspeech.recognization.StatusRecogListener;
import com.why.project.baiduspeech.util.Logger;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by HaiyuKing
 * Used 普通话 input输入法模型,适用于长句及长语音,有逗号分割,无语义【基本上和SpeechBottomSheetDialog代码相同】
 */

public class SpeechLongBottomSheetDialog extends DialogFragment {
    private static final String TAG = SpeechBottomSheetDialog.class.getSimpleName();

    private Context mContext;
    /**View实例*/
    private View myView;

    private ImageView img_close;
    private ProgressBar loadProgressBar;
    private TextView tv_tishi;
    private RecyclerView result_list;
    private Button btn_start;

    private ArrayList<String> resultWordList;
    private SpeechResultAdapter speechResultAdapter;

    private String BtnStartText = "按一下开始听音";
    private String BtnStopText = "按一下结束听音";
    private String BtnSearchingText = "正在识别";

    private String TishiNoText = "没听清,请重说一遍";

    /**识别控制器,使用MyRecognizer控制识别的流程*/
    protected MyRecognizer myRecognizer;
    /**控制UI按钮的状态*/
    protected int status;

    protected Handler handler;


    public static SpeechLongBottomSheetDialog getInstance(Context mContext)
    {
        SpeechLongBottomSheetDialog speechLongBottomSheetDialog = new SpeechLongBottomSheetDialog();
        speechLongBottomSheetDialog.mContext = mContext;

        return speechLongBottomSheetDialog;
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));//设置背景为透明,并且没有标题
        myView = inflater.inflate(R.layout.dialog_bottomsheet_speech, container, false);
        return myView;

    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);

        initHandler();//初始化handler
        initRecog();//初始化语音

        initViews();
        initDatas();
        initEvents();
    }

    /**
     * 设置宽度和高度值,以及打开的动画效果
     */
    @Override
    public void onStart() {
        super.onStart();
        //设置对话框的宽高,必须在onStart中
        DisplayMetrics metrics = new DisplayMetrics();
        this.getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
        Window window = this.getDialog().getWindow();
        window.setLayout(metrics.widthPixels, this.getDialog().getWindow().getAttributes().height);
        window.setGravity(Gravity.BOTTOM);//设置在底部
        //打开的动画效果
        //设置dialog的 进出 动画
        getDialog().getWindow().setWindowAnimations(R.style.speechbottomsheetdialog_animation);
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        LogUtil.w(TAG,"{onDismiss}");
        //当对话框消失的时候统一执行销毁语音功能
        destroyRecog();//销毁语音
    }


    private void initViews() {
        img_close = (ImageView) myView.findViewById(R.id.img_close);
        loadProgressBar = (ProgressBar) myView.findViewById(R.id.loadProgressBar);
        tv_tishi = (TextView) myView.findViewById(R.id.tv_tishi);
        result_list = (RecyclerView) myView.findViewById(R.id.result_list);
        btn_start = (Button) myView.findViewById(R.id.btn_start);
    }

    /**初始化数据*/
    private void initDatas() {
        resultWordList = new ArrayList<String>();
        speechResultAdapter = null;
        //设置布局管理器
        LinearLayoutManager linerLayoutManager = new LinearLayoutManager(getActivity());
        result_list.setLayoutManager(linerLayoutManager);

        btn_start.setText(BtnStartText);//显示文字,和下面的二选一即可 why
        //可以设置为打开后自动识别语音
        /*startRecog();
        showProgress();*/
    }

    private void initEvents() {
        //关闭图标的点击事件
        img_close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });

        //按钮的点击事件
        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                switch (status) {
                    case IStatus.STATUS_NONE: // 初始状态
                        startRecog();
                        status = IStatus.STATUS_WAITING_READY;
                        updateBtnTextByStatus();//更改按钮的文本
                        //显示加载区域
                        showProgress();
                        break;
                    case IStatus.STATUS_WAITING_READY: // 调用本类的start方法后,即输入START事件后,等待引擎准备完毕。
                    case IStatus.STATUS_READY: // 引擎准备完毕。
                    case IStatus.STATUS_SPEAKING:
                    case IStatus.STATUS_FINISHED: // 长语音情况
                    case IStatus.STATUS_RECOGNITION:
                        stopRecog();
                        status = IStatus.STATUS_STOPPED; // 引擎识别中
                        updateBtnTextByStatus();//更改按钮的文本
                        //对于长语音来讲,需要手动执行代码,否则还得点击一次才能取消why
                        btn_start.callOnClick();
                        break;
                    case IStatus.STATUS_STOPPED: // 引擎识别中
                        cancelRecog();
                        hiddenAll();//隐藏加载区域why
                        status = IStatus.STATUS_NONE; // 识别结束,回到初始状态
                        updateBtnTextByStatus();//更改按钮的文本
                        break;
                    default:
                        break;
                }
            }
        });
    }


    /**
     * 显示加载进度区域,隐藏其他区域*/
    private void showProgress(){
        loadProgressBar.setVisibility(View.VISIBLE);
        tv_tishi.setVisibility(View.GONE);
        result_list.setVisibility(View.GONE);
    }

    /**
     * 显示文本提示区域,隐藏其他区域*/
    private void showTishi(){
        tv_tishi.setVisibility(View.VISIBLE);
        loadProgressBar.setVisibility(View.GONE);
        result_list.setVisibility(View.GONE);
    }

    /**
     * 显示语音结果区域,隐藏其他区域*/
    private void showListView(){
        result_list.setVisibility(View.VISIBLE);
        loadProgressBar.setVisibility(View.GONE);
        tv_tishi.setVisibility(View.GONE);
    }

    /**隐藏所有的区域【主要用于长语音】why*/
    private void hiddenAll(){
        result_list.setVisibility(View.GONE);
        loadProgressBar.setVisibility(View.GONE);
        tv_tishi.setVisibility(View.GONE);
    }

    //======================================语音相关代码==========================================
    /**
     * 初始化handler*/
    private void initHandler(){
        handler = new Handler() {
            /*@param msg*/
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                handleMsg(msg);
            }
        };
        Logger.setHandler(handler);
    }


    /**
     * 在onCreate中调用。初始化识别控制类MyRecognizer
     */
    protected void initRecog() {

        StatusRecogListener listener = new MessageStatusRecogListener(handler);
        myRecognizer = new MyRecognizer(mContext,listener);

        status = IStatus.STATUS_NONE;//默认什么也没有做
    }

    /**
     * 销毁时需要释放识别资源。
     */
    protected void destroyRecog() {
        myRecognizer.release();
        Log.i(TAG, "destroyRecog");
    }

    /**
     * 开始录音,点击“开始”按钮后调用。
     */
    protected void startRecog() {
        Map<String, Object> params = new LinkedHashMap<String, Object>();
        params.put(SpeechConstant.ACCEPT_AUDIO_DATA, false);//是否保存音频
        params.put(SpeechConstant.DISABLE_PUNCTUATION, false);//是否禁用标点符号,在选择输入法模型的前提下生效【不禁用的话,说完一段话,就自带标点符号】
        params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);//暂时不知道什么意思
        //下面的1936和1537选择其中一个 why
        //params.put(SpeechConstant.PID, 1936); // 普通话 far,远场模型,高级,适用于音源离麦克风较远(>1m)的录音,有逗号分隔,可以有语义
        params.put(SpeechConstant.PID, 1537); // 普通话 input输入法模型,适用于长句及长语音,有逗号分割,无语义
        params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 0); // 长语音,建议搭配input输入法模型
        myRecognizer.start(params);
    }

    /**
     * 开始录音后,手动停止录音。SDK会识别在此过程中的录音。点击“停止”按钮后调用。
     */
    private void stopRecog() {
        myRecognizer.stop();
    }

    /**
     * 开始录音后,取消这次录音。SDK会取消本次识别,回到原始状态。点击“取消”按钮后调用。
     */
    private void cancelRecog() {
        myRecognizer.cancel();
    }


    protected void handleMsg(Message msg) {
        switch (msg.what) { // 处理MessageStatusRecogListener中的状态回调
            case IStatus.STATUS_FINISHED:
                //识别结束时候的调用【判断显示结果列表区域还是提示区域】
                if (msg.arg2 == 1) {
                    //解析json字符串
                    try {
                        JSONObject msgObj = new JSONObject(msg.obj.toString());
                        String error = msgObj.getString("error");
                        if(error.equals("0")){
                            //直接输入到文本框中 why
                            JSONArray recognitionObj = msgObj.getJSONArray("results_recognition");
                            String result = recognitionObj.getString(0);
                            if(mOnResultListItemClickListener != null){
                                mOnResultListItemClickListener.onItemClick(result);
                            }
                        }else if(error.equals("7")){
                            tv_tishi.setText(TishiNoText);
                            showTishi();
                        }else{//应该根据不同的状态值,显示不同的提示
                            tv_tishi.setText(TishiNoText);
                            showTishi();
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                        tv_tishi.setText(TishiNoText);
                        showTishi();
                    }
                }else if(msg.arg2 == 0){//无网络的情况
                    //解析json字符串{"origin_result":{"sn":"","error":2,"desc":"Network is not available","sub_error":2100},"error":2,"desc":"Network is not available","sub_error":2100}
                    try {
                        JSONObject msgObj = new JSONObject(msg.obj.toString());
                        JSONObject origin_resultObj = msgObj.getJSONObject("origin_result");
                        String error = origin_resultObj.getString("error");
                        if(error.equals("2")){
                            //解析结果集合,展现列表
                            String desc = origin_resultObj.getString("desc");
                            Toast.makeText(mContext,desc,Toast.LENGTH_SHORT).show();
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                status = msg.what;
                updateBtnTextByStatus();
                break;
            case IStatus.STATUS_NONE:
            case IStatus.STATUS_READY:
            case IStatus.STATUS_SPEAKING:
            case IStatus.STATUS_RECOGNITION:
                status = msg.what;
                updateBtnTextByStatus();
                break;
            default:
                break;
        }
    }

    /**更改按钮的文本*/
    private void updateBtnTextByStatus() {
        switch (status) {
            case IStatus.STATUS_NONE:
                btn_start.setText(BtnStartText);
                btn_start.setEnabled(true);
                break;
            case IStatus.STATUS_WAITING_READY:
            case IStatus.STATUS_READY:
            case IStatus.STATUS_SPEAKING:
            case IStatus.STATUS_RECOGNITION:
                btn_start.setText(BtnStopText);
                btn_start.setEnabled(true);
                break;
            case IStatus.STATUS_STOPPED:
                btn_start.setText(BtnSearchingText);
                btn_start.setEnabled(true);
                break;
            default:
                break;
        }
    }

    //========================================更改列表==========================
    /**获取集合数据,并显示*/
    private void initList(JSONArray wordList){
        //先清空
        if(resultWordList.size() > 0){
            resultWordList.clear();
        }
        //再赋值
        for(int i=0;i<wordList.length();i++){
            String wordItem = "";
            try {
                wordItem = wordList.getString(i);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            resultWordList.add(wordItem);
        }

        if(speechResultAdapter == null){
            //设置适配器
            speechResultAdapter = new SpeechResultAdapter(getActivity(), resultWordList);
            result_list.setAdapter(speechResultAdapter);
            //添加分割线
            //设置添加删除动画

            //调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
            result_list.setSelected(true);
        }else{
            speechResultAdapter.notifyDataSetChanged();
        }

        speechResultAdapter.setOnItemClickLitener(new SpeechResultAdapter.OnItemClickLitener() {
            @Override
            public void onItemClick(int position) {
                dismiss();
                if(mOnResultListItemClickListener != null){
                    mOnResultListItemClickListener.onItemClick(resultWordList.get(position));
                }
            }
        });
    }

    //=========================语音列表项的点击事件监听==============================
    public static abstract interface OnResultListItemClickListener
    {
        //语音结果列表项的点击事件接口
        public abstract void onItemClick(String title);
    }

    private OnResultListItemClickListener mOnResultListItemClickListener;

    public void seOnResultListItemClickListener(OnResultListItemClickListener mOnResultListItemClickListener)
    {
        this.mOnResultListItemClickListener = mOnResultListItemClickListener;
    }
}

三 使用方法
因为要导入外部库文件,将项目中的modular变成libraries引用依赖,所以需要配置相应权限。
这里写图片描述
在Activity中调用

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.why.project.baiduspeechdemo.MainActivity">

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.448"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.325"/>

    <Button
        android:id="@+id/btn_openSpeechDialog"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="32dp"
        android:text="打开搜索模型语音识别对话框"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.419"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/btn_openSpeechLongDialog"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:text="打开input输入模型语音识别对话框"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_openSpeechDialog"/>

</android.support.constraint.ConstraintLayout>

activity_main.xml
package com.why.project.baiduspeechdemo;

import android.Manifest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.tbruyelle.rxpermissions2.RxPermissions;
import com.why.project.baiduspeech.dialog.SpeechBottomSheetDialog;
import com.why.project.baiduspeech.dialog.SpeechLongBottomSheetDialog;

import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    private Button mOpenSpeechDialogBtn;
    private Button mOpenSpeechLongDialogBtn;
    private TextView mResultTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        onePermission();

        initViews();
        initEvents();
    }

    private void initViews() {
        mOpenSpeechDialogBtn = findViewById(R.id.btn_openSpeechDialog);
        mOpenSpeechLongDialogBtn = findViewById(R.id.btn_openSpeechLongDialog);
        mResultTv = findViewById(R.id.tv_result);
    }

    private void initEvents() {
        mOpenSpeechDialogBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //打开百度语音对话框
                SpeechBottomSheetDialog speechBottomSheetDialog = SpeechBottomSheetDialog.getInstance(MainActivity.this);
                speechBottomSheetDialog.seOnResultListItemClickListener(new SpeechBottomSheetDialog.OnResultListItemClickListener() {
                    @Override
                    public void onItemClick(String title) {
                        //填充到输入框中
                        mResultTv.setText(title);
                    }
                });
                speechBottomSheetDialog.show(getSupportFragmentManager(), TAG);
            }
        });
        mOpenSpeechLongDialogBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //打开百度语音对话框
                SpeechLongBottomSheetDialog speechLongBottomSheetDialog = SpeechLongBottomSheetDialog.getInstance(MainActivity.this);
                speechLongBottomSheetDialog.seOnResultListItemClickListener(new SpeechLongBottomSheetDialog.OnResultListItemClickListener() {
                    @Override
                    public void onItemClick(String title) {
                        //填充到输入框中
                        mResultTv.setText(mResultTv.getText()+title);
                    }
                });
                speechLongBottomSheetDialog.show(getSupportFragmentManager(), TAG);
            }
        });

    }

    /**只有一个运行时权限申请的情况*/
    private void onePermission(){
        RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
        rxPermissions.request(Manifest.permission.RECORD_AUDIO,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) //权限名称,多个权限之间逗号分隔开
                .subscribe(new Consumer<Boolean>() {
                    @Override
                    public void accept(Boolean granted) throws Exception {
                        Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
                        if (granted) { // 在android 6.0之前会默认返回true
                            // 已经获取权限
                        } else {
                            // 未获取权限
                            Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
                    }
                }, new Action() {
                    @Override
                    public void run() throws Exception {
                        Log.e(TAG,"{run}");//执行顺序——2
                    }
                });
    }
}

参考资料
http://ai.baidu.com/tech/speech
集成指南

备注
1 引入外部项目时不要忘记需要在setting.gradle中配置
这里写图片描述

2018-01-08 14:53:39 androidzsp 阅读数 2490
  • Android 实战开发 三方SDK 讯飞语音SDK

    Android 第三方SDK开发视频教程,给课程结合讯飞语音这个第三方SDK进行实战教学,实现在线语音合成,将文字信息转化为声音信息,给应用配上“嘴巴;语音听写,将连续语音识别为文字,给应用配上“耳朵”。

    4827 人正在学习 去看看 Frank Lee

1.下载科大讯飞语音识别sdk(http://www.xfyun.cn/sdk/dispatcher)选择语音听写SDK(如下图) ,下载前会让你先创建应用,创建应用后会得到一个appid。然后点“立即开通”去开通“语音识别”功能,之后就会跳出“SDK下载”的页面,然后就可以下载了(未注册账号的要先注册一个账号)。


2.如果是android开发选择android如果是ios选择ios平台(如图)


3.将下载好的sdk中的libs里面的msc.jar以及libmsc.so文件复制到自己创建的libs下面 (如图)


4.接下来将Manifest中添加一下权限并且创建appid时包名需要跟自己创建的工程包名保持一致 (例如 com.vice.android)并且在application中设置android:name以及bunid gradle里面配置sourceSets(如下图)

<!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->  
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!--连接网络权限,用于执行云端语音能力 -->
<uses-permission android:name="android.permission.INTERNET" />
<!--读取网络信息状态 -->  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--获取当前wifi状态 -->  
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许程序改变网络连接状态 --> 
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!--读取手机信息权限 -->  
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

5. 具体代码目录结构


6.主要代码如下

package com.voice.android;

import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceActivity;
import android.view.Window;

/**
 * 听写设置界面
 */
public class IatSettings extends PreferenceActivity implements OnPreferenceChangeListener {
   
   public static final String PREFER_NAME = "com.iflytek.setting";
   private EditTextPreference mVadbosPreference;
   private EditTextPreference mVadeosPreference;
   
   @SuppressWarnings("deprecation")
   public void onCreate(Bundle savedInstanceState) {
      requestWindowFeature(Window.FEATURE_NO_TITLE);
      super.onCreate(savedInstanceState);
      getPreferenceManager().setSharedPreferencesName(PREFER_NAME);
      addPreferencesFromResource(R.xml.iat_setting);
      
      mVadbosPreference = (EditTextPreference)findPreference("iat_vadbos_preference");
      mVadbosPreference.getEditText().addTextChangedListener(new SettingTextWatcher(IatSettings.this,mVadbosPreference,0,10000));
      
      mVadeosPreference = (EditTextPreference)findPreference("iat_vadeos_preference");
      mVadeosPreference.getEditText().addTextChangedListener(new SettingTextWatcher(IatSettings.this,mVadeosPreference,0,10000));
   }
   @Override
   public boolean onPreferenceChange(Preference preference, Object newValue) {
      return true;
   }
}

package com.voice.android;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
/**
 * Json结果解析类
 */
public class JsonParser {

   public static String parseIatResult(String json) {
      StringBuffer ret = new StringBuffer();
      try {
         JSONTokener tokener = new JSONTokener(json);
         JSONObject joResult = new JSONObject(tokener);

         JSONArray words = joResult.getJSONArray("ws");
         for (int i = 0; i < words.length(); i++) {
            // 转写结果词,默认使用第一个结果
            JSONArray items = words.getJSONObject(i).getJSONArray("cw");
            JSONObject obj = items.getJSONObject(0);
            ret.append(obj.getString("w"));
         }
      } catch (Exception e) {
         e.printStackTrace();
      } 
      return ret.toString();
   }
}

package com.voice.android;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private EditText et_name;
    private ImageView iv_yuyin_button;
    // 语音识别对象
    private SpeechRecognizer mAsr;
    private Toast mToast;
    private SharedPreferences mSharedPreferences;
    // 语音听写UI
    private RecognizerDialog mIatDialog;
    private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_name= (EditText) findViewById(R.id.et_name);
        iv_yuyin_button= (ImageView) findViewById(R.id.iv_yuyin_button);
        initXfun();
        initView();
        initListener();
        mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
    }
    @Override
    public void onClick(View view) {
        switch (view.getId()) {

            case R.id.iv_yuyin_button:
                voiceTurnWords();
                break;

            default:
                break;

        }
    }
    private void initView(){
        mIatDialog = new RecognizerDialog(this, mInitListener);
    }
    private void initListener(){
        iv_yuyin_button.setOnClickListener(this);
    }
    private void initXfun(){
        mAsr = SpeechRecognizer.createRecognizer(MainActivity.this, mInitListener);
    }
    /**
     * 初始化监听器。
     */
    private InitListener mInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            if (code != ErrorCode.SUCCESS) {
                showTip("初始化失败,错误码:"+code);
            }
        }
    };
    private void showTip(final String str) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mToast.setText(str);
                mToast.show();
            }
        });
    }
    private void voiceTurnWords(){
        setParam();
        mIatDialog.setListener(mRecognizerDialogListener);
        mIatDialog.show();
        showTip(getString(R.string.text_begin));
    }
    public void setParam() {
        // 清空参数
        mAsr.setParameter(SpeechConstant.PARAMS, null);
        // 设置听写引擎
        mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        // 设置返回结果格式
        mAsr.setParameter(SpeechConstant.RESULT_TYPE, "json");
        // 设置语言
        mAsr.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        // 设置语言区域
        mAsr.setParameter(SpeechConstant.ACCENT, "mandarin");
        // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
        mAsr.setParameter(SpeechConstant.VAD_BOS,"4000");
        // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
        mAsr.setParameter(SpeechConstant.VAD_EOS,  "1000");
        // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
        mAsr.setParameter(SpeechConstant.ASR_PTT,  "0");
    }
    /**
     * 听写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));
        }

        et_name.setText(resultBuffer.toString());
        et_name.setSelection(et_name.length());
    }
}
package com.voice.android;

import java.util.regex.Pattern;
import android.content.Context;
import android.preference.EditTextPreference;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.widget.Toast;

/**
 * 输入框输入范围控制
 */
public class SettingTextWatcher implements TextWatcher {
   private int editStart ;
   private int editCount ;
   private EditTextPreference mEditTextPreference;
   int minValue;//最小值
   int maxValue;//最大值
   private Context mContext;
   
   public SettingTextWatcher(Context context,EditTextPreference e,int min, int max) {
      mContext = context;
      mEditTextPreference = e;
      minValue = min;
      maxValue = max;
    }
   
   @Override
   public void onTextChanged(CharSequence s, int start, int before, int count) {
      editStart = start;
      editCount = count;
   }
   
   @Override
   public void beforeTextChanged(CharSequence s, int start, int count,int after) {       
   }
   
   @Override
   public void afterTextChanged(Editable s) {
      if (TextUtils.isEmpty(s)) {
         return;
      }
      String content = s.toString();
      if (isNumeric(content)) {
         int num = Integer.parseInt(content);
         if (num > maxValue || num < minValue) {
            s.delete(editStart, editStart+editCount);
            mEditTextPreference.getEditText().setText(s);
            Toast.makeText(mContext, "超出有效值范围", Toast.LENGTH_SHORT).show();
         }
      }else {
         s.delete(editStart, editStart+editCount);
         mEditTextPreference.getEditText().setText(s);
         Toast.makeText(mContext, "只能输入数字哦", Toast.LENGTH_SHORT).show();
      }
   }
   
   /**
    * 正则表达式-判断是否为数字
    */
   public static boolean isNumeric(String str){ 
       Pattern pattern = Pattern.compile("[0-9]*"); 
       return pattern.matcher(str).matches();    
    } 

};
package com.voice.android;

import android.app.Application;
import com.iflytek.cloud.Setting;
import com.iflytek.cloud.SpeechUtility;

public class SpeechApp extends Application {

   @Override
   public void onCreate() {
      // 应用程序入口处调用,避免手机内存过小,杀死后台进程后通过历史intent进入Activity造成SpeechUtility对象为null
      // 如在Application中调用初始化,需要在Mainifest中注册该Applicaiton
      // 注意:此接口在非主进程调用会返回null对象,如需在非主进程使用语音功能,请增加参数:SpeechConstant.FORCE_LOGIN+"=true"
      // 参数间使用半角“,”分隔。
      // 设置你申请的应用appid,请勿在'='appid之间添加空格及空转义符
      // 注意: appid 必须和下载的SDK保持一致,否则会出现10407错误
      SpeechUtility.createUtility(SpeechApp.this, "appid=5a4ae664");
      // 以下语句用于设置日志开关(默认开启),设置成false时关闭语音云SDK日志打印
      super.onCreate();
   }
   
}



2014-01-06 09:36:13 qinyuanpei 阅读数 9799
  • Android 实战开发 三方SDK 讯飞语音SDK

    Android 第三方SDK开发视频教程,给课程结合讯飞语音这个第三方SDK进行实战教学,实现在线语音合成,将文字信息转化为声音信息,给应用配上“嘴巴;语音听写,将连续语音识别为文字,给应用配上“耳朵”。

    4827 人正在学习 去看看 Frank Lee

            今天我们来继续学习百度语音识别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"/>

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


        

没有更多推荐了,返回首页