全部产品
阿里云办公

C++ SDK 2.0

更新时间:2018-11-15 11:26:27

版本提示

本文档中的SDK只适用于7月5日新发布的2.0版语音服务,如果您是之前开通的,要使用此SDK需要新开通2.0版服务

C++ SDK 2.0提供了异步识别方式同步识别方式。异步识别方式通过设置回调函数来获取识别结果,数据的发送和识别结果的获取运行在不同的线程中;同步识别方式通过get接口即可获取识别结果,数据的发送和识别结果的获取可以运行在同一个线程中。

当前最新版本:2.3.9,发布日期:2018年11月15号。

下载安装

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下使用。

编译运行

  1. 运行编译脚本build.sh
  2. 1. 请确认本地系统以安装Cmake,最低版本3.1Glibc 2.5Gcc 4.1.2及以上
  3. 2. cd path/to/sdk/lib
  4. 3. tar -zxvpf linux.tar.gz
  5. 4. cd path/to/sdk
  6. 5. 执行./build.sh 编译demo
  7. 6. 编译完毕,进入path/to/sdk/demo目录。可以看见以生成三个demo可执行程序:srDemo(一句话异步识别)、srSyncDemo(一句话同步识别)、stDemo(实时音频异步识别)、stSyncDemo(实时音频同步识别)、syDemo(语音合成)。
  8. 7. 执行[./demo <your appkey> <your AccessKey ID> <your AccessKey Secret>]
  9. 如果不支持cmake,可尝试手动编译:
  10. 1: cd path/to/sdk/lib
  11. 2: tar -zxvpf linux.tar.gz
  12. 3: cd path/to/sdk/demo
  13. 4: g++ -o srDemo speechRecognizerDemo.cpp -I../include -L../lib/linux -lnlsCppSdk -lnlsCommonSdk -lcurl -lssl -lcrypto -lopus -lpthread -luuid -ljsoncpp -D_GLIBCXX_USE_CXX11_ABI=0
  14. 5: export LD_LIBRARY_PATH=path/to/sdk/lib/linux/
  15. 6: ./demo <your appkey> <your AccessKey ID> <your AccessKey Secret>
  16. Windows平台需要用户自己搭建工程。

Token获取方式可见demo.cpp, 或访问链接:获取访问令牌

注意:

  1. linux环境下,运行环境最低要求:Glibc 2.5及以上, Gcc4、Gcc5
  2. 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失败. 释放资源,重新开始识别流程.

代码示例

说明:Demo中使用的音频文件为16000Hz采样率,请在管控台中将appKey对应项目的模型设置为“通用”模型,以获取正确的识别结果;如果使用其他音频,请设置为支持该音频场景的模型,模型设置请阅读管理项目一节。

一句话异步识别示例

