Android——讯飞语音唤醒简介及实现

前段时间写了一个关于百度语音唤醒文章,最近有做了一个讯飞语音的应用,在这里把学习的资料整理一下。
唤醒的整个过程如下:
这里写图片描述(图源自讯飞官网)
讯飞的语音唤醒功能实现起来挺方便的(相比百度,百度语音Android端的语音唤醒是基于service实现的)百度语音唤醒识别效果对于不建议使用的唤醒词识别较差,而讯飞相对较容易。并且讯飞语音唤醒可以自己设定很多参数,来提高识别率,百度提供给用户的设置接口很少。俗话说“鱼和熊掌不可兼得”,一句话总结这两个平台就是——百度免费,讯飞收费。
Android——讯飞语音唤醒简介及实现_第1张图片
Android——讯飞语音唤醒简介及实现_第2张图片
大家可以根据自己项目的实际需求作抉择。
下面我们就言归正传:
我们先来讲一讲讯飞语音唤醒的参数设置。下面是讯飞官方文档的内容Android——讯飞语音唤醒简介及实现_第3张图片
唤醒业务类型,分为如下几种:
唤醒: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端为例来说明。对于第一次使用讯飞语音的人,首先先要创建一个应用
Android——讯飞语音唤醒简介及实现_第4张图片

  • 开通服务

大家可以根据自己的实际需求开通相应的服务。
Android——讯飞语音唤醒简介及实现_第5张图片
这里大家一定要记住Appid很重要,这就相当于你应用的身份证号码。

  • 下载SDK

下载分为组合下载和单个服务SDK下载
Android——讯飞语音唤醒简介及实现_第6张图片

  • 文件拷贝

我们下载的SDK正常情况下为
Android——讯飞语音唤醒简介及实现_第7张图片
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) {

        }
    }
}

讯飞语音唤醒大体实现过程就是如上所述,其他功能也类似。我这里知识简单的实现了一下,语音唤醒里面还有其他方法,我把文档截图放在这里,大几可以参考一下。
Android——讯飞语音唤醒简介及实现_第8张图片
Android——讯飞语音唤醒简介及实现_第9张图片

原创文章不容易,转载请注明出处!!Thank you!

(昨天晚上写到凌晨,今天总算把后面的内容写完了,这样一来总算把国内做语音唤醒的比较好的平台介绍完了,今天放五一假,是不是应该出去走走呢?)

你可能感兴趣的:(移动开发)