1. Rokid语音SDK使用文档

1.1. 目录

1.2. 一、概述

RokidAiSdk 集合前端算法Turen相关功能,通过speech、云端来进行语音语义识别,并返回处理信息给三方开发者,附带Rokid的TTS功能,同时适用于Rokid外置语音Kenobi方案。 面向Android 软件开发工程师, 提供aar形式的SDK,简化接入流程,适应单独apk形式的集成,更方便用户接入Rokid AI语音技术。 RokidAiSdk 是语音技能全链路解决方案的核心引擎,用户接收到nlp数据,可以选择继续集成Rokid云端技能方案(RokidAiSkillEngine、RokidAiCloudApp)、本地技能方案(RokidLocalSkillSdk),打造一款完美的智能语音交互体验设备。

1.3. 二、集成准备

1.3.1. 2.1 开发者账号注册

Rokid 有自己的开发者账号、社区体系,使用Rokid的技术需要在Rokid开放平台的注册开发者账号,同时可以获取相关技术支持。

1.3.2. 2.2 设备注册

Rokid 语音技术需要硬件设备做承接,相关的硬件信息同时也需要在Rokid开发者网站上进行产品报备。在Rokid开放平台的控制台的语音接入中,创建对应的产品,Rokid后台会自动生成KeySecretdeviceTypeId,同时会为每个设备预生成10个测试用的deviceId(sn)seed,这些信息会被组合起来做授权认证,保证语音SDK正常初始化。

1.3.3. 2.3 SDK获取

1、可以从Rokid开放平台开放平台获取,注册相应类型设备的同时,会生成相应的SDK,供开发者下载。参考产品创建及Sn导入

2、从参考Demo程序获取最新SDK:https://github.com/Rokid/RokidAiSdkDemo (最新版本1.4.3)

1.4. 三、集成说明

1.4.1. 3.1 硬件及系统环境

1、Android方案:

  • 带麦克风的Android 系统机器一台,系统Android 6.0及以上;
  • 完全使用Android的AudioRecord录音,只支持单路或双路数据。

2、Kenobi方案:

  • 支持USB并且可以插接外置kenobi卡板的Android 系统机器一台,系统Android 6.0及以上;
  • Kenobi 单片机及相关USB线(Rokid提供)。

3、Android 系统定制方案:

  • 带定制麦克风的Android 系统机器一台,系统Android 6.0及以上;
  • 自定义pcm数据获取方案:
    • Rokid mic array方式,配合lothalproc使用;
    • 修改系统的audio源码,AudioRecord录音后独立解码成Rokid语音可支持的格式。
  • 这种方式支持各种麦克风组合方案,多路数据。

4、附Rokid mic array方式Rokid语音支持的麦克风说明:麦克风阵列音频采集程序集成说明文档

1.4.2. 3.2 所需Android权限

    <!-- 网络 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 录音 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <!-- 读取SD卡 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <!-- 设备网络状态 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!-- Rokid技能权限 -->
    <uses-permission android:name="com.rokid.ai.skill.provider.READ_PROVIDER" />
    <uses-permission android:name="com.rokid.ai.skill.provider.WRITE_PROVIDER" />
  • 上述Android权限需要开发者在SDK接入的app入口页面事先实现权限获取,否则部分功能将无法正常运行

1.4.3. 3.3 配置文件

3.3.1 使用说明

Rokid语音SDK中包含众多语音算法,在整体流程的搭配中,我们对外提供基于默认配置上的一些可配置文件,方便不同设备实现不同的定制化语音功能。

  • 配置文件路径:
    └── workdir_asr_cn
      ├── logging.conf
      ├── lothal_double.ini
      ├── lothal_double_modules.ini
      ├── lothal_single.ini
      ├── lothal_single_modules.ini
      ├── model
      │   └── emb
      │       ├── output_graph.bin
      │       └── symbol_table.txt
      ├── rasr.emb.double.ini
      ├── rasr.emb.single.ini
      └── words.ini
    
    上述配置需要开发者根据自己的硬件设备修改后放置到app 的 assert 目录中。 简单的配置会随示例给出,如果用户的麦克风进行了复杂的阵列设计,或者定制过激活词,建议走商务渠道让Rokid专业人员来进行个性化配置。

3.3.2 主要文件说明

3.3.2.1 lothal_*.ini

SDK集成配置文件,单通道/双通道,其他需要根据硬件麦克风状况进行修改,主要包括:

  • 麦克风阵列配置: 对应文件中的[mic_array]部分,包含了对麦克风阵列参数的配置
# Mic阵列相关的配置
[mic_array]
# Mic通道数(包含AEC参考信号通道)
mic_num=8    
# 表示一次采样的bit位宽,支持可配置值 int16, int32, float32
audio_type=int32  
# Mic采样率
audio_rate=48000  
# Mic阵列类型:线麦(10)或环麦(11)
sl_micarray_shape=11