完整示例,详见SDK压缩包中的demo目录speechRecognizerDemo.cpp文件。

  1. // 工作线程
  2. void* pthreadFunc(void* arg) {
  3. bool tmpStatus = true;
  4. int sleepMs = 0;
  5. ParamCallBack cbParam;
  6. SpeechRecognizerCallback* callback = NULL;
  7. // 初始化自定义回调参数, 以下两变量仅作为示例表示参数传递, 在demo中不起任何作用
  8. cbParam.iExg = 1;
  9. cbParam.sExg = "exg.";
  10. //控制发送流程
  11. pthread_mutex_init(&(cbParam.mtx), NULL);
  12. cbParam.bSend = true;
  13. // 0: 从自定义线程参数中获取token, 配置文件等参数.
  14. ParamStruct *tst = (ParamStruct *) arg;
  15. if (tst == NULL) {
  16. cout << "arg is not valid." << endl;
  17. return NULL;
  18. }
  19. // 打开音频文件, 获取数据
  20. ifstream fs;
  21. fs.open(tst->fileName.c_str(), ios::binary | ios::in);
  22. if (!fs) {
  23. cout << tst->fileName << " isn't exist.." << endl;
  24. return NULL;
  25. }
  26. /*
  27. * 1: 创建并设置回调函数
  28. */
  29. callback = new SpeechRecognizerCallback();
  30. callback->setOnRecognitionStarted(OnRecognitionStarted, &cbParam); // 设置start()成功回调函数
  31. callback->setOnTaskFailed(OnRecognitionTaskFailed, &cbParam); // 设置异常识别回调函数
  32. callback->setOnChannelClosed(OnRecognitionChannelCloseed, &cbParam); // 设置识别通道关闭回调函数
  33. callback->setOnRecognitionResultChanged(OnRecognitionResultChanged, &cbParam); // 设置中间结果回调函数
  34. callback->setOnRecognitionCompleted(OnRecognitionCompleted, &cbParam); // 设置识别结束回调函数
  35. /*
  36. * 创建一句话识别SpeechRecognizerRequest对象, 参数为callback对象.
  37. * request对象在一个会话周期内可以重复使用.
  38. * 会话周期是一个逻辑概念. 比如Demo中, 指读取, 发送完整个音频文件数据的时间.
  39. * 音频文件数据发送结束时, 可以releaseRecognizerRequest()释放对象.
  40. * createRecognizerRequest(), start(), sendAudio(), stop(), releaseRecognizerRequest()请在
  41. * 同一线程内完成, 跨线程使用可能会引起异常错误。
  42. * 如果需要识别多次,请每次创建一个SpeechRecognizerRequest请求,执行start-sendAudio-stop,然后释放SpeechRecognizerRequest请求。
  43. */
  44. /*
  45. * 2: 创建一句话识别SpeechRecognizerRequest对象
  46. */
  47. SpeechRecognizerRequest *request = NlsClient::getInstance()->createRecognizerRequest(callback);
  48. if (request == NULL) {
  49. cout << "createRecognizerRequest failed." << endl;
  50. delete callback;
  51. callback = NULL;
  52. return NULL;
  53. }
  54. request->setAppKey(tst->appkey.c_str()); // 设置AppKey, 必填参数, 请参照官网申请
  55. request->setFormat("pcm"); // 设置音频数据编码格式, 可选参数, 目前支持pcm, opu, opus, speex. 默认是pcm
  56. request->setSampleRate(SAMPLE_RATE); // 设置音频数据采样率, 可选参数, 目前支持16000, 8000. 默认是16000
  57. request->setIntermediateResult(false); // 设置是否返回中间识别结果, 可选参数. 默认false
  58. request->setPunctuationPrediction(false); // 设置是否在后处理中添加标点, 可选参数. 默认false
  59. request->setInverseTextNormalization(false); // 设置是否在后处理中执行ITN, 可选参数. 默认false
  60. request->setToken(tst->token.c_str()); // 设置账号校验token, 必填参数
  61. /*
  62. * 3: start()为阻塞操作, 发送start指令之后, 会等待服务端响应, 或超时之后才返回
  63. */
  64. if (request->start() < 0) {
  65. cout << "start() failed." << endl;
  66. NlsClient::getInstance()->releaseRecognizerRequest(request); // start()失败,释放request对象
  67. delete callback;
  68. callback = NULL;
  69. return NULL;
  70. }
  71. // 文件是否读取完毕, 或者接收到TaskFailed, closed, completed回调, 终止send
  72. while ((!fs.eof()) && (tmpStatus)) {
  73. char data[FRAME_SIZE] = {0};
  74. fs.read(data, sizeof(char) * FRAME_SIZE);
  75. int nlen = (int) fs.gcount();
  76. /*
  77. * 4: 发送音频数据. sendAudio返回-1表示发送失败, 需要停止发送. 对于第三个参数:
  78. * format为opu(发送原始音频数据必须为PCM, FRAME_SIZE大小必须为640)时, 需设置为true. 其它格式默认使用false.
  79. */
  80. nlen = request->sendAudio(data, nlen, false);
  81. if (nlen < 0) {
  82. // 发送失败, 退出循环数据发送
  83. cout << "send data fail." << endl;
  84. break;
  85. }else {
  86. cout << "send len:" << nlen << " ." << endl;
  87. }
  88. /*
  89. *语音数据发送控制:
  90. *语音数据是实时的, 不用sleep控制速率, 直接发送即可.
  91. *语音数据来自文件, 发送时需要控制速率, 使单位时间内发送的数据大小接近单位时间原始语音数据存储的大小.
  92. */
  93. sleepMs = getSendAudioSleepTime(nlen, SAMPLE_RATE, 1); // 根据 发送数据大小,采样率,数据压缩比 来获取sleep时间
  94. /*
  95. * 5: 语音数据发送延时控制
  96. */
  97. #if defined(_WIN32)
  98. Sleep(sleepMs);
  99. #else
  100. usleep(sleepMs * 1000);
  101. #endif
  102. pthread_mutex_lock(&(cbParam.mtx));
  103. tmpStatus = cbParam.bSend;
  104. pthread_mutex_unlock(&(cbParam.mtx));
  105. }
  106. // 关闭音频文件
  107. fs.close();
  108. /*
  109. * 6: 数据发送结束,关闭识别连接通道.
  110. * stop()为阻塞操作, 在接受到服务端响应, 或者超时之后, 才会返回.
  111. */
  112. request->stop();
  113. // 7: 识别结束, 释放request对象
  114. NlsClient::getInstance()->releaseRecognizerRequest(request);
  115. // 8: 释放callback对象
  116. delete callback;
  117. callback = NULL;
  118. return NULL;
  119. }
  120. /**
  121. * 根据AccessKey ID和AccessKey Secret重新生成一个token,并获取其有效期时间戳
  122. */
  123. int generateToken(string akId, string akSecret, string* token, long* expireTime) {
  124. NlsToken nlsTokenRequest;
  125. nlsTokenRequest.setAccessKeyId(akId);
  126. nlsTokenRequest.setKeySecret(akSecret);
  127. if (-1 == nlsTokenRequest.applyNlsToken()) {
  128. cout << "Failed: " << nlsTokenRequest.getErrorMsg() << endl; /*获取失败原因*/
  129. return -1;
  130. }
  131. *token = nlsTokenRequest.getToken();
  132. *expireTime = nlsTokenRequest.getExpireTime();
  133. return 0;
  134. }
  135. /**
  136. * 识别单个音频数据
  137. */
  138. int speechRecognizerFile(const char* appkey) {
  139. /**
  140. * 获取当前系统时间戳,判断token是否过期
  141. */
  142. std::time_t curTime = std::time(0);
  143. if (g_expireTime - curTime < 10) {
  144. cout << "the token will be expired, please generate new token by AccessKey-ID and AccessKey-Secret." << endl;
  145. if (-1 == generateToken(g_akId, g_akSecret, &g_token, &g_expireTime)) {
  146. return -1;
  147. }
  148. }
  149. ParamStruct pa;
  150. pa.token = g_token;
  151. pa.appkey = appkey;
  152. pa.fileName = "test0.wav";
  153. pthread_t pthreadId;
  154. // 启动一个工作线程, 用于单次识别
  155. pthread_create(&pthreadId, NULL, &pthreadFunc, (void *)&pa);
  156. pthread_join(pthreadId, NULL);
  157. return 0;
  158. }

