本文档中的SDK只适用于7月5日新发布的2.0版语音服务,如果您是之前开通的,要使用此SDK需要新开通2.0版服务。否则请继续使用旧版SDK,并按照1.0版文档对接。
C++ SDK 2.0实时语音识别提供了异步识别方式和同步识别方式。异步识别方式通过设置回调函数来获取识别结果,数据的发送和识别结果的获取运行在不同的线程中;同步识别方式通过get接口即可获取识别结果,数据的发送和识别结果的获取可以运行在同一个线程中。
下载安装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 |
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版本32/64位libnlsCppSdk.so(glibc2.5及以上, Gcc4, Gcc5), windows版本32/64位nlsCppSdk.dll(VS2013、VS2015)。
- readme.txt SDK说明。
- release.log 版本说明。
- version 版本号。
- build.sh demo编译脚本。
依赖库:SDK 依赖 openssl(l-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下使用。SDK压缩包内提供的依赖库为64位,不提供32位。在32位下,需要用户自行编译。
编译运行
Linux平台下cmake编译: 1: 请确认本地系统以安装Cmake,最低版本2.6 2: cd path/to/sdk/lib 3: tar -zxvpf linux.tar.gz 4: cd path/to/sdk 3: 执行[./build.sh]编译demo 4: 编译完毕,cd path/to/sdk/demo,执行[./stDemo your-token your-appkey]
如果不支持cmake,可尝试手动编译: 1: cd path/to/sdk/lib 2: tar -zxvpf linux.tar.gz 3: cd path/to/sdk/demo 4: g++ -o stDemo speechTranscriberDemo.cpp -I./path/to/sdk/include -L./path/to/sdk/lib/linux -lnlsCppSdk -lssl -lcrypto -lopus -luuid -lpthread -ljsoncpp -D_GLIBCXX_USE_CXX11_ABI=0 5: export LD_LIBRARY_PATH=path/to/sdk/lib/linux/ 6: ./stDemo your-token your-appkey
Windows平台需要用户自己搭建工程。
Token获取方式可见链接:获取访问令牌
注意:
- linux环境下,运行环境最低要求:Glibc 2.5及以上, Gcc4、Gcc5
- windows下,目前支持VS2013,VS2015
关键接口基础接口
- NlsClient:语音处理Client,相当于所有语音相关处理类的Factory,全局创建一个实例即可。
- NlsEvent:事件对象,用户可以从中获取Request状态码、云端返回结果、失败信息等。
异步识别接口
- SpeechTranscriberRequest:实时音频流识别请求对象。
- SpeechTranscriberCallback:回调事件函数集合的对象,语音结果、异常等回调的统一入口。
同步识别接口
- SpeechTranscriberSyncRequest: 一句话识别同步请求对象。
更多介绍参见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失败. 释放资源,重新开始识别流程. |
代码示例实时语音异步识别示例完整示例,详见SDK压缩包中的demo目录speechTranscriberDemo.cpp文件。
// 工作线程 void* pthreadFunc(void* arg) { int sleepMs = 0; ParamCallBack cbParam; SpeechTranscriberCallback* callback = NULL;
// 0: 从自定义线程参数中获取token, 配置文件等参数. ParamStruct* tst = (ParamStruct*)arg; if (tst == NULL) { cout << "arg is not valid." << endl; return NULL; }
// 初始化自定义回调参数, 仅作为示例表示参数传递, 在demo中不起任何作用 cbParam.iExg = 1; cbParam.sExg = "exg.";
/* 打开音频文件, 获取数据 */ 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 SpeechTranscriberCallback(); callback->setOnTranscriptionStarted(onTranscriptionStarted, &cbParam); // 设置识别启动回调函数 callback->setOnTranscriptionResultChanged(onTranscriptionResultChanged, &cbParam); // 设置识别结果变化回调函数 callback->setOnTranscriptionCompleted(onTranscriptionCompleted, &cbParam); // 设置语音转写结束回调函数 callback->setOnSentenceBegin(onSentenceBegin, &cbParam); // 设置一句话开始回调函数 callback->setOnSentenceEnd(onSentenceEnd, &cbParam); // 设置一句话结束回调函数 callback->setOnTaskFailed(onTaskFailed, &cbParam); // 设置异常识别回调函数 callback->setOnChannelClosed(onChannelClosed, &cbParam); // 设置识别通道关闭回调函数
/* * 创建实时音频流识别SpeechTranscriberRequest对象, 参数为callback对象. * request对象在一个会话周期内可以重复使用. * 会话周期是一个逻辑概念. 比如Demo中, 指读取, 发送完整个音频文件数据的时间. * 音频文件数据发送结束时, 可以releaseTranscriberRequest()释放对象. * createTranscriberRequest(), start(), sendAudio(), stop(), releaseTranscriberRequest()请在 * 同一线程内完成, 跨线程使用可能会引起异常错误. */ /* * 2: 创建实时音频流识别SpeechTranscriberRequest对象 */ SpeechTranscriberRequest* request = NlsClient::getInstance()->createTranscriberRequest(callback); if (request == NULL) { cout << "createTranscriberRequest failed." << endl;
delete callback; callback = NULL;
return NULL; }
request->setAppKey(tst->appkey.c_str()); // 设置AppKey, 必填参数, 请参照官网申请 request->setFormat("pcm"); // 设置音频数据编码格式, 可选参数,目前支持pcm, opu. 默认是pcm request->setSampleRate(16000); // 设置音频数据采样率, 可选参数,目前支持16000, 8000. 默认是16000 request->setIntermediateResult(false); // 设置是否返回中间识别结果, 可选参数. 默认false request->setPunctuationPrediction(false); // 设置是否在后处理中添加标点, 可选参数. 默认false request->setInverseTextNormalization(false); // 设置是否在后处理中执行数字转写, 可选参数. 默认false request->setSemanticSentenceDetection(false); // 设置是否语义断句, 可选参数. 默认false request->setMaxSentenceSilence(500); // 设置vad阀值, 可选参数. 合法参数范围200~2000(ms), 默认值800ms
request->setToken(tst->token.c_str()); // 设置账号校验token, 必填参数
/* * 3: start()为阻塞操作, 发送start指令之后, 会等待服务端响应, 或超时之后才返回 */ if (request->start() < 0) { cout << "start() failed." << endl; NlsClient::getInstance()->releaseTranscriberRequest(request); // start()失败,释放request对象
delete callback; callback = NULL;
return NULL; }
// 文件是否读取完毕, 或者接收到TaskFailed, closed, completed回调, 终止send while (!fs.eof()) { char data[FRAME_SIZE] = {0};
fs.read(data, sizeof(char) * FRAME_SIZE); int nlen = fs.gcount();
/* * 4: 发送音频数据. sendAudio返回-1表示发送失败, 需要停止发送. 对于第三个参数: * request对象format参数为pcm时, 使用false即可. format为opu, 使用压缩数据时, 需设置为true. */ nlen = request->sendAudio(data, nlen, false); if (nlen < 0) { // 发送失败, 退出循环数据发送 cout << "send data fail." << endl; break; } else { cout << "send len:" << nlen << " ." << endl; }
/* *语音数据发送控制: *语音数据是实时的, 不用sleep控制速率, 直接发送即可. *语音数据来自文件, 发送时需要控制速率, 使单位时间内发送的数据大小接近单位时间原始语音数据存储的大小. */ sleepMs = getSendAudioSleepTime(6400, 16000, 1); // 根据 发送数据大小,采样率,数据压缩比 来获取sleep时间
/* * 5: 语音数据发送延时控制 */ #ifdef _WIN32 Sleep(sleepMs); #else usleep(sleepMs * 1000); #endif }
// 关闭音频文件 fs.close();
/* * 6: 数据发送结束,关闭识别连接通道. * stop()为阻塞操作, 在接受到服务端响应, 或者超时之后, 才会返回. */ request->stop(); /* * 7: 识别结束, 释放request对象 */ NlsClient::getInstance()->releaseTranscriberRequest(request);
/* * 8: 释放callback对象 */ delete callback; callback = NULL;
return NULL; }
实时语音同步识别示例完整示例,详见SDK压缩包中的demo目录speechTranscriberSyncDemo.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);
/* * 创建实时音频流同步识别SpeechTranscriberSyncRequest对象. * request对象在一个会话周期内可以重复使用. * 会话周期是一个逻辑概念. 比如Demo中, 指读取, 发送完整个音频文件数据的时间. * 音频文件数据发送结束时, 可以releaseTranscriberSyncRequest()释放对象. * createTranscriberSyncRequest(), sendSyncAudio(), getTranscriberResult(), releaseTranscriberSyncRequest()请在 * 同一线程内完成, 跨线程使用可能会引起异常错误. */ /* * 1: 创建实时音频流识别SpeechTranscriberSyncRequest对象 */ SpeechTranscriberSyncRequest* request = NlsClient::getInstance()->createTranscriberSyncRequest(); if (request == NULL) { cout << "createTranscriberSyncRequest failed." << endl; return NULL; }
request->setAppKey(tst->appkey.c_str()); // 设置AppKey, 必填参数, 请参照官网申请 request->setFormat("pcm"); // 设置音频数据编码格式, 可选参数,目前支持pcm, opu. 默认是pcm request->setSampleRate(16000); // 设置音频数据采样率, 可选参数,目前支持16000, 8000. 默认是16000 request->setIntermediateResult(true); // 设置是否返回中间识别结果, 可选参数. 默认false request->setPunctuationPrediction(true); // 设置是否在后处理中添加标点, 可选参数. 默认false request->setInverseTextNormalization(true); // 设置是否在后处理中执行数字转写, 可选参数. 默认false request->setSemanticSentenceDetection(false); // 设置是否语义断句, 可选参数. 默认false request->setMaxSentenceSilence(500); // 设置vad阀值, 可选参数. 合法参数范围200~2000(ms), 默认值800ms request->setToken(tst->token.c_str()); // 设置账号校验token, 必填参数
int sentSize = 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表示发送失败, 可在getTranscriberResult函数中获得失败的具体信息 * 对于第四个参数, request对象format参数为pcm时, 使用false即可. format为opu, 使用压缩数据时, 需设置为true. */ request->sendSyncAudio(data, size, status);
/* *语音数据发送控制: *语音数据是实时的, 不用sleep控制速率, 直接发送即可. *语音数据来自文件, 发送时需要控制速率, 使单位时间内发送的数据大小接近单位时间原始语音数据存储的大小. */ sleepMs = getSendAudioSleepTime(6400, 16000, 1); // 根据 发送数据大小,采样率,数据压缩比 来获取sleep时间
/* * 3: 语音数据发送延时控制 */ #ifdef _WIN32 Sleep(sleepMs); #else usleep(sleepMs * 1000); #endif
/* * 4: 获取识别结果 * 接收到EventType为TaskFailed, closed, completed事件类型时,停止发送数据 * 部分错误可收到多次TaskFailed事件,只要发生TaskFailed事件,请停止发送数据 */ bool isFinished = false; std::queue<NlsEvent> eventQueue; request->getTranscriberResult(&eventQueue); while (!eventQueue.empty()) { NlsEvent _event = eventQueue.front(); eventQueue.pop();
NlsEvent::EventType type = _event.getMsgType(); switch (type) { case NlsEvent::TranscriptionStarted: cout << "************* Transcriber started *************" << endl; break; case NlsEvent::SentenceBegin: cout << "************* Detected sentence begin *************" << endl; cout << "sentence index: " << _event.getSentenceIndex() << endl; cout << "sentence time: " << _event.getSentenceTime() << endl; break; case NlsEvent::TranscriptionResultChanged: cout << "************* Transcriber has sentence middle result *************" << endl; cout << "sentence index: " << _event.getSentenceIndex() << endl; cout << "sentence time: " << _event.getSentenceTime() << endl; cout << "result: " << _event.getResult() << endl; break; case NlsEvent::SentenceEnd: cout << "************* Detected sentence end *************" << endl; cout << "sentence index: " << _event.getSentenceIndex() << endl; cout << "sentence time: " << _event.getSentenceTime() << endl; cout << "result: " << _event.getResult() << endl; break; case NlsEvent::TranscriptionCompleted: cout << "************* Transcriber completed *************" << 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()->releaseTranscriberSyncRequest(request);
return NULL; }
|