前段时间写了一个关于百度语音唤醒文章,最近有做了一个讯飞语音的应用,在这里把学习的资料整理一下。
唤醒的整个过程如下:
(图源自讯飞官网)
讯飞的语音唤醒功能实现起来挺方便的(相比百度,百度语音Android端的语音唤醒是基于service实现的)百度语音唤醒识别效果对于不建议使用的唤醒词识别较差,而讯飞相对较容易。并且讯飞语音唤醒可以自己设定很多参数,来提高识别率,百度提供给用户的设置接口很少。俗话说“鱼和熊掌不可兼得”,一句话总结这两个平台就是——百度免费,讯飞收费。
大家可以根据自己项目的实际需求作抉择。
下面我们就言归正传:
我们先来讲一讲讯飞语音唤醒的参数设置。下面是讯飞官方文档的内容
唤醒业务类型,分为如下几种:
唤醒:wakeup;(单唤醒词,多唤醒词,或特定人唤醒)
注册:enroll;(特定人唤醒注册,又称为“训练”,用于特定人唤醒时,注册用户唤醒词)
唤醒识别:oneshot;
唤醒门限值:
格式:id:门限值;* (*代表可多个),根据资源携带的唤醒词个数按照“id:门限;id:门限” 的格式传入。门限值越高,则要求匹配度越高,才能唤醒。
是否必须设置:否
默认值:0
值范围:[-150, 150]
持续唤醒:
在持续唤醒时,唤醒一次后,当前会话依然继续,录音还在继续,当有匹配的唤醒 时,会返回结果;否则,唤醒一次后,当前会话已结束,录音也结束,不会再监听。
此参数对唤醒识别不起作用,见IVW_SST。
是否必须设置:否
默认值:0
值范围:{null, 0, 1}
唤醒资源路径:
唤醒需要使用本地资源,通过此参数设置本地资源所在的路径。多个资源间,以英文分号”;”分隔。 与IVW_ENROLL_RES_PATH一样,用于使用的资源,需要通过 ResourceUtil.generateResourcePath(Context, com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE, java.lang.String)生成标准的资源路径值。 请参考 ResourceUtil.generateResourcePath(Context, com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE, java.lang.String)。
是否必须设置:是(在非注册时)
默认值:null
值范围:有效的资源文件路径
引擎类型:
设置使用的引擎类型:在线、离线、混合。在申请了离线合成资源和权限, 或使用语记方式时,可以选择使用本地或在线的方式进行语音服务。使用在线模式(又称云端模式)时,需要使用网络,产生一定流量,但有更好的识别 或合成的效果,如更高的识别匹配度,更多的发音人等。使用离线模式(又称本地模式)时,不需要使用网络,且识别和合成的速度更快,但同 时要求使用对应的离线资源或安装“语记”(安卓或iOS平台)。在混合模式时,可以通过混合类型、 云端超时、本地置信门限 使用对应的策略,提高识别准确度与成功率。详情参见前面的几个参数说明。
在离线或混合模式下,需要设置对应的资源。请参考
合成资源路径:ResourceUtil.TTS_RES_PATH;
识别资源路径:ResourceUtil.ASR_RES_PATH;
唤醒资源路径:IVW_RES_PATH;
关于离线资源的其他介绍,参考ResourceUtil类的说明。
是否必须设置:否
默认值:”cloud”
值范围:{ “cloud”, “local”,”mixed” }
讯飞 语音唤醒实现起来相当简单,具体步骤如下
首先需要去讯飞开放平台申请一个账号,之后注册一个自己的应用,这里我们以Android端为例来说明。对于第一次使用讯飞语音的人,首先先要创建一个应用
大家可以根据自己的实际需求开通相应的服务。
这里大家一定要记住Appid很重要,这就相当于你应用的身份证号码。
我们下载的SDK正常情况下为
assets文件夹下面主要是讯飞语音的一些界面图标,如果你需要使用讯飞的语音输入界面,可以将这个文件夹下面的内容拷贝到你相应的Android工程目录下。doc下面为文档libs下面使我们需要的.so文件和jar文件,libs下面有不同cpu下的so文件,不同的cpu平台需要不同的so文件,这里面的so文件是使用c/c++写的,根据需求自己选择,并将相应的文件拷贝到自己的Android工程对应的目录下。如果Android工程中没有libs目录,需要我们自己创建一个目录。res下面是一些讯飞语音的资源文件,需要将这些文件拷贝到自己Android工程的assets文件中,res中的ivw文件为唤醒词的资源文件。sample文件是一个demo工程,大家可以参考demo完成自己的功能需求。
代码实现之前我们还需要添加一些权限,Android6.0以及之后的版本需要动态申请权限,这里大家自行学习,我不在赘述。
在AndroidManifest.xml文件中添加如下权限
<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.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" />
在代码实现过程中,首先我们需要初始化讯飞语音,代码如下:
/**
* 初始化讯飞语音
*/
private void initializeIflytek()
{
StringBuffer param = new StringBuffer();
//IflytekAPP_id为我们申请的Appid
param.append("appid="+getString(R.string.IflytekAPP_id));
param.append(",");
// 设置使用v5+
param.append(SpeechConstant.ENGINE_MODE+"="+SpeechConstant.MODE_MSC);
SpeechUtility.createUtility(DWEApplication.this, param.toString());
}
初始化最好放在APP初始化阶段,也就是所继承Application类,然后把讯飞初始化的内容放到该类里面。
前面说的内容适合于讯飞的所有语音产品,下面我讲给出讯飞语音唤醒的代码实现。
import org.json.JSONException;
import org.json.JSONObject;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.VoiceWakeuper;
import com.iflytek.cloud.WakeuperListener;
import com.iflytek.cloud.WakeuperResult;
import com.iflytek.cloud.util.ResourceUtil;
import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
/**
* 讯飞语音唤醒
* @author Administrator
*
*/
public class IflytekWakeUp {
private Context mContext;
//唤醒的阈值,就相当于门限值,当用户输入的语音的置信度大于这一个值的时候,才被认定为成功唤醒。
private int curThresh = 10;
//是否持续唤醒
private String keep_alive = "1";
/**
* 闭环优化网络模式有三种:
* 模式0:关闭闭环优化功能
*
* 模式1:开启闭环优化功能,允许上传优化数据。需开发者自行管理优化资源。
* sdk提供相应的查询和下载接口,请开发者参考API文档,具体使用请参考本示例
* queryResource及downloadResource方法;
*
* 模式2:开启闭环优化功能,允许上传优化数据及启动唤醒时进行资源查询下载;
* 本示例为方便开发者使用仅展示模式0和模式2;
*/
private String ivwNetMode = "0";
// 语音唤醒对象
private VoiceWakeuper mIvw;
//存储唤醒词的ID
private String wordID = "";
public IflytekWakeUp(Context context)
{
this.mContext = context;
// 初始化唤醒对象
mIvw = VoiceWakeuper.createWakeuper(mContext, null);
}
/**
* 开启唤醒功能
*/
public void startWakeuper()
{
//非空判断,防止因空指针使程序崩溃
mIvw = VoiceWakeuper.getWakeuper();
if(mIvw != null) {
// 清空参数
mIvw.setParameter(SpeechConstant.PARAMS, null);
// 唤醒门限值,根据资源携带的唤醒词个数按照“id:门限;id:门限”的格式传入
mIvw.setParameter(SpeechConstant.IVW_THRESHOLD, "0:"+ curThresh);
// 设置唤醒模式
mIvw.setParameter(SpeechConstant.IVW_SST, "wakeup");
// 设置持续进行唤醒
mIvw.setParameter(SpeechConstant.KEEP_ALIVE, keep_alive);
// 设置闭环优化网络模式
mIvw.setParameter(SpeechConstant.IVW_NET_MODE, ivwNetMode);
// 设置唤醒资源路径
mIvw.setParameter(SpeechConstant.IVW_RES_PATH, getResource());
// 设置唤醒录音保存路径,保存最近一分钟的音频
mIvw.setParameter( SpeechConstant.IVW_AUDIO_PATH, Environment.getExternalStorageDirectory().getPath()+"/msc/ivw.wav" );
mIvw.setParameter( SpeechConstant.AUDIO_FORMAT, "wav" );
// 如有需要,设置 NOTIFY_RECORD_DATA 以实时通过 onEvent 返回录音音频流字节
//mIvw.setParameter( SpeechConstant.NOTIFY_RECORD_DATA, "1" );
// 启动唤醒
mIvw.startListening(new MyWakeuperListener());
}
}
/**
* 获取唤醒词功能
* @return 返回文件位置
*/
private String getResource() {
final String resPath = ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "ivw/"+mContext.getString(R.string.IflytekAPP_id)+".jet");
return resPath;
}
/**
* 销毁唤醒功能
*/
public void destroyWakeuper()
{
// 销毁合成对象
mIvw = VoiceWakeuper.getWakeuper();
if (mIvw != null) {
mIvw.destroy();
}
}
/**
* 停止唤醒
*/
public void stopWakeuper()
{
mIvw.stopListening();
}
/**
* 唤醒词监听类
* @author Administrator
*
*/
private class MyWakeuperListener implements WakeuperListener
{
//开始说话
@Override
public void onBeginOfSpeech() {
}
//错误码返回
@Override
public void onError(SpeechError arg0) {
}
@Override
public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
}
@Override
public void onResult(WakeuperResult result) {
if(!"1".equalsIgnoreCase(keep_alive)) {
//setRadioEnable(true);
}
try {
String text = result.getResultString();
JSONObject object;
object = new JSONObject(text);
StringBuffer buffer = new StringBuffer();
buffer.append("【RAW】 "+text);
buffer.append("\n");
buffer.append("【操作类型】"+ object.optString("sst"));
buffer.append("\n");
buffer.append("【唤醒词id】"+ object.optString("id"));
buffer.append("\n");
buffer.append("【得分】" + object.optString("score"));
buffer.append("\n");
buffer.append("【前端点】" + object.optString("bos"));
buffer.append("\n");
buffer.append("【尾端点】" + object.optString("eos"));
resultString =buffer.toString();
} catch (JSONException e) {
e.printStackTrace();
}
/**
*声音改变回调
*/
@Override
public void onVolumeChanged(int arg0) {
}
}
}
讯飞语音唤醒大体实现过程就是如上所述,其他功能也类似。我这里知识简单的实现了一下,语音唤醒里面还有其他方法,我把文档截图放在这里,大几可以参考一下。
原创文章不容易,转载请注明出处!!Thank you!
(昨天晚上写到凌晨,今天总算把后面的内容写完了,这样一来总算把国内做语音唤醒的比较好的平台介绍完了,今天放五一假,是不是应该出去走走呢?)