C# SDK

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

SDK下载

说明
  • 当前最新版本:3.1.17,该版本基于C++ SDK API 3.1.x。发布日期:2023年08月28日。

  • 此SDK是底层C++包裹了C#组成,仅支持Windows平台,不支持跨平台能力。

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

可通过以下两种方法获取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.17-master_fd7c7d8.zip

    SDK源码

    8beeaad832d4b249464f4338429c3b15

    NlsCsharpSdk_Windows_3.1.17_fd7c7d8.zip

    Windows

    81fdd1579e103d8c93b4dab98ee0f71c

    其中:

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

    • NlsCsharpSdk_Windows_<版本号>_<github commit id>.zip为Windows平台下开发需要的SDK包,详见内部readme.md。

Windows平台C#编译运行

推荐直接使用已经编译好的库NlsCsharpSdk_Windows_<version>_<github commit id>.zip进行集成。若有编译需求,请下载alibabacloud-nls-cpp-sdk<version>-master_<github commit id>.zip并解压到本地,或从GitHub获取最新代码,然后参考其中readme.md的编译步骤。

关键接口

using nlsCsharpSdk;
  • 基础接口

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

      接口名

      启用版本

      功能描述

      SetLogConfig

      3.1.9

      设置日志文件与存储路径。越早调用记录的信息越详细。

      GetVersion

      3.1.9

      获取SDK版本号。

      CreateNlsToken

      3.1.9

      创建Token获取对象,用于获取阿里云token,详见下方NlsToken相关表格。

      ReleaseNlsToken

      3.1.9

      销毁CreateNlsToken所建立的NlsToken对象。

      SetDirectHost

      3.1.16

      跳过DNS域名解析直接设置服务器IP地址,若调用则需要在StartWorkThread之前。

      StartWorkThread

      3.1.9

      启动工作线程数,默认1即启动一个线程,若-1则启动CPU核数的线程数。在高并发的情况下建议选择4。这一接口有初始化NlsClient的作用。

      ReleaseInstance

      3.1.9

      销毁NlsClient对象实例,即释放NLS SDK。此操作需要在销毁所有请求后再调用。

      CreateNlsToken

      3.1.9

      创建Token获取对象,用于申请获取TokenId。详见下方NlsToken相关说明。

      ReleaseNlsToken

      3.1.9

      销毁Token获取对象。

      CreateSynthesizerRequest

      3.1.9

      创建语音合成对象,线程安全,支持高并发请求。通过入参控制短文本/长文本模式,更多信息请参见接口说明

      ReleaseSynthesizerRequest

      3.1.9

      销毁语音合成对象,需要在当前请求的closed事件后调用。

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

      接口名

      功能描述

      SetAccessKeyId

      设置阿里云账号AccessKey ID。

      SetKeySecret

      设置阿里云账号AccessKey Secret。

      ApplyNlsToken

      申请获取TokenId。此TokenId在有效期内对所有此阿里云账号AccessKey ID下的所有语音请求有效,无需在每个语音请求前申请获得。

      GetToken

      获取TokenId。

      GetExpireTime

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

      GetErrorMsg

      获取TokenId失败的错误信息。

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

      接口名

      功能描述

      statusCode

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

      taskId

      获取任务的TaskId。

      msg

      获取云端返回的response结果,用于获得事件信息,如Started、Closed、TaskFailed、Conpleted、MetaInfo回调的事件信息。

      result

      获取云端返回的识别结果,语音合成功能中此参数同msg。

  • 识别接口

    SpeechSynthesizerRequest:语音合成请求对象,用于语音合成及长文本语音合成。

    接口名

    功能描述

    SetOnSynthesisCompleted

    设置语音合成结束回调函数。

    SetOnChannelClosed

    设置通道关闭回调函数。

    SetOnTaskFailed

    设置错误回调函数。

    SetOnBinaryDataReceived

    设置语音合成二进制音频数据接收回调函数。

    SetOnMetaInfo

    设置文本对应的日志信息接收回调函数。

    SetAppKey

    设置Appkey。

    SetToken

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

    SetUrl

    设置服务URL地址,默认可不设置则调用公有云上海域名的服务。

    SetText

    待合成音频文本内容text设置,UTF-8格式。短文本语音合成模式下默认,支持一次性合成300字符以内的文字,其中1个汉字、1个英文字母或1个标点均算作1个字符,超过300个字符的内容将会报错或者截断。超过300个字符可考虑长文本语音合成,更多信息请参见接口说明

    SetVoice

    发音人voice设置,更多信息请参见接口说明

    SetVolume

    音量volume设置。范围为0~100,可选参数,默认50。

    SetFormat

    输出音频编码格式Format设置。

    SetSampleRate

    音频采样率设置。

    SetSpeechRate

    语速设置。范围为-500~500,可选参数,默认是0。

    SetPitchRate

    语调设置。范围为-500~500,可选参数,默认是0。

    SetEnableSubtitle

    是否开启字幕功能。开启后可获得详细的合成信息,比如每个字的时间戳,通过MetaInfo回调返回。

    SetMethod

    合成方法method设置,默认为0。

    • 0:统计参数合成。基于统计参数的语音合成,优点是能适应的韵律特征的范围较宽,合成器比特率低,资源占用小,性能高,音质适中。

    • 1:波形拼接合成。基于高质量音库提取学习合成,资源占用相对较高,音质较好,更加贴近真实发音,但没有参数合成稳定。

    SetTimeout

    设置Socket接收超时时间。

    SetPayloadParam

    参数设置,入参为JSON格式字符串。如指定声学模型,例如"{\"model\":\"test-regression-model\"}")

    SetContextParam

    设置用户自定义参数,入参为JSON格式字符串。

    SetOutputFormat

    设置输出文本的编码格式,Windows平台下默认为GBK。非中文语种情况下,请设置成UTF-8,否则会出现乱码。

    GetOutputFormat

    获得输出文本的编码格式,Windows平台下默认为GBK。

    AppendHttpHeaderParam

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

    Start

    异步接口,启动SpeechSynthesizerRequest

    Cancel

    不会与服务端确认关闭,直接关闭语音合成过程。

