java speech sdk_BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.7.3)

本文介绍如何将百度语音SDK集成到Android项目中,提供了一个名为BaiduSpeech的module,包含了普通话search搜索模型和input输入法模型。详细步骤包括创建应用获取API Key,导入SDK,实现语音识别监听器,创建UI对话框,以及处理识别结果。
摘要由CSDN通过智能技术生成

版权声明:本文为HaiyuKing原创文章,转载请注明出处!

前言

本Demo将百度语音SDK(其中一部分功能)和自定义的UI对话框封装到一个module中,便于后续的SDK版本更新以及调用。

本Demo使用的百度语音SDK版本是audiobd_speech_sdk_asr_v3.0.7.3_bdasr_20180313_726f26e。

本Demo中使用的appkey已失效,请自行创建应用,使用新的appkey。

效果图

9a81d73b05d66d9484d02c9278462f14.gif

前提

(1)新建项目(获取包名)

681e6514639b6fd4196f73d60e65fecd.png

(2)在百度AI开发平台上创建应用,获取API Key及Secret Key

1、成为开发者

参考《接入指南》

2、创建应用

2.1、点击百度AI开放平台导航右侧的控制台,选择需要使用的AI服务项【这里选择语音技术】。

bce4dbcc645891651589f824807776be.png

2.2、创建应用

2d57432e9f227a5b46050ffb386ce7bd.png

2.3、填写应用信息

fa371a9de1e4af08f28ee3bf4c49f46b.png

dbbdf7fa67a4bc35c5ecb621cca8978c.png

2.4、创建成功

d885cdbb81a54a162ad391c0b62674b4.png

2.5、应用列表

c2e3b76c09f96ec94c2e46081417c8c8.png

(3)下载SDK

3.1、管理应用

8040015dae56bc3bff4b74dcdccb487b.png

3.2、下载SDK

94e65159db99ea6dd735049fb6db2634.png

1170cfa656a8bac593cf1ed5779009e5.png

47d09bc930b43ce11bb968b0f1fb0ffe.png

代码分析

普通话 search搜索模型:参考SpeechBottomSheetDialog.java类

普通话 input输入法模型,适用于长句及长语音,有逗号分割,无语义:参考SpeechLongBottomSheetDialog.java类

注意:关于语音识别状态维护,API调用的代码,是自己根据官网demo的理解进行整理的,可能有所偏颇,仅供参考。【希望官网demo可以添加百度APP的语音对话框效果就好了】

使用步骤

一、项目组织结构图

25dda05f794f4f4612fe80899ef4b759.png

debe533dbfa513d86e31fff332f1c0e4.png

9655cc54b0a525b178a4cf812744c8e4.png

a9085299642cd48e247abb4454941c6b.png

注意事项:

1、  导入类文件后需要change包名以及重新import R文件路径

2、  Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖

二、导入步骤

(1)新建module,命名为BaiduSpeech

478fe53956d6dfd921a5b1f62114114d.png

1a683ac589e2040c557e23577b56a2dc.png

(2)在baiduspeech的AndroidManifest.xml中添加以下代码

从官方demo的AndroidManifest.xml中找到如下信息,然后复制到您自己的同名文件中。此处需要您复制1、权限2、官网申请的应用信息3、SDK的Service。

注意:此时标签那里是红色错误的标记,暂时不用管,导入jar、so文件后编译下就正常了。

1cfbdb8650209ae97d083c96b131d74a.png

(3)复制jar 文件

将官方demo中的app\libs\bdasr_V3_20180320_9066860.jar复制进您项目的同名目录。

1f0cdfb0741eb15ac8937900fafa9e12.png

在build.gradle中确认是否含有以下红色标记的代码

bd3124a2d79fd7cdc26a7b4d00078077.png

(4)复制jni库的so文件

复制官方demo中 app\src\main\jniLibs 至项目的同名目录。

501e4645c177e552b1dcb523ee06c7b4.png

这个时候编译下,就会发现AndroidManifest.xml文件的标签那里正常了。

