C++ SDK

本文介绍如何使用阿里云智能语音服务提供的C++ SDK,包括SDK的安装方法及SDK代码示例。

SDK下载

说明

  • 当前最新版本:3.1.13,支持Linux、Windows及Android平台。发布日期:2022年04月18日。

  • 使用SDK前,请先阅读接口说明,详情请参见接口说明

  • 该版本C++ SDK API 3.1和上一版本API 2.0(已下线)定义有区别,本文以当前版本为例进行介绍。

可通过以下两种方法获取SDK。

  • 方法一:从GitHub获取最新源码,详细编译和运行方式可见下文,或查看源码中的readme.md。

git clone --depth 1 https://github.com/aliyun/alibabacloud-nls-cpp-sdk
  • 方法二:直接从下文表中选取需要SDK包进行下载。其中SDK源码包为SDK原始代码,需要通过下文编译方法生成集成所需的库文件。其他对应平台的SDK包内含相关库文件、头文件,无需编译。

最新SDK包

平台

MD5

alibabacloud-nls-cpp-sdk3.1.13-master_d1b6694.zip

SDK源码

f9f0b479c7008abcc20089e38df8a4ae

NlsCppSdk_Linux_3.1.13_d1b6694.tar.gz

Linux

7849eee151310b22a069ec1c77b93583

NlsCppSdk_Android_3.1.13_d1b6694.tar.gz

Android

0107c1ac58c92b94f35f6d98e2cbf6cf

NlsCppSdk_Windows_3.1.13_d1b6694.zip

Windows

9a658492e7dba4977451e74f4c88ebe0

其中:

  • alibabacloud-nls-cpp-sdk<version>-master_<github commit id>.zip为SDK源码包。

  • NlsCppSdk_<平台>_<版本号>_<github commit id>.tar.gz为对应平台下开发需要的SDK包,详见内部readme.md。

SDK包文件说明

  • scripts/build_linux.sh:SDK源码中,以Linux平台为例的示例编译脚本。

  • CMakeLists.txt:SDK源码中,以Linux/Android平台为例的示例代码工程CMakeList文件。

  • demo目录:SDK包中,集成示例代码,以Linux平台为例,如下表所示。

  • 文件名

    描述

    speechRecognizerDemo.cpp

    一句话识别示例。

    speechSynthesizerDemo.cpp

    语音合成示例。

    speechTranscriberDemo.cpp

    实时语音识别示例。

    fileTransferDemo.cpp

    录音文件识别示例。

  • resource目录:SDK源码中,语音服务范例音频,可用于功能测试,如下表所示。

  • 文件名

    描述

    • test0.wav

    • test1.wav

    • test2.wav

    • test3.wav

    测试音频(16k采样频率、16bit采样位数的音频文件)。

  • include:SDK源码中的头文件,如下表所示。

    文件名

    描述

    nlsClient.h

    SDK实例。

    nlsEvent.h

    回调事件说明。

    nlsGlobal.h

    SDK全局头文件。

    nlsToken.h

    SDK Access Token实例。

    iNlsRequest.h

    NLS请求基础头文件。

    speechRecognizerRequest.h

    一句话识别。

    speechSynthesizerRequest.h

    语音合成、长文本语音合成。

    speechTranscriberRequest.h

    实时音频流识别。

    FileTrans.h

    录音文件识别。

  • lib:SDK库文件。

  • readme.md:SDK说明。

  • release.log:版本说明。

  • version:版本号。

编译运行

Linux平台编译

  1. 安装工具的最低版本要求如下:

    • CMake 3.1

    • Glibc 2.5

    • Gcc 4.1.2

  2. 在Linux终端运行如下脚本。

    1. 进入SDK源码的根目录。

    2. 生成SDK库文件和可执行程序:srDemo(一句话识别)、stDemo(实时语音识别)、syDemo(语音合成)、daDemo(语音对话)。

      ./scripts/build_linux.sh
    3. 查看范例使用方式。

      cd build/demo 
      ./stDemo 

Android平台编译