SDK错误码

状态码

状态消息

原因

解决方案

0

Success

成功

-10

DefaultError

默认错误

暂未使用。

-11

JsonParseFailed

错误的JSON格式

请检查传入的JSON字符串是否符合JSON格式。

-12

JsonObjectError

错误的JSON对象

建议重新尝试。

-13

MallocFailed

Malloc失败

请检查内存是否充足。

-14

ReallocFailed

Realloc失败

请检查内存是否充足。

-15

InvalidInputParam

传入无效的参数

暂未使用。

-50

InvalidLogLevel

无效日志级别

请检查设置的Log级别。

-51

InvalidLogFileSize

无效日志文件大小

请检查设置的Log文件大小参数。

-52

InvalidLogFileNum

无效日志文件数量

请检查设置的Log文件数量参数。

-100

EncoderExistent

NLS的编码器已存在

建议重新尝试。

-101

EncoderInexistent

NLS的编码器不存在

建议重新初始化。

-102

OpusEncoderCreateFailed

Opus编码器创建失败

建议重新初始化。

-103

OggOpusEncoderCreateFailed

OggOpus编码器创建失败

建议重新初始化。

-150

EventClientEmpty

主工作线程空指针,已释放

建议重新初始化,即startWorkThread()。

-151

SelectThreadFailed

工作线程选择失败,未初始化

建议重新初始化,即startWorkThread()。

-160

StartCommandFailed

发送start命令失败

建议重新尝试。

-161

InvokeStartFailed

请求状态机不对,导致start失败

请检查当前请求是否未创建或者已经完成。

-162

InvokeSendAudioFailed

请求状态机不对,导致sendAudio失败

请检查当前请求是否已经启动()即收到started事件回调)或者已经完成。

-163

InvalidOpusFrameSize

opus帧长无效,默认为640字节

OPU编码模式下,sendAudio一帧只接收640字节数据。

-164

InvokeStopFailed

请求状态机不对,导致stop失败

请检查当前请求是否未启动(即收到started事件回调)或者已经完成。

-165

InvokeCancelFailed

请求状态机不对,导致stop失败

请检查当前请求是否未启动(即收到started事件回调)或者已经完成。

-166

InvokeStControlFailed

请求状态机不对,导致stControl失败

请检查当前请求是否未启动(即收到started事件回调)或者已经完成。

-200

NlsEventEmpty

NLS事件为空

SDK内部使用,NlsEvent帧丢失。

-201

NewNlsEventFailed

创建NlsEvent失败

SDK内部使用,NlsEvent帧创建失败。

-202

NlsEventMsgEmpty

NLS事件中消息为空

