单项功能概述(Windows)
1、SDK云端功能
1.1 产品介绍
云端SDK 提供在线语音识别,在线语音合成,长语音实时识别,以及录音文件长语音转写功能等单项语音服务。
目前SDK提供的单项语音服务如下:
1) 在线语音识别(Automatic Speech Recognition,ASR):识别语音内容,转化为相应的文字。
2) 在线语音合成(Text to Speech,TTS):将文字信息转变为可以听得懂的、流利的汉语。
3) 长语音实时识别:将很长的一段语音内容,实时转化为相应的文字。
4) 录音文件长语音转写:将很长的一段录音文件,转化为相应的文字。
1.2 预备工作
1) 账号:DUI平台的账号,进行SDK集成的必备前提之一。
2) 产品:在控制台上创建产品后,会自动生成一个产品ID。创建流程见:单项基础技术接入
3) SDK:前往SDK下载页下载Windows平台的压缩包,支持x86和x86_64的windows10平台,并且含有集成手册、开发手册、FAQ,example。
4) 网络:SDK仅支持纯云端功能,因此必须连接网络才能正常使用,用来和dui平台进行交互,完成识别、合成等功能。
1.3 接口描述
SDK包含两个功能接口和一系列消息接口
功能接口为dds_start和dds_send,其中dds_start用于启动SDK服务,dds_send用于发送消息
消息接口为以dds_msg_xxx开头的函数,它们用于组合不同的消息类型,通过dds_send接口发送出去
注意:dds_send接口是线程安全的,可以在不同的线程中调用,但是不要在dds的回调函数中调用,头文件介绍如下:
#ifndef __DDS_H__ #define __DDS_H__
#ifdef __cplusplus extern "C" { #endif
#if (!(defined DDS_CALL) || !(defined DDS_IMPORT_OR_EXPORT)) #if defined _WIN32 #if defined _WIN64 #define DDS_CALL __stdcall//windos系统和linux 系统,函数参数压栈方向不一样 #else #define DDS_CALL #endif
#ifdef DDS_IMPLEMENTION #define DDS_IMPORT_OR_EXPORT __declspec(dllexport)//类似标准ANSI c的 export方法,供被调用 #else #define DDS_IMPORT_OR_EXPORT __declspec(dllimport) #endif #if 0 #elif defined __ANDROID__ #define DDS_CALL #define DDS_IMPORT_OR_EXPORT #undef JNIEXPORT #define JNIEXPORT __attribute ((visibility("default"))) #endif #elif defined __APPLE__ #define DDS_CALL #define DDS_IMPORT_OR_EXPORT #elif defined __unix__ #define DDS_CALL #define DDS_IMPORT_OR_EXPORT __attribute ((visibility("default"))) #else #define DDS_CALL #define DDS_IMPORT_OR_EXPORT #endif #endif
#define DDS_VERSION "DDS 0.2.26" #define DDS_VERSION_NUM 226
/* callback event */ #define DDS_EV_OUT_RECORD_AUDIO 1 //dds主动索要音频数据,一般100ms一次, #define DDS_EV_OUT_NATIVE_CALL 2 //dds 查询本地数据,通过DDS_EV_IN_NATIVE_RESPONSE 消息返回给dds server #define DDS_EV_OUT_COMMAND 3 //向客户端发送控制命令,一般为json格式字符串,比如打开台灯 #define DDS_EV_OUT_MEDIA 4 //云端返回的json格式的播放列表 #define DDS_EV_OUT_STATUS 5 //云端返回dds状态,idle,listening,understanding #define DDS_EV_OUT_TTS 6 //语音合成,返回合成的音频的url,nlg文本可选 #define DDS_EV_OUT_ERROR 7 //dds 异常 #define DDS_EV_OUT_ASR_RESULT 8 //语音识别,返回识别后的文本和拼音 #define DDS_EV_OUT_DUI_RESPONSE 9 //dui 服务返回完整结果,json格式 #define DDS_EV_OUT_DUI_LOGIN 10 //返回login注册结果,设备名 #define DDS_EV_OUT_CINFO_RESULT 11 //获得get的操作结果,成功失败,tts或词库的返回结果 #define DDS_EV_OUT_OAUTH_RESULT 12 //第三方授权结果返回 #define DDS_EV_OUT_PRODUCT_CONFIG_RESULT 13 //获取产品配置信息 #define DDS_EV_OUT_WEB_CONNECT 14 //返回和dui平台端tcp连接成功与否的消息 #define DDS_EV_OUT_DUI_DEVICENAME 15 //返回当前设备名 #define DDS_EV_OUT_REFRESH_TOKEN 23 //refresh token更新结果 #define DDS_EV_OUT_LASR_RT_RESULT 24 //长语音实时结果返回 #define DDS_EV_OUT_LASR_RT_RAW 25 //长语音实时结果(服务端返回结果) #define DDS_EV_OUT_LASR_RAW 26 //长语音文件转写结果返回 #define DDS_EV_OUT_REQUEST_ID 27 //request id生成通知 #define DDS_EV_OUT_VAD_RESULT 28 //全链路云端vad结果 #define DDS_EV_OUT_TTS_MULTIPLE 29 //tts多路复刻结果
/* external event */ #define DDS_EV_IN_SPEECH 101 //语音输入开始事件,start,end #define DDS_EV_IN_WAKEUP 102 //唤醒事件,触发读取音频 #define DDS_EV_IN_NATIVE_RESPONSE 103 #define DDS_EV_IN_RESET 104 //重置对话,该接口阻塞实现 #define DDS_EV_IN_EXIT 105 // 退出SDK #define DDS_EV_IN_CUSTOM_TTS_TEXT 106 // 需要合成的中文文本 #define DDS_EV_IN_AUDIO_STREAM 107 //发送音频流到dds server #define DDS_EV_IN_PLAYER_STATUS 108 //当前播放状态,播放结束后 dds server进入listening #define DDS_EV_IN_NLU_TEXT 109 //语义请求 #define DDS_EV_IN_WAKEUP_WORD 110 //配置单个唤醒词 #define DDS_EV_IN_CINFO_OPERATE 111 //删除终端自定义配置 #define DDS_EV_IN_OAUTH_OPERATE 112 #define DDS_EV_IN_DM_INTENT 113 #define DDS_EV_IN_COMMON_WAKEUP_WORD 114 #define DDS_EV_IN_PHRASE_HINTS 115 #define DDS_EV_IN_PRODUCT_CONFIG 116 //获取DUI控制台产品配置 #define DDS_EV_IN_TTS_STOP 128 //停止tts多路复刻 #define DDS_EV_IN_LASR_RT_START 129 //长语音实时识别开始接口 #define DDS_EV_IN_LASR_RT_STOP 130 //长语音实时识别结束接口 #define DDS_EV_IN_LASR_FILE_UPLOAD 131 //长语音文件转写文件分片上传接口 #define DDS_EV_IN_LASR_TASK_CREATE 132 //长语音文件转写创建识别任务接口 #define DDS_EV_IN_LASR_TASK_QUERY 133 //长语音文件转写结果查询接口
/* error id */ #define DDS_ERROR_BASE 1000 #define DDS_ERROR_FATAL (DDS_ERROR_BASE + 1) #define DDS_ERROR_TIMEOUT (DDS_ERROR_BASE + 2) #define DDS_ERROR_NETWORK (DDS_ERROR_BASE + 3) #define DDS_ERROR_SERVER (DDS_ERROR_BASE + 4) #define DDS_ERROR_LOGIC (DDS_ERROR_BASE + 5) #define DDS_ERROR_INPUT (DDS_ERROR_BASE + 6)
struct dds_msg; typedef int (*dds_ev_callback)(void *userdata, struct dds_msg *msg);//dds 回调函数,所有out 事件在此接口处理
struct dds_opt { dds_ev_callback _handler; void *userdata; };
DDS_IMPORT_OR_EXPORT int DDS_CALL dds_start(struct dds_msg *conf, struct dds_opt *opt); //dds 服务启动接口,阻塞运行,需要传送产品配置参数,pID,aliaskey,profile必选和opt操作句柄,dds服务启动后会一直阻塞等待消息 DDS_IMPORT_OR_EXPORT int DDS_CALL dds_send(struct dds_msg *msg); //发送消息给dds 服务,dds回调函数收到回复消息并处理
/* message pack or unpack */ DDS_IMPORT_OR_EXPORT struct dds_msg * DDS_CALL dds_msg_new(); //新建一个消息,并分配保存消息的内存 DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_delete(struct dds_msg *msg); //删除一个消息,并回收内存 DDS_IMPORT_OR_EXPORT void DDS_CALL dds_msg_print(struct dds_msg *msg); //打印出start消息的地址和当前消息之间的长度
DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_set_type(struct dds_msg *msg, int value); //设置消息type 类型,DDS_EV_IN_SPEECH DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_set_integer(struct dds_msg *msg, const char *key, int value); //key 变量赋值为整形value DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_set_double(struct dds_msg *msg, const char *key, double value); //key 变量赋值为double 型value DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_set_boolean(struct dds_msg *msg, const char *key, int value); //key 变量赋值为boolean value DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_set_string(struct dds_msg *msg, const char *key, const char *value); //key 变量赋值为字符串 DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_set_bin(struct dds_msg *msg, const char *key, const char *value, int value_len); //设置 audio stream 数据流给key DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_set_bin_p(struct dds_msg *msg, const char *key, const char *value, int value_len); //设置 value 指向的数据流文件给key
DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_get_type(struct dds_msg *msg, int *value); DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_get_integer(struct dds_msg *msg, const char *key, int *value); DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_get_double(struct dds_msg *msg, const char *key, double *value); DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_get_boolean(struct dds_msg *msg, const char *key, int *value); DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_get_string(struct dds_msg *msg, const char *key, char **value); DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_get_bin(struct dds_msg *msg, const char *key, char **value, int *value_len); DDS_IMPORT_OR_EXPORT int DDS_CALL dds_msg_get_bin_p(struct dds_msg *msg, const char *key, char **value, int *value_len);
#ifdef __cplusplus } #endif #endif |
1.4 输入和输出
在调用dds_start的时候会注册一个回调函数,在回调中返回各种消息,消息的类型定义是以DDS_EV_OUT_开头的宏
通过dds_send发送各种消息,驱动SDK工作,支持的输入消息类型是以DDS_EV_IN_开头的宏
1.5 启动与授权
dds_start用于启动服务,它是一个阻塞接口,实现为一个死循环,用于接收dds_send发送的消息,并进行处理,所以该接口运行于一个独立的线程。
示例代码如下
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include "dds.h"
static int dds_ev_ccb(void *userdata, struct dds_msg *msg) {//事件回调函数,dds云端返回的响应都会回调此函数 int type; if (!dds_msg_get_type(msg, &type)) {//获得消息对应的事件类型 switch (type) { case DDS_EV_OUT_DUI_LOGIN: { printf("\n"); char *value; if (!dds_msg_get_string(msg, "error", &value)) {//如果云端login失败,打印出错误码 printf("ERROR: %s\n", value); } else if (!dds_msg_get_string(msg, "deviceName", &value)) {//如果无法获得错误码,打印设备名字,表示授权成功 printf("deviceName: %s\n", value); } break; } default: break; } } return 0; }
void *_run(void *arg) {//一般在main函数中创建线程回调函数 struct dds_msg *msg = dds_msg_new(); dds_msg_set_string(msg, "productId", "产品ID"); dds_msg_set_string(msg, "asrRes", "aihome"); dds_msg_set_string(msg, "savedProfile", "./xxx.profile");
dds_msg_set_string(msg, "productKey", "产品Key"); dds_msg_set_string(msg, "productSecret", "产品Secret"); dds_msg_set_string(msg, "devInfo", "{\"deviceName\": \"设备唯一标识\", \"platform\": \"linux\"}");
struct dds_opt opt; opt._handler = dds_ev_ccb; opt.userdata = arg; dds_start(msg, &opt); dds_msg_delete(msg); return NULL; }
int main(int argc, char **argv) { struct dds_msg *msg = NULL;
pthread_t tid;//创建一个线程的 id pthread_create(&tid, NULL, _run, NULL);//创建一个线程,创建完毕后立即执行回调_run
/*do something*/ sleep(5);
msg = dds_msg_new(); dds_msg_set_type(msg, DDS_EV_IN_EXIT); dds_send(msg); dds_msg_delete(msg);
pthread_join(tid, NULL);//阻塞方式等待子线程执行结束,回收线程资源
return 0; } |
正如上面的示例,dds_start的时候需要传入两个参数:
- struct dds_msg
该参数用于设置SDK的一些配置信息,主要包含产品配置和授权配置
产品配置:
参数名称 | 是否必选 | 描述 |
productId |
必选 | 产品id,是在dui平台上新建的产品 |
asrRes | 语音识别产品必选 | 识别模型,取值可为“aihome”、"aicomm"、"aicar"、"airobot" |
授权配置:针对不同的使用场景,dds支持两种授权方式,两种授权方式的比较如下表
授权方式 |
离线预烧录授权 |
在线productKey授权 |
使用场景 |
没有唯一id的设备,比如MCU |
有唯一id的设备,比如mac地址 |
使用方法 |
产线给每台设备烧录一个profile文件 |
设备启动时,上传唯一id,获取profile |
获取profile |
DUI平台上申请 |
设备运行时在线下载 |
配置项 |
savedProfile:profile文件的路径 |
productKey:DUI平台上生成的产品Key productSecret:DUI平台上生成的产品Secret savedProfile:下载的profile文件的保存路径和文件名 devInfo:JSON格式,其中deviceName为设备唯一id |
- struct dds_opt
该参数用于注册回调,传递需要透传的用户指针,dds的所有输出都通过该回调返回,并透传userdata
1.6 日志调试
dds_msg_set_boolean(msg, "logEnable", 1); dds_msg_set_string(msg, "logFile", "./dds.log"); |
2、SDK离线功能
2.1 产品介绍
离线SDK支持前端信号处理(线性麦克风阵列,环麦麦克风阵列,线性双麦)、离线语音识别、离线语音合成、单麦语音唤醒、语音断点检测、以及语法编译等单项语音服务。
目前SDK提供的单项语音服务如下:
1) 线性麦克风阵列(fespl):支持线性四麦和线性六麦,包含回声消除(echo),声源定位(doa),波速成形(beamforming)和语音唤醒(wakeup)
2) 环形麦克风阵列(fespa):支持环形六麦,包含回声消除(echo),声源定位(doa),波速成形(beamforming)和语音唤醒(wakeup)
3) 线性双麦(fespd):包含回声消除(echo),声源定位(doa),波速成形(beamforming)和语音唤醒(wakeup)
4) 离线线语音识别(Automatic Speech Recognition,ASR):识别语音内容,转化为相应的文字。
5) 离线语音合成(Text to Speech,TTS):将文字信息转变为可以听得懂的、流利的汉语,输出16K 16bit 单通道的PCM。
6) 单麦语音唤醒(wakeup):又称关键词检测(keyword spooting),一般输入经过信号处理后的单通道音频数据。若有关键词音频,则输出唤醒结果。
7) 语音端点检测(Voice Activity Detection, VAD):检测语音的开始和结束时间点,过滤静音,提取有效人声,一般配合语音识别使用。
8) 语法编译(gram):基于ebnf的语法格式,对输入的文本内容进行解析,生成可用于离线语音识别的语法网络资源。
2.2 预备工作
1) 账号:DUI平台的账号,进行SDK集成的必备前提之一。
2) 产品:在控制台上创建产品后,会自动生成一个产品ID。创建流程见:单项基础技术接入
3) SDK:前往SDK下载页下载Windows平台的压缩包,支持x86和x86_64的windows10平台,并且含有集成手册、开发手册、FAQ,example。
2.3 注意事项
- 不包含业务逻辑与云端功能
- 默认只支持单线程使用,不保证多线程接口调用安全
- 支持多实例使用
- 回调中禁用接口
2.4 典型调用流程
各个模块接口典型调用顺序如下:
2.5 回调函数定义
2.5.1 通用回到函数
typedef int (*duilite_callback)(void * userdata, int type, char *msg, int len);
接口能力
负责输出结果,通用回调函数吗,若无特殊说明所有模块均使用此回调函数。
输入参数
userdata - 用户数据,注册回调时传入,回调时透传;
type - 回调数据类型,
DUILITE_MSG_TYPE_JSON表示JSON字符串;
DUILITE_MSG_TYPE_BINARY表示二进制数据;
DUILITE_MSG_TYPE_TLV表示TLV数据包;
msg - 回调数据,在各个模块中详细说明;
len - 回调数据的长度;
返回值
一般为0,语音合成模块例外,详见语音合成模块。
2.5.2 模型数据回调函数(暂时不支持)
typedef int (*duilite_model_callback)(void *userdata, int type, char *id, char**data, int *data_size, int *data_nmemb);
接口能力
负责输出模型数据,用于支持模型数据外部存储功能,具体使用方式参见各个模块,目前仅支持声纹模块。
输入参数
userdata - 用户数据,注册回调时传入,回调时透传;
type – 模型数据操作类型,详见各模块中说明;
id – 该条模型数据的标识符;
data – 模型数据,数组;
data_size – 每条模型数据的大小,数组;
data_nmemb – 模型数据的数量;
返回值
成功 – 0;
失败 – 非0;
2.6 授权接口
2.6.1 duilite_library_load
int duilite_library_load(char *cfg)
接口能力
加载库函数,完成初始化与授权,接口阻塞,调用一次即可。
输入参数
cfg – 初始化参数,省略部分为授权相关,授权配置详见附录。
{ ...... "prof": { "enable": 1, "output": "", "level": 1 },
"deviceId": "abcd", "userId": "user", "productVersion": "0.1.2", "upload": { "enable": 1, "logId": 141, "tmpdir":"upload_dir", "tmpdirMaxSize": 104857600, "netType": "wifi", "mno": "office", "clientIP": "20.13.21.24" } } |
字段 |
释义 |
类型 |
|
prof |
enable |
日志开关,1为开,0为关,可选,默认为关 |
int |
output |
日志输出路径,可选,默认为标准输出 |
string |
|
level |
日志等级,默认为1 |
int |
|
deviceId |
设备唯一标识,用于数据上传 |
string |
|
userId |
用户标识,可选,用于数据上传 |
string |
|
productVersion |
dui发布产品版本,使用数据上传时必选 |
string |
|
upload |
enable |
数据上传开关,1为开,0为关,可选,默认为关 |
int |
logId |
云端日志id,必选,统一使用141 |
int |
|
tmpdir |
存储目录,需要有可写权限,必选 |
string |
|
tmpdirMaxSize |
存储目录最大空间,单位为byte,可选,默认为100m |
int |
|
netType |
客户端网络类型,可选 |
string |
|
mno |
网络运营商类型,可选 |
string |
|
clientIP |
客户端ip,可选 |
string |
日志等级取值如下:
Level |
Value |
Type |
VERBOSE |
1 |
Int |
DEBUG |
2 |
Int |
INFO |
3 |
Int |
WARNING |
4 |
Int |
ERROR |
5 |
Int |
返回值
成功 – 0;
失败 – 非0;
2.6.2 duilite_library_release
void duilite_library_release()
接口能力
释放库资源。
输入参数
无
返回值
无
2.6.3 duilite_library_opt
int duilite_library_opt(int opt, char *data, int size)
接口能力
实现一些辅助功能,如获取版本号和检查授权结果等。
输入参数
opt – 功能类型:
opt |
功能说明 |
DUILITE_OPT_VERSION_STR_GET |
获取版本信息 |
DUILITE_OPT_AUTH_CHECK |
duilite_library_load时授权失败后,获取服务端授权错误码 |
DUILITE_OPT_AUTH_TRY |
执行授权操作 |
DUILITE_OPT_UPLOAD_MODE_GET |
重新从服务端更新数据上传的权限 |
data – 调用者外部申请的内存与该块内存大小,作用如下:
opt |
data |
DUILITE_OPT_VERSION_STR_GET |
用于存放输出的版本信息 |
DUILITE_OPT_AUTH_CHECK |
NULL |
DUILITE_OPT_AUTH_TRY |
输入授权参数,同duilite_library_load授权相关参数 |
DUILITE_OPT_UPLOAD_MODE_GET |
NULL |
size – data大小;
返回值
opt |
返回值 |
DUILITE_OPT_VERSION_STR_GET |
成功 - 输入参数data中版本信息的实际大小 失败 - 非0 |
DUILITE_OPT_AUTH_CHECK |
成功 – 服务端授权错误码 失败 - 非0,若为-1,则为授权库返回,一般为本地校验失败 |
DUILITE_OPT_AUTH_TRY |
成功 - 0 失败 - 非0 |
DUILITE_OPT_UPLOAD_MODE_GET |
成功 - 0 失败 - 非0 |
2.7 附录
DUILite SDK必须通过授权方可使用,目前支持如下三种授权方式,配置参数在初始化时输入,具体的申请方式与收费模式,请咨询相关人员。
预烧录
预烧录方式,涉及到产线支持,一般只应用于特殊的嵌入式硬件产品。需要在DUI平台产品授权页面下载已生成好的profile文件,烧录到设备中去,一台设备对应一个profile文件,不需要联网,sdk配置如下:
{ "productId": "xxx", "savedProfile": "xxx", "deviceProfile": "xxx" } |
参数 |
释义 |
productId |
DUI平台产品ID |
deviceProfile |
deviceProfile文件内容 |
savedProfile |
deviceProfile文件路径 |
deviceProfile与savedProfile二选一即可,若都填写,则使用deviceProfile。
预登记
预登记方式不涉及到产线支持,推荐嵌入式产品使用此种方式,需要开发者在控制台上传所有设备的DeviceName列表的文本文件,即白名单,并要求设备在一次运行时进行了联网注册,只有在白名单内的设备才会注册成功, sdk配置如下:
{ "productId": "xxx", "savedProfile": "xxx", "productKey": "xxx", "productSecret": "xxx", "devInfo": { "deviceName": "xxx", "platform": "xxx", "productId": "xxx", "deviceId": "xxx", "clientName": "xxx", "instructionSet": "xxx", "chipModel": "xxx" } } |
参数 |
释义 |
|
productId |
DUI平台产品ID |
|
savedProfile |
保存deviceProfile文件的路径 |
|
productKey |
与productSecret一起作为产品密钥 |
|
productSecret |
与productKey一起作为产品密钥 |
|
devInfo |
|
设备详细信息,部分可选 |
deviceName |
设备标识,一台设备对应一个设备标识,必选 |
|
platform |
设备平台类型,如Linux,必选 |
|
productId |
DUI平台产品ID,可选 |
|
deviceId |
设备ID,可选 |
|
clientName |
客户端名字,可选 |
|
instructionSet |
指令集,可选 |
|
chipModel |
芯片型号,可选 |
devInfo中的deviceName,用于标识唯一的一台设备,可以使用设备MAC ID等信息。若两台设备使用相同的deviceName,则前一台设备会下线,只允许最近使用该deviceName的设备访问服务。
动态注册
动态注册方式与预登记配置的参数是相同的,不同之处在于动态注册使用的deviceName不需要进行预登记,在设备运行时进行动态的注册即可。同一个产品动态注册和预登记方式的productKey和productSecret是不相同的。