版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
上一篇集成的是V3.0.7.3版本的SDK《》,这次发现官网的SDK进行了升级,感觉有必要进行重新集成。
1、修复了APP同时集成多个SDK,不能同时使用的问题;——所以需要使用新sdk的jar文件;
2、既然官网也使用了module方式;——那么就不需要自己创建module了,直接在官网的core这个module中优化;
3、修复长语音无结束回调;——增加长语音结束回调的监听;
本Demo中使用的appkey已失效,请自行创建应用,使用新的appkey。
效果图
和《》类似,这里就不单独截图了。
代码分析
普通话 search搜索模型:参考SpeechBottomSheetDialog.java类
普通话 input输入法模型,适用于长句及长语音,有逗号分割,无语义:参考SpeechLongBottomSheetDialog.java类
注意:关于语音识别状态维护,API调用的代码,是自己根据官网demo的理解进行整理的,可能有所偏颇,仅供参考。【希望官网demo可以添加百度APP的语音对话框效果就好了】
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
(1)在项目中导入官网demo中的core这个module,同时修改名称,修改为baiduspeech
(2)修改baiduspeech的AndroidManifest.xml(修改官网申请的应用信息)
(3)修改MessageStatusRecogListener.java文件【根据实际情况进行修改】
package com.baidu.aip.asrwakeup3.core.recog.listener;import android.os.Handler;import android.os.Message;import android.util.Log;import com.baidu.aip.asrwakeup3.core.recog.RecogResult;import com.baidu.speech.asr.SpeechConstant;/** * Created by fujiayi on 2017/6/16. */public class MessageStatusRecogListener extends StatusRecogListener { private Handler handler; private long speechEndTime = 0; private boolean needTime = true; private static final String TAG = "MesStatusRecogListener"; public MessageStatusRecogListener(Handler handler) { this.handler = handler; } @Override public void onAsrReady() { super.onAsrReady(); speechEndTime = 0; sendStatusMessage(SpeechConstant.CALLBACK_EVENT_WAKEUP_READY, "引擎就绪,可以开始说话。"); } @Override public void onAsrBegin() { super.onAsrBegin(); sendStatusMessage(SpeechConstant.CALLBACK_EVENT_ASR_BEGIN, "检测到用户说话"); } @Override public void onAsrEnd() { super.onAsrEnd(); speechEndTime = System.currentTimeMillis(); sendMessage("【asr.end事件】检测到用户说话结束"); } @Override public void onAsrPartialResult(String[] results, RecogResult recogResult) { sendStatusMessage(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL, "临时识别结果,结果是“" + 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(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL, message + ";原始json:" + recogResult.getOrigalJson()); if (speechEndTime > 0) { long currentTime = System.currentTimeMillis(); long diffTime = currentTime - speechEndTime; //message += ";说话结束到识别结束耗时【" + diffTime + "ms】";// why 实际中可以去掉,不需要 } speechEndTime = 0; sendMessage(message, status, true); } @Override public void onAsrFinishError(int errorCode, int subErrorCode, String descMessage, RecogResult recogResult) { super.onAsrFinishError(errorCode, subErrorCode, 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(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL, message); 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(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL, "原始语义识别结果json:" + nluResult); } } @Override public void onAsrFinish(RecogResult recogResult) { super.onAsrFinish(recogResult); sendStatusMessage(SpeechConstant.CALLBACK_EVENT_ASR_FINISH, "识别一段话结束。如果是长语音的情况会继续识别下段话。"); } /** * 长语音识别结束 */ @Override public void onAsrLongFinish() { super.onAsrLongFinish(); sendStatusMessage(SpeechConstant.CALLBACK_EVENT_ASR_LONG_SPEECH, "长语音识别结束。"); } /** * 使用离线命令词时,有该回调说明离线语法资源加载成功 */ @Override public void onOfflineLoaded() { sendStatusMessage(SpeechConstant.CALLBACK_EVENT_ASR_LOADED, "离线资源加载成功。没有此回调可能离线语法功能不能使用。"); } /** * 使用离线命令词时,有该回调说明离线语法资源加载成功 */ @Override public void onOfflineUnLoaded() { sendStatusMessage(SpeechConstant.CALLBACK_EVENT_ASR_UNLOADED, "离线资源卸载成功。"); } @Override public void onAsrExit() { super.onAsrExit(); sendStatusMessage(SpeechConstant.CALLBACK_EVENT_ASR_EXIT, "识别引擎结束并空闲中"); } private void sendStatusMessage(String eventName, String message) { message = "[" + eventName + "]" + 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中了,下一步就是创建UI对话框(建议再单独创建一个新的module)。
(4)新建baiduspeechdialog这个module
1、在baiduspeechdialog的build.gradle中引用recyclerview【版本号和项目的appcompat保持一致】【因为demo中用到了】【注意:还需要导入baiduspeech这个module】
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(include: ['*.jar'], dir: 'libs') 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' //baiduspeech implementation project(':baiduspeech')}
2、对话框类、列表适配器类、布局文件xml文件、图片资源、动画style样式等复制到baiduspeechdialog中【参考《》】
3、SpeechBottomSheetDialog.java和SpeechLongBottomSheetDialog.java在V3.0.7.3版本和V3.0.8.1版本的区别
3.1、需要将Logger修改为MyLogger
修改为:
三、使用方法
(1)因为需要使用到运行时权限,所以参考《》在APP的build.gradle中引入第三方库
(2)在APP的build.gradle中引入baiduspeechdialog
(3)在Activity中调用
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.baiduspeechdialog.dialog.SpeechBottomSheetDialog;import com.why.project.baiduspeechdialog.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() { @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 () { @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 } }); }}
混淆配置
#=====================百度语音混淆=====================-keep class com.baidu.speech.**{*;}