支持arm64-v8a、armeabi、armeabi-v7a、x86、x86_64编译指令,在SDK源码运行如下编译脚本。

./scripts/build_android.sh #默认增量编译,生成arm64-v8a架构Debug版本
./scripts/build_android.sh all debug arm64-v8a    #全量编译,生成arm64-v8a架构Debug版本
./scripts/build_android.sh incr debug arm64-v8a   #增量编译,生成arm64-v8a架构Debug版本
./scripts/build_android.sh all release arm64-v8a    #全量编译,生成arm64-v8a架构Release版本
./scripts/build_android.sh incr release arm64-v8a    #增量编译,生成arm64-v8a架构Release版本

Windows平台编译

此方式使用已经编译好的第三方库进行编译。

  1. 下载alibabacloud-nls-cpp-sdk<version>-master_<github commit id>.zip并解压到本地,或从GitHub获取最新代码。

  2. 进入scripts目录,使用文本编辑工具分别打开build_windows_64_prebuild.batbuild_windows_64_package.bat,修改解压缩工具WinRAR。

    例如,您的个人电脑WinRAR.exe所在路径为C:\Program Files (x86)\WinRAR\WinRAR.exe,则修改脚本文件中第三行为 set winRar="C:\Program Files (x86)\WinRAR\WinRAR.exe" 为您的个人电脑中WinRAR路径。

  3. 双击批处理脚本build_windows_64_prebuild.bat,从而解压SDK源码中包含的各第三方库,并把依赖头文件释放到合适位置。

  4. 使用Visual Studio(VS2015及以上版本)打开nlsCppSdk.sln,直接编译需要的范例工程。

    说明
    • 需要确认好各项目属性中的目标平台版本平台工具集,按需选择。例如,您的目标平台版本10.0.19041.0平台工具集Visual Studio 2015(v140)

    • 目前支持Debug_x64,Release_x64,Debug_win32和Release_win32。本文档说明均以x64为例。

  5. 右键单击speechTranscriberDemo项目,单击生成进行编译。

  6. 编译Debug_x64和Release_x64。

    • Debug生成物路径:{ProjectRoot}\build\build_win64\nlsCppSdk\x64\Debug

    • Release生成物路径:{ProjectRoot}\build\build_win64\nlsCppSdk\x64\Release

    各路径包含所有生成的dll和测试exe文件。其中{ProjectRoot}为SDK源码路径。

  7. 若需要对生成的库文件、测试exe文件、头文件、说明文档等对外披露的文件进行打包,则在scripts目录下双击运行build_windows_64_package.bat,生成{ProjectRoot}\build\install\NlsSdk3.X_win64.zip。其中{ProjectRoot}为SDK源码路径。