parseJsonMsg()进行解析时发现消息字符串为空。

-203

InvalidNlsEventMsgType

无效的NLS事件中消息类型

SDK内部使用,NlsEvent帧的事件类型不合法。

-204

InvalidNlsEventMsgStatusCode

无效的NLS事件中消息状态码

SDK内部使用,NlsEvent帧的事件消息状态不合法。

-205

InvalidNlsEventMsgHeader

无效的NLS事件中消息头

SDK内部使用,NlsEvent帧的事件消息头不合法。

-250

CancelledExitStatus

已调用cancel

暂未使用。

-251

InvalidWorkStatus

无效的工作状态

SDK内部使用,当前请求内部状态不合法。

-252

InvalidNodeQueue

workThread中NodeQueue无效

SDK内部使用,当前待运行的请求不合法,建议释放当前请求重新尝试。

-300

InvalidRequestParams

请求的入参无效

sendAudio传入的数据为空。

-301

RequestEmpty

请求是空指针

SDK内部使用,当前请求已经释放,建议释放当前请求重新尝试。

-302

InvalidRequest

无效的请求

SDK内部使用,当前请求已经释放,建议释放当前请求重新尝试。

-303

SetParamsEmpty

设置传入的参数为空

请检查传入的参数是否为空。

-350

GetHttpHeaderFailed

获得http头失败

SDK内部使用,根据日志中反馈信息详细定位。

-351

HttpGotBadStatus

http错误的状态

SDK内部使用,根据日志中反馈信息详细定位。

-352

WsResponsePackageFailed

解析websocket返回包失败

SDK内部使用,根据日志中反馈信息详细定位。

-353

WsResponsePackageEmpty

解析websocket返回包为空

SDK内部使用,根据日志中反馈信息详细定位。

-354

WsRequestPackageEmpty

websocket请求包为空

SDK内部使用,根据日志中反馈信息详细定位。

-355

UnknownWsFrameHeadType

未知websocket帧头类型

SDK内部使用,根据日志中反馈信息详细定位。

-356

InvalidWsFrameHeaderSize

无效的websocket帧头大小

SDK内部使用,根据日志中反馈信息详细定位。

-357

InvalidWsFrameHeaderBody

无效的websocket帧头本体

SDK内部使用,根据日志中反馈信息详细定位。

-358

InvalidWsFrameBody

无效的websocket帧本体

SDK内部使用,根据日志中反馈信息详细定位。

-359

WsFrameBodyEmpty

帧数据为空,常见为收到了脏数据

SDK内部使用,根据日志中反馈信息详细定位。

-400

NodeEmpty

node为空指针

建议释放当前请求重新尝试。

-401

InvaildNodeStatus

node所处状态无效

SDK内部使用,建议释放当前请求重新尝试。

-402

GetAddrinfoFailed

通过DNS解析地址识别

SDK内部使用,请检查当前环境的DNS是否可用。

-403

ConnectFailed

联网失败

请检查当前网络环境是否可用。

-404

InvalidDnsSource

当前设备无DNS

SDK内部使用,请检查当前环境的DNS是否可用。

-405

ParseUrlFailed

无效URL

请检查设置的URL是否有效。

-406

SslHandshakeFailed

SSL握手失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-407

SslCtxEmpty

SSL_CTX未空

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-408

SslNewFailed

SSL_new失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-409

SslSetFailed

SSL设置参数失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-410

SslConnectFailed

SSL_connect失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-411

SslWriteFailed

SSL发送数据失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-412

SslReadSysError

SSL接收数据收到SYSCALL错误

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-413

SslReadFailed

SSL接收数据失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-414

SocketFailed

创建socket失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-415

SetSocketoptFailed

设置socket参数失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-416

SocketConnectFailed

进行socket链接失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-417

SocketWriteFailed

socket发送数据失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-418

SocketReadFailed

socket接收数据失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-430

NlsReceiveFailed

NLS接收帧数据失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-431

NlsReceiveEmpty

NLS接收帧数据为空

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-432

ReadFailed

接收数据失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-433

NlsSendFailed

NLS发送数据失败

SDK内部使用,请检查当前网络环境是否可用,并再次尝试。

-434

NewOutputBufferFailed

创建buffer失败

SDK内部使用,请检查内存是否充足。

-435

NlsEncodingFailed

音频编码失败

SDK内部使用,建议释放当前请求重新尝试。