一句话同步识别示例

完整示例,详见SDK压缩包中的demo目录speechRecognizerSyncDemo.cpp文件。

  1. // 工作线程
  2. void* pthreadFunc(void* arg) {
  3. int sleepMs = 0;
  4. // 0: 从自定义线程参数中获取token, 音频文件等参数.
  5. ParamStruct* tst = (ParamStruct*)arg;
  6. if (tst == NULL) {
  7. cout << "arg is not valid." << endl;
  8. return NULL;
  9. }
  10. // 打开音频文件, 获取数据
  11. FILE* file = fopen(tst->fileName.c_str(), "rb");
  12. if (NULL == file) {
  13. cout << tst->fileName << " isn't exist." << endl;
  14. return NULL;
  15. }
  16. fseek(file, 0, SEEK_END);
  17. int fileSize = ftell(file); // 获取音频文件的长度
  18. fseek(file, 0, SEEK_SET);
  19. /*
  20. * 创建一句话同步识别SpeechRecognizerSyncRequest对象
  21. * request对象在一个会话周期内可以重复使用.
  22. * 会话周期是一个逻辑概念. 比如Demo中, 指读取, 发送完整个音频文件数据的时间.
  23. * 音频文件数据发送结束时, 可以releaseRecognizerSyncRequest()释放对象.
  24. * createRecognizerSyncRequest(), sendSyncAudio(), getRecognizerResult(), releaseRecognizerSyncRequest()请在
  25. * 同一线程内完成, 跨线程使用可能会引起异常错误。
  26. * 如果需要识别多次,请每次创建一个SpeechRecognizerSyncRequest请求,循环执行sendAudio-getRecognizerResult,
  27. * 然后释放SpeechRecognizerSyncRequest请求。
  28. */
  29. /*
  30. * 1: 创建一句话同步识别SpeechRecognizerSyncRequest对象
  31. */
  32. SpeechRecognizerSyncRequest* request = NlsClient::getInstance()->createRecognizerSyncRequest();
  33. if (request == NULL) {
  34. cout << "createRecognizerSyncRequest failed." << endl;
  35. return NULL;
  36. }
  37. request->setAppKey(tst->appkey.c_str()); // 设置AppKey, 必填参数, 请参照官网申请
  38. request->setFormat("pcm"); // 设置音频数据编码格式, 可选参数, 目前支持pcm, opu, opus, speex. 默认是pcm
  39. request->setSampleRate(SAMPLE_RATE); // 设置音频数据采样率, 可选参数, 目前支持16000, 8000. 默认是16000
  40. request->setIntermediateResult(true); // 设置是否返回中间识别结果, 可选参数. 默认false
  41. request->setPunctuationPrediction(true); // 设置是否在后处理中添加标点, 可选参数. 默认false
  42. request->setInverseTextNormalization(true); // 设置是否在后处理中执行ITN, 可选参数. 默认false
  43. request->setToken(tst->token.c_str()); // 设置账号校验token, 必填参数
  44. int sentSize = 0; // 已发送的文件数据大小
  45. int retSize = 0;
  46. while (sentSize < fileSize) {
  47. char data[FRAME_SIZE] = {0};
  48. int size = fread(data, sizeof(char), sizeof(char) * FRAME_SIZE, file);
  49. AudioDataStatus status;
  50. if (sentSize == 0) {
  51. status = AUDIO_FIRST; // 发送第一块音频数据
  52. }
  53. else if (sentSize + size < fileSize) {
  54. status = AUDIO_MIDDLE; // 发送中间音频数据
  55. }
  56. else if (sentSize + size == fileSize) {
  57. status = AUDIO_LAST; // 发送最后一块音频数据
  58. }
  59. sentSize += size;
  60. /*
  61. * 2: 发送音频数据. sendAudio返回-1表示发送失败, 可在getRecognizerResult函数中获得失败的具体信息
  62. * 对于第四个参数: format为opu(发送原始音频数据必须为PCM, FRAME_SIZE大小必须为640)时, 需设置为true. 其它格式默认使用false.
  63. */
  64. retSize = request->sendSyncAudio(data, size, status);
  65. /*
  66. * 语音数据发送控制:
  67. * 语音数据是实时的, 不用sleep控制速率, 直接发送即可.
  68. * 语音数据来自文件, 发送时需要控制速率, 使单位时间内发送的数据大小接近单位时间原始语音数据存储的大小.
  69. */
  70. if (retSize > 0) {
  71. cout << "sendSyncAudio:" << retSize << endl;
  72. sleepMs = getSendAudioSleepTime(retSize, SAMPLE_RATE, 1); // 根据 发送数据大小,采样率,数据压缩比 来获取sleep时间
  73. }
  74. /*
  75. * 3: 语音数据发送延时控制
  76. */
  77. #if defined(_WIN32)
  78. Sleep(sleepMs);
  79. #else
  80. usleep(sleepMs * 1000);
  81. #endif
  82. /*
  83. * 4: 获取识别结果
  84. * 接收到EventType为TaskFailed, closed, completed事件类型时,停止发送数据
  85. * 部分错误可收到多次TaskFailed事件,只要发生TaskFailed事件,请停止发送数据
  86. */
  87. bool isFinished = false;
  88. std::queue<NlsEvent> eventQueue;
  89. request->getRecognizerResult(&eventQueue);
  90. while (!eventQueue.empty()) {
  91. NlsEvent _event = eventQueue.front();
  92. eventQueue.pop();
  93. NlsEvent::EventType type = _event.getMsgType();
  94. switch (type)
  95. {
  96. case NlsEvent::RecognitionStarted:
  97. cout << "************* Recognizer started *************" << endl;
  98. break;
  99. case NlsEvent::RecognitionResultChanged:
  100. cout << "************* Recognizer has middle result *************" << endl;
  101. cout << "result: " << _event.getResult() << endl;
  102. break;
  103. case NlsEvent::RecognitionCompleted:
  104. cout << "************* Recognizer completed *************" << endl;
  105. cout << "result: " << _event.getResult() << endl;
  106. isFinished = true;
  107. break;
  108. case NlsEvent::TaskFailed:
  109. cout << "************* TaskFailed *************" << endl;
  110. isFinished = true;
  111. break;
  112. case NlsEvent::Close:
  113. cout << "************* Closed *************" << endl;
  114. isFinished = true;
  115. break;
  116. default:
  117. break;
  118. }
  119. cout << "allMessage: " << _event.getAllResponse() << endl;
  120. }
  121. if (isFinished) {
  122. break;
  123. }
  124. }
  125. // 关闭音频文件
  126. fclose(file);
  127. // 5: 识别结束, 释放request对象
  128. NlsClient::getInstance()->releaseRecognizerSyncRequest(request);
  129. return NULL;
  130. }
  131. /**
  132. * 根据AccessKey ID和AccessKey Secret重新生成一个token,并获取其有效期时间戳
  133. */
  134. int generateToken(string akId, string akSecret, string* token, long* expireTime) {
  135. NlsToken nlsTokenRequest;
  136. nlsTokenRequest.setAccessKeyId(akId);
  137. nlsTokenRequest.setKeySecret(akSecret);
  138. if (-1 == nlsTokenRequest.applyNlsToken()) {
  139. cout << "Failed: " << nlsTokenRequest.getErrorMsg() << endl; /*获取失败原因*/
  140. return -1;
  141. }
  142. *token = nlsTokenRequest.getToken();
  143. *expireTime = nlsTokenRequest.getExpireTime();
  144. return 0;
  145. }
  146. /**
  147. * 识别单个音频数据
  148. */
  149. int speechRecognizerFile(const char* appkey) {
  150. /**
  151. * 获取当前系统时间戳,判断token是否过期
  152. */
  153. std::time_t curTime = std::time(0);
  154. if (g_expireTime - curTime < 10) {
  155. cout << "the token will be expired, please generate new token by AccessKey-ID and AccessKey-Secret." << endl;
  156. if (-1 == generateToken(g_akId, g_akSecret, &g_token, &g_expireTime)) {
  157. return -1;
  158. }
  159. }
  160. ParamStruct pa;
  161. pa.token = g_token;
  162. pa.appkey = appkey;
  163. pa.fileName = "test0.wav";
  164. pthread_t pthreadId;
  165. // 启动一个工作线程, 用于单次识别
  166. pthread_create(&pthreadId, NULL, &pthreadFunc, (void *)&pa);
  167. pthread_join(pthreadId, NULL);
  168. return 0;
  169. }