关键接口

  • 基础接口

    • NlsClient:语音处理客户端,利用该客户端可以进行一句话识别、实时语音识别和语音合成的语音处理任务。该客户端为线程安全,建议全局仅创建一个实例。

      接口名

      功能描述

      getInstance

      获取(创建)NlsClient实例。

      setLogConfig

      设置日志文件与存储路径。

      startWorkThread

      启动工作线程数,默认1即启动一个线程,若-1则启动CPU核数的线程数。在高并发的情况下建议选择-1。

      releaseInstance

      销毁NlsClient对象实例。

      getVersion

      获取SDK版本号。

      createTranscriberRequest

      创建实时语音识别对象,线程安全,支持高并发请求。

      releaseTranscriberRequest

      销毁实时语音识别对象,需要在当前请求的closed事件后调用。

    • NlsToken:创建Token对象,用于申请获取TokenId。申请新Token时需要先获取有效时间戳,若超过有效时间则再申请。若在有效时间内多次申请Token会导致TokenId错误而无法使用。

      接口名

      功能描述

      setAccessKeyId

      设置阿里云账号AccessKey ID。

      setKeySecret

      设置阿里云账号AccessKey Secret。

      applyNlsToken

      申请获取TokenId。

      getToken

      获取TokenId。

      getExpireTime

      获取Token有效期时间戳(秒)。

    • NlsEvent:事件对象,您可以从中获取Request状态码、云端返回结果、失败信息等。

      接口名

      功能描述

      getStatusCode

      获取状态码,正常情况为0或者20000000,失败时对应失败的错误码。

      getErrorMessage

      在TaskFailed回调中,获取NlsRequest操作过程中出现失败时的错误信息。

      getTaskId

      获取任务的TaskId。

      getAllResponse

      获取云端返回的识别结果。

      getResult

      获取中间识别结果和最终结果。

      getSentenceIndex

      获取实时语音检测的句子编号。

      getSentenceTime

      获取实时语音检测的句子的音频时长,单位是毫秒。

      getSentenceBeginTime

      对应的SentenceBegin事件的时间,单位是毫秒。

  • 识别接口

    SpeechTranscriberRequest:实时语音识别请求对象,用于长语音实时识别。

    接口名

    功能描述

    setOnTaskFailed

    设置错误回调函数。

    setOnTranscriptionStarted

    设置实时音频流识别开始回调函数。

    setOnSentenceBegin

    设置一句话开始回调。

    setOnSentenceEnd

    设置一句话结束回调函数。

    setOnTranscriptionResultChanged

    设置实时音频流识别中间结果回调函数。

    setOnTranscriptionCompleted

    设置服务端结束服务回调函数。

    setOnChannelClosed

    设置通道关闭回调函数。

    setAppKey

    设置AppKey。

    setToken

    口令认证。所有的请求都必须通过SetToken方法认证通过,才可以使用。

    setUrl

    设置服务URL地址。

    setIntermediateResult

    设置是否返回中间识别结果。

    setPunctuationPrediction

    设置是否在后处理中添加标点。

    setInverseTextNormalization

    设置是否在后处理中执行数字转换。

    setFormat

    设置音频数据编码格式。

    setSampleRate

    音频采样率设置。

    setSemanticSentenceDetection

    设置是否使用语义断句。

    setMaxSentenceSilence

    设置vad阈值。

    setCustomizationId

    设置定制模型。

    setVocabularyId

    使用该接口也可以把项目和热词关联起来。如果同时配置了控制台热词和SDK,则SDK配置优先级最高,将会覆盖控制台热词配置。

    setTimeout

    设置Socket接收超时时间。

    setEnableNlp

    设置是否开启NLP服务。

    setNlpModel

    设置NLP模型名称,开启NLP服务后必填。

    setSessionId

    设置Session ID。

    setOutputFormat

    设置输出文本的编码格式。

    setPayloadParam

    参数设置。

    setContextParam

    设置用户自定义参数。

    AppendHttpHeaderParam

    设置用户自定义ws阶段http header参数。

    start

    启动SpeechTranscriberRequest。

    stop

    会与服务端确认关闭,正常停止实时音频流识别操作。

    cancel

    不会与服务端确认关闭,直接关闭实时音频流识别过程。

    control

    要求服务端更新识别参数。

    sendAudio

    发送语音数据。

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 &amp;lt;= 0.

发送错误。请检查发送参数是否正确。

10000014

Start invoke failed.

调用start方法超时错误。请调用stop方法释放资源,重新开始识别流程。

10000015

connect failed.

调用connect方法失败。请调用stop方法释放资源,重新开始识别流程。

服务端响应状态码

关于服务状态码,请参见接口说明

代码示例

说明

  • 示例中使用的音频文件为16000 Hz采样率,管控台设置的模型为通用模型。如果使用其他音频,请设置为支持该音频场景的模型。关于模型设置,请参见管理项目

  • 示例中使用了SDK内置的默认实时语音识别服务的外网访问服务端URL,如果您使用阿里云上海ECS且需要使用内网访问服务端URL,则在创建speechTranscriberRequest的对象中设置内网访问的URL。

    request->setUrl("ws://nls-gateway.cn-shanghai-internal.aliyuncs.com/ws/v1");
  • 完整示例,参见SDK压缩包中Demo目录的speechTranscriberDemo.cpp文件。