-436

EventEmpty

event为空

SDK内部使用,建议释放当前请求重新尝试。

-437

EvbufferTooMuch

evbuffer中数据太多

SDK内部使用,发送数据缓存已满(16K音频最大缓存320000,8K音频最大缓存160000),请检查是否发送音频数据过频或一次发送过多数据。

-438

EvutilSocketFailed

evutil设置参数失败

SDK内部使用,建议释放当前请求重新尝试。

-439

InvalidExitStatus

无效的退出状态

请检查是否已经cancel了当前请求。

-450

InvalidAkId

阿里云账号ak id无效

请检查阿里云账号ak id是否为空。

-451

InvalidAkSecret

阿里云账号ak secret无效

请检查阿里云账号ak secret是否为空。

-452

InvalidAppKey

项目appKey无效

请检查阿里云项目appKey是否为空。

-453

InvalidDomain

domain无效

请检查输入的domain是否为空。

-454

InvalidAction

action无效

请检查输入的action是否为空。

-455

InvalidServerVersion

ServerVersion无效

请检查输入的ServerVersion是否为空。

-456

InvalidServerResource

ServerResource无效

请检查输入的ServerResource是否为空。

-457

InvalidRegionId

RegionId无效

请检查输入的RegionId是否为空。

-500

InvalidFileLink

无效的录音文件链接

录音文件转写文件链接为空。

-501

ErrorStatusCode

错误的状态码

录音文件转写返回错误,详见错误码。

-502

IconvOpenFailed

申请转换描述失败

UTF8与GBK转换失败。

-503

IconvFailed

编码转换失败

UTF8与GBK转换失败。

-504

ClientRequestFaild

账号客户端请求失败

录音文件转写返回失败。

-999

NlsMaxErrorCode

其他状态码

状态消息

原因

解决方案

10000001

NewSslCtxFailed

SSL: couldn't create a context!

建议重新初始化。

10000002

DefaultErrorCode

return of SSL_read: error:00000000:lib(0):func(0):reason(0)

建议重新尝试。

return of SSL_read: error:140E0197:SSL routines:SSL_shutdown:shutdown while in init

10000003

SysErrorCode

系统错误。

根据系统反馈的错误信息进行处理。

10000004

EmptyUrl

URL: The url is empty.

传入的URL为空,请重新填写正确URL。

10000005

InvalidWsUrl

Could not parse WebSocket url:

传入的URL格式错误,请重新填写正确URL。

10000007

JsonStringParseFailed

JSON: Json parse failed.

JSON格式异常,请通过日志查看具体的错误点。

10000008

UnknownWsHeadType

WEBSOCKET: unkown head type.

联网失败,请检查本机DNS解析和URL是否有效。

10000009

HttpConnectFailed

HTTP: connect failed.

与云端连接失败,请检查网络后重试。

10000010

MemNotEnough

内存不足。

请检查内存是否充足。

10000015

SysConnectFailed

connect failed.

联网失败,请检查本机DNS解析和URL是否有效。

10000100

HttpGotBadStatusWith403

Got bad status host=xxxxx line=HTTP/1.1 403 Forbidden

链接被拒,请检查账号特别是token是否过期。

10000101

EvSendTimeout

Send timeout. socket error:

libevent发送event超时,请检查回调中是否有耗时任务,或并发过大导致无法及时处理事件。

10000102

EvRecvTimeout

Recv timeout. socket error:

libevent接收event超时,请检查回调中是否有耗时任务,或并发过大导致无法及时处理事件。

10000103

EvUnknownEvent

Unknown event:

未知的libevent事件,建议重新尝试。

10000104

OpNowInProgress

Operation now in progress

链接正在进行中,建议重新尝试。

10000105

BrokenPipe

Broken pipe

pipe处理不过来,建议重新尝试。

10000110

TokenHasExpired

Gateway:ACCESS_DENIED:The token 'xxx' has expired!

请更新Token。

10000111

TokenIsInvalid

Meta:ACCESS_DENIED:The token 'xxx' is invalid!

请检查Token的有效性。

10000112

NoPrivilegeToVoice

Gateway:ACCESS_DENIED:No privilege to this voice! (voice: zhinan, privilege: 0)

此发音人无权使用。

10000113

MissAuthHeader

Gateway:ACCESS_DENIED:Missing authorization header!

请检查账号是否有权限,或并发是否在限度内。

10000120

