全部产品
云市场

C++ SDK - 新

更新时间:2020-01-09 22:58:15

提示:

  • 在使用SDK之前,请先确保已阅读了 接口说明文档
  • 当前最新版本:3.0.8,发布日期:2020年01月09号。该版本只支持Linux平台,暂不支持Windows平台。
  • 该版本api和上一版本C++ SDK api有不同定义,如果您之前在此之前使用过早期C++ SDK,注意对比区分。
  • 上一版C++ SDK可以从查看该链接:https://help.aliyun.com/document_detail/84554.html ,但仍建议您集成本页面的最新SDK。

下载安装

SDK下载

C++ SDK 可从CppSdk中下载,压缩文件包含以下几个部分:

  • CMakeLists.txt 示例代码工程的CMakeList文件。
  • build 编译目录。
  • readme.txt SDK说明。
  • release.log 版本说明。
  • version 版本号。
  • build.sh demo编译脚本。
  • lib SDK库文件。
  • demo 包含各个示例demo,各语音服务配置文件。各文件描述见下表:
文件名 描述
speechRecognizerDemo.cpp 一句话识别demo
speechSynthesizerDemo.cpp 语音合成demo
speechTranscriberDemo.cpp 实时语音识别demo
speechLongSynthesizerDemo.cpp 长文本语音合成demo
test0.wav等 测试音频(16k 16bit音频文件)
  • include sdk头文件
文件名 描述
nlsClient.h SDK实例
nlsEvent.h 回调事件说明
speechRecognizerRequest.h 一句哈识别
speechSynthesizerRequest.h 语音合成&长文本语音合成
speechTranscriberRequest.h 实时音频流识别

编译运行

cmake编译:

  1. 请确认本地系统以安装Cmake(最低版本3.1)、Glibc 2.5Gcc 4.1.2及以上。
  2. mkdir build
  3. cd build && cmake .. && make
  4. cd ../demo 可以看见以生成demo可执行程序: srDemo(一句话识别)、stDemo(实时语音识别)、syDemo(语音合成)、syLongDemo(长文本语音合成)。
  5. ./demo (Appkey) (AccessKeyId) (AccessKey Secret) # 测试使用

关键接口