#include <pthread.h>
#include <unistd.h>
#include <ctime>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <fstream>
#include "nlsClient.h"
#include "nlsEvent.h"
#include "speechTranscriberRequest.h"
#include "nlsToken.h"

#define FRAME_SIZE 3200
#define SAMPLE_RATE 16000

using namespace AlibabaNlsCommon;
using AlibabaNls::NlsClient; 
using AlibabaNls::NlsEvent; 
using AlibabaNls::LogDebug; 
using AlibabaNls::LogInfo; 
using AlibabaNls::SpeechTranscriberRequest; 

// 自定义线程参数。
struct ParamStruct { 
    std::string fileName;  
    std::string token; 
    std::string appkey; 
}; 
// 自定义事件回调参数。
struct ParamCallBack { 
    int userId; 
    char userInfo[10]; 
}; 

//全局维护一个服务鉴权token和其对应的有效期时间戳,
//每次调用服务之前,首先判断token是否已经过期。
//如果已经过期,则根据AccessKey ID和AccessKey Secret重新生成一个token,并更新这个全局的token和其有效期时间戳。
//说明:只需在token即将过期时进行重新生成。所有的服务并发可共用一个token。 
std::string g_akId = ""; 
std::string g_akSecret = ""; 
std::string g_token = ""; 
long g_expireTime = -1; 
int generateToken(std::string akId, std::string akSecret, std::string* token, long* expireTime) { 
    NlsToken nlsTokenRequest; 
    nlsTokenRequest.setAccessKeyId(akId); 
    nlsTokenRequest.setKeySecret(akSecret);  
    if (-1 == nlsTokenRequest.applyNlsToken()) {  
        // 获取失败原因。
        printf("generateToken Failed: %s\n", nlsTokenRequest.getErrorMsg());   
        return -1; 
    }
    *token = nlsTokenRequest.getToken(); 
    *expireTime = nlsTokenRequest.getExpireTime(); 
    return 0; 
}

//@brief 获取sendAudio发送延时时间 //@param dataSize 待发送数据大小
//@param sampleRate 采样率:16k/8K
//@param compressRate 数据压缩率,例如压缩比为10:1的16k OPUS编码,此时为10,非压缩数据则为1。
//@return 返回sendAudio之后需要sleep的时间。
//@note 对于8k pcm 编码数据, 16位采样,建议每发送1600字节 sleep 100 ms.
//             对于16k pcm 编码数据, 16位采样,建议每发送3200字节 sleep 100 ms.
//             对于其它编码格式(OPUS)的数据, 由于传递给SDK的仍然是PCM编码数据,
//             按照SDK OPUS/OPU 数据长度限制, 需要每次发送640字节 sleep 20ms.
unsigned int getSendAudioSleepTime(int dataSize, int sampleRate, int compressRate) { 
    // 仅支持16位采样
    const int sampleBytes = 16;     // 仅支持单通道
    const int soundChannel = 1;     // 当前采样率,采样位数下每秒采样数据的大小。
    int bytes = (sampleRate * sampleBytes * soundChannel) / 8;     // 当前采样率,采样位数下每毫秒采样数据的大小。
    int bytesMs = bytes / 1000;     // 待发送数据大小除以每毫秒采样数据大小,以获取sleep时间。
    int sleepMs = (dataSize * compressRate) / bytesMs; 
    return sleepMs; 
}

//@brief 调用start(),成功与云端建立连接,SDK内部线程上报started事件。
//@param cbEvent 回调事件结构,详见nlsEvent.h。
//@param cbParam 回调自定义参数,默认为NULL。可以根据需求自定义参数。
void onTranscriptionStarted(NlsEvent* cbEvent, void* cbParam) { 
    ParamCallBack* tmpParam = (ParamCallBack*)cbParam;  
    // 演示如何打印/使用用户自定义参数示例。
    printf("onTranscriptionStarted: %d\n", tmpParam->userId); 
    // 当前任务的task id,方便定位问题。
    printf("onTranscriptionStarted: status code=%d, task id=%s\n", 
            cbEvent->getStatusCode(), cbEvent->getTaskId()); 

    // 获取服务端返回的全部信息
    //printf("onTranscriptionStarted: all response=%s\n", cbEvent->getAllResponse()); 
} 