(5)在官方demo中找到下面的文件复制到项目中(按照下面的包名进行查找)【注意,复制过来后,需要重新import 相关类】

ed47b24aaf49c9adbb17a2b240fd7e81.png

(6)修改MessageStatusRecogListener.java文件【根据实际情况进行修改】

packagecom.why.project.baiduspeech.recognization;importandroid.os.Handler;importandroid.os.Message;importandroid.util.Log;/*** Created by fujiayi on 2017/6/16.*/

public class MessageStatusRecogListener extendsStatusRecogListener {privateHandler handler;private longspeechEndTime;private boolean needTime = true;private static final String TAG = "MesStatusRecogListener";publicMessageStatusRecogListener(Handler handler) {this.handler =handler;

}

@Overridepublic voidonAsrReady() {super.onAsrReady();

sendStatusMessage("引擎就绪,可以开始说话。");

}

@Overridepublic voidonAsrBegin() {super.onAsrBegin();

sendStatusMessage("检测到用户说话");

}

@Overridepublic voidonAsrEnd() {super.onAsrEnd();

speechEndTime=System.currentTimeMillis();

sendMessage("检测到用户说话结束");

}

@Overridepublic voidonAsrPartialResult(String[] results, RecogResult recogResult) {

sendStatusMessage("临时识别结果,结果是“" + results[0] + "”;原始json:" +recogResult.getOrigalJson());super.onAsrPartialResult(results, recogResult);

}

@Overridepublic voidonAsrFinalResult(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);

}

@Overridepublic void onAsrFinishError(int errorCode, intsubErrorCode, 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;

}

@Overridepublic voidonAsrOnlineNluResult(String nluResult) {super.onAsrOnlineNluResult(nluResult);if (!nluResult.isEmpty()) {

sendStatusMessage("原始语义识别结果json:" +nluResult);

}

}

@Overridepublic voidonAsrFinish(RecogResult recogResult) {super.onAsrFinish(recogResult);

sendStatusMessage("识别一段话结束。如果是长语音的情况会继续识别下段话。");

}/*** 长语音识别结束*/@Overridepublic voidonAsrLongFinish() {super.onAsrLongFinish();

sendStatusMessage("长语音识别结束。");

}/*** 使用离线命令词时,有该回调说明离线语法资源加载成功*/@Overridepublic voidonOfflineLoaded() {

sendStatusMessage("【重要】asr.loaded:离线资源加载成功。没有此回调可能离线语法功能不能使用。");

}/*** 使用离线命令词时,有该回调说明离线语法资源加载成功*/@Overridepublic voidonOfflineUnLoaded() {

sendStatusMessage(" 离线资源卸载成功。");

}