基础接口:

  • NlsClient:语音处理Client,相当于所有语音相关处理类的Factory,全局创建一个实例即可。
  • NlsEvent:事件对象,您可以从中获取Request状态码、云端返回结果、失败信息等。

    识别接口:

  • SpeechRecognizerRequest:一句话识别请求对象,用于短语音识别。

    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:
    1. request->setUrl("ws://nls-gateway.cn-shanghai-internal.aliyuncs.com/ws/v1");

    一句话识别示例

    完整示例,详见SDK压缩包中的demo目录speechRecognizerDemo.cpp文件。
    1. #include <string.h>
    2. #include <unistd.h>
    3. #include <pthread.h>
    4. #include <stdlib.h>
    5. #include <ctime>
    6. #include <string>
    7. #include <iostream>
    8. #include <vector>
    9. #include <fstream>
    10. #include <sys/time.h>
    11. #include "nlsClient.h"
    12. #include "nlsEvent.h"
    13. #include "speechRecognizerRequest.h"
    14. #include "nlsCommonSdk/Token.h"
    15. #define FRAME_SIZE 3200
    16. #define SAMPLE_RATE 16000
    17. using namespace AlibabaNlsCommon;
    18. using AlibabaNls::NlsClient;
    19. using AlibabaNls::NlsEvent;
    20. using AlibabaNls::LogDebug;
    21. using AlibabaNls::LogInfo;
    22. using AlibabaNls::LogError;
    23. using AlibabaNls::SpeechRecognizerRequest;
    24. // 自定义线程参数
    25. struct ParamStruct {
    26. std::string fileName;
    27. std::string appkey;
    28. std::string token;
    29. };
    30. // 自定义事件回调参数
    31. struct ParamCallBack {
    32. int userId;
    33. char userInfo[8];
    34. };
    35. //全局维护一个服务鉴权token和其对应的有效期时间戳,
    36. //每次调用服务之前,首先判断token是否已经过期,
    37. //如果已经过期,则根据AccessKey ID和AccessKey Secret重新生成一个token,并更新这个全局的token和其有效期时间戳。
    38. //注意:不要每次调用服务之前都重新生成新token,只需在token即将过期时重新生成即可。所有的服务并发可共用一个token。
    39. std::string g_akId = "";
    40. std::string g_akSecret = "";
    41. std::string g_token = "";
    42. long g_expireTime = -1;
    43. struct timeval tv;
    44. struct timeval tv1;
    45. // 根据AccessKey ID和AccessKey Secret重新生成一个token,并获取其有效期时间戳
    46. // token使用规则:在有效期到期前可以一直使用,且可以多个进程/多个线程/多个应用使用均可,建议在有效期快到期时提起申请新的token
    47. int generateToken(std::string akId, std::string akSecret, std::string* token, long* expireTime) {
    48. NlsToken nlsTokenRequest;
    49. nlsTokenRequest.setAccessKeyId(akId);
    50. nlsTokenRequest.setKeySecret(akSecret);
    51. if (-1 == nlsTokenRequest.applyNlsToken()) {
    52. // 获取失败原因
    53. printf("generateToken Failed: %s\n", nlsTokenRequest.getErrorMsg());
    54. return -1;
    55. }
    56. *token = nlsTokenRequest.getToken();
    57. *expireTime = nlsTokenRequest.getExpireTime();
    58. return 0;
    59. }
    60. //@brief 获取sendAudio发送延时时间
    61. //@param dataSize 待发送数据大小
    62. //@param sampleRate 采样率 16k/8K
    63. //@param compressRate 数据压缩率,例如压缩比为10:1的16k opus编码,此时为10;非压缩数据则为1
    64. //@return 返回sendAudio之后需要sleep的时间
    65. //@note 对于8k pcm 编码数据, 16位采样,建议每发送1600字节 sleep 100 ms.
    66. // 对于16k pcm 编码数据, 16位采样,建议每发送3200字节 sleep 100 ms.
    67. // 对于其它编码格式的数据, 用户根据压缩比, 自行估算, 比如压缩比为10:1的 16k opus,
    68. // 需要每发送3200/10=320 sleep 100ms.
    69. unsigned int getSendAudioSleepTime(int dataSize, int sampleRate, int compressRate) {
    70. // 仅支持16位采样
    71. const int sampleBytes = 16;
    72. // 仅支持单通道
    73. const int soundChannel = 1;
    74. // 当前采样率,采样位数下每秒采样数据的大小
    75. int bytes = (sampleRate * sampleBytes * soundChannel) / 8;
    76. // 当前采样率,采样位数下每毫秒采样数据的大小
    77. int bytesMs = bytes / 1000;
    78. // 待发送数据大小除以每毫秒采样数据大小,以获取sleep时间
    79. int sleepMs = (dataSize * compressRate) / bytesMs;
    80. return sleepMs;
    81. }
    82. //@brief 调用start(), 成功与云端建立连接, sdk内部线程上报started事件
    83. //@param cbEvent 回调事件结构, 详见nlsEvent.h
    84. //@param cbParam 回调自定义参数,默认为NULL, 可以根据需求自定义参数
    85. void OnRecognitionStarted(NlsEvent* cbEvent, void* cbParam) {
    86. ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
    87. // 演示如何打印/使用用户自定义参数示例
    88. printf("OnRecognitionStarted: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
    89. // 获取消息的状态码,成功为0或者20000000,失败时对应失败的错误码
    90. // 当前任务的task id,方便定位问题,建议输出,特别提醒该taskid非常重要,是和服务端交互的唯一标识,因此建议在实际使用时建议输出该taskid
    91. printf("OnRecognitionStarted: status code=%d, task id=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId());
    92. // 获取服务端返回的全部信息
    93. //printf("OnRecognitionStarted: all response=%s\n", cbEvent->getAllResponse());
    94. }
    95. //@brief 设置允许返回中间结果参数, sdk在接收到云端返回到中间结果时, sdk内部线程上报ResultChanged事件
    96. //@param cbEvent 回调事件结构, 详见nlsEvent.h
    97. //@param cbParam 回调自定义参数,默认为NULL, 可以根据需求自定义参数
    98. void OnRecognitionResultChanged(NlsEvent* cbEvent, void* cbParam) {
    99. ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
    100. // 演示如何打印/使用用户自定义参数示例
    101. printf("OnRecognitionResultChanged: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
    102. // 当前任务的task id,方便定位问题,建议输出,特别提醒该taskid非常重要,是和服务端交互的唯一标识,因此建议在实际使用时建议输出该taskid
    103. printf("OnRecognitionResultChanged: status code=%d, task id=%s, result=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getResult());
    104. // 获取服务端返回的全部信息
    105. //printf("OnRecognitionResultChanged: response=%s\n", cbEvent->getAllResponse());
    106. }
    107. //@brief sdk在接收到云端返回识别结束消息时, sdk内部线程上报Completed事件
    108. //@note 上报Completed事件之后, SDK内部会关闭识别连接通道. 此时调用sendAudio会返回-1, 请停止发送.
    109. //@param cbEvent 回调事件结构, 详见nlsEvent.h
    110. //@param cbParam 回调自定义参数,默认为NULL, 可以根据需求自定义参数
    111. void OnRecognitionCompleted(NlsEvent* cbEvent, void* cbParam) {
    112. ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
    113. // 演示如何打印/使用用户自定义参数示例
    114. printf("OnRecognitionCompleted: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
    115. // 当前任务的task id,方便定位问题,建议输出,特别提醒该taskid非常重要,是和服务端交互的唯一标识,因此建议在实际使用时建议输出该taskid
    116. printf("OnRecognitionCompleted: status code=%d, task id=%s, result=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getResult());
    117. // 获取服务端返回的全部信息
    118. //printf("OnRecognitionCompleted: response=%s\n", cbEvent->getAllResponse());
    119. }
    120. //@brief 识别过程发生异常时, sdk内部线程上报TaskFailed事件
    121. //@note 上报TaskFailed事件之后, SDK内部会关闭识别连接通道. 此时调用sendAudio会返回-1, 请停止发送.
    122. //@param cbEvent 回调事件结构, 详见nlsEvent.h
    123. //@param cbParam 回调自定义参数,默认为NULL, 可以根据需求自定义参数
    124. //@return
    125. void OnRecognitionTaskFailed(NlsEvent* cbEvent, void* cbParam) {
    126. ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
    127. // 演示如何打印/使用用户自定义参数示例
    128. printf("OnRecognitionTaskFailed: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
    129. // 当前任务的task id,方便定位问题,建议输出,特别提醒该taskid非常重要,是和服务端交互的唯一标识,因此建议在实际使用时建议输出该taskid
    130. printf("OnRecognitionTaskFailed: status code=%d, task id=%s, error message=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getErrorMessage());
    131. // 获取服务端返回的全部信息
    132. //printf("OnRecognitionTaskFailed: response=%s\n", cbEvent->getAllResponse());
    133. }
    134. //@brief 识别结束或发生异常时,会关闭连接通道, sdk内部线程上报ChannelCloseed事件
    135. //@param cbEvent 回调事件结构, 详见nlsEvent.h
    136. //@param cbParam 回调自定义参数,默认为NULL, 可以根据需求自定义参数
    137. void OnRecognitionChannelClosed(NlsEvent* cbEvent, void* cbParam) {
    138. ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
    139. // 演示如何打印/使用用户自定义参数示例
    140. printf("OnRecognitionChannelClosed: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
    141. // 获取服务端返回的全部信息
    142. printf("OnRecognitionChannelClosed: response=%s\n", cbEvent->getAllResponse());
    143. delete tmpParam; //识别流程结束,释放回调参数
    144. }
    145. void* pthreadFunction(void* arg) {
    146. int sleepMs = 0;
    147. ParamCallBack *cbParam = NULL;
    148. //初始化自定义回调参数, 以下两变量仅作为示例表示参数传递, 在demo中不起任何作用
    149. //回调参数在堆中分配之后, SDK在销毁requesr对象时会一并销毁, 外界无需在释放
    150. cbParam = new ParamCallBack;
    151. cbParam->userId = rand() % 100;
    152. strcpy(cbParam->userInfo, "User.");
    153. // 0: 从自定义线程参数中获取token, 配置文件等参数.
    154. ParamStruct *tst = (ParamStruct *) arg;
    155. if (tst == NULL) {
    156. printf("arg is not valid\n");
    157. return NULL;
    158. }
    159. // 打开音频文件, 获取数据
    160. std::ifstream fs;
    161. fs.open(tst->fileName.c_str(), std::ios::binary | std::ios::in);
    162. if (!fs) {
    163. printf("%s isn't exist..\n", tst->fileName.c_str());
    164. return NULL;
    165. }
    166. //1: 创建一句话识别SpeechRecognizerRequest对象
    167. SpeechRecognizerRequest *request = NlsClient::getInstance()->createRecognizerRequest();
    168. if (request == NULL) {
    169. printf("createRecognizerRequest failed\n");
    170. return NULL;
    171. }
    172. request->setOnRecognitionStarted(OnRecognitionStarted, cbParam); // 设置start()成功回调函数
    173. request->setOnTaskFailed(OnRecognitionTaskFailed, cbParam); // 设置异常识别回调函数
    174. request->setOnChannelClosed(OnRecognitionChannelClosed, cbParam); // 设置识别通道关闭回调函数
    175. request->setOnRecognitionResultChanged(OnRecognitionResultChanged, cbParam); // 设置中间结果回调函数
    176. request->setOnRecognitionCompleted(OnRecognitionCompleted, cbParam); // 设置识别结束回调函数
    177. request->setAppKey(tst->appkey.c_str()); // 设置AppKey, 必填参数, 请参照官网申请
    178. request->setFormat("pcm"); // 设置音频数据编码格式, 可选参数, 目前支持pcm, opus. 默认是pcm
    179. request->setSampleRate(SAMPLE_RATE); // 设置音频数据采样率, 可选参数, 目前支持16000, 8000. 默认是16000
    180. request->setIntermediateResult(true); // 设置是否返回中间识别结果, 可选参数. 默认false
    181. request->setPunctuationPrediction(true); // 设置是否在后处理中添加标点, 可选参数. 默认false
    182. request->setInverseTextNormalization(true); // 设置是否在后处理中执行ITN, 可选参数. 默认false
    183. //request->setEnableVoiceDetection(true); //是否启动语音检测, 可选, 默认是False
    184. //允许的最大开始静音, 可选, 单位是毫秒, 超出后服务端将会发送RecognitionCompleted事件, 结束本次识别. 注意: 需要先设置enable_voice_detection为true
    185. //request->setMaxStartSilence(5000);
    186. //允许的最大结束静音, 可选, 单位是毫秒, 超出后服务端将会发送RecognitionCompleted事件, 结束本次识别. 注意: 需要先设置enable_voice_detection为true
    187. //request->setMaxEndSilence(800);
    188. //request->setCustomizationId("TestId_123"); //定制语言模型id, 可选.
    189. //request->setVocabularyId("TestId_456"); //定制泛热词id, 可选.
    190. // 用于传递某些定制化、高级参数设置,参数格式为json格式: {"key": "value"}
    191. //request->setPayloadParam("{\"vad_model\": \"farfield\"}");
    192. request->setToken(tst->token.c_str()); // 设置账号校验token, 必填参数
    193. // 2: start()为异步操作。成功返回started事件。失败返回TaskFailed事件。
    194. if (request->start() < 0) {
    195. printf("start() failed. may be can not connect server. please check network or firewalld\n");
    196. NlsClient::getInstance()->releaseRecognizerRequest(request); // start()失败,释放request对象
    197. return NULL;
    198. }
    199. while (!fs.eof()) {
    200. uint8_t data[FRAME_SIZE] = {0};
    201. fs.read((char *) data, sizeof(uint8_t) * FRAME_SIZE);
    202. size_t nlen = fs.gcount();
    203. if (nlen <= 0) {
    204. continue;
    205. }
    206. // 3: 发送音频数据. sendAudio为异步操作, 返回-1表示发送失败, 需要停止发送.
    207. int ret = request->sendAudio(data, nlen);
    208. if (ret < 0) {
    209. // 发送失败, 退出循环数据发送
    210. printf("send data fail.\n");
    211. break;
    212. }
    213. // 语音数据发送控制:
    214. // 语音数据是实时的, 不用sleep控制速率, 直接发送即可.
    215. // 语音数据来自文件(也即本示例代码模拟的语音流发送机制), 发送时需要控制速率, 使单位时间内发送的数据大小接近单位时间原始语音数据存储的大小.
    216. sleepMs = getSendAudioSleepTime(nlen, SAMPLE_RATE, 1); // 根据 发送数据大小,采样率,数据压缩比 来获取sleep时间
    217. // 4: 语音数据发送延时控制
    218. usleep(sleepMs * 1000);
    219. }
    220. printf("sendAudio done.\n");
    221. //5: 关闭音频文件
    222. fs.close();
    223. //6: 通知云端数据发送结束.
    224. //stop()为异步操作.失败返回TaskFailed事件。
    225. request->stop();
    226. //7: 通知SDK释放request.
    227. NlsClient::getInstance()->releaseRecognizerRequest(request);
    228. return NULL;
    229. }
    230. //线程循环识别
    231. //需要调整count值和每次要识别的文件,Demo中默认每次识别一个文件
    232. void* multiRecognize(void* arg) {
    233. int count = 2;
    234. while (count > 0) {
    235. pthreadFunction(arg);
    236. count--;
    237. }
    238. return NULL;
    239. }
    240. // 识别单个音频数据
    241. int speechRecognizerFile(const char* appkey) {
    242. //获取当前系统时间戳,判断token是否过期
    243. std::time_t curTime = std::time(0);
    244. if (g_expireTime - curTime < 10) {
    245. printf("the token will be expired, please generate new token by AccessKey-ID and AccessKey-Secret.\n");
    246. if (-1 == generateToken(g_akId, g_akSecret, &g_token, &g_expireTime)) {
    247. return -1;
    248. }
    249. }
    250. ParamStruct pa;
    251. pa.token = g_token;
    252. pa.appkey = appkey;
    253. pa.fileName = "test0.wav";
    254. pthread_t pthreadId;
    255. // 启动一个工作线程, 用于单次识别
    256. pthread_create(&pthreadId, NULL, &pthreadFunction, (void *)&pa);
    257. // 启动一个工作线程, 用于循环识别
    258. // pthread_create(&pthreadId, NULL, &multiRecognize, (void *)&pa);
    259. pthread_join(pthreadId, NULL);
    260. return 0;
    261. }
    262. //识别多个音频数据;
    263. //sdk多线程指一个音频数据源对应一个线程, 非一个音频数据对应多个线程.
    264. //示例代码为同时开启2个线程识别2个文件;
    265. //免费用户并发连接不能超过2个;
    266. #define AUDIO_FILE_NUMS 2
    267. #define AUDIO_FILE_NAME_LENGTH 32
    268. int speechRecognizerMultFile(const char* appkey) {
    269. //获取当前系统时间戳,判断token是否过期
    270. std::time_t curTime = std::time(0);
    271. if (g_expireTime - curTime < 10) {
    272. printf("the token will be expired, please generate new token by AccessKey-ID and AccessKey-Secret.\n");
    273. if (-1 == generateToken(g_akId, g_akSecret, &g_token, &g_expireTime)) {
    274. return -1;
    275. }
    276. }
    277. char audioFileNames[AUDIO_FILE_NUMS][AUDIO_FILE_NAME_LENGTH] = {"test0.wav", "test1.wav"};
    278. ParamStruct pa[AUDIO_FILE_NUMS];
    279. for (int i = 0; i < AUDIO_FILE_NUMS; i ++) {
    280. pa[i].token = g_token;
    281. pa[i].appkey = appkey;
    282. pa[i].fileName = audioFileNames[i];
    283. }
    284. std::vector<pthread_t> pthreadId(AUDIO_FILE_NUMS);
    285. // 启动2个工作线程, 同时识别2个音频文件
    286. for (int j = 0; j < AUDIO_FILE_NUMS; j++) {
    287. pthread_create(&pthreadId[j], NULL, &pthreadFunction, (void *)&(pa[j]));
    288. }
    289. for (int j = 0; j < AUDIO_FILE_NUMS; j++) {
    290. pthread_join(pthreadId[j], NULL);
    291. }
    292. return 0;
    293. }
    294. int main(int arc, char* argv[]) {
    295. if (arc < 4) {
    296. printf("params is not valid. Usage: ./demo <your appkey> <your AccessKey ID> <your AccessKey Secret>\n");
    297. return -1;
    298. }
    299. std::string appkey = argv[1];
    300. g_akId = argv[2];
    301. g_akSecret = argv[3];
    302. // 根据需要设置SDK输出日志, 可选. 此处表示SDK日志输出至log-recognizer.txt, LogDebug表示输出所有级别日志,支持LogInfo、LogWarning、LogError, 400表示单个文件400MB
    303. int ret = NlsClient::getInstance()->setLogConfig("log-recognizer", LogDebug, 400);
    304. if (-1 == ret) {
    305. printf("set log failed.\n");
    306. return -1;
    307. }
    308. //启动工作线程
    309. NlsClient::getInstance()->startWorkThread(4);
    310. // 识别单个音频数据
    311. speechRecognizerFile(appkey.c_str());
    312. // 并发识别多个音频数据
    313. //speechRecognizerMultFile(appkey.c_str());
    314. // 所有工作完成,进程退出前,释放nlsClient. 请注意, releaseInstance()非线程安全.
    315. NlsClient::releaseInstance();
    316. return 0;
    317. }