//@brief 服务端检测到了一句话的开始,SDK内部线程上报SentenceBegin事件。
//@param cbEvent 回调事件结构,详情参见nlsEvent.h。
//@param cbParam 回调自定义参数,默认为NULL,可以根据需求自定义参数。
void onSentenceBegin(NlsEvent* cbEvent, void* cbParam) { 
    ParamCallBack* tmpParam = (ParamCallBack*)cbParam; 
    // 演示如何打印/使用用户自定义参数示例。
    printf("onSentenceBegin: %d\n", tmpParam->userId); 
    printf("onSentenceBegin: status code=%d, task id=%s, index=%d, time=%d\n", 
            cbEvent->getStatusCode(), cbEvent->getTaskId(),  
            cbEvent->getSentenceIndex(), //句子编号,从1开始递增。
            cbEvent->getSentenceTime() //当前已处理的音频时长,单位:毫秒。   
    );

    // 获取服务端返回的全部信息
    //printf("onTranscriptionStarted: all response=%s\n", cbEvent->getAllResponse()); 
} 

//@brief 服务端检测到了一句话结束,SDK内部线程上报SentenceEnd事件。
//@param cbEvent 回调事件结构,详情参见nlsEvent.h。
//@param cbParam 回调自定义参数,默认为NULL,可以根据需求自定义参数。
void onSentenceEnd(NlsEvent* cbEvent, void* cbParam) {  
    ParamCallBack* tmpParam = (ParamCallBack*)cbParam; 
    // 演示如何打印
    //使用用户自定义参数示例。
    printf("onSentenceEnd: %d\n", tmpParam->userId);     
    printf("onSentenceEnd: status code=%d, task id=%s, index=%d, time=%d, begin_time=%d, result=%s\n", 
            cbEvent->getStatusCode(), 
            cbEvent->getTaskId(), 
            cbEvent->getSentenceIndex(), //句子编号,从1开始递增。  
            cbEvent->getSentenceTime(), //当前已处理的音频时长,单位:毫秒。     
            cbEvent->getSentenceBeginTime(), // 对应的SentenceBegin事件的时间。  
            cbEvent->getResult()    // 当前句子的完整识别结果。   
    ); 
    // 获取服务端返回的全部信息
    //printf("onTranscriptionStarted: all response=%s\n", cbEvent->getAllResponse()); 
} 

//@brief 识别结果发生了变化,SDK在接收到云端返回的最新结果时,其内部线程上报ResultChanged事件。
//@param cbEvent 回调事件结构,详情参见nlsEvent.h。
//@param cbParam 回调自定义参数,默认为NULL,可以根据需求自定义参数。
void onTranscriptionResultChanged(NlsEvent* cbEvent, void* cbParam) {  
    ParamCallBack* tmpParam = (ParamCallBack*)cbParam; 
    // 演示如何打印/使用用户自定义参数示例。
    printf("onTranscriptionResultChanged: %d\n", tmpParam->userId);   
    printf("onTranscriptionResultChanged: status code=%d, task id=%s, index=%d, time=%d, result=%s\n", 
            cbEvent->getStatusCode(), 
            cbEvent->getTaskId(),                 
            cbEvent->getSentenceIndex(), //句子编号,从1开始递增。  
            cbEvent->getSentenceTime(), //当前已处理的音频时长,单位:毫秒。  
            cbEvent->getResult()    // 当前句子的完整识别结果  
    );     
    // 获取服务端返回的全部信息
    //printf("onTranscriptionStarted: all response=%s\n", cbEvent->getAllResponse()); 
}

