调用流程
DEMO在SDK的基础上,封装了输入和输出格式,您可以直接使用SDK,或者使用DEMO封装好SDK接口的类。
使用SDK方式的话,比较底层,需要自行实现一部分逻辑。可以参考DEMO中对SDK的调用封装。基于SDK集成和基于DEMO集成方式2选1即可。
在线识别调用流程
调用流程
SDK 的调用过程可以参见DEMO中的ActivityMiniRecog类
DEMO的调用过程可以参考DEMO中的ActivityAbstractRecog类
1 初始化
1.1 初始化EventManager对象
SDK中,通过工厂创建语音识别的事件管理器。注意识别事件管理器只能维持一个,请勿同时使用多个实例。即创建一个新的识别事件管理器后,之前的那个置为null,并不再使用。
EventManager asr = EventManagerFactory.create(this, "asr");
// this是Activity或其它Context类
详见ActivityMiniRecog类中”基于sdk集成1.1 初始化EventManager对象"
1.2 自定义输出事件类
SDK中,需要实现EventListener的输出事件回调接口。该类需要处理SDK在识别过程中的回调事件。可以参考DEMO中对SDK的调用封装。
EventListener yourListener = new EventListener() {
@Override
public void onEvent(String name, String params, byte [] data, int offset, int length) {
if(name.equals(SpeechConstant.CALLBACK_EVENT_ASR_READY)){
// 引擎就绪,可以说话,一般在收到此事件后通过UI通知用户可以说话了
}
if(name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)){
// 一句话的临时结果,最终结果及语义结果
}
// ... 支持的输出事件和事件支持的事件参数见“输入和输出参数”一节
}
};
详见ActivityMiniRecog类中”基于sdk集成1.2 自定义输出事件类"
1.3 注册自己的输出事件类
asr.registerListener(yourListener);
详见ActivityMiniRecog类中”基于sdk集成1.3 注册自己的输出事件类”
DEMO中,以上两步合并为
IRecogListener listener = new MessageStatusRecogListener(handler);
// 可以传入IRecogListener的实现类,也可以如SDK,传入EventListener实现类
//如果传入IRecogListener类,在RecogEventAdapter为您做了大多数的json解析。
MyRecognizer myRecognizer = new MyRecognizer(this, listener);
//this是Activity或其它Context类
详见ActivityAbstractRecog类中”基于DEMO集成第1.1, 1.2, 1.3 步骤 初始化EventManager类并注册自定义输出事件
2 开始识别
开始事件的参数可以参见"输入和输出参数"。
2.1 设置识别输入参数
SDK中,您需要根据文档或者demo确定您的输入参数。DEMO中有UI界面简化选择和测试过程。demo中,在点击“开始录音”按钮后,您可以在界面或者日志中看见ASR_START事件的json格式的参数。
// asr.params(反馈请带上此行日志):{"accept-audio-data":false,"disable-punctuation":false,"accept-audio-volume":true,"pid":1736}
//其中{"accept-audio-data":false,"disable-punctuation":false,"accept-audio-volume":true,"pid":1736}为ASR_START事件的参数
String json ="{\"accept-audio-data\":false,\"disable-punctuation\":false,\"accept-audio-volume\":true,\"pid\":1736}"
详见ActivityMiniRecog类中”基于SDK集成2.1 设置识别参数‘’
2.2 发送start开始事件
asr.send(SpeechConstant.ASR_START, json, null, 0, 0);
详见ActivityMiniRecog类中”基于SDK集成2.2 发送开始事件
DEMO中, 您需要传递Map<String,Object>的参数,会将Map自动序列化为json
Map<String, Object> params;
... // 设置识别参数
// params ="accept-audio-data":false,"disable-punctuation":false,"accept-audio-volume":true,"pid":1736
myRecognizer.start(params);
详见ActivityAbstractRecog类中"基于DEMO集成2.1, 2.2 设置识别参数并发送开始事件"
3 收到回调事件
3.1开始回调事件
回调事件在您实现的EventListener中获取。OnEvent方法中, name是输出事件名,params该事件的参数,(data,offset, length)三者一起组成额外数据。如回调的音频数据,从data[offset]开始至data[offset + length] 结束,长度为length。
public void onEvent(String name, String params, byte [] data, int offset, int length);
详见ActivityMiniRecog类中”基于SDK集成3.1 开始回调事件"
DEMO中, 回调事件在您实现的IRecogListener中获取。
详见RecogEventAdapter类中”基于DEMO集成3.1 开始回调事件"
4控制识别
4.1 控制停止识别
asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0);
//发送停止录音事件,提前结束录音等待识别结果
详见ActivityMiniRecog类中”基于SDK集成4.1 发送停止事件"
4.2 控制取消识别
asr.send(SpeechConstant.ASR_CANCEL, null, null, 0, 0);
//取消本次识别,取消后将立即停止不会返回识别结果
详见ActivityMiniRecog类中”基于SDK集成4.2 发送取消事件"
DEMO 中:
myRecognizer.stop();
// 发送停止录音事件,提前结束录音等待识别结果
详见ActivityAbstractRecog类中”基于DEMO集成4.1 发送停止事件"
myRecognizer.cancel();
// 取消本次识别,取消后将立即停止不会返回识别结果
详见ActivityAbstractRecog类中”基于DEMO集成4.2 发送取消事件"
5 事件管理器退出
5.1 在线不需要卸载离线命令词
先启动取消,避免有还在运行的识别。 之后需要将之前的listener卸载,不卸载的话,可能有内存溢出
asr.send(SpeechConstant.ASR_CANCEL, null, null, 0, 0); // 取消识别
5.2 释放资源
asr.unregisterListener(this);
详见ActivityMiniRecog类中基于SDK集成5.2 退出事件管理器"
DEMO中,
myRecognizer.release();
// 含有离线引擎卸载
详见ActivityAbstractRecog类中基于DEMO的5.2 退出事件管理器"
离线命令词调用流程
离线命令词的bsg文件设置:
在语音控制台的左侧功能栏中,进入“离线词&语义设置”模块,根据页面上的引导自行定义词条和语法,并生成bsg文件。其中右侧“说法”部分,为固定语法,下载后不可更改。左侧“词条”部分,代码中可以动态定义覆盖。
离线命令词功能可以测试DEMO中的第二个按钮“离线命令词识别”
调用流程:
离线命令词功能需要首先实现之前的在线识别功能的代码。离线引擎加载需要在EventManager初始化之后,识别事件之前。 在SDK中,
HashMap map = new HashMap();
map.put(SpeechConstant.DECODER, 2);
// 0:在线 2.离在线融合(在线优先)
map.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, "/sdcard/yourpath/baidu_speech_grammar.bsg");
//设置离线命令词文件路径
// 下面这段可选,用于生成SLOT_DATA参数, 用于动态覆盖ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH文件的词条部分
JSONObject json = new JSONObject();
json.put("name", new JSONArray().put("王自强").put("叶问")).put("appname", new
JSONArray().put("手百").put("度秘"));
map.put(SpeechConstant.SLOT_DATA, json.toString());
// SLOT_DATA 参数添加完毕
1.1 到1.3同在线
1.4 加载离线资源
asr.send(SpeechConstant.ASR_KWS_LOAD_ENGINE,new
JSONObject(map).toString());
//加载离线引擎,使用离线命令词时使用,请在整个离线识别任务结束之后卸载离线引擎
详见ActivityMiniRecog类中”基于SDK离线命令词1.4 加载离线资源(离线时使用)"
//离线引擎加载完毕事件后,开始你的识别流程,此处开始你的识别流程,注意离线必须断网生效或者SDK无法连接百度服务器时生效,只能识别bsg文件里定义的短语。
2.1-4.2 步骤同在线
5.1 卸载离线资源
//不再需要识别功能后,卸载离线引擎。再次需要识别功能的话,可以重复以上步骤。即依旧需要EventManager初始化之后,识别事件之前加载离线引擎。
asr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0);
详见ActivityMiniRecog类中”基于SDK集成5.1 卸载离线资源步骤(离线时使用)"
在demo中,
HashMap<String, Object> map = new HashMap<String, Object>();
map.put(SpeechConstant.DECODER, 2);
// 0:在线 2.离在线融合(在线优先)
map.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, "/sdcard/yourpath/baidu_speech_grammar.bsg");
//设置离线命令词文件路径
// 下面这段可选,用于生成SLOT_DATA参数, 用于动态覆盖ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH文件的词条部分
JSONObject json = new JSONObject();
json.put("name", new
JSONArray().put("王自强").put("叶问")).put("appname", new
JSONArray().put("手百").put("度秘"));
map.put(SpeechConstant.SLOT_DATA, json.toString());
// SLOT_DATA 参数添加完毕
myRecognizer.loadOfflineEngine(map);
//加载离线引擎,使用离线命令词时使用,请在整个离线识别任务结束之后卸载离线引擎
详见ActivityAbstractRecog类中”基于DEMO集成1.4 加载离线资源步骤(离线时使用)"
//离线引擎加载完毕事件后,开始你的识别流程,注意离线必须断网生效或者SDK无法连接百度服务器时生效,只能识别bsg文件里定义的短语。
//不再需要识别功能后,卸载离线引擎。再次需要识别功能的话,可以重复以上步骤, 新建MyRecognizer类即可。
myRecognizer.release();
详见ActivityAbstractRecog类中”基于DEMO5.1 卸载离线资源(离线时使用)"
唤醒词调用流程
SDK 的调用过程可以参见DEMO中的ActivityMiniWakeUp类
DEMO的调用过程可以参考DEMO中的ActivityWakeUp类
1 初始化
1.1 初始化EventManager对象
SDK中,通过工厂创建语音唤醒词的事件管理器。注意唤醒词事件管理器同识别事件管理器一样只能维持一个,请勿同时使用多个实例。即创建一个新的唤醒词事件管理器后,之前的那个设置为null。并不再使用。
EventManager wp= EventManagerFactory.create(this,"wp");
//this是Activity或其它Context类
详见ActivityMiniWakeUp类中”基于SDK唤醒词集成1.1 初始化EventManager"
1.2 自定义输出事件类
DEMO中,初始化过程合并到下一步。注意SDK和DEMO调用方式2选1即可。 注册用户自己实现的输出事件类
EventListener yourListener = new EventListener() {
@Override
public void onEvent(String name, String params, byte [] data, int
offset, int length) {
Log.d(TAG, String.format("event: name=%s, params=%s", name, params));
//唤醒事件
if(name.equals("wp.data")){
try {
JSONObject json = new JSONObject(params);
int errorCode = json.getInt("errorCode");
if(errorCode == 0){
//唤醒成功
} else {
//唤醒失败
}
} catch (JSONException e) {
e.printStackTrace();
}
} else if("wp.exit".equals(name)){
//唤醒已停止
}
}
};
详见ActivityMiniWakeUp类中”基于SDK唤醒词集成1.2 自定义输出事件类"
1.3 注册自己的输出事件类
wp.registerListener(yourListener);
详见ActivityMiniWakeUp类中”基于SDK唤醒词集成1.3 注册输出事件"
DEMO中,以上两步合并为
IWakeupListener listener = new SimpleWakeupListener();
myWakeup = new MyWakeup(this,listener);
// this是Activity或其它Context类
详见ActivityWakeUp类中”基于DEMO唤醒词集成第1.1, 1.2, 1.3步骤"
2 开始唤醒
2.1 设置唤醒输入参数
SDK中,您需要根据文档或者demo确定您的输入参数。DEMO中有UI界面简化选择和测试过程。demo中,在点击“开始”按钮后,您可以在界面或者日志中看见WAKEUP_START事件的json格式的参数。
wakeup.params(反馈请带上此行日志):{"kws-file":"assets:\/\/\/WakeUp.bin"} // 其中{"kws-file":"assets:\/\/\/WakeUp.bin"}为WAKEUP_START事件的参数
HashMap map = new HashMap();
map.put(SpeechConstant.WP_WORDS_FILE, "assets://WakeUp.bin");
详见ActivityMiniWakeUp类中”基于SDK唤醒词集成第2.1 设置唤醒的输入参数" 唤醒词文件请去http://ai.baidu.com/tech/speech/wake\#tech-demo设置并下载
2.2 发送start开始事件
wp.send(SpeechConstantWAKEUP_START, json, null, 0, 0);
详见ActivityMiniWakeUp类中”基于SDK唤醒词集成第2.2 发送开始事件开始唤醒"
DEMO中, 您需要传递Map 的参数,会将Map自动序列化为json
HashMap<String,Object> params = new
HashMap<String,Object>();
params.put(SpeechConstant.WP_WORDS_FILE, "assets://WakeUp.bin");
myWakeup.start(params);
详见ActivityWakeUp类中”基于DEMO唤醒词集成第2.1, 2.2 发送开始事件开始唤醒"
3 收到回调事件
3.1 开始回调事件
SDK中,回调事件在您实现的EventListener中获取。OnEvent中, name是输出事件名,params该事件的参数,(data,offset, length)三者一起组成额外数据。如回调的音频数据,从data[offset]开始至data[offset + length] 结束,长度为length。
public void onEvent(String name, String params, byte [] data, int offset, int length);
详见ActivityMiniWakeUp类中”基于SDK唤醒3.1 开始回调事件"
DEMO中, 回调事件在您实现的IWakeupListener中获取。
详见WakeupEventAdapter类中”基于DEMO唤醒3.1 开始回调事件"
4 控制唤醒
SDK中,
4.1 控制停止唤醒
wp.send(SpeechConstant.WAKEUP_STOP, null, null, 0, 0);
详见ActivityMiniWakeUp类中”基于SDK唤醒词集成第4.1 发送停止事件"
DEMO中,
myWakeup.stop();
详见ActivityWakeUp类中”基于DEMO唤醒词集成第4.1 发送停止事件"
5 事件管理器退出
SDK中无需调用任何逻辑,但需要创建一个新的唤醒词事件管理器的话,之前的事件管理器请设置为null,并不再使用。
DEMO中,
myWakeup.release();
详见ActivityWakeUp类中”基于DEMO唤醒词集成第5 退出事件管理器">
集成指南
- DEMO 中已经集成了 SDK。您可以参考DEMO,集成SDK。
- 集成前,请先测通DEMO,了解调用原理。
- 如果您自己代码过于复杂,可以使用一个helloworld项目了解集成过程。
- DEMO目录下的doc_integration_DOCUMENT的目录中有图文集成教程。
本文以Android Studio 作为示例
集成时请确认已经复制或者修改了以下文件,一共4步:
- AndroidManifest.xml 和 AuthUtil.java
- app/libs/bdasr_V3_xxxxx_xxxxx.jar
- app/src/main/jniLibs 下armeabi等5个目录
- 官网申请应用时的包名与build.gradle里一致,demo的包名是"com.baidu.speech.recognizerdemo"。这步没做会导致离线命令词或者唤醒报“no licence” 错误
- 运行时 getApplicationInfo().nativeLibraryDir 目录下查看是否有完整so文件。 特别是系统app需要手动push so文件到这个目录下。
AndroidManifest.xml 文件
- 设置权限
<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.WRITE_EXTERNAL_STORAGE" />
AuthUtil.java 文件
- 设置APP_ID, APP_KEY, SECRET_KEY
public static String getAppId(){
return "请填入您的appId";
}
public static String getAk(){
return "请填入您的apiKey";
}
public static String getSk(){
return "请填入您的secretKey";
}
也可以作为识别和唤醒的参数填入这3个鉴权信息。 AuthUtil工具类中填入自己的鉴权信息写方式仅供测试参考使用,上线后请使用APP_ID, APP_KEY, SECRET填写鉴权信息,建议代码里直接传入APP_ID, APP_KEY, SECRET,请参考在线识别具体功能参数- 鉴权信息部分,填写这3个鉴权信息。
android 6.0 以上版本权限申请
以下代码可以在demo中查找
/**
* android 6.0 以上需要动态申请权限
*/
private void initPermission() {
String permissions[] = {Manifest.permission.RECORD_AUDIO,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.INTERNET,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
ArrayList<String> toApplyList = new ArrayList<String>();
for (String perm :permissions){
if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, perm)) {
toApplyList.add(perm);
//进入到这里代表没有权限.
}
}
String tmpList[] = new String[toApplyList.size()];
if (!toApplyList.isEmpty()){
ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// 此处为android 6.0以上动态授权的回调,用户自行实现。
bdasr_V3_xxxxxxxx_xxxx.jar 库
将core/libs/bdasr_V3_xxxxx_xxxxx.jar 复制到您的项目的同名目录中。
复制NDK 架构目录
- 将 core/src/main/jniLibs 下armeabi等包含so文件的5个目录,复制合并到您的项目的同名或者存放so的目录中。如果build.gradle中定义过jniLibs.srcDirs ,则复制合并到这个目录。
- 如与第三方库集成,至少要保留armeabi目录。如第三方库有7个架构目录,比语音识别SDK多出2个目录 mips和mips64,请将mips和mips64目录删除,剩下5个同名目录合并。
- 如第三方库仅有armeabi这一个目录,请将语音识别SDK的额外4个目录如armeabi-v7a删除,合并armeabi目录下的so。 即目录取交集,so文件不可随意更改所属目录。
- 打包成apk文件,按照zip格式解压出libs目录可以验证。
- 运行时 getApplicationInfo().nativeLibraryDir 目录下查看是否有完整so文件。 特别是系统app需要手动push so文件到这个目录下。
build.gradle 文件及包名确认
- 根目录下build.gradle确认下gradle的版本。
- app/build.gradle 确认下 applicationId 包名是否与官网申请应用时相一致(离线功能需要)。 demo的包名是"com.baidu.speech.recognizerdemo"。
- 确认 compileSdkVersion buildToolsVersion 及 targetSdkVersion
proguard文件
-keep class com.baidu.speech.**{*;}
BEST PRACTICE
- 请先测通DEMO,了解DEMO的功能,代码的运行原理后再集成。DEMO有bug,请立即反馈。
- 对应任何第三方库,从一开始集成,边开发边测试,不要等所有功能都开发完再集成。否则一旦有问题,难以隔离排查。
- 有问题先与DEMO做对比。DEMO有bug,请查看错误码文档,如无法解决请立即反馈;DEMO无bug,自身代码有问题,请设置同样的输入参数后,对比两边代码及日志,自行排查问题。