@Overridepublic voidonAsrExit() {super.onAsrExit();

sendStatusMessage("识别引擎结束并空闲中");

}private voidsendStatusMessage(String message) {

sendMessage(message, status);

}private voidsendMessage(String message) {

sendMessage(message, WHAT_MESSAGE_STATUS);

}private void sendMessage(String message, intwhat) {

sendMessage(message, what,false);

}private void sendMessage(String message, int what, booleanhighlight) {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【根据实际情况自行修改UI布局】

1、在baiduspeech的build.gradle中引用recyclerview【版本号和项目的appcompat保持一致】【因为demo中用到了】

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中

0af4439240ad0217fbee1796a4ce39ce.png

946f5c8cbe5d2fbdaea5b27a32b498c7.png

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

packagecom.why.project.baiduspeech.dialog;importandroid.content.Context;importandroid.content.DialogInterface;importandroid.graphics.drawable.ColorDrawable;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Message;importandroid.support.v4.app.DialogFragment;importandroid.support.v7.widget.LinearLayoutManager;importandroid.support.v7.widget.RecyclerView;importandroid.util.DisplayMetrics;importandroid.util.Log;importandroid.view.Gravity;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.view.Window;importandroid.widget.Button;importandroid.widget.ImageView;importandroid.widget.ProgressBar;importandroid.widget.TextView;importandroid.widget.Toast;importcom.baidu.speech.asr.SpeechConstant;importcom.baidu.speech.utils.LogUtil;importcom.why.project.baiduspeech.R;importcom.why.project.baiduspeech.control.MyRecognizer;importcom.why.project.baiduspeech.recognization.IStatus;importcom.why.project.baiduspeech.recognization.MessageStatusRecogListener;importcom.why.project.baiduspeech.recognization.StatusRecogListener;importcom.why.project.baiduspeech.util.Logger;importorg.json.JSONArray;importorg.json.JSONException;importorg.json.JSONObject;importjava.util.ArrayList;importjava.util.LinkedHashMap;importjava.util.Map;/*** Created by HaiyuKing

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

public class SpeechBottomSheetDialog extendsDialogFragment {private static final String TAG = SpeechBottomSheetDialog.class.getSimpleName();privateContext mContext;/**View实例*/

privateView myView;privateImageView img_close;privateProgressBar loadProgressBar;privateTextView tv_tishi;privateRecyclerView result_list;privateButton btn_start;private ArrayListresultWordList;privateSpeechResultAdapter speechResultAdapter;private String BtnStartText = "按一下开始听音";private String BtnStopText = "按一下结束听音";private String BtnSearchingText = "正在识别";private String TishiNoText = "没听清,请重说一遍";/**识别控制器,使用MyRecognizer控制识别的流程*/

protectedMyRecognizer myRecognizer;/**控制UI按钮的状态*/

protected intstatus;protectedHandler handler;public staticSpeechBottomSheetDialog getInstance(Context mContext)

{

SpeechBottomSheetDialog speechBottomSheetDialog= newSpeechBottomSheetDialog();

speechBottomSheetDialog.mContext=mContext;returnspeechBottomSheetDialog;

}publicView onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));//设置背景为透明,并且没有标题

myView = inflater.inflate(R.layout.dialog_bottomsheet_speech, container, false);returnmyView;

}

@Overridepublic voidonActivityCreated(Bundle savedInstanceState) {//TODO Auto-generated method stub

super.onActivityCreated(savedInstanceState);

initHandler();//初始化handler

initRecog();//初始化语音

initViews();

initDatas();

initEvents();

}/*** 设置宽度和高度值,以及打开的动画效果*/@Overridepublic voidonStart() {super.onStart();//设置对话框的宽高,必须在onStart中

DisplayMetrics metrics = newDisplayMetrics();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);

}

@Overridepublic voidonDismiss(DialogInterface dialog) {super.onDismiss(dialog);

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

destroyRecog();//销毁语音

}private voidinitViews() {

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 voidinitDatas() {

resultWordList= new ArrayList();

speechResultAdapter= null;//设置布局管理器

LinearLayoutManager linerLayoutManager = newLinearLayoutManager(getActivity());

result_list.setLayoutManager(linerLayoutManager);//可以设置为打开后自动识别语音startRecog();

showProgress();

}private voidinitEvents() {//关闭图标的点击事件

img_close.setOnClickListener(newView.OnClickListener() {

@Overridepublic voidonClick(View v) {

dismiss();

}

});//按钮的点击事件

btn_start.setOnClickListener(newView.OnClickListener() {

@Overridepublic voidonClick(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: //引擎准备完毕。

caseIStatus.STATUS_SPEAKING:case IStatus.STATUS_FINISHED: //长语音情况

caseIStatus.STATUS_RECOGNITION:

stopRecog();

status= IStatus.STATUS_STOPPED; //引擎识别中

updateBtnTextByStatus();//更改按钮的文本

break;case IStatus.STATUS_STOPPED: //引擎识别中

cancelRecog();

status= IStatus.STATUS_NONE; //识别结束,回到初始状态

updateBtnTextByStatus();//更改按钮的文本

break;default:break;

}

}

});

}/*** 显示加载进度区域,隐藏其他区域*/

private voidshowProgress(){

loadProgressBar.setVisibility(View.VISIBLE);

tv_tishi.setVisibility(View.GONE);

result_list.setVisibility(View.GONE);

}/*** 显示文本提示区域,隐藏其他区域*/