//@brief 服务端停止实时音频流识别时,SDK内部线程上报Completed事件。
//@note 上报Completed事件之后,SDK内部会关闭识别连接通道。此时调用sendAudio会返回-1,请停止发送。
//@param cbEvent 回调事件结构,详情参见nlsEvent.h。
//@param cbParam 回调自定义参数,默认为NULL,可以根据需求自定义参数。
void onTranscriptionCompleted(NlsEvent* cbEvent, void* cbParam) {    
    ParamCallBack* tmpParam = (ParamCallBack*)cbParam;     
    // 演示如何打印/使用用户自定义参数示例。
    printf("onTranscriptionCompleted: %d\n", tmpParam->userId);     
    printf("onTranscriptionCompleted: status code=%d, task id=%s\n", 
            cbEvent->getStatusCode(), 
            cbEvent->getTaskId()); 
} 

//@brief 识别过程(包含start()、send()、stop())发生异常时,SDK内部线程上报TaskFailed事件。
//@note 上报TaskFailed事件之后,SDK内部会关闭识别连接通道。此时调用sendAudio会返回-1,请停止发送。
//@param cbEvent 回调事件结构,详情参见nlsEvent.h。
//@param cbParam 回调自定义参数,默认为NULL,可以根据需求自定义参数。
void onTaskFailed(NlsEvent* cbEvent, void* cbParam) { 
    ParamCallBack* tmpParam = (ParamCallBack*)cbParam; 
    // 演示如何打印/使用用户自定义参数示例。
    printf("onTaskFailed: %d\n", tmpParam->userId); 
    printf("onTaskFailed: status code=%d, task id=%s, error message=%s\n", 
            cbEvent->getStatusCode(), 
            cbEvent->getTaskId(), 
            cbEvent->getErrorMessage()
    );     
    // 获取服务端返回的全部信息
    //printf("onTaskFailed: all response=%s\n", cbEvent->getAllResponse()); 
} 

//@brief SDK内部线程上报语音表单结果事件
//@param cbEvent 回调事件结构,详情参见nlsEvent.h。
//@param cbParam 回调自定义参数,默认为NULL,可以根据需求自定义参数。
void onSentenceSemantics(NlsEvent* cbEvent, void* cbParam) {     
    ParamCallBack* tmpParam = (ParamCallBack*)cbParam;     
    // 演示如何打印/使用用户自定义参数示例。
    printf("onSentenceSemantics: %d\n", tmpParam->userId);     
    // 获取服务端返回的全部信息。
    printf("onSentenceSemantics: all response=%s\n", cbEvent->getAllResponse()); 
} 

//@brief 识别结束或发生异常时,会关闭连接通道,SDK内部线程上报ChannelCloseed事件。
//@param cbEvent 回调事件结构,详情参见nlsEvent.h。
//@param cbParam 回调自定义参数,默认为NULL,可以根据需求自定义参数。
void onChannelClosed(NlsEvent* cbEvent, void* cbParam) {     
    ParamCallBack* tmpParam = (ParamCallBack*)cbParam;     
    delete tmpParam; //识别流程结束,释放回调参数。 
} 