Utf8ConvertError

utf8ToGbk failed

utf8转码失败,常为系统问题,建议重新尝试。

20000000

SuccessStatusCode

成功

服务端响应状态码

关于服务状态码,请参见服务状态码

代码示例

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

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

    SpeechSynthesizerRequest syPtr;
    syPtr.SetUrl(syPtr, "ws://nls-gateway.cn-shanghai-internal.aliyuncs.com/ws/v1")
  • 以下为简要示例,完整示例请参见SDK压缩包中demo目录的nlsCsharpSdkDemo.cs文件。

    using System;
    using System.IO;
    using System.Threading;
    using System.Windows.Forms;
    using nlsCsharpSdk;
    
    namespace nlsCsharpSdkDemo
    {
        public partial class nlsCsharpSdkDemo : Form
        {
            private NlsClient nlsClient;
            private SpeechSynthesizerRequest syPtr;
            private NlsToken tokenPtr;
            private UInt64 expireTime;
    
            private string appKey;
            private string akId;
            private string akSecret;
            private string token;
            private string url;
    
            static bool running;
            static string cur_nls_result;
    
            static string cur_sy_completed;
            static string cur_sy_closed;
    
            private void FlushLab()
            {
                while (running)
                {
                    if (cur_nls_result != null && cur_nls_result.Length > 0)
                    {
                        nlsResult.Text = cur_nls_result;
                    }
    
                    if (cur_st_result != null && cur_st_result.Length > 0)
                    {
                        stResult.Text = cur_st_result;
                    }
                    if (cur_st_completed != null && cur_st_completed.Length > 0)
                    {
                        stCompleted.Text = cur_st_completed;
                    }
                    if (cur_st_closed != null && cur_st_closed.Length > 0)
                    {
                        stClosed.Text = cur_st_closed;
                    }
    
                    if (cur_sr_result != null && cur_sr_result.Length > 0)
                    {
                        srResult.Text = cur_sr_result;
                    }
                    if (cur_sr_completed != null && cur_sr_completed.Length > 0)
                    {
                        srCompleted.Text = cur_sr_completed;
                    }
                    if (cur_sr_closed != null && cur_sr_closed.Length > 0)
                    {
                        srClosed.Text = cur_sr_closed;
                    }
    
                    if (cur_sy_completed != null && cur_sy_completed.Length > 0)
                    {
                        syCompleted.Text = cur_sy_completed;
                    }
                    if (cur_sy_closed != null && cur_sy_closed.Length > 0)
                    {
                        syClosed.Text = cur_sy_closed;
                    }
                    Thread.Sleep(200);
                }
            }
    
            public nlsCsharpSdkDemo()
            {
                InitializeComponent();
                System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false
    
                nlsClient = new NlsClient();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                // 开启日志系统,以Debug级别将名字为nlsLog.log的日志以单个400MB 10个日志文件循环的形式储存。
                int ret = nlsClient.SetLogConfig("nlsLog", LogLevel.LogDebug, 400, 10);
                if (ret == 0)
                    nlsResult.Text = "OpenLog Success";
                else
                    nlsResult.Text = "OpenLog Failed";
            }
    
            private void button1_Click_1(object sender, EventArgs e)
            {
                string version = nlsClient.GetVersion();
                nlsResult.Text = version;
            }
    
            private void button1_Click_2(object sender, EventArgs e)
            {
                // -1则表示启动CPU核数的事件池数量,用于进行内部事件的处理。
                // 单路调用的情况下,建议入参为1,即启动单个事件池进行处理。
                // 高并发(几百路)的情况下,入参建议4 ~ CPU核数,入参越大,处理延迟越低但是CPU占用越高。
                nlsClient.StartWorkThread(1);
                nlsResult.Text = "StartWorkThread and init NLS success.";
                running = true;
                Thread t = new Thread(FlushLab);
                t.Start();
            }
    
            private void button1_Click_3(object sender, EventArgs e)
            {
                nlsClient.ReleaseInstance();
                nlsResult.Text = "Release NLS success.";
            }
    
            #region Info
            private void textBox1_TextChanged(object sender, EventArgs e)
            {
                akId = tAkId.Text;
            }
    
            private void tAppKey_TextChanged(object sender, EventArgs e)
            {
                appKey = tAppKey.Text;
            }
    
            private void tAkSecret_TextChanged(object sender, EventArgs e)
            {
                akSecret = tAkSecret.Text;
            }
    
            private void tToken_TextChanged(object sender, EventArgs e)
            {
                token = tToken.Text;
            }
    
            private void tUrl_TextChanged(object sender, EventArgs e)
            {
                url = tUrl.Text;
            }
            #endregion
    
            #region TokenButton
            // create token
            private void button3_Click_1(object sender, EventArgs e)
            {
                int ret = -1;
                tokenPtr = nlsClient.CreateNlsToken();
                if (tokenPtr.native_token != IntPtr.Zero)
                {
                    if (akId != null && akSecret != null & akId.Length > 0 && akSecret.Length > 0)
                    {
                        tokenPtr.SetAccessKeyId(tokenPtr, akId);
                        tokenPtr.SetKeySecret(tokenPtr, akSecret);
    
                        ret = tokenPtr.ApplyNlsToken(tokenPtr);
                        if (ret < 0)
                        {
                            System.Diagnostics.Debug.WriteLine("ApplyNlsToken failed");
                            nlsResult.Text = tokenPtr.GetErrorMsg(tokenPtr);
                        }
                        else
                        {
                            System.Diagnostics.Debug.WriteLine("ApplyNlsToken success");
                            token = tokenPtr.GetToken(tokenPtr);
                            tToken.Text = token;
                            expireTime = tokenPtr.GetExpireTime(tokenPtr);
                            nlsResult.Text = "ExpireTime:" + expireTime.ToString();
                        }
                    }
                    else
                    {
                        nlsResult.Text = "CreateToken Failed, akId or Secret is null";
                    }
                }
                else
                {
                    nlsResult.Text = "CreateToken Failed";
                }
            }
    
            // release token
            private void button4_Click(object sender, EventArgs e)
            {
                if (tokenPtr.native_token != IntPtr.Zero)
                {
                    nlsClient.ReleaseNlsToken(tokenPtr);
                    tokenPtr.native_token = IntPtr.Zero;
                    nlsResult.Text = "ReleaseNlsToken Success";
                }
                else
                {
                    nlsResult.Text = "ReleaseNlsToken is nullptr";
                }
            }
            #endregion
    
            #region SynthesizerCallback
            private CallbackDelegate DemoOnBinaryDataReceived =
                (ref NLS_EVENT_STRUCT e,ref string uuid) =>
                {
                    System.Diagnostics.Debug.WriteLine("DemoOnBinaryDataReceived uuid = {0}", uuid);
                    System.Diagnostics.Debug.WriteLine("DemoOnBinaryDataReceived taskId = {0}", e.taskId);
                    System.Diagnostics.Debug.WriteLine("DemoOnBinaryDataReceived dataSize = {0}", e.binaryDataSize);
                    //cur_sy_completed = e.taskId + ", binaryDataSize : " + e.binaryDataSize;
                };
            private CallbackDelegate DemoOnSynthesisClosed =
                (ref NLS_EVENT_STRUCT e, ref string uuid) =>
                {
                    System.Diagnostics.Debug.WriteLine("DemoOnSynthesisClosed user uuid = {0}", uuid);
                    string msg = System.Text.Encoding.Default.GetString(e.msg).TrimEnd('\0');
                    System.Diagnostics.Debug.WriteLine("DemoOnSynthesisClosed msg = {0}", msg);
                    cur_sy_closed = "msg : " + msg;
                };
            private CallbackDelegate DemoOnSynthesisTaskFailed =
                (ref NLS_EVENT_STRUCT e, ref string uuid) =>
                {
                    System.Diagnostics.Debug.WriteLine("DemoOnSynthesisTaskFailed user uuid = {0}", uuid);
                    string msg = System.Text.Encoding.Default.GetString(e.msg).TrimEnd('\0');
                    System.Diagnostics.Debug.WriteLine("DemoOnSynthesisTaskFailed msg = {0}", msg);
                    cur_sy_completed = "msg : " + msg;
                };
            private CallbackDelegate DemoOnSynthesisCompleted =
                (ref NLS_EVENT_STRUCT e, ref string uuid) =>
                {
                    System.Diagnostics.Debug.WriteLine("DemoOnSynthesisCompleted user uuid = {0}", uuid);
                    string msg = System.Text.Encoding.Default.GetString(e.msg).TrimEnd('\0');
                    System.Diagnostics.Debug.WriteLine("DemoOnSynthesisCompleted msg = {0}", msg);
                    cur_sy_completed = "result : " + msg;
                };
            private CallbackDelegate DemoOnMetaInfo =
                (ref NLS_EVENT_STRUCT e, ref string uuid) =>
                {
                    System.Diagnostics.Debug.WriteLine("DemoOnMetaInfo user uuid = {0}", uuid);
                    // 若识别为非中文,请设置UTF-8格式,并用UTF-8解码,否则可能乱码。
                    // string msg = System.Text.Encoding.UTF8.GetString(e.msg).TrimEnd('\0');
                    string msg = System.Text.Encoding.Default.GetString(e.msg).TrimEnd('\0');
                    System.Diagnostics.Debug.WriteLine("DemoOnMetaInfo msg = {0}", msg);
                    cur_sy_completed = "metaInfo : " + msg;
                };
            #endregion
    
            // create synthesizer
            private void button12_Click(object sender, EventArgs e)
            {
                /*
                 * 默认为实时短文本语音合成请求, 支持一次性合成300字符以内的文字,
                 * 其中1个汉字、1个英文字母或1个标点均算作1个字符,
                 * 超过300个字符的内容将会报错(或者截断).
                 * 一次性合成超过300字符可考虑长文本语音合成功能.
                 */
                syPtr = nlsClient.CreateSynthesizerRequest(TtsVersion.ShortTts);
                if (syPtr.native_request != IntPtr.Zero)
                {
                    nlsResult.Text = "CreateSynthesizerRequest Success";
                }
                else
                {
                    nlsResult.Text = "CreateSynthesizerRequest Failed";
                }
                cur_sy_closed = "null";
                cur_sy_completed = "null";
            }
    
            // start synthesizer
            private void button10_Click(object sender, EventArgs e)
            {
                int ret = -1;
                if (syPtr.native_request != IntPtr.Zero)
                {
                    syPtr.SetAppKey(syPtr, appKey);
                    syPtr.SetToken(syPtr, token);
                    syPtr.SetUrl(syPtr, url);
                    syPtr.SetText(syPtr, "今天天气真不错,我想去操场踢足球。");
                    syPtr.SetVoice(syPtr, "siqi");
                    syPtr.SetVolume(syPtr, 50);
                    syPtr.SetFormat(syPtr, "wav");
                    syPtr.SetSampleRate(syPtr, 16000);
                    syPtr.SetSpeechRate(syPtr, 0);
                    syPtr.SetPitchRate(syPtr, 0);
                    syPtr.SetEnableSubtitle(syPtr, true); // 开启字幕
                    
                    string uuid = System.Guid.NewGuid().ToString("N");
    
                    syPtr.SetOnSynthesisCompleted(syPtr, DemoOnSynthesisCompleted, uuid);
                    syPtr.SetOnBinaryDataReceived(syPtr, DemoOnBinaryDataReceived, uuid);
                    syPtr.SetOnTaskFailed(syPtr, DemoOnSynthesisTaskFailed, uuid);
                    syPtr.SetOnChannelClosed(syPtr, DemoOnSynthesisClosed, uuid);
                    syPtr.SetOnMetaInfo(syPtr, DemoOnMetaInfo, uuid);
    
                    ret = syPtr.Start(syPtr);
                }
    
                if (ret != 0)
                {
                    nlsResult.Text = "Synthesizer Start failed";
                }
                else
                {
                    nlsResult.Text = "Synthesizer Start success";
                }
            }
    
            // cancel synthesizer
            private void button9_Click(object sender, EventArgs e)
            {
                int ret = -1;
                if (syPtr.native_request != IntPtr.Zero)
                    ret = syPtr.Cancel(syPtr);
    
                if (ret != 0)
                {
                    nlsResult.Text = "Synthesizer Cancel failed";
                }
                else
                {
                    nlsResult.Text = "Synthesizer Cancel success";
                }
            }
    
            private void btnSYrelease_Click(object sender, EventArgs e)
            {
                if (syPtr.native_request != IntPtr.Zero)
                {
                    nlsClient.ReleaseSynthesizerRequest(syPtr);
                    syPtr.native_request = IntPtr.Zero;
                    nlsResult.Text = "ReleaseSynthesizerRequest Success";
                }
                else
                {
                    nlsResult.Text = "ReleaseSynthesizerRequest is nullptr";
                }
                cur_sy_closed = "null";
                cur_sy_completed = "null";
            }
        }
    }