提示:
- 在使用SDK之前,请先确保已阅读了接口说明文档。
- C++ SDK 2.0提供了异步识别方式和同步识别方式。异步识别方式通过设置回调函数来获取识别结果,数据的发送和识别结果的获取运行在不同的线程中;同步识别方式通过get接口即可获取识别结果,数据的发送和识别结果的获取可以运行在同一个线程中。
- 当前最新版本:2.3.16,发布日期:2019年8月4号。
下载安装
SDK下载
C++ SDK 可从CppSdk2.0中下载,压缩文件包含以下几个部分:
- CMakeLists.txt demo工程的CMakeList文件。
- build 编译目录。
- demo 包含demo.cpp,各语音服务配置文件。各文件描述见下表:
文件名 | 描述 |
---|---|
sdkDemo.cpp | windows专用,默认为一句话识别功能demo,如需可自行替换成其它功能(编码格式:UTF-8 代签名) |
speechRecognizerDemo.cpp | 一句话异步识别demo |
speechRecognizerSyncDemo.cpp | 一句话同步识别demo |
speechSynthesizerDemo.cpp | 语音合成demo |
speechTranscriberDemo.cpp | 实时语音异步识别demo |
speechTranscriberSyncDemo.cpp | 实时语音同步识别demo |
testX.wav | 测试音频 |
- include 包含sdk头文件,以及部分第三方头文件。各文件描述见下表
文件名 | 描述 |
---|---|
openssl | openssl |
pthread | pthread线(windows下使用) |
uuid | uuid(linux下使用) |
opus | opus |
jsoncpp | jsoncpp |
curl | nls SDK并不依赖curl,仅用于demo中,用以获取token) |
nlsCommonSdknls | nls sdk并不依赖nlsCommonSdk,仅用于demo中,用以获取token |
nlsClient.h | SDK实例 |
nlsEvent.h | 事件说明 |
speechRecognizerRequest.h | 一句话异步识别接口 |
speechRecognizerSyncRequest.h | 一句话同步识别接口 |
speechSynthesizerRequest.h | 语音合成接口 |
speechTranscriberRequest.h | 实时语音异步识别接口 |
speechTranscriberSyncRequest.h | 实时语音同步识别接口 |
iNlsRequest.h | Request基础 |
- lib 包含sdk,以及第三方依赖库。linux.tar.gz为linux平台lib压缩包。windows.zip为windows平台lib压缩包。其中根据平台不同,可以选择linux版本libnlsCppSdk.so(glibc2.5及以上, Gcc4, Gcc5), windows(x86/x64)版本nlsCppSdk.dll(VS2013、VS2015)。
- readme.txt SDK说明。
- release.log 版本说明。
- version 版本号。
- build.sh demo编译脚本。
依赖库:
SDK 依赖 openssl(1.0.2j),opus(1.2.1),jsoncpp(0.10.6), uuid(1.0.3),pthread(2.9.1)。依赖库放置在 path/to/sdk/lib 下。
注意:path/to/sdk/lib/linux/uuid仅在linux下使用。path/to/sdk/lib/windwos/1x.0/pthread仅在windows下使用。
编译运行
运行编译脚本build.sh:
1. 请确认本地系统以安装Cmake,最低版本3.1、Glibc 2.5、Gcc 4.1.2及以上
2. cd NlsSdkCpp2.0//lib
3. tar -zxvpf linux.tar.gz
4. cd NlsSdkCpp2.0/
5. 执行./build.sh 编译demo
6. 编译完毕,进入NlsSdkCpp2.0//demo目录。可以看见以生成三个demo可执行程序:srDemo(一句话异步识别)、srSyncDemo(一句话同步识别)、stDemo(实时音频异步识别)、stSyncDemo(实时音频同步识别)、syDemo(语音合成)。
7. 执行[./srdemo <your appkey> <your AccessKey ID> <your AccessKey Secret>]
如果不支持cmake,可尝试手动编译:
1: cd NlsSdkCpp2.0/lib
2: tar -zxvpf linux.tar.gz
3: cd NlsSdkCpp2.0/demo
4: g++ -o srDemo speechRecognizerDemo.cpp -I../include -L../lib/linux -lnlsCppSdk -lnlsCommonSdk -lopus -lcurl -lssl -lcrypto -lpthread -luuid -ljsoncpp -D_GLIBCXX_USE_CXX11_ABI=0
5: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib/linux
6: ./srdemo <your appkey> <your AccessKey ID> <your AccessKey Secret>
Windows平台需要您自己搭建工程(请将Demo文件修改为含有BOM的UTF-8编码格式)。
Token获取方式可见demo.cpp, 或访问链接:获取访问令牌
注意:
- linux环境下,运行环境最低要求:Glibc 2.5及以上, Gcc4、Gcc5
- windows下,目前支持VS2013,VS2015
关键接口
基础接口:
- NlsClient:语音处理Client,相当于所有语音相关处理类的Factory,全局创建一个实例即可。
- NlsEvent:事件对象,您可以从中获取Request状态码、云端返回结果、失败信息等。
异步识别接口:
- SpeechRecognizerRequest:一句话识别异步请求对象,用于短语音识别。
- SpeechRecognizerCallback:回调事件函数集合的对象,语音结果、异常等回调的统一入口。
同步识别接口:
- SpeechRecognizerSyncRequest: 一句话识别同步请求对象。
更多介绍参见api文档链接:C++ API接口说明
C++ SDK自定义错误码
错误码 | 错误描述 | 解决方案 |
---|---|---|
10000001 | SSL: couldn’t create a ……! | 建议重试 |
10000002 | openssl官方错误描述 | 根据描述提示处理之后,建议重试 |
10000003 | 系统错误描述 | 根据系统错误描述提示处理 |
10000004 | URL: The url is empty. | 检查是否设置 云端URL地址 |
10000005 | URL: Could not parse WebSocket url | 检查是否正确设置 云端URL地址 |
10000006 | MODE: unsupport mode. | 检查时都正确设置了语音功能模式 |
10000007 | JSON: Json parse failed. | 服务端发送错误响应内容,请提供task_id,并反馈给阿里云 |
10000008 | WEBSOCKET: unkown head type. | 服务端发送错误WebSocket类型,请提供task_id,并反馈给阿里云 |
10000009 | HTTP: connect failed. | 与云端连接失败,请检查网络,在重试 |
HTTP协议官方状态码 | HTTP: Got bad status. | 根据HTTP协议官方描述提示处理 |
系统错误码 | IP: ip address is not valid. | 根据系统错误描述提示处理 |
系统错误码 | ENCODE: convert to utf8 error. | 根据系统错误描述提示处理 |
10000010 | please check if the memory is enough | 内存不足. 请检查本地机器内存 |
10000011 | Please check the order of execution | 接口调用顺序错误(接收到Failed/complete事件时,SDK内部会关闭连接。此时在调用send会上报错误。) |
10000012 | StartCommand/StopCommand Send failed | 参数错误. 请检查参数设置是否正确 |
10000013 | The sent data is null or dataSize <= 0. | 发送错误. 请检查发送参数是否正确 |
10000014 | Start invoke failed. | start超时错误. 请调用stop,释放资源,重新开始识别流程. |
10000015 | connect failed等 | connect失败. 释放资源,重新开始识别流程. |
代码示例
说明1:Demo中使用的音频文件为16000Hz采样率,请在管控台中将appKey对应项目的模型设置为通用模型,以获取正确的识别结果;如果使用其他音频,请设置为支持该音频场景的模型,模型设置请阅读管理项目一节。
说明2:Demo中使用了SDK内置的默认一句话识别服务的外网访问URL,如果您使用阿里云上海ECS并想使用内网访问URL,则在创建SpeechRecognizerRequest的对象中设置内网访问的URL:
request->setUrl("ws://nls-gateway.cn-shanghai-internal.aliyuncs.com/ws/v1");
一句话异步识别示例
完整示例,详见SDK压缩包中的demo目录speechRecognizerDemo.cpp文件。
// 工作线程
void* pthreadFunc(void* arg) {
bool tmpStatus = true;
int sleepMs = 0;
ParamCallBack cbParam;
SpeechRecognizerCallback* callback = NULL;
// 初始化自定义回调参数, 以下两变量仅作为示例表示参数传递, 在demo中不起任何作用
cbParam.iExg = 1;
cbParam.sExg = "exg.";
//控制发送流程
pthread_mutex_init(&(cbParam.mtx), NULL);
cbParam.bSend = true;
// 0: 从自定义线程参数中获取token, 配置文件等参数.
ParamStruct *tst = (ParamStruct *) arg;
if (tst == NULL) {
cout << "arg is not valid." << endl;
return NULL;
}
// 打开音频文件, 获取数据
ifstream fs;
fs.open(tst->fileName.c_str(), ios::binary | ios::in);
if (!fs) {
cout << tst->fileName << " isn't exist.." << endl;
return NULL;
}
/*
* 1: 创建并设置回调函数
*/
callback = new SpeechRecognizerCallback();
callback->setOnRecognitionStarted(OnRecognitionStarted, &cbParam); // 设置start()成功回调函数
callback->setOnTaskFailed(OnRecognitionTaskFailed, &cbParam); // 设置异常识别回调函数
callback->setOnChannelClosed(OnRecognitionChannelCloseed, &cbParam); // 设置识别通道关闭回调函数
callback->setOnRecognitionResultChanged(OnRecognitionResultChanged, &cbParam); // 设置中间结果回调函数
callback->setOnRecognitionCompleted(OnRecognitionCompleted, &cbParam); // 设置识别结束回调函数
/*
* 创建一句话识别SpeechRecognizerRequest对象, 参数为callback对象.
* request对象在一个会话周期内可以重复使用.
* 会话周期是一个逻辑概念. 比如Demo中, 指读取, 发送完整个音频文件数据的时间.
* 音频文件数据发送结束时, 可以releaseRecognizerRequest()释放对象.
* createRecognizerRequest(), start(), sendAudio(), stop(), releaseRecognizerRequest()请在
* 同一线程内完成, 跨线程使用可能会引起异常错误。
* 如果需要识别多次,请每次创建一个SpeechRecognizerRequest请求,执行start-sendAudio-stop,然后释放SpeechRecognizerRequest请求。
*/
/*
* 2: 创建一句话识别SpeechRecognizerRequest对象
*/
SpeechRecognizerRequest *request = NlsClient::getInstance()->createRecognizerRequest(callback);
if (request == NULL) {
cout << "createRecognizerRequest failed." << endl;
delete callback;
callback = NULL;
return NULL;
}
request->setAppKey(tst->appkey.c_str()); // 设置AppKey, 必填参数, 请参照官网申请
request->setFormat("pcm"); // 设置音频数据编码格式, 可选参数, 目前支持pcm, opu, opus, speex. 默认是pcm
request->setSampleRate(SAMPLE_RATE); // 设置音频数据采样率, 可选参数, 目前支持16000, 8000. 默认是16000
request->setIntermediateResult(false); // 设置是否返回中间识别结果, 可选参数. 默认false
request->setPunctuationPrediction(false); // 设置是否在后处理中添加标点, 可选参数. 默认false
request->setInverseTextNormalization(false); // 设置是否在后处理中执行ITN, 可选参数. 默认false
request->setToken(tst->token.c_str()); // 设置账号校验token, 必填参数
/*
* 3: start()为阻塞操作, 发送start指令之后, 会等待服务端响应, 或超时之后才返回
*/
if (request->start() < 0) {
cout << "start() failed." << endl;
NlsClient::getInstance()->releaseRecognizerRequest(request); // start()失败,释放request对象
delete callback;
callback = NULL;
return NULL;
}
// 文件是否读取完毕, 或者接收到TaskFailed, closed, completed回调, 终止send
while ((!fs.eof()) && (tmpStatus)) {
char data[FRAME_SIZE] = {0};
fs.read(data, sizeof(char) * FRAME_SIZE);
int nlen = (int) fs.gcount();
/*
* 4: 发送音频数据. sendAudio返回-1表示发送失败, 需要停止发送. 对于第三个参数:
* format为opu(发送原始音频数据必须为PCM, FRAME_SIZE大小必须为640)时, 需设置为true. 其它格式默认使用false.
*/
nlen = request->sendAudio(data, nlen, false);
if (nlen < 0) {
// 发送失败, 退出循环数据发送
cout << "send data fail." << endl;
break;
}else {
cout << "send len:" << nlen << " ." << endl;
}
/*
*语音数据发送控制:
*语音数据是实时的, 不用sleep控制速率, 直接发送即可.
*语音数据来自文件, 发送时需要控制速率, 使单位时间内发送的数据大小接近单位时间原始语音数据存储的大小.
*/
sleepMs = getSendAudioSleepTime(nlen, SAMPLE_RATE, 1); // 根据 发送数据大小,采样率,数据压缩比 来获取sleep时间
/*
* 5: 语音数据发送延时控制
*/
#if defined(_WIN32)
Sleep(sleepMs);
#else
usleep(sleepMs * 1000);
#endif
pthread_mutex_lock(&(cbParam.mtx));
tmpStatus = cbParam.bSend;
pthread_mutex_unlock(&(cbParam.mtx));
}
// 关闭音频文件
fs.close();
/*
* 6: 数据发送结束,关闭识别连接通道.
* stop()为阻塞操作, 在接受到服务端响应, 或者超时之后, 才会返回.
*/
request->stop();
// 7: 识别结束, 释放request对象
NlsClient::getInstance()->releaseRecognizerRequest(request);
// 8: 释放callback对象
delete callback;
callback = NULL;
return NULL;
}
/**
* 根据AccessKey ID和AccessKey Secret重新生成一个token,并获取其有效期时间戳
*/
int generateToken(string akId, string akSecret, string* token, long* expireTime) {
NlsToken nlsTokenRequest;
nlsTokenRequest.setAccessKeyId(akId);
nlsTokenRequest.setKeySecret(akSecret);
if (-1 == nlsTokenRequest.applyNlsToken()) {
cout << "Failed: " << nlsTokenRequest.getErrorMsg() << endl; /*获取失败原因*/
return -1;
}
*token = nlsTokenRequest.getToken();
*expireTime = nlsTokenRequest.getExpireTime();
return 0;
}
/**
* 识别单个音频数据
*/
int speechRecognizerFile(const char* appkey) {
/**
* 获取当前系统时间戳,判断token是否过期
*/
std::time_t curTime = std::time(0);
if (g_expireTime - curTime < 10) {
cout << "the token will be expired, please generate new token by AccessKey-ID and AccessKey-Secret." << endl;
if (-1 == generateToken(g_akId, g_akSecret, &g_token, &g_expireTime)) {
return -1;
}
}
ParamStruct pa;
pa.token = g_token;
pa.appkey = appkey;
pa.fileName = "test0.wav";
pthread_t pthreadId;
// 启动一个工作线程, 用于单次识别
pthread_create(&pthreadId, NULL, &pthreadFunc, (void *)&pa);
pthread_join(pthreadId, NULL);
return 0;
}
一句话同步识别示例
完整示例,详见SDK压缩包中的demo目录speechRecognizerSyncDemo.cpp文件。
// 工作线程
void* pthreadFunc(void* arg) {
int sleepMs = 0;
// 0: 从自定义线程参数中获取token, 音频文件等参数.
ParamStruct* tst = (ParamStruct*)arg;
if (tst == NULL) {
cout << "arg is not valid." << endl;
return NULL;
}
// 打开音频文件, 获取数据
FILE* file = fopen(tst->fileName.c_str(), "rb");
if (NULL == file) {
cout << tst->fileName << " isn't exist." << endl;
return NULL;
}
fseek(file, 0, SEEK_END);
int fileSize = ftell(file); // 获取音频文件的长度
fseek(file, 0, SEEK_SET);
/*
* 创建一句话同步识别SpeechRecognizerSyncRequest对象
* request对象在一个会话周期内可以重复使用.
* 会话周期是一个逻辑概念. 比如Demo中, 指读取, 发送完整个音频文件数据的时间.
* 音频文件数据发送结束时, 可以releaseRecognizerSyncRequest()释放对象.
* createRecognizerSyncRequest(), sendSyncAudio(), getRecognizerResult(), releaseRecognizerSyncRequest()请在
* 同一线程内完成, 跨线程使用可能会引起异常错误。
* 如果需要识别多次,请每次创建一个SpeechRecognizerSyncRequest请求,循环执行sendAudio-getRecognizerResult,
* 然后释放SpeechRecognizerSyncRequest请求。
*/
/*
* 1: 创建一句话同步识别SpeechRecognizerSyncRequest对象
*/
SpeechRecognizerSyncRequest* request = NlsClient::getInstance()->createRecognizerSyncRequest();
if (request == NULL) {
cout << "createRecognizerSyncRequest failed." << endl;
return NULL;
}
request->setAppKey(tst->appkey.c_str()); // 设置AppKey, 必填参数, 请参照官网申请
request->setFormat("pcm"); // 设置音频数据编码格式, 可选参数, 目前支持pcm, opu, opus, speex. 默认是pcm
request->setSampleRate(SAMPLE_RATE); // 设置音频数据采样率, 可选参数, 目前支持16000, 8000. 默认是16000
request->setIntermediateResult(true); // 设置是否返回中间识别结果, 可选参数. 默认false
request->setPunctuationPrediction(true); // 设置是否在后处理中添加标点, 可选参数. 默认false
request->setInverseTextNormalization(true); // 设置是否在后处理中执行ITN, 可选参数. 默认false
request->setToken(tst->token.c_str()); // 设置账号校验token, 必填参数
int sentSize = 0; // 已发送的文件数据大小
int retSize = 0;
while (sentSize < fileSize) {
char data[FRAME_SIZE] = {0};
int size = fread(data, sizeof(char), sizeof(char) * FRAME_SIZE, file);
AudioDataStatus status;
if (sentSize == 0) {
status = AUDIO_FIRST; // 发送第一块音频数据
}
else if (sentSize + size < fileSize) {
status = AUDIO_MIDDLE; // 发送中间音频数据
}
else if (sentSize + size == fileSize) {
status = AUDIO_LAST; // 发送最后一块音频数据
}
sentSize += size;
/*
* 2: 发送音频数据. sendAudio返回-1表示发送失败, 可在getRecognizerResult函数中获得失败的具体信息
* 对于第四个参数: format为opu(发送原始音频数据必须为PCM, FRAME_SIZE大小必须为640)时, 需设置为true. 其它格式默认使用false.
*/
retSize = request->sendSyncAudio(data, size, status);
/*
* 语音数据发送控制:
* 语音数据是实时的, 不用sleep控制速率, 直接发送即可.
* 语音数据来自文件, 发送时需要控制速率, 使单位时间内发送的数据大小接近单位时间原始语音数据存储的大小.
*/
if (retSize > 0) {
cout << "sendSyncAudio:" << retSize << endl;
sleepMs = getSendAudioSleepTime(retSize, SAMPLE_RATE, 1); // 根据 发送数据大小,采样率,数据压缩比 来获取sleep时间
}
/*
* 3: 语音数据发送延时控制
*/
#if defined(_WIN32)
Sleep(sleepMs);
#else
usleep(sleepMs * 1000);
#endif
/*
* 4: 获取识别结果
* 接收到EventType为TaskFailed, closed, completed事件类型时,停止发送数据
* 部分错误可收到多次TaskFailed事件,只要发生TaskFailed事件,请停止发送数据
*/
bool isFinished = false;
std::queue<NlsEvent> eventQueue;
request->getRecognizerResult(&eventQueue);
while (!eventQueue.empty()) {
NlsEvent _event = eventQueue.front();
eventQueue.pop();
NlsEvent::EventType type = _event.getMsgType();
switch (type)
{
case NlsEvent::RecognitionStarted:
cout << "************* Recognizer started *************" << endl;
break;
case NlsEvent::RecognitionResultChanged:
cout << "************* Recognizer has middle result *************" << endl;
cout << "result: " << _event.getResult() << endl;
break;
case NlsEvent::RecognitionCompleted:
cout << "************* Recognizer completed *************" << endl;
cout << "result: " << _event.getResult() << endl;
isFinished = true;
break;
case NlsEvent::TaskFailed:
cout << "************* TaskFailed *************" << endl;
isFinished = true;
break;
case NlsEvent::Close:
cout << "************* Closed *************" << endl;
isFinished = true;
break;
default:
break;
}
cout << "allMessage: " << _event.getAllResponse() << endl;
}
if (isFinished) {
break;
}
}
// 关闭音频文件
fclose(file);
// 5: 识别结束, 释放request对象
NlsClient::getInstance()->releaseRecognizerSyncRequest(request);
return NULL;
}
/**
* 根据AccessKey ID和AccessKey Secret重新生成一个token,并获取其有效期时间戳
*/
int generateToken(string akId, string akSecret, string* token, long* expireTime) {
NlsToken nlsTokenRequest;
nlsTokenRequest.setAccessKeyId(akId);
nlsTokenRequest.setKeySecret(akSecret);
if (-1 == nlsTokenRequest.applyNlsToken()) {
cout << "Failed: " << nlsTokenRequest.getErrorMsg() << endl; /*获取失败原因*/
return -1;
}
*token = nlsTokenRequest.getToken();
*expireTime = nlsTokenRequest.getExpireTime();
return 0;
}
/**
* 识别单个音频数据
*/
int speechRecognizerFile(const char* appkey) {
/**
* 获取当前系统时间戳,判断token是否过期
*/
std::time_t curTime = std::time(0);
if (g_expireTime - curTime < 10) {
cout << "the token will be expired, please generate new token by AccessKey-ID and AccessKey-Secret." << endl;
if (-1 == generateToken(g_akId, g_akSecret, &g_token, &g_expireTime)) {
return -1;
}
}
ParamStruct pa;
pa.token = g_token;
pa.appkey = appkey;
pa.fileName = "test0.wav";
pthread_t pthreadId;
// 启动一个工作线程, 用于单次识别
pthread_create(&pthreadId, NULL, &pthreadFunc, (void *)&pa);
pthread_join(pthreadId, NULL);
return 0;
}