// 工作线程
void* pthreadFunc(void* arg) {     
    int sleepMs = 0;     
    ParamCallBack *cbParam = NULL;     
    //初始化自定义回调参数,以下两变量仅作为示例表示参数传递,在demo中不起任何作用。
    //回调参数在堆中分配之后,SDK在销毁request对象时会一并销毁。     
    cbParam = new ParamCallBack;     
    cbParam->userId = 1234;     
    strcpy(cbParam->userInfo, "User.");     
    // 0: 从自定义线程参数中获取token,配置文件等参数。     
    ParamStruct* tst = (ParamStruct*)arg;     
    if (tst == NULL) {         
        printf("arg is not valid\n");         
        return NULL;     
    }     
    /* 打开音频文件,获取数据 */     
    std::ifstream fs;     
    fs.open(tst->fileName.c_str(), std::ios::binary | std::ios::in);     
    if (!fs) {         
        printf("%s isn't exist..\n", tst->fileName.c_str());         
        return NULL;     
    }     
    //2: 创建实时音频流识别SpeechTranscriberRequest对象。     
    SpeechTranscriberRequest* request = NlsClient::getInstance()->createTranscriberRequest();    
    if (request == NULL) {         
        printf("createTranscriberRequest failed.\n");         
        return NULL;     
    }     
    request->setOnTranscriptionStarted(onTranscriptionStarted, cbParam);                // 设置识别启动回调函数     
    request->setOnTranscriptionResultChanged(onTranscriptionResultChanged, cbParam);    // 设置识别结果变化回调函数     
    request->setOnTranscriptionCompleted(onTranscriptionCompleted, cbParam);            // 设置语音转写结束回调函数     
    request->setOnSentenceBegin(onSentenceBegin, cbParam);                              // 设置一句话开始回调函数     
    request->setOnSentenceEnd(onSentenceEnd, cbParam);                                  // 设置一句话结束回调函数     
    request->setOnTaskFailed(onTaskFailed, cbParam);                                    // 设置异常识别回调函数     
    request->setOnChannelClosed(onChannelClosed, cbParam);                              // 设置识别通道关闭回调函数     
    request->setAppKey(tst->appkey.c_str());            // 设置appkey,必选参数。     
    request->setFormat("pcm");                          // 设置音频数据编码格式,默认值PCM。    
    request->setSampleRate(SAMPLE_RATE);                // 设置音频数据采样率,可选参数,目前支持16000/8000,默认值16000。     
    request->setIntermediateResult(true);               // 设置是否返回中间识别结果,可选参数,默认false。     
    request->setPunctuationPrediction(true);            // 设置是否在后处理中添加标点,可选参数,默认false。     
    request->setInverseTextNormalization(true);         // 设置是否在后处理中执行数字转写,可选参数,默false。
    //语音断句检测阈值,一句话之后静音长度超过该值,即本句结束,合法参数范围200ms~2000ms,默认值800ms。
    //request->setMaxSentenceSilence(800);
    //request->setCustomizationId("TestId_123"); //定制模型id,可选。
    //request->setVocabularyId("TestId_456"); //定制泛热词id,可选。
    // 用于传递某些定制化、高级参数设置,参数格式为JSON格式: {"key": "value"}
    //request->setPayloadParam("{\"vad_model\": \"farfield\"}");
    //设置是否开启词模式。     
    request->setPayloadParam("{\"enable_words\": true}");
    //语义断句,默认false,非必需则不建议设置。
    //request->setPayloadParam("{\"enable_semantic_sentence_detection\": false}");
    //是否开启顺滑,默认不开启,非必需则不建议设置。
    //request->setPayloadParam("{\"disfluency\": true}");
    //设置vad的模型,默认不设置,非必需则不建议设置。
    //request->setPayloadParam("{\"vad_model\": \"farfield\"}");
    //设置是否忽略单句超时
    //request->setPayloadParam("{\"enable_ignore_sentence_timeout\": false}");
    //vad断句开启后处理,默认不设置,非必需则不建议设置。
    //request->setPayloadParam("{\"enable_vad_unify_post\": true}");     
    request->setToken(tst->token.c_str());     
    //3: start()为异步操作。成功返回started事件,失败返回TaskFailed事件。
    if (request->start() < 0) {         
        printf("start() failed. may be can not connect server. please check network or firewalld\n"); 
        NlsClient::getInstance()->releaseTranscriberRequest(request); // start()失败,释放request对象。
        return NULL;    
    }     
    while (!fs.eof()) {         
        uint8_t data[FRAME_SIZE] = {0};         
        fs.read((char *)data, sizeof(uint8_t) * FRAME_SIZE);         
        size_t nlen = fs.gcount();         
        if (nlen <= 0) {             
            continue;         
        }         
        //4: 发送音频数据。sendAudio返回-1表示发送失败,需要停止发送。
        int ret = request->sendAudio(data, nlen);         
        if (ret < 0) {             
            // 发送失败,退出循环数据发送。
            printf("send data fail.\n");             
            break;         
        }         
         //语音数据发送控制:
        //语音数据是实时的,不需要sleep控制速率。
        //语音数据来自文件,发送时需要控制速率,使单位时间内发送的数据大小接近单位时间原始语音数据存储的大小。         
        sleepMs = getSendAudioSleepTime(nlen, SAMPLE_RATE, 1);  // 根据发送数据大小、采样率、数据压缩比,获取sleep时间。
        //5: 语音数据发送延时控制
        usleep(sleepMs * 1000);    
    }
    // 关闭音频文件     
    fs.close();     
    //6: 通知云端数据发送结束
    //stop()为异步操作,失败返回TaskFailed事件。     
    request->stop();     
    //7: 识别结束,释放request对象。     
    NlsClient::getInstance()->releaseTranscriberRequest(request);     
    return NULL;
} 

