本地语音唤醒(Android)

一. 唤醒 SDK概述

Wakeup 提供单独的离线语音唤醒能力,通过不间断侦测语音,当出现唤醒词的语音时可执行相关事件的技术,具有功耗低、唤醒率高的特点。可以设置自定义唤醒词。

二. SDK使用说明

使用当前功能时,请先授权,否则禁止使用。请参考 授权说明

2.1 准备

  1. 在 DUI开发平台 上创建账号
  2. 创建 "单项技术" 的产品
  3. 在授权管理标签申请 apiKey,这样可获取产品 apiKey, productId,productKey, productSecret 
  4. 下载 DUI Lite SDK,可在 SDK下载页 或者 发布管理 页下载 SDK,SDK 包含 demo,javadoc,jar,so 以及相应的资源文件

 

 

三. 集成

DUI Lite SDK 包括 jar、JavaDoc 、so 动态库以及功能对应的资源。

DUI Lite SDK 支持 Android 4.0及以上系统,so 动态库目前支持 arm64-v8a, armeabi, armeabi-v7a, x86, x86_64,若需支持其它架构,请提工单申请。

3.1. 引入对应的jar 包 , DUI-lite-SDK-for-Android-xxx.jar

在gradle文件中添加对SDK的依赖

DUI Lite SDK依赖于okhttp网络库,所以在你的项目里需要依赖 okhttp
gradle

dependencies {
implementation files('libs/DUI-lite-SDK-for-Android-xxx.jar')
//dui lite sdk依赖于 okhttp 必须外部依赖或导入,否则报错
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
}

3.2. 引入对应的  libwakeup.so 库

3.3.引入对应的资源,可以放在assets目录中,也可以自己手动放在磁盘中,比如/sdcard/

 3.4 添加需要的权限

<!--获取手机录音机使用权限,识别、语义理解需要用到此权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 授权需要 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--保存文件需要用到此权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--保存文件需要用到此权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--云端功能需要用到此权限 -->
<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" />

targetSdkVersion 版本高于30,需要增加权限

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
 
if (Build.VERSION.SDK_INT >= 30) {
    if (!Environment.isExternalStorageManager()) {
        Intent intent = new Intent("android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION");
        startActivity(intent);
    }
}

 

四. 功能使用

详细使用示例请参考:sample 和 javaDoc 文档

4.1. init:实例化引擎 并 配置config 信息

 

/**
     * 初始化config信息,资源路径的设置共有以下两种方式
     * {@code
     * //方案一:设置唤醒资源在assets目录下的路径,包含文件名
     * config.setWakeupResource(SampleConstants.WAKEUP_RES);
     * //方案二:设置唤醒资源的绝对路径,包含文件名
     * config.setWakeupResource("/sdcard/aispeech/wakeup1.bin");}
     */
    private void initWakeupConfig() {
        AIWakeupConfig config = new AIWakeupConfig();
        config.setWakeupResource(SampleConstants.WAKEUP_RES); // SampleConstants.WAKEUP_RES
        mEngine.init(config, new AIWakeupListenerImpl());
    }

 

初始化配置说明请参考: AIWakeupConfig 文档,部分参数配置信息如下:

方法
方法说明
参数说明
默认值
备注
setWakeupResource(String wakeupResource) 设置唤醒资源

