Android 讯飞语音听写SDK快速接入(附空指针解决和修改对话框文字方法)
1、账号准备工作
首先要有一个讯飞的账号啦,为后面申请appid、appkey等东西做准备。顺带一提:讯飞对不同认证类型用户开
放的sdk的使用次数是有不同的,详情如下图。
账号申请完成后,需要去你自己的注册你的应用,同时也可以看到你的应用对应的 appid 等属性,开通的功能,调用量剩余次数等信息。
本文介绍的是android sdk的接入,这是android sdk的下载地址,可以根据项目的具体需求具体分析。
2、sdk集成准备工作
如果参照官方文档中或者官方demo的做法,需要把对应架构的文件拷贝到 android工程的libs目录下 。
而官方提供的demo中,它只拷贝了armeabi-v7a架构。如下图所示(我信了它的邪,在我第一次接入时,就因为参考了官方demo只导入了armeabi-v7a架构,导致出了一大堆毛病?)
为了避免这个坑,我的建议是:把提供的架构都拷贝到工程里。(有特殊设备需求的除外)
然后在build.gradle文件中,添加sdk的依赖
implementation files('libs/msc.jar')
如果将sdk导入到lib文件夹后,可能还会有无法识别的错误。
可以试下在build.gradle(app)中注释掉以下的代码(玄学操作~~),再继续排查。
// ndk { // //选择要添加的对应cpu类型的.so库。 // abifilters 'armeabi-v7a', 'armeabi' // } // sourcesets { // main{ // jnilibs.srcdirs = ['libs'] // } // }
3、在 androidmanifest.xml 文件 添加所需权限
静态添加权限部分,参考了官方文档的说法。
<!--连接网络权限,用于执行云端语音能力 --> <uses-permission android:name="android.permission.internet"/> <!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 --> <uses-permission android:name="android.permission.record_audio"/> <!--读取网络信息状态 --> <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.read_contacts"/> <!--外存储写权限,构建语法需要用到此权限 --> <uses-permission android:name="android.permission.write_external_storage"/> <!--外存储读权限,构建语法需要用到此权限 --> <uses-permission android:name="android.permission.read_external_storage"/> <!--配置权限,用来记录应用配置信息 --> <uses-permission android:name="android.permission.write_settings"/> <!--手机定位信息,用来为语义等功能提供定位,提供更精准的服务--> <!--定位信息是敏感信息,可通过setting.setlocationenable(false)关闭定位请求 --> <uses-permission android:name="android.permission.access_fine_location"/> <!--如需使用人脸识别,还要添加:摄相头权限,拍照需要用到 --> <uses-permission android:name="android.permission.camera" />
不过,静态申请了权限,还不够哦。对于现在的手机,很大部分都已经是android版本678910的了,应用是需要动态申请权限的,得让用户确认同意了,app才可以使用这些权限。
动态申请权限的方法有很多,也有很多开源的项目,这里就不做介绍了。
4、sdk初始化
sdk初始化建议放在程序入口处(如application、activity的oncreate方法),非常简单,就一行语句。
初始化代码如下:
//将“1234567”替换成您申请的appid speechutility.createutility(context, speechconstant.appid +"=1234567");
注意:speechconstant.appid +"=1234567" 采用的是拼接的方式,所以不可以在“=”与appid之间添加任何空字符或者转义符。
5、调用语音听写功能
最重要的来了,前面铺垫这么久,就是为了能调用它的语音听写啊。
离线听写方式,需要购买且下载特定的离线识别sdk,故这里使用的是在线听写。
在线听写的sdk,提供了两种识别方式,分别是带语音对话框识别和无ui识别。
一.无ui识别
//初始化识别无ui识别对象 //使用speechrecognizer对象,可根据回调消息自定义界面--自己的语音识别ui miat = speechrecognizer.createrecognizer(iatdemo.this, minitlistener); //设置语法id和 subject 为空,以免因之前有语法调用而设置了此参数;或直接清空所有参数,具体可参考 demo 的示例。 miat.setparameter( speechconstant.cloud_grammar, null ); miat.setparameter( speechconstant.subject, null ); //设置返回结果格式,目前支持json,xml以及plain 三种格式,其中plain为纯听写文本内容 miat.setparameter(speechconstant.result_type, "json"); //此处enginetype为“cloud” miat.setparameter( speechconstant.engine_type, enginetype ); //设置语音输入语言,zh_cn为简体中文 miat.setparameter(speechconstant.language, "zh_cn"); //设置结果返回语言 miat.setparameter(speechconstant.accent, "mandarin"); // 设置语音前端点:静音超时时间,单位ms,即用户多长时间不说话则当做超时处理 //取值范围{1000~10000} miat.setparameter(speechconstant.vad_bos, "4000"); //设置语音后端点:后端点静音检测时间,单位ms,即用户停止说话多长时间内即认为不再输入, //自动停止录音,范围{0~10000} miat.setparameter(speechconstant.vad_eos, "1000"); //设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点 miat.setparameter(speechconstant.asr_ptt,"1"); //开始识别,并设置监听器 miat.startlistening(mrecoglistener);
二.带语音对话框识别(sdk自带)
// 初始化听写dialog,如果只使用有ui听写功能,无需创建speechrecognizer // 使用ui听写功能,请根据sdk文件目录下的notice.txt,放置布局文件和图片资源 miatdialog = new recognizerdialog(iatdemo.this, minitlistener); //以下为dialog设置听写参数 miatdialog.setparameter(speechconstant.result_type, "json"); //设置语音输入语言,zh_cn为简体中文 miatdialog.setparameter(speechconstant.language, "zh_cn"); //设置结果返回语言 miatdialog.setparameter(speechconstant.accent, "mandarin"); // 设置语音前端点:静音超时时间,单位ms,即用户多长时间不说话则当做超时处理 //取值范围{1000~10000} miatdialog.setparameter(speechconstant.vad_bos, "4500"); //设置语音后端点:后端点静音检测时间,单位ms,即用户停止说话多长时间内即认为不再输入, //自动停止录音,范围{0~10000} miatdialog.setparameter(speechconstant.vad_eos, "1500"); //开始识别并设置监听器 miatdialog.setlistener(mrecognizerdialoglistener); //开始识别并设置语音ui监听器 miatdialog.setlistener(mrecognizerdialoglistener); //显示听写对话框,show方法实际是内部调用无ui识别方式 miatdialog.show();
重点来了,也是很多人很困扰的一步,官方文档的说法是使用这个sdk自带的语音识别对话框,需要把对应的布局文件和图片资源放入工程中。然而,很多人这样做了之后, miatdialog.show();
调用了还是会出现空指针的异常。。例如:?
java.lang.nullpointerexception at com.iflytek.cloud.ui.a.a(unknown source) at com.iflytek.cloud.ui.recognizerdialog.setparameter(unknown source) atcom.example.mediaplayer.activity.searchactivity.setparam(searchactivity.java:111) at com.example.mediaplayer.activity.searchactivity.onclick(searchactivity.java:86) at android.view.view.performclick(view.java:4438) at android.view.view$performclick.run(view.java:18422) at android.os.handler.handlecallback(handler.java:733) at android.os.handler.dispatchmessage(handler.java:95) at android.os.looper.loop(looper.java:136) at android.app.activitythread.main(activitythread.java:5045) at java.lang.reflect.method.invokenative(native method) at java.lang.reflect.method.invoke(method.java:515) at com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:779) at com.android.internal.os.zygoteinit.main(zygoteinit.java:595) at dalvik.system.nativestart.main(native method)
解决方法,如下:
首先,在asset文件内,放入所需的资源。注意:asset文件夹的位置,是要在src/main/
的下一级,然后在与
asset文件夹同级的地方创建 jnilibs
文件夹,把 libs
/文件夹的对应sdk文件拷贝到 jnilibs
中,如图:
同时检查下,sdk初始化的 appid 有无出错的可能。
获取数据
解决了空指针的问题后,接下来调用 show 方法,就可以在自定义的监听器里愉快地获取到返回的听写数据了
//创建语音识别ui对话框 miatdialog = new recognizerdialog(getactivity(), searchviewmodel.minitlistener); /** * 初始化听写事件监听器。 */ public initlistener minitlistener = new initlistener() { @override public void oninit(int code) { if (code != errorcode.success) { //todo } } }; /** * 听写ui监听器 讯飞 */ public recognizerdialoglistener mrecognizerdialoglistener = new recognizerdialoglistener() { /** * 接收语音听写回调信息 * @param recognizerresult 回调结果 * @param b 是否翻译 */ @override public void onresult(com.iflytek.cloud.recognizerresult recognizerresult, boolean b) { //返回的数据 string data = recognizerresult.getresultstring(); } /** * 识别回调错误. */ public void onerror(speecherror error) { if(error.geterrorcode() == 14002) { //todo } else { //todo } } };
修改默认对话框的文字
//动态更换了讯飞自带对话框的底部文字,必须在dialog的show执行后更换,否则空指针报错 textview recorderdialogtextview = (textview) miatdialog.getwindow().getdecorview().findviewwithtag("textlink"); recorderdialogtextview.settext(r.string.recorder_dialog_textview_text);
返回的听写数据实例,用于创建实体类:
{ "sn": 1, "ls": true, "bg": 0, "ed": 0, "ws": [ { "bg": 0, "cw": [ { "w": "今天", "sc": 0 } ] }, { "bg": 0, "cw": [ { "w": "的", "sc": 0 } ] }, { "bg": 0, "cw": [ { "w": "天气", "sc": 0 } ] }, { "bg": 0, "cw": [ { "w": "怎么样", "sc": 0 } ] }, { "bg": 0, "cw": [ { "w": "。", "sc": 0 } ] } ] }
注意:若在sdk中开通了 动态修正的功能,返回的数据会出现格式不一致的情况。官方的说法如下:
动态修正:
- 未开启动态修正:实时返回识别结果,每次返回的结果都是对之前结果的追加;
- 开启动态修正:实时返回识别结果,每次返回的结果有可能是对之前结果的的追加,也有可能是要替换之前某次返回的结果(即修正);
- 开启动态修正,相较于未开启,返回结果的颗粒度更小,视觉冲击效果更佳;
- 使用动态修正功能需到控制台-流式听写-高级功能处点击开通,并设置相应参数方可使用,参数设置方法:miat.setparameter(“dwa”, “wpgs”); ;
- 动态修正功能仅 中文 支持;
- 未开启与开启返回的结果格式不同,详见下方;
若开通了动态修正功能并设置了dwa=wpgs(仅中文支持),会有如下字段返回:
参数 | 类型 | 描述 |
---|---|---|
pgs | string | 开启wpgs会有此字段 取值为 “apd"时表示该片结果是追加到前面的最终结果;取值为"rpl” 时表示替换前面的部分结果,替换范围为rg字段 |
rg | array | 替换范围,开启wpgs会有此字段 假设值为[2,5],则代表要替换的是第2次到第5次返回的结果 |
ps:一般项目中的语音听写需求,完全可以不使用动态修正功能,但若要使用同步显示语音识别结果或者比较需要比较精准的结果,可以考虑使用此功能。
总结
讯飞语音听写sdk,坑点不少,但是都不是很难,还是适项目快速接入语音听写需求的。。?
如果要更多操作和功能,请参考讯飞语音听写sdk官方文档
上一篇: 超雷人女儿,老爸爆囧
下一篇: 用 Hystrix 构建高可用服务架构