private voidshowTishi(){

tv_tishi.setVisibility(View.VISIBLE);

loadProgressBar.setVisibility(View.GONE);

result_list.setVisibility(View.GONE);

}/*** 显示语音结果区域,隐藏其他区域*/

private voidshowListView(){

result_list.setVisibility(View.VISIBLE);

loadProgressBar.setVisibility(View.GONE);

tv_tishi.setVisibility(View.GONE);

}//======================================语音相关代码==========================================

/*** 初始化handler*/

private voidinitHandler(){

handler= newHandler() {/*@param msg*/@Overridepublic voidhandleMessage(Message msg) {super.handleMessage(msg);

handleMsg(msg);

}

};

Logger.setHandler(handler);

}/*** 在onCreate中调用。初始化识别控制类MyRecognizer*/

protected voidinitRecog() {

StatusRecogListener listener= newMessageStatusRecogListener(handler);

myRecognizer= newMyRecognizer(mContext,listener);

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

}/*** 销毁时需要释放识别资源。*/

protected voiddestroyRecog() {

myRecognizer.release();

Log.i(TAG,"destroyRecog");

}/*** 开始录音,点击“开始”按钮后调用。*/

protected voidstartRecog() {

Map params = new LinkedHashMap();

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 voidstopRecog() {

myRecognizer.stop();

}/*** 开始录音后,取消这次录音。SDK会取消本次识别,回到原始状态。点击“取消”按钮后调用。*/

private voidcancelRecog() {

myRecognizer.cancel();

}protected voidhandleMsg(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中的状态回调

caseIStatus.STATUS_FINISHED://识别结束时候的调用【判断显示结果列表区域还是提示区域】

if (msg.arg2 == 1) {//解析json字符串

try{

JSONObject msgObj= newJSONObject(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= newJSONObject(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;caseIStatus.STATUS_NONE:caseIStatus.STATUS_READY:caseIStatus.STATUS_SPEAKING:caseIStatus.STATUS_RECOGNITION:

status=msg.what;

updateBtnTextByStatus();break;default:break;

}

}/**更改按钮的文本*/

private voidupdateBtnTextByStatus() {switch(status) {caseIStatus.STATUS_NONE:

btn_start.setText(BtnStartText);

btn_start.setEnabled(true);break;caseIStatus.STATUS_WAITING_READY:caseIStatus.STATUS_READY:caseIStatus.STATUS_SPEAKING:caseIStatus.STATUS_RECOGNITION:

btn_start.setText(BtnStopText);

btn_start.setEnabled(true);break;caseIStatus.STATUS_STOPPED:

btn_start.setText(BtnSearchingText);

btn_start.setEnabled(true);break;default:break;

}

}//========================================更改列表==========================

/**获取集合数据,并显示*/

private voidinitList(JSONArray wordList){//先清空

if(resultWordList.size() > 0){

resultWordList.clear();

}//再赋值

for(int i=0;i

String wordItem= "";try{

wordItem=wordList.getString(i);

}catch(JSONException e) {

e.printStackTrace();

}

resultWordList.add(wordItem);

}if(speechResultAdapter == null){//设置适配器

speechResultAdapter = newSpeechResultAdapter(getActivity(), resultWordList);

result_list.setAdapter(speechResultAdapter);//添加分割线//设置添加删除动画//调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局

result_list.setSelected(true);

}else{

speechResultAdapter.notifyDataSetChanged();

}

speechResultAdapter.setOnItemClickLitener(newSpeechResultAdapter.OnItemClickLitener() {

@Overridepublic void onItemClick(intposition) {

dismiss();if(mOnResultListItemClickListener != null){

mOnResultListItemClickListener.onItemClick(resultWordList.get(position));

}

}

});

}//=========================语音列表项的点击事件监听==============================

public static abstract interfaceOnResultListItemClickListener

{//语音结果列表项的点击事件接口

public abstract voidonItemClick(String title);

}privateOnResultListItemClickListener mOnResultListItemClickListener;public voidseOnResultListItemClickListener(OnResultListItemClickListener mOnResultListItemClickListener)

{this.mOnResultListItemClickListener =mOnResultListItemClickListener;

}

}

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

packagecom.why.project.baiduspeech.dialog;importandroid.content.Context;importandroid.content.DialogInterface;importandroid.graphics.drawable.ColorDrawable;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Message;importandroid.support.v4.app.DialogFragment;importandroid.support.v7.widget.LinearLayoutManager;importandroid.support.v7.widget.RecyclerView;importandroid.util.DisplayMetrics;importandroid.util.Log;importandroid.view.Gravity;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.view.Window;importandroid.widget.Button;importandroid.widget.ImageView;importandroid.widget.ProgressBar;importandroid.widget.TextView;importandroid.widget.Toast;importcom.baidu.speech.asr.SpeechConstant;importcom.baidu.speech.utils.LogUtil;importcom.why.project.baiduspeech.R;importcom.why.project.baiduspeech.control.MyRecognizer;importcom.why.project.baiduspeech.recognization.IStatus;importcom.why.project.baiduspeech.recognization.MessageStatusRecogListener;importcom.why.project.baiduspeech.recognization.StatusRecogListener;importcom.why.project.baiduspeech.util.Logger;importorg.json.JSONArray;importorg.json.JSONException;importorg.json.JSONObject;importjava.util.ArrayList;importjava.util.LinkedHashMap;importjava.util.Map;/*** Created by HaiyuKing

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

public class SpeechLongBottomSheetDialog extendsDialogFragment {private static final String TAG = SpeechBottomSheetDialog.class.getSimpleName();privateContext mContext;/**View实例*/

privateView myView;privateImageView img_close;privateProgressBar loadProgressBar;privateTextView tv_tishi;privateRecyclerView result_list;privateButton btn_start;private ArrayListresultWordList;privateSpeechResultAdapter speechResultAdapter;private String BtnStartText = "按一下开始听音";private String BtnStopText = "按一下结束听音";private String BtnSearchingText = "正在识别";private String TishiNoText = "没听清,请重说一遍";/**识别控制器,使用MyRecognizer控制识别的流程*/

protectedMyRecognizer myRecognizer;/**控制UI按钮的状态*/

protected intstatus;protectedHandler handler;public staticSpeechLongBottomSheetDialog getInstance(Context mContext)

{

SpeechLongBottomSheetDialog speechLongBottomSheetDialog= newSpeechLongBottomSheetDialog();

speechLongBottomSheetDialog.mContext=mContext;returnspeechLongBottomSheetDialog;

}publicView onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));//设置背景为透明,并且没有标题

myView = inflater.inflate(R.layout.dialog_bottomsheet_speech, container, false);returnmyView;

}