# Mic坐标参数,根据Mic阵列的尺寸和Mic所在的位置进行计算
# 阵列的坐标是量出直径(环麦)或最大长度(线麦) x(单位:m),然后根据环麦或线麦按随意选定的坐标
# 系计算出来。比如如下为正圆六环麦,均匀分布,坐标通过正余弦计算得出
pos0= -0.043000,  0.000000,  0.000000
pos1= -0.021500, -0.037239,  0.000000
pos2=  0.021500, -0.037239,  0.000000
pos3=  0.043000,  0.000000,  0.000000
pos4=  0.021500,  0.037239,  0.000000
pos5= -0.021500,  0.037239,  0.000000
pos6=  0,         0,         0
pos7=  0,         0,         0

# 增益缩放系数
mics_big=1,1,1,1,1,1,1,1

# 表明需要做AEC算法的通道
aec_mics=0,1,2,3,4,5  

# 表明参考通道的位置
ref_mics=6,7  

# Mic各通道的延迟,默认为0,一般不要修改,如果硬件确实存在延时,需要硬件工程师介入调试
mic_delay=0,0,0,0,0,0,0,0
  • SDK内部算法模块配置: 对应文件中的[modules]部分,其中包含了指定模型配置文件module.ini的路径
# 语音处理流水线工作模块配置
[modules]

# 设置语音处理流水线工作模块,默认无需修改,当前包括:
# IN -  用于将输入音频转成float 32
# RDC - 去直流零票
# RS - 重采样,输出16K采样的音频
# NS - 噪音消除模块
# AEC - 回声消除
# ENGINE - 用于语音激活引擎,支持二次确认,CTC/CRNN
# VAD - 语音端点检测模块
# OPUS - 将PCM音频编码成opu
# OUT - 用于输出最终音频
sequence=IN,RDC,RS,AEC,ENGINE,VAD,OPUS,OUT   

# 指定针对上述各个模块的具体调优参数配置,稍后下一节会具体介绍
# modules.ini 相对路径 
config=lothal_single_modules.ini
  • 激活词配置: 对应文件中的[words]部分,其中包含了指定唤醒词配置文件words.ini的路径。
# 激活词配置
[words]
# 激活词的拼音, 示例中使用的是若琪
words=ruoqi
# 指定激活词配置文件,会跟唤醒词模型同时输出,模型训练好后,无需修改,只需替换
config=words.ini
  • 调试配置 - 对应文件中的[debug]部分,目前包含了日志打印级别的配置
# 调试配置
[debug]
# SDK输出日志级别 1 表示简略日志,0 表示大量调试日志
log.level=1
3.3.2.2 lothal_single_modules.ini / lothal_double_modules.ini
  • 模型配置文件,各种模型配置项,示例中对应了单麦/双麦。
  • 需要指定模型配置文件rasr.emb.*.ini的路径配置,配置方式:
rasr_ini= rasr.emb.*.ini
3.3.2.3 rasr.emb.*.ini
  • 模型及算法优化配置文件,内部涉及到麦克风信息的地方需要开发者进行修改。
3.3.2.4 words.ini
  • 激活词配置文件,需要根据实际激活词信息配置即可,特殊自定义激活词需要跟Rokid商务联系进行定制。
3.3.2.5 model
  • 唤醒词模型文件夹,不要修改。
3.3.2.6 logging.conf
  • 日志配置文件,不要修改。

1.4.4. 3.4 Android 项目gradle引入SDK相关aar

1、SDK提供aar文件说明:

  • basic.aar : 提供语音基础工具类;
  • turenso.aar : 核心语音处理工程,独立进程运行;
  • audioai.aar : 语音处理结果接收及后续分发;
  • nlpconsumer.aar : nlp技能控制相关,对接RokidAiSkillEngine或其他技能服务。

2、将SDK提供的 basic.aar, turenso.aar, audioai.aar, nlpconsumer.aar 放到app工程的libs目录下;

3、在app工程的build.gradle文件中引入上述aar;

defaultConfig {
    // ... 保证app运行时使用armeabi-v7a 中的so,RokidAiSdk目前没有提供64位的so
    ndk {
        abiFilters "armeabi-v7a"
    }
}
// 设置依赖查找目录,其中 basic.aar, turenso.aar, audioai.aar, nlpconsumer.aar 放到app工程的libs目录
repositories{
    flatDir{
        dirs 'libs'
    }
}
// gradle merge 操作时,忽略掉多出的部分so文件
packagingOptions {
    pickFirst 'lib/armeabi-v7a/librlog.so'
    pickFirst 'lib/armeabi-v7a/libcaps.so'
}
// 引入依赖, gson、appcompat-v7需要用户引入,版本可以自定
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation (name:'basic-1.4.3', ext:'aar')
    implementation (name:'turenso-1.4.3', ext:'aar')
    implementation (name:'nlpconsumer-1.4.3', ext:'aar')
    implementation (name:'audioai-1.4.3', ext:'aar')
    implementation "com.google.code.gson:gson:2.8.5"
    implementation 'com.android.support:appcompat-v7:27.1.1'
    // ...
}

4、混淆配置,如果用户app需要混淆的话,请不要混淆rokid语音SDK相关代码

# 保持 native 方法不被混淆
-keepclasseswithmembernames class * { 
   native <methods>;
}
-keep class com.rokid.** { *; }

1.4.5. 3.5 SDK初始化

3.5.1 启动语音服务

1、开发者需要创建一个符合自己需求的ServerConfig 实例;