//识别单个音频数据
int speechTranscriberFile(const char* appkey) {     
    // 获取当前系统时间戳,判断token是否过期。     
    std::time_t curTime = std::time(0);     
    if (g_expireTime - curTime < 10) {         
        printf("the token will be expired, please generate new token by AccessKey-ID and AccessKey-Secret.\n");         
        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多线程指一个音频数据对应一个线程,多个音频数据对应多个线程。
//示例代码为同时开启2个线程识别2个文件。
//免费用户并发连接不能超过2个。
#define AUDIO_FILE_NUMS 2
#define AUDIO_FILE_NAME_LENGTH 32
int speechTranscriberMultFile(const char* appkey) {     
    // 获取当前系统时间戳,判断token是否过期。     
    std::time_t curTime = std::time(0);     
    if (g_expireTime - curTime < 10) {         
        printf("the token will be expired, please generate new token by AccessKey-ID and AccessKey-Secret.\n");         
        if (-1 == generateToken(g_akId, g_akSecret, &g_token, &g_expireTime)) {             
            return -1;         
        }     
    }     
    char audioFileNames[AUDIO_FILE_NUMS][AUDIO_FILE_NAME_LENGTH] = 
    {
        "test0.wav", 
        "test1.wav"
    };     
    ParamStruct pa[AUDIO_FILE_NUMS];     
    for (int i = 0; i < AUDIO_FILE_NUMS; i ++) {         
        pa[i].token = g_token;         
        pa[i].appkey = appkey;         
        pa[i].fileName = audioFileNames[i];     
    }     
    std::vector<pthread_t> pthreadId(AUDIO_FILE_NUMS);     
    // 启动2个工作线程,同时识别2个音频文件。
    for (int j = 0; j < AUDIO_FILE_NUMS; j++) {         
        pthread_create(&pthreadId[j], NULL, &pthreadFunc, (void *)&(pa[j]));    
    }     
    for (int j = 0; j < AUDIO_FILE_NUMS; j++) {         
        pthread_join(pthreadId[j], NULL);     
    }     
    return 0; 
}

int main(int arc, char* argv[]) {     
    if (arc < 4) {         
        printf("params is not valid. Usage: ./demo <your appkey> <your AccessKey ID> <your AccessKey Secret>\n");         
        return -1;     
    }     
    std::string appkey = argv[1];     
    g_akId = argv[2];     
    g_akSecret = argv[3];     
    // 根据需要设置SDK输出日志,可选。此处表示SDK日志输出至log-Transcriber.txt,LogDebug表示输出所有级别日志。
    int ret = NlsClient::getInstance()->setLogConfig("log-transcriber", LogDebug);     
    if (-1 == ret) {         
        printf("set log failed\n");         
        return -1;     
    }     
    //启动工作线程     
    NlsClient::getInstance()->startWorkThread(4);     // 识别单个音频数据
    speechTranscriberFile(appkey.c_str());     // 识别多个音频数据
    // speechTranscriberMultFile(appkey.c_str());
    // 所有工作完成,进程退出前释放nlsClient,releaseInstance()非线程安全。
    NlsClient::releaseInstance();     
    return 0; 
}
阿里云首页 智能语音交互 相关技术圈