@Overridepublic voidonActivityCreated(Bundle savedInstanceState) {//TODO Auto-generated method stub

super.onActivityCreated(savedInstanceState);

initHandler();//初始化handler

initRecog();//初始化语音

initViews();

initDatas();

initEvents();

}/*** 设置宽度和高度值,以及打开的动画效果*/@Overridepublic voidonStart() {super.onStart();//设置对话框的宽高,必须在onStart中

DisplayMetrics metrics = newDisplayMetrics();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);

}

@Overridepublic voidonDismiss(DialogInterface dialog) {super.onDismiss(dialog);

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

destroyRecog();//销毁语音

}private voidinitViews() {

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 voidinitDatas() {

resultWordList= new ArrayList();

speechResultAdapter= null;//设置布局管理器

LinearLayoutManager linerLayoutManager = newLinearLayoutManager(getActivity());

result_list.setLayoutManager(linerLayoutManager);

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

/*startRecog();

showProgress();*/}private voidinitEvents() {//关闭图标的点击事件

img_close.setOnClickListener(newView.OnClickListener() {

@Overridepublic voidonClick(View v) {

dismiss();

}

});//按钮的点击事件

btn_start.setOnClickListener(newView.OnClickListener() {

@Overridepublic voidonClick(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: //引擎准备完毕。

caseIStatus.STATUS_SPEAKING:case IStatus.STATUS_FINISHED: //长语音情况

caseIStatus.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 voidshowProgress(){

loadProgressBar.setVisibility(View.VISIBLE);

tv_tishi.setVisibility(View.GONE);

result_list.setVisibility(View.GONE);

}/*** 显示文本提示区域,隐藏其他区域*/

private voidshowTishi(){

tv_tishi.setVisibility(View.VISIBLE);

loadProgressBar.setVisibility(View.GONE);

result_list.setVisibility(View.GONE);

}/*** 显示语音结果区域,隐藏其他区域*/

private voidshowListView(){

result_list.setVisibility(View.VISIBLE);

loadProgressBar.setVisibility(View.GONE);

tv_tishi.setVisibility(View.GONE);

}/**隐藏所有的区域【主要用于长语音】why*/

private voidhiddenAll(){

result_list.setVisibility(View.GONE);

loadProgressBar.setVisibility(View.GONE);

tv_tishi.setVisibility(View.GONE);

}//======================================语音相关代码==========================================

/*** 初始化handler*/

private voidinitHandler(){

handler= newHandler() {/*@param msg*/@Overridepublic voidhandleMessage(Message msg) {super.handleMessage(msg);

handleMsg(msg);

}

};

Logger.setHandler(handler);

}/*** 在onCreate中调用。初始化识别控制类MyRecognizer*/

protected voidinitRecog() {

StatusRecogListener listener= newMessageStatusRecogListener(handler);

myRecognizer= newMyRecognizer(mContext,listener);

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

}/*** 销毁时需要释放识别资源。*/

protected voiddestroyRecog() {

myRecognizer.release();

Log.i(TAG,"destroyRecog");

}/*** 开始录音,点击“开始”按钮后调用。*/

protected voidstartRecog() {

Map params = new LinkedHashMap();

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 voidstopRecog() {

myRecognizer.stop();

}/*** 开始录音后,取消这次录音。SDK会取消本次识别,回到原始状态。点击“取消”按钮后调用。*/

private voidcancelRecog() {

myRecognizer.cancel();

}protected voidhandleMsg(Message msg) {switch (msg.what) { //处理MessageStatusRecogListener中的状态回调

caseIStatus.STATUS_FINISHED://识别结束时候的调用【判断显示结果列表区域还是提示区域】

if (msg.arg2 == 1) {//解析json字符串

try{

JSONObject msgObj= newJSONObject(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= newJSONObject(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;caseIStatus.STATUS_NONE:caseIStatus.STATUS_READY:caseIStatus.STATUS_SPEAKING:caseIStatus.STATUS_RECOGNITION:

status=msg.what;

updateBtnTextByStatus();break;default:break;

}

}/**更改按钮的文本*/

private voidupdateBtnTextByStatus() {switch(status) {caseIStatus.STATUS_NONE:

btn_start.setText(BtnStartText);

btn_start.setEnabled(true);break;caseIStatus.STATUS_WAITING_READY:caseIStatus.STATUS_READY:caseIStatus.STATUS_SPEAKING:caseIStatus.STATUS_RECOGNITION:

btn_start.setText(BtnStopText);

btn_start.setEnabled(true);break;caseIStatus.STATUS_STOPPED:

btn_start.setText(BtnSearchingText);

btn_start.setEnabled(true);break;default:break;

}

}//========================================更改列表==========================

/**获取集合数据,并显示*/

private voidinitList(JSONArray wordList){//先清空

if(resultWordList.size() > 0){

resultWordList.clear();

}//再赋值

for(int i=0;i

String wordItem= "";try{

wordItem=wordList.getString(i);

}catch(JSONException e) {

e.printStackTrace();

}

resultWordList.add(wordItem);

}if(speechResultAdapter == null){//设置适配器

speechResultAdapter = newSpeechResultAdapter(getActivity(), resultWordList);

result_list.setAdapter(speechResultAdapter);//添加分割线//设置添加删除动画//调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局

result_list.setSelected(true);

}else{

speechResultAdapter.notifyDataSetChanged();

}

speechResultAdapter.setOnItemClickLitener(newSpeechResultAdapter.OnItemClickLitener() {

@Overridepublic void onItemClick(intposition) {

dismiss();if(mOnResultListItemClickListener != null){

mOnResultListItemClickListener.onItemClick(resultWordList.get(position));

}

}

});

}//=========================语音列表项的点击事件监听==============================

public static abstract interfaceOnResultListItemClickListener

{//语音结果列表项的点击事件接口

public abstract voidonItemClick(String title);

}privateOnResultListItemClickListener mOnResultListItemClickListener;public voidseOnResultListItemClickListener(OnResultListItemClickListener mOnResultListItemClickListener)

{this.mOnResultListItemClickListener =mOnResultListItemClickListener;

}

}

三、使用方法

(1)因为需要使用到运行时权限,所以参考《Android6.0运行时权限(基于RxPermission开源库)》在APP的build.gradle中引入第三方库

6383ac87c43bfb38cc3169ce229cff75.png

(2)在APP的build.gradle中引入baiduspeech

ece1b40da96c3020609e945bf3024eac.png

(3)在Activity中调用

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

activity_main.xml

packagecom.why.project.baiduspeechdemo;importandroid.Manifest;importandroid.os.Bundle;importandroid.support.v7.app.AppCompatActivity;importandroid.util.Log;importandroid.view.View;importandroid.widget.Button;importandroid.widget.TextView;importandroid.widget.Toast;importcom.tbruyelle.rxpermissions2.RxPermissions;importcom.why.project.baiduspeech.dialog.SpeechBottomSheetDialog;importcom.why.project.baiduspeech.dialog.SpeechLongBottomSheetDialog;importio.reactivex.functions.Action;importio.reactivex.functions.Consumer;public class MainActivity extendsAppCompatActivity {private static final String TAG = MainActivity.class.getSimpleName();privateButton mOpenSpeechDialogBtn;privateButton mOpenSpeechLongDialogBtn;privateTextView mResultTv;

@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

onePermission();

initViews();

initEvents();

}private voidinitViews() {

mOpenSpeechDialogBtn=findViewById(R.id.btn_openSpeechDialog);

mOpenSpeechLongDialogBtn=findViewById(R.id.btn_openSpeechLongDialog);

mResultTv=findViewById(R.id.tv_result);

}private voidinitEvents() {

mOpenSpeechDialogBtn.setOnClickListener(newView.OnClickListener() {

@Overridepublic voidonClick(View view) {//打开百度语音对话框

SpeechBottomSheetDialog speechBottomSheetDialog = SpeechBottomSheetDialog.getInstance(MainActivity.this);

speechBottomSheetDialog.seOnResultListItemClickListener(newSpeechBottomSheetDialog.OnResultListItemClickListener() {

@Overridepublic voidonItemClick(String title) {//填充到输入框中mResultTv.setText(title);

}

});

speechBottomSheetDialog.show(getSupportFragmentManager(), TAG);

}

});

mOpenSpeechLongDialogBtn.setOnClickListener(newView.OnClickListener() {

@Overridepublic voidonClick(View view) {//打开百度语音对话框

SpeechLongBottomSheetDialog speechLongBottomSheetDialog = SpeechLongBottomSheetDialog.getInstance(MainActivity.this);

speechLongBottomSheetDialog.seOnResultListItemClickListener(newSpeechLongBottomSheetDialog.OnResultListItemClickListener() {

@Overridepublic voidonItemClick(String title) {//填充到输入框中

mResultTv.setText(mResultTv.getText()+title);

}

});

speechLongBottomSheetDialog.show(getSupportFragmentManager(), TAG);

}

});

}/**只有一个运行时权限申请的情况*/

private voidonePermission(){

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() {

@Overridepublic void accept(Boolean granted) throwsException {

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() {

@Overridepublic void accept(Throwable throwable) throwsException {

Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理

}

},newAction() {

@Overridepublic void run() throwsException {

Log.e(TAG,"{run}");//执行顺序——2

}

});

}

}

混淆配置

#=====================百度语音混淆=====================

-keep class com.baidu.speech.**{*;}

参考资料

项目demo下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值