private ServerConfig getServiceConfig() {

    ServerConfig config = null;
    // Android 的 AudioRecord 录音最多只支持2个麦克风
    // 使用一个麦克风配置
    // "workdir_asr_cn": 算法配置文件在assets目录中的位置
    // "lothal_single.ini": 算法库启动配置文件名
    // useOtherAudio: 是否使用用户自己的audio数据模块, false 代表使用Rokid 的Kenobi方案。
    config = new ServerConfig("workdir_asr_cn", "lothal_single.ini", true);
    // 使用两个个麦克风配置
    // config = new ServerConfig("workdir_asr_cn", "lothal_double.ini", true);

    // 设置log日志级别
    config.setLogConfig(Logger.LEVEL_D, true, true);

    // key: Rokid开放平台注册时生成的Key
    String key = "2FA1968AE2B14942BA56D3B874A9C5B0";
    // secret: Rokid开放平台注册时生成的Secret
    String secret = "3540CBB498DB4D348E8AD784B21DD7D1";
    // deviceTypeId: Rokid开放平台注册时生成的DeviceTypeId
    String deviceTypeId = "0ABA0AA4F71949C4A3FB0418BF025113";
    // deviceId: 设备SN号,由6~15位的字母和数字组成,不能含有空格和特殊符号
    String deviceId = "0502031835000134";
    // seed: 设备seed号,跟rokid设备账号绑定时使用
    String seed = "gQ5H5k0936G71077KZ1Xzy7Y7A71z9";

    config.setKey(key).setSecret(secret).setDeviceTypeId(deviceTypeId).setDeviceId(deviceId)
            .setSeed(seed);
    // 使用语音处理软件处理NLP技能
    config.setUseNlpConsumer(true);

    return config;
}

上述代码只使用基础的语音功能,其他特殊的语音功能设置请参考 SDK具体功能使用

2、开发者需要startService的方式来创建AudioAiService; 注意:在启动语音Service之前,Android 6.0以上系统,开发者需要自行申请所需Android权限并且用户点击通过

// 开始启动AudioAiService 
// SDK和app在独立进程方式
Intent mServiceIntent = AudioAiConfig.getIndependentIntent(this);
// SDK和app在相同进程方式
// Intent mServiceIntent = AudioAiConfig.getAttachmentIntent(this);
mServiceIntent.putExtra(AudioAiConfig.PARAM_SERVICE_START_CONFIG, getServiceConfig());
startService(mServiceIntent);

// 在用户需要彻底结束语音AudioAiService时,需要调用stop
// stopService(mServiceIntent);

3、开发者启动AudioAiService 服务后,需要再使用binder方式来绑定服务,以便可以和服务进行交互;

// 绑定AudioAiService 
private IRokidAudioAiService mAudioAiService;
private ServiceConnection mAiServiceConnection;

private void createConnection() {
    if (mAiServiceConnection != null) {
        return;
    }
    mAiServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Logger.d(TAG, "the onServiceConenct is called");
            if (service != null) {
                Logger.d(TAG, "onServiceConenct asInterface ");
                mAudioAiService = IRokidAudioAiService.Stub.asInterface(service);
                //try {
                //    service.linkToDeath(mDeathRecipient, 0);
                //    Logger.d(TAG, "onServiceConenct registAudioAiListener ");
                //    mAudioAiService.registAudioAiListener(mAudioAiListener);
                //} catch (RemoteException e) {
                //    e.printStackTrace();
                //}
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mAudioAiService = null;
        }
    };
}
// 需要在用户startService 调用之后再进行绑定,最好两个调用之间有些微弱的时间间隔
bindService(mServiceIntent, mAiServiceConnection, BIND_AUTO_CREATE);

// 在用户需要彻底结束语音AudioAiService时,需要先解除绑定再结束
// unbindService(mAiServiceConnection);

3.5.2 注册返回结果监听

1、IRokidAudioAiService服务绑定后,需要立即注册语音处理结果监听;

mAiServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Logger.d(TAG, "the onServiceConenct is called");
        if (service != null) {
            Logger.d(TAG, "onServiceConenct asInterface ");
            mAudioAiService = IRokidAudioAiService.Stub.asInterface(service);
            try {
            //    service.linkToDeath(mDeathRecipient, 0);
                Logger.d(TAG, "onServiceConenct registAudioAiListener ");
                mAudioAiService.registAudioAiListener(mAudioAiListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mAudioAiService = null;
    }
};

2、创建AudioAiListener 实例,主要用来监听语音SDK的返回结果(event、asr、nlp、error);

private IRokidAudioAiListener mAudioAiListener = new IRokidAudioAiListener.Stub() {

    private String mListenerKey = FileUtil.getStringID();

    @Override
    public void onIntermediateSlice(int id, String asr, boolean isLocal) throws RemoteException {
        Logger.d(TAG, "onIntermediateSlice(): " + (isLocal ? "LOCAL" : "NET") + " asr = " + asr);
    }

    @Override
    public void onIntermediateEntire(int id, String asr, boolean isLocal) throws RemoteException {
        Logger.d(TAG, "onIntermediateEntire(): " + (isLocal ? "LOCAL" : "NET") + " asr = " + asr);
    }

    @Override
    public void onCompleteNlp(int id, String nlp, String action, boolean isLocal) throws RemoteException {
        Logger.d(TAG, "onCompleteNlp(): " + (isLocal ? "LOCAL" : "NET") + " nlp = " + nlp + " action = " + action + "\n\r");
    }

    @Override
    public void onVoiceEvent(int id, int event, float sl, float energy, String extra) throws RemoteException {
        Logger.d(TAG, "onVoiceEvent(): event = " + event + ", sl = " + sl + ", energy = " + energy + ", extra = " + extra + "\n\r");
    }

    @Override
    public void onRecognizeError(int id, int errorCode) throws RemoteException {
        Logger.d(TAG, "onRecognizeError(): errorCode = " + errorCode + "\n\r");
    }

    @Override
    public void onServerSocketCreate(String ip, int port) throws RemoteException {
        Logger.d(TAG,"onServerSocketCreate(): ip = " + ip + ", port = " + port);
    }

    @Override
    public void onPcmServerPrepared() throws RemoteException {
        Logger.d(TAG,"onPcmServerPrepared(): called");
    }

    @Override
    public String getKey() throws RemoteException {
        return mListenerKey;
    }

    @Override
    public void controlNlpAppExit() throws RemoteException {
        Logger.d(TAG,"controlNlpAppExit(): called");
    }

    @Override
    public boolean interceptCloudNlpControl(int id, String nlp, String action) throws RemoteException {
        Logger.d(TAG,"interceptCloudNlpControl(): called");
        return false;
    }

    @Override
    public void onVerifyFailed(String deviceTypeId, String deviceId, String seed, String mac) throws RemoteException {
        Logger.d(TAG,"onVerifyFailed(): deviceTypeId = " + deviceTypeId +
                ",deviceId = " + deviceId + ",seed = " + seed + ",mac = " + mac);
    }
};

3、如果使用SDK和app在各自独立进程方式,推荐做一下服务绑定失效监听,这样失效后可以立即再次绑定(非必要);

private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        try {
            Logger.d(TAG, "DeathRecipient(): binderDied start");
            startService(mServiceIntent);
            bindService(mServiceIntent, mAiServiceConnection, BIND_AUTO_CREATE);
            Logger.d(TAG, "DeathRecipient(): binderDied end");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
};

mAiServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Logger.d(TAG, "the onServiceConenct is called");
        if (service != null) {
            Logger.d(TAG, "onServiceConenct asInterface ");
            mAudioAiService = IRokidAudioAiService.Stub.asInterface(service);
            try {
                service.linkToDeath(mDeathRecipient, 0);
                Logger.d(TAG, "onServiceConenct registAudioAiListener ");
                mAudioAiService.registAudioAiListener(mAudioAiListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mAudioAiService = null;
    }
};

// 在用户需要彻底结束语音AudioAiService时,需要先去除失效监听,然后再解除绑定,结束Service
// try {
//     if (mAudioAiService != null) {
//         mAudioAiService.asBinder().unlinkToDeath(mDeathRecipient, 0);
//         mAudioAiService = null;
//     }
// } catch (Throwable e) {
// }

1.4.6. 3.6 校验机制

Rokid语音SDK内部附带校验机制,需要开发者在启动服务时提供正确的设备启动信息:

  • key :Rokid开放平台注册时生成的Key
  • secret :Rokid开放平台注册时生成的Secret
  • deviceTypeId :Rokid开放平台注册时生成的DeviceTypeId
  • deviceId :设备SN号,由6~15位的字母和数字组成,不能含有空格和特殊符号
  • seed :设备seed号,跟rokid设备账号绑定时使用
  • macAddress :设备网络的mac 地址,每一对deviceId、seed只能对应一个设备,即一个macAddress。请开发者谨慎使用十个免费的测试deviceId和seed,如果想要大量商用的,请联系Rokid商务进行正式的SN、Seed信息导入。

在IRokidAudioAiService的回调函数中,会接收到校验失败返回信息

/**
 * 校验失败回调
 * 
 * @param deviceTypeId 设备deviceTypeId
 * @param deviceId 设备deviceId
 * @param seed 设备seed
 * @param mac 设备真实mac
 * @throws RemoteException
 */
@Override
public void onVerifyFailed(String deviceTypeId, String deviceId, String seed, String mac) throws RemoteException {
    Logger.d(TAG,"onVerifyFailed(): deviceTypeId = " + deviceTypeId +
            ",deviceId = " + deviceId + ",seed = " + seed + ",mac = " + mac);
}

1.4.7. 3.7 基础识别结果处理

3.7.1 语音识别Asr处理

在IRokidAudioAiService的回调函数中,会接收到相关asr识别返回信息

  • 返回语音识别中间结果片段
/**
 * 返回语音识别中间结果片段
 *
 * @param id 会话ID:一次激活开始到识别结束,nlp或error返回过程中的统一识别ID
 * @param asr asr String 数据
 * @param isLocal 是否是本地离线识别 true:离线识别,false:有网络在线识别
 * @throws RemoteException
 */
@Override
public void onIntermediateSlice(int id, String asr, boolean isLocal) throws RemoteException {
    Logger.d(TAG, "onIntermediateSlice(): " + (isLocal ? "LOCAL" : "NET") + " asr = " + asr);
    }

}
  • 返回语音识别最终结果完整的数据
/**
 * 返回语音识别最终结果完整的数据
 *
 * @param id 会话ID:一次激活开始到识别结束,nlp或error返回过程中的统一识别ID
 * @param asr asr String 数据
 * @param isLocal 是否是本地离线识别 true:离线识别,false:有网络在线识别
 * @throws RemoteException
 */
@Override
public void onIntermediateEntire(int id, String asr, boolean isLocal) throws RemoteException {
    Logger.d(TAG, "onIntermediateEntire(): " + (isLocal ? "LOCAL" : "NET") + " asr = " + asr);
    }
}

3.7.2 语音识别技能nlp处理

在IRokidAudioAiService的回调函数中,会接收到语音识别技能nlp处理返回信息

/**
 * 返回语音识别技能结果nlp、action
 *
 * @param id 会话ID:一次激活开始到识别结束,nlp或error返回过程中的统一识别ID
 * @param nlp 技能结果nlp
 * @param action 技能结果action,Rokid云技能使用
 * @param isLocal 是否是本地离线识别 true:离线识别,false:有网络在线识别
 * @throws RemoteException
 */
@Override
public void onCompleteNlp(int id, String nlp, String action, boolean isLocal) throws RemoteException {
    Logger.d(TAG, "onCompleteNlp(): " + (isLocal ? "LOCAL" : "NET") + " nlp = " + nlp + " action = " + action + "\n\r");

}

3.7.3 语音识别Event处理

在IRokidAudioAiService的回调函数中,会接收到语音识别Event处理返回信息

/**
 * 返回语音唤醒事件
 *
 * @param id 会话ID:一次激活开始到识别结束,nlp或error返回过程中的统一识别ID
 * @param event 事件号 语音事件类型VoiceRecognize.Event的ordinal()值
 * @param sl  当前唤醒角度(0到360度之间)
 * @param energy 当前说话能量值(0到1之间的浮点数)
 * @param extra 其他事件的附加信息
 * @throws RemoteException
 */
@Override
public void onVoiceEvent(int id, int event, float sl, float energy, String extra) throws RemoteException {
    Logger.d(TAG, "onVoiceEvent(): event = " + event + ", sl = " + sl + ", energy = " + energy + ", extra = " + extra + "\n\r");
}

事件说明:VoiceRecognize.Event

  • EVENT_VOICE_LOCAL_WAKE:本地激活成功
  • EVENT_VOICE_LOCAL_SLEEP:本地休眠事件
  • EVENT_VOICE_COMING:本地激活语音数据到来
  • EVENT_VOICE_ACCEPT:激活词云端二次确认成功
  • EVENT_VOICE_REJECT:激活词云端二次确认失败
  • EVENT_VOICE_CANCEL:激活取消
  • EVENT_VOICE_SYS_EXIT:本次激活系统退出
  • EVENT_VOICE_OUTSERVER_READY:Turen系统重启,重新连接

3.7.4 语音识别Error处理

在IRokidAudioAiService的回调函数中,会接收到语音识别Error处理返回信息

/**
 * 返回语音识别出错信息
 *
 * @param id 会话ID:一次激活开始到识别结束,nlp或error返回过程中的统一识别ID
 * @param errorCode 错误码 VoiceRecognize.ExceptionCode的ordinal()值
 * @throws RemoteException
 */
@Override
public void onRecognizeError(int id, int errorCode) throws RemoteException {
    Logger.d(TAG, "onRecognizeError(): errorCode = " + errorCode + "\n\r");
}

错误码说明:https://developer.rokid.com/docs/5-enableVoice/rokid-vsvy-sdk-docs/common/err_code.html

1.5. 四、SDK具体功能使用

1.5.1. 4.1 使用NlpConsumer来继续分发NLP

如果用户需要使用Rokid的nlp、技能相关的后续功能链路,需要打开NlpConsumer来继续分发NLP功能。

// 在ServerConfig中打开NlpConsumer开关
private ServerConfig getServiceConfig(int status) {

    ServerConfig config = null;
    // ...
    // 使用语音处理软件处理NLP技能 默认为false
    config.setUseNlpConsumer(true);
    // ...
    return config;
}

1.5.2. 4.2 使用RokidAiSkillEngine、RokidAiCloudApp 来处理Rokid 云端技能

1、RokidAiSkillEngine.apk:需要安装SDK包内附带的RokidAiSkillEngine,主要负责技能的分发、技能与语音SDK之间的交互,对云端技能、本地技能的控制。

2、RokidAiCloudApp.apk:需要安装SDK包内附带的RokidAiCloudApp,主要云端技能的处理,一些较小技能需求,推荐使用Rokid云技能方案来解决,快速稳定。

3、技能开发推荐参考:https://developer.rokid.com/docs/2-RokidDocument/1-SkillsKit/getting-started/creat.html

1.5.3. 4.3 使用RokidAiSkillEngine、RokidAILocalSkillSdk 来处理Rokid 本地技能

1、RokidAiSkillEngine.apk:需要安装SDK包内附带的RokidAiSkillEngine,主要负责技能的分发、技能与语音SDK之间的交互,对云端技能、本地技能的控制。

2、RokidAILocalSkillSdk.aar:需要在开发者的本地技能apk中引入使用,Rokid 语音SDK 本地技能快速开发工具,方便开发配合Rokid语音SDK一起使用的本地技能。

3、本地技能开发及SDK使用文档请参考:https://developer.rokid.com/docs/5-enableVoice/rokid-vsvy-sdk-docs/LocalSkillSdk/LocalSkillSdk.html

1.5.4. 4.4 使用算法处理过程中的相关pcm数据:必须通过校验

1、算法配置修改;

# 在*_modules.ini中, 每个算法步骤的配置模块,都可以对外吐出算法处理的pcm数据

# 注:每一个步骤处理露出的pcm数据格式都是不同的
# 注:不同步骤的数据格式请咨询Rokid商务,因对外提供pcm会影响Rokid语音SDK对硬件设备资源的占用,需要Rokid专用人员对相关硬件设备能否使用作出评估。

# eg:将[ENGINE]步骤处理的数据映射到30003端口
# ...
[ENGINE]
dump.uri=socket:30003
# ...

# eg:将[AEC]步骤处理的数据映射到30010端口
# ...
[AEC]
dump.uri=socket:30010
# ...

2、在算法配置的同时,需要java层用socket来主动获取,我们的aar中已经提供了获取pcm数据的工具类;

private PcmClientManager mPcmSocketManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...
    mPcmSocketManager = new PcmClientManager();
}

private IRokidAudioAiListener mAudioAiListener = new IRokidAudioAiListener.Stub() {
    // ......

    @Override
    public void onPcmServerPrepared() throws RemoteException {
        Logger.d(TAG,"onPcmServerPrepared(): called");
        if (mPcmSocketManager != null) {
        // 端口为用户自己在配置文件上定义的 dump.uri=socket:30003
            mPcmSocketManager.startSocket(null, mPcmReceiver, 30003);
        }
    }
};

private IReceiverPcmListener mPcmReceiver = new IReceiverPcmListener() {
    @Override
    public void onPcmReceive(int length, byte[] data) {
        Logger.d(TAG, "onPcmReceive(): len = " + length + "\n\r");
        // showPcmData(length, data);
    }
};

@Override
protected void onDestroy() {
    // ...
    mPcmSocketManager.onDestroy();
    mPcmSocketManager = null;

    super.onDestroy();
}

1.5.5. 4.5 使用kenobi设备

如果用户要配合Rokid kenobi设备来一起使用SDK。

// 在ServerConfig中关闭useOtherAudio 
// useOtherAudio 是否使用用户自己的audio数据模块, false 代表使用kenobi设备
private ServerConfig getServiceConfig() {

    ServerConfig config = null;
    config = new ServerConfig("workdir_asr_cn","lothal_single.ini", false);

    // ...
    return config;
}

1.5.6. 4.6 关闭speech,只接收语音event、离线asr、pcm

如果用户不需要使用Rokid的speech功能,只使用前端算法的部分功能,可以通过开关来关闭speech 方式启动。

// 在ServerConfig中关闭speech功能开关
private ServerConfig getServiceConfig() {

    ServerConfig config = null;
    // ...
    // 是否打开speech 默认为true
    config.setUseSpeech(false);
    // ...
    return config;
}

1.5.7. 4.7 使用离线asr功能

如果用户需要使用Rokid的离线asr功能,需要做两部操作:

1、通过Rokid 商务来定制离线asr指令,并使用Rokid提供的专业配置文件(包含离线词表配置)

2、需要打开离线asr开关,这样Rokid语音会在设备处于离线环境时启动离线asr功能;

// 在ServerConfig中打开NlpConsumer开关
private ServerConfig getServiceConfig() {

    ServerConfig config = null;
    // ...
    // 使用离线asr开关,默认为false
    config.setUseOffLine(true);
    // ...
    return config;
}

1.5.8. 4.8 使用有线mac地址来做校验

如果用户需要使用有线mac地址来做设备校验的话,需要开启有线校验开关。

// 在ServerConfig中开启有线校验开关
private ServerConfig getServiceConfig() {

    ServerConfig config = null;
    // ...
    // 是否开启有线校验 默认为false
    config.setNotUseWifi(true);
    // ...
    return config;
}

1.5.9. 4.9 使用turenproc方式运行语音SDK

Rokid 算法集成库可以使用系统独立进程方式运行,在这种模式下,RokidAiSdk可以用来只作为Event、asr、nlp、error的接收方。

1、参考系统全链路方式初步集成算法so、将turenproc放到init rc中开机启动,同时准备与设备对应的pcm读取工具,mic_array.so。参考:https://developer.rokid.com/docs/5-enableVoice/rokid-vsvy-sdk-docs/fullLink/fulllink.html;

2、可以在gradle 依赖中去掉turenso.aar相关的依赖;

3、在ServerConfig中打开使用turenproc的开关;

// 在ServerConfig中打开使用turenproc功能开关
private ServerConfig getServiceConfig() {

    ServerConfig config = null;
    // ...
    // 是否打开turenproc开关 默认为false
    config.setUseTurenProc(true);
    // ...
    return config;
}

1.6. 五、主要API参考

1.6.1. 5.1 IRokidAudioAiService.java

ASR 主Service的binder接口

返回值 方法和说明
void playTtsVoice(java.lang.String text)用tts服务播放text语音
void setUserMediaPlaying(boolean userMediaPlaying)通知当前设备是否有用户媒体流在播放
boolean srartAudioAiServer(ServerConfig config, IRokidAudioAiListener listener)根据配置信息启动服务, 并注册Asr语音服务处理结果的监听(若当前服务已启动,则不会重新启动)true:表示监听添加成功,false:表示监听添加失败,config中的Key、Secret、DeviceTypeId三个值与服务启动时的config中的三个值不相等
void registAudioAiListener(IRokidAudioAiListener listener)注册Asr语音服务处理结果的监听
void unRegistAudioAiListener(IRokidAudioAiListener listener)注销Asr语音服务处理结果的监听
void setPickUp(boolean open) 在单独的激活模块中,主动开启拾音和关闭拾音 true: 开启拾音, false: 结束拾音
int control(String action) 发送控制命令:action "ACTION_SET_STATE_AWAKE" :开始拾音;"ACTION_SET_STATE_SLEEP" :设置为接受激活状态;"ACTION_OPEN_MIC" :打开麦克风(打开才能激活、拾音);"ACTION_CLOSE_MIC" :关闭麦克风(无法激活、拾音)
int addVtWord(String vtWordType, String word, String pinyin) 添加自定义激活词 vtWordType : 激活词类型 "AWAKE"、"SLEEP"、"HOTWORD"、"OTHER";word : 激活词中文;pinyin : 激活词拼音
int removeVtWord(String content) 去除激活词
List<String> getVtWords() 获取当前所有自定义激活词
int updateStack(String currAppId, String prevAppId) 更新turen Stack 技能栈 currAppId : 当前的AppId;prevAppId : 上一个AppId
int setSkillOption(String skillOption) 设置SkillOption

1.6.2. 5.2 IRokidAudioAiListener.java

监听AudioAiService服务对语音的处理结果

返回值 方法和说明
void onIntermediateSlice(int id, String asr, boolean isLocal) 返回语音识别中间结果片段 (id: 本次激活会话id)
void onIntermediateEntire(int id, String asr, boolean isLocal) 返回语音识别中间结果完整的数据(id: 本次激活会话id)
void onCompleteNlp(int id, String nlp, String action, boolean isLocal) 返回最终语音识别结果(id: 本次激活会话id,nlp:自然语义解析结果, action:云端skill结果)
void onVoiceEvent(int id, int event, float sl, float energy, String extra) 返回语音唤醒事件(id: 本次激活会话id,event: 语音事件类型VoiceRecognize.Event的ordinal()值(见VoiceRecognize.Event enum 类型说明), sl:当前唤醒角度(0到360度之间), energy:当前说话能量值(0到1之间的浮点数))
void onRecognizeError(int id, int errorCode) 返回语音识别出错信息(id: 本次激活会话id,errorCode:错误码,见错误码说明
void onServerSocketCreate(String ip, int port) 接收pcm数据的socket启动成功时的回调 (ip:socket的ip地址, post:socket的端口)
void onPcmServerPrepared() 发送算法处理过后的pcm数据的服务已经准备好
String getKey() 返回当前IRokidAudioAiListener 唯一标志 (不可为null或"",否则IRokidAudioAiListener将会注册失败)
void controlNlpAppExit() 处理NLP中的退出所有app指令
boolean interceptCloudNlpControl(int id, String nlp, String action) 对NlpConsumer云端处理NLP进行拦截(id:会话ID,nlp:自然语义解析结果, action:云端skill结果)
void onVerifyFailed(String deviceTypeId, String deviceId, String seed, String mac) 设备校验失败回调(deviceTypeId:设备类型ID,deviceId:设备sn, seed:账号值, mac:mac地址)
void onRecogniseStatusChange(boolean isOnLine)) 识别状态变更通知(isOnLine:是否是在线识别 true-在线)

1.6.3. 5.3 ServiceConfig.java

启动参数配置类

返回值 方法和说明
java.lang.String getAssetsConfigPath()获取Assets目录中算法库配置文件路径
java.lang.String getConfigFileName()获取初始化turen配置文件名
java.lang.String getDeviceId()获取设备的DeviceId, sn号
java.lang.String getDeviceTypeId()获取当前DeviceTypeId
java.lang.String getKey()获取当前Key
int getLogLevel()返回log等级
java.lang.String getRealConfigPath()获取算法库配置文件真实路径
java.lang.String getSecret()获取当前Secret
java.lang.String getSpeechConfig()
boolean isShowDecoderSoLog()返回decode so日志是否展示
boolean isShowTurenLog()查看Turen Log的展示
boolean isTestWays()获取是否开启测试模式
boolean isUseNlp()查询是否输出NLP功能
boolean isUseNlpConsumer()查询是否使用NLP云端、本地技能语音处理功能
boolean isUseOtherAudio()获取当前是否使用用户自己的audio数据模块
boolean isUsePcm()查询是否输出PCM功能
boolean isUseTurenProc()查询是否turenproc命令行工具启动Turen方式
ServerConfig setAssetsConfigPath(java.lang.String path)设置Assets目录中算法库配置文件路径
ServerConfig setConfigFileName(java.lang.String fileName)设置初始化turen配置文件名
ServerConfig setDeviceId(java.lang.String mDeviceId)设置设备的DeviceId, sn号
ServerConfig setDeviceTypeId(java.lang.String mDeviceTypeId)设置开放平台注册时生成的Type ID
ServerConfig setKey(java.lang.String key)设置开放平台注册时生成的KEY
ServerConfig setLogConfig(int logLevel, boolean showTurenLog, boolean showDecoderSoLog)设置log等级
ServerConfig setRealConfigPath(java.lang.String path)设置算法库配置文件真实路径
ServerConfig setSecret(java.lang.String secret)设置开放平台注册时生成的Secret
ServerConfig setShowDecoderSoLog(boolean show)设置decode so日志是否展示
ServerConfig setShowTurenLog(boolean show)设置Turen Log的展示
ServerConfig setTestWays(boolean testWays)设置是否开启测试模式,识别服务器会有区别
ServerConfig setUseMacArray(boolean useMacArray)设置是否使用mic_array方式获取PCM数据
ServerConfig setUseNlpConsumer(boolean useNlpConsumer)设置是否使用NLP云端、本地技能语音处理功能
ServerConfig setUseOtherAudio(boolean useOtherAudio)设置是否使用用户自己的audio数据模块(默认使用SDK的BSP Audio数据模块)
ServerConfig setNotUseWifi(boolean notUseWifi)是否不使用WiFi,使用有线网卡,mac地址用
ServerConfig setSpeechBranch(String speechBranch)设置Speech 请求分支
ServerConfig setSpeechPort(int speechPort)设置Speech 请求端口
ServerConfig setSpeechHost(String speechHost)设置Speech 请求host

1.6.4. 5.4 VoiceRecognize.Event

Event Enum 类型说明

类型 语音唤醒事件枚举定义
EVENT_VOICE_COMING 激活即将开始(sl 存在值,energy值为0)
EVENT_VOICE_LOCAL_WAKE 本地已经激活(sl 存在值,energy值为0)
EVENT_VOICE_START 开始上传VAD(sl 值为0,energy存在值 )
EVENT_VOICE_NONE 二次确认结果为空,只出于已经在激活状态下,直接说语音命令
EVENT_VOICE_ACCEPT 云端二次确认通过
EVENT_VOICE_REJECT 云端二次确认不通过
EVENT_VOICE_CANCEL 取消当前上传VAD
EVENT_VOICE_LOCAL_SLEEP 通过休眠词从激活状态进入休眠状态

1.6.5. 5.5 RecordClientManager

录音Pcm的Client Socket, 用来向语音SDK发送录音录到的pcm数据

类型 描述
boolean isUseQueue()查看是否使用队列缓存数据发送
void onDestroy()
void sendRecordData(byte[] data)发送录音数据
void setUseQueue(boolean useQueue)设置是否使用队列缓存数据发送
void startSocket(java.lang.String ip, int port, ClientSocketManager.IConnnectListener listener) 启动一个socket长连接

1.6.6. 5.5 IRecordPcmReceiver

录音pcm数据获取后处理监听回调

类型 描述
void onPcmReceive(int length, byte[] data)录音pcm数据获取后处理

1.6.7. 5.6 ClientSocketManager.IConnnectListener

Socket连接监听

类型 描述
void onConnectFailed(ClientSocketManager socketManager)连接失败
void onConnectSuccess(ClientSocketManager socketManager)连接成功

1.6.8. 5.7 PcmClientManager

算法Pcm工具类的Client Socket,用来获取算法各步骤的pcm数据

类型 描述
boolean isUseQueue()查看是否使用队列缓存数据发送
void onDestroy()
void sendRecordData(byte[] data)发送录音数据
void setUseQueue(boolean useQueue)设置是否使用队列缓存数据发送
void startSocket(ClientSocketManager.IConnnectListener listener, IReceiverPcmListener pcmReceiver) 启动一个socket长连接

1.6.9. 5.8 IReceiverPcmListener

算法pcm数据获取后处理监听回调

类型 描述
void onPcmReceive(int length, byte[] data)算法pcm数据获取后处理

1.6.10. 5.9 错误码说明

错误描述
0 成功
3 与服务器连接数量过多
4 服务器资源不足
5 服务器忙
6 服务器内部错误
7 语音识别超时
101 无法连接到服务器
103 语音请求服务器超时未响应
104 未知错误

1.7. 六、其他说明

1.7.1. 6.1 最新版本

SDK 版本:(aar)1.4.3

  • audioai-1.4.3.aar
  • basic-1.4.3.aar
  • nlpconsumer-1.4.3.aar
  • turenso-1.4.3.aar

1.7.2. 6.2 参考demo地址(包含最新SDK)

github:https://github.com/Rokid/RokidAiSdkDemo

1.7.3. 6.3 主要调用流程图

AudioAiSdk 时序

results matching ""

    No results matching ""