1. 如在 sd 里设置为绝对路径 如/sdcard/speech/***.bin

2. 如在 assets 里设置为名称

NA NA
setOneShotCacheTime(int oneShotCacheTime) 设置oneshot功能下需要缓存的音频时长,根据具体的硬件性能和唤醒词长度调节。 单位毫秒 1200ms NA

 

 

4.2. start: 配置intent 并开启唤醒

 

AIWakeupIntent intent = new AIWakeupIntent();
            // 设置唤醒词,支持中文拼音、英文
            intent.setWakeupWord(new String[]{"ni hao xiao chi"}, new float[]{0.1f});
            mEngine.start(intent);

 

intent 参数配置参考: AIWakeupIntent 文档,部分参数配置信息如下:

方法
方法说明
参数说明
默认值
备注
setWakeupWord(String[] pinyin, float[] threshold) 设置唤醒词列表

pinyin    唤醒词的拼音,建议三到五字,如:["ni hao xiao chi","xiao chi ni hao"]

threshold 阈值,0-1,可根据需求自行调整,如:[0.1f, 0.1f]

NA NA

 

4.3. 动态设置唤醒信息

 
/**
     * 动态设置唤醒信息,在engine.start之后调用
     * {@code
     * //方案一
     * mEngine.setDynamicParam(new String[]{"ni hao xiao chi"}, new float[]{0.2f});
     * //方案二
     * mEngine.setDynamicParam("words=ni hao xiao chi;thresh=0.2;");    // 效果同上}
     */
    private void setDynamicParam() {
        //注释中的代码为动态设置唤醒env(当前只支持更新thresh)
    }

 

AIWakeupEngine 方法说明参考: AIWakeupEngine 文档, 部分方法说明如下:

方法
方法说明
参数说明
默认值
备注
init(AIWakeupConfig config, AIWakeupListener listener) 初始化引擎

config :配置参数

listener:回调方法

NA NA
setDynamicParam(String[] pinyin, float[] thresh) 动态调整参数,目前只支持更新唤醒词的thresh

pinyin 唤醒词,必须在AIWakeupIntent设置过,参数示例:["ni hao xiao chi"]

thresh 唤醒词对应的阈值,参数示例:[0.2]

NA NA
feedData(byte[] data, int size) 自行feed音频数据,不使用内部录音机时可用

data 音频数据

size 音频数据大小

NA NA
start(AIWakeupIntent aiWakeupIntent) 开启唤醒,如果使用内部录音机的话一并开启 aiWakeupIntent 配置参数 NA NA
stop() 关闭唤醒,如果使用内部录音机的话一并关闭 NA NA NA
destroy() 销毁唤醒内核和录音机 NA NA NA

 

4.4.唤醒回调

回调详细说明请参考:AIWakeupListener 文档

private class AIWakeupListenerImpl implements AIWakeupListener {
 
        @Override
        public void onError(AIError error) {
            Log.e(TAG, "error " + error.toString());
            showTip(error.toString());
        }
 
        @Override
        public void onInit(final int status) {
            Log.i(TAG, "Init result " + status);
            if (status == AIConstant.OPT_SUCCESS) {
                resultText.append("初始化成功!");
                btnStart.setEnabled(true);
                btnStop.setEnabled(true);
            else {
                resultText.setText("初始化失败!code:" + status);
            }
        }
 
 
        @Override
        public void onWakeup(String recordId, final double confidence, final String wakeupWord) {
            Log.d(TAG, "wakeup foreground");
            resultText.append("\n唤醒成功  wakeupWord = " + wakeupWord + "  confidence = " + confidence
                    "\n");
            //在这里启动其他引擎,比如tts或者识别
        }
 
        @Override
        public void onPreWakeup(String recordId, double confidence, String wakeupWord) {
 
        }
 
        @Override
        public void onReadyForSpeech() {
            Log.d(TAG, "onReadyForSpeech");
        }
 
        @Override
        public void onResultDataReceived(byte[] buffer, int size, int wakeupType) {
 
        }
 
 
        @Override
        public void onResultDataReceived(byte[] buffer, int size) {
            Log.d(TAG, "onResultDataReceived " + size);
        }
 
        @Override
        public void onRawWakeupDataReceived(byte[] bytes, int size) {
            Log.d(TAG, "onRawWakeupDataReceived " + size);
        }
 
        @Override
        public void onOneshot(String word, OneshotCache<byte[]> buffer) {
 
        }
 
        @Override
        public void onNotOneshot(String word) {
 
        }
 
        @Override
        public void onRawDataReceived(byte[] buffer, int size) {
            //nothing to do
        }
 
        @Override
        public void onVprintCutDataReceived(int dataType, byte[] data, int size) {
            //nothing to do
        }
    }
 

4.5. 停止并销毁引擎

 

mEngine.stop();
mEngine.destroy();

请在合适的位置调用以上两个方法。

 
AIWakeupEngine mEngine;
mEngine = AIWakeupEngine.createInstance();
 
    /**
     * 初始化config信息,资源路径的设置共有以下两种方式
     * {@code
     * //方案一:设置唤醒资源在assets目录下的路径,包含文件名
     * config.setWakeupResource(SampleConstants.WAKEUP_RES);
     * //方案二:设置唤醒资源的绝对路径,包含文件名
     * config.setWakeupResource("/sdcard/aispeech/wakeup1.bin");}
     */
    private void initWakeupConfig() {
        AIWakeupConfig config = new AIWakeupConfig();
        config.setWakeupResource(SampleConstants.WAKEUP_RES); // SampleConstants.WAKEUP_RES
        mEngine.init(config, new AIWakeupListenerImpl());
    }
 
 
 AIWakeupIntent intent = new AIWakeupIntent();
            // 唤醒词支持 中文拼音、英文
            intent.setWakeupWord(new String[]{"ni hao xiao chi"}, new float[]{0.1f});
            intent.setDumpWakeupTime(3000);
            mEngine.start(intent);
             
     
     
             
 
    @Override
    public void onStop() {
        super.onStop();
        if (mEngine != null) {
            mEngine.stop();
        }
    }
 
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mEngine != null) {
            mEngine.destroy();
            mEngine = null;
        }
    }
 
    /**
     * 动态设置唤醒信息,在engine.start之后调用
     * {@code
     * //方案一
     * mEngine.setDynamicParam(new String[]{"ni hao xiao chi"}, new float[]{0.2f});
     * //方案二
     * mEngine.setDynamicParam("words=ni hao xiao chi;thresh=0.2;");    // 效果同上}
     */
    private void setDynamicParam() {
        //注释中的代码为动态设置唤醒env(当前只支持更新thresh)
    }
 
    private class AIWakeupListenerImpl implements AIWakeupListener {
 
        @Override
        public void onError(AIError error) {
            Log.e(TAG, "error " + error.toString());
            showTip(error.toString());
        }
 
        @Override
        public void onInit(final int status) {
            Log.i(TAG, "Init result " + status);
            if (status == AIConstant.OPT_SUCCESS) {
                resultText.append("初始化成功!");
                btnStart.setEnabled(true);
                btnStop.setEnabled(true);
            else {
                resultText.setText("初始化失败!code:" + status);
            }
        }
 
 
        @Override
        public void onWakeup(String recordId, final double confidence, final String wakeupWord) {
            Log.d(TAG, "wakeup foreground");
            resultText.append("\n唤醒成功  wakeupWord = " + wakeupWord + "  confidence = " + confidence
                    "\n");
            //在这里启动其他引擎,比如tts或者识别
        }
 
        @Override
        public void onPreWakeup(String recordId, double confidence, String wakeupWord) {
 
        }
 
        @Override
        public void onReadyForSpeech() {
            Log.d(TAG, "onReadyForSpeech");
        }
 
        @Override
        public void onResultDataReceived(byte[] buffer, int size, int wakeupType) {
 
        }
 
 
        @Override
        public void onResultDataReceived(byte[] buffer, int size) {
            Log.d(TAG, "onResultDataReceived " + size);
        }
 
        @Override
        public void onRawWakeupDataReceived(byte[] bytes, int size) {
            Log.d(TAG, "onRawWakeupDataReceived " + size);
        }
 
        @Override
        public void onOneshot(String word, OneshotCache<byte[]> buffer) {
 
        }
 
        @Override
        public void onNotOneshot(String word) {
 
        }
 
        @Override
        public void onRawDataReceived(byte[] buffer, int size) {
            //nothing to do
        }
 
        @Override
        public void onVprintCutDataReceived(int dataType, byte[] data, int size) {
            //nothing to do
        }
    }
}

五. 错误码

错误码

 

六. 接口文档

 

更多的接口内容与描述请参阅 javadoc