C++ SDK

Updated at:

This topic describes how to use the C++ software development kit (SDK) provided by Alibaba Cloud Intelligent Speech Interaction. It covers installation methods, code examples, and frequently asked questions (FAQ).

SDK download

Note
  • The latest version is 3.2.1b, which supports the Linux platform. This version was released on December 25, 2024.

  • Before you use the SDK, read the API reference. For more information, see API reference.

  • The definitions in the C++ SDK API 3.1 differ from those in the previous offline version, API 2.0. This topic uses the current version for its examples.

You can obtain the SDK in one of the following two ways.

  • Method 1: Obtain the latest source code from GitHub. For detailed compilation and execution instructions, see the following sections or the readme.md file in the source code.

    git clone --depth 1 https://github.com/aliyun/alibabacloud-nls-cpp-sdk
  • Method 2: Download the required SDK package from the table below. The SDK source code package contains the original SDK code, which you must compile to generate the library files required for integration. The other SDK packages for specific platforms contain the relevant library and header files and do not require compilation.

    Latest SDK package

    Platform

    MD5

    alibabacloud-nls-cpp-sdk3.3.0b-master_cbcac53.zip

    SDK source code

    7257c0998654e611cf2e8ca9867670ef

    NlsCppSdk_Linux-x86_64_3.3.0b_cbcac53.tar.gz

    Linux x86_64

    9a93df607f26f1558bc1043a425af6d1

    NlsCppSdk_Linux-aarch64_3.1.15_fa30fba.tar.gz

    Linux aarch64

    76c34a3ab397d7285963a139b9270ff4

    Where:

    • alibabacloud-nls-cpp-sdk<version>-master_<github commit id>.zip is the SDK source code package.

    • NlsCppSdk_<Platform>_<Version number>_<github commit id>.tar.gz is the SDK package required for development on the corresponding platform. For more information, see the readme.md file in the package.

SDK package file description

  • scripts/build_linux.sh: An example compilation script for the Linux platform, located in the SDK source code.

  • CMakeLists.txt: An example CMakeLists.txt file for a code-based project on the Linux platform, located in the SDK source code.

  • demo folder: Contains integration code examples in the SDK package. The following table lists the examples for the Linux platform.

  • File name

    Description

    speechRecognizerDemo.cpp

    Short sentence recognition demo.

    speechSynthesizerDemo.cpp

    Speech synthesis demo.

    speechTranscriberDemo.cpp

    Real-time speech recognition demo.

    fileTransferDemo.cpp

    Recorded audio file recognition demo.

  • resource folder: Contains sample audio files for the Voice Service, located in the SDK source code. You can use these files for functional testing. The files are listed in the following table.

  • File name

    Description

    • test0.wav

    • test1.wav

    • test2.wav

    • test3.wav

    Test audio files (16 kHz sample rate, 16-bit audio bit depth).

  • include the following: Contains the SDK header files from the SDK source code, as shown in the following table.

    File name

    Description

    nlsClient.h

    SDK instance.

    nlsEvent.h

    Callback event description.

    nlsGlobal.h

    Global SDK header file.

    nlsToken.h

    SDK Access Token instance.

    iNlsRequest.h

    Base header file for NLS requests.

    speechRecognizerRequest.h

    Short sentence recognition.

    speechSynthesizerRequest.h

    Speech synthesis and long text-to-speech.

    speechTranscriberRequest.h

    Real-time audio stream recognition.

    FileTrans.h

    Recorded audio file recognition.

  • lib: SDK library files.

  • readme.md: SDK instructions.

  • release.log: Version guide.

  • version: Version number.

Compile and run

  1. The minimum tool version requirements are as follows:

    • CMake 3.0

    • Glibc 2.5

    • Gcc 4.8.5

  2. Run the following scripts in the Linux terminal.

    1. Go to the root directory of the SDK source code.

    2. Generate the SDK library files and executable programs: srDemo (short sentence recognition), stDemo (real-time speech recognition), syDemo (speech synthesis), and daDemo (voice conversation).

      ./scripts/build_linux.sh
    3. View the usage instructions for the examples.

      cd build/demo 
      ./srDemo 

Key interfaces

  • Basic interfaces

    • NlsClient: The voice processing client. You can use this client for short sentence recognition, real-time speech recognition, and speech synthesis tasks. This client is thread-safe. We recommend that you create only one global instance.

      Interface name

      Enabled version

      Description

      getInstance

      2.x

      Gets (creates) an NlsClient instance.

      setLogConfig

      2.x

      Sets the log file and storage path.

      setDirectHost

      3.x

      Skips domain name resolution through DNS and directly sets the server IPv4 address. If you call this interface, you must call it before you call startWorkThread.

      setAddrInFamily

      3.1.12

      Sets the type of the socket address structure. The default value is AF_INET, which returns only IPv4-related address information. You must call this interface before you call startWorkThread.

      setUseSysGetAddrInfo

      3.1.13

      If the DNS of libevent does not meet your requirements and cannot complete the DNS resolution, you can call this interface to switch to the system's interface. You must call this interface before you call startWorkThread.

      setSyncCallTimeout

      3.1.17

      Sets the timeout period (in ms) for the synchronous call mode. The default value is 0, which means the synchronous mode is disabled.

      When you use the synchronous call mode:

      • start() is blocked until a result is received from the server.

      • stop() is blocked until the close() callback is triggered.

      setPreconnectedPool

      3.3.0

      Sets a pre-connection pool for each domain name URL.

      • Function:

        Creates a persistent connection pool for a domain name URL. Connections are automatically reused after requests are complete.

        • Reduces the connection time before each request is initiated.

        • Significantly reduces the first-packet latency.

      • This conflicts with the long-lived connection mode and will disable any configured long-lived connection mode.

      • Disabled scenario: Tingwu scenarios.

      • Call constraint: You must call this interface before you call startWorkThread.

      startWorkThread

      3.x

      Starts the worker threads. The default value is 1, which starts one thread. If you set this parameter to -1, the number of started threads is equal to the number of CPU cores. In high-concurrency scenarios, we recommend that you set this parameter to -1. This can be considered the initialization of the NlsClient instance and must be called.

      releaseInstance

      3.x

      Destroys the NlsClient object instance.

      getVersion

      2.x

      Gets the SDK version number.

      createRecognizerRequest

      2.x

      Creates a short sentence recognition object. It is thread-safe and supports high-concurrency requests.

      releaseRecognizerRequest

      2.x

      Destroys the short sentence recognition object. You must call this after the closed event of the current request.

    • NlsToken: Creates a Token object to request a TokenId. When you request a new token, you must first obtain a valid timestamp. If the token expires, you must request a new one. Requesting tokens multiple times within the validity period may generate an incorrect TokenId that cannot be used.

      Interface name

      Description

      setAccessKeyId

      Sets the AccessKey ID of your Alibaba Cloud account.

      setKeySecret

      Sets the AccessKey secret of your Alibaba Cloud account.

      setDomain

      Sets the domain name. This parameter is optional.

      setServerVersion

      Sets the API version. This parameter is optional.

      setServerResourcePath

      Sets the service path. This parameter is optional.

      setRegionId

      Sets the service region ID. This parameter is optional.

      setAction

      Sets the feature. This parameter is optional.

      applyNlsToken

      Requests a TokenId.

      getToken

      Gets the TokenId.

      getExpireTime

      Gets the UNIX timestamp (in seconds) when the token expires.

      getErrorMsg

      Gets the error message.

    • NlsEvent: The event object. You can use it to obtain the request status code, the result returned from the cloud, failure information, and more.

      Interface name

      Description

      getStatusCode

      Gets the status code. A value of 0 or 20000000 indicates success. Otherwise, an error code is returned.

      getErrorMessage

      In the TaskFailed callback, gets the error message when an NlsRequest operation fails.

      getTaskId

      Gets the TaskId of the task.

      getAllResponse

      Gets the recognition result returned from the cloud.

      getResult

      Gets the intermediate and final recognition results.

  • Recognition interfaces

    SpeechRecognizerRequest: The request object for short sentence recognition. It is used for short audio recognition. For more information about the interface, see the speechRecognizerRequest.h file.

    Interface name

    Enabled version

    Description

    setOnTaskFailed

    2.x

    Sets the error callback function.

    setOnRecognitionStarted

    2.x

    Sets the callback function for when short sentence recognition starts.

    setOnRecognitionResultChanged

    2.x

    Sets the callback function for intermediate results of short sentence recognition.

    setOnRecognitionCompleted

    2.x

    Sets the callback function for when the server-side service ends.

    setOnChannelClosed

    2.x

    Sets the callback function for when the channel is closed.

    setOnMessage

    3.1.16

    Sets the callback function for server response messages. All callbacks are output from this callback for you to parse. This parameter is optional. After setting it, you must call setEnableOnMessage to enable it.

    setAppKey

    2.x

    Sets the AppKey.

    setToken

    2.x

    Token authentication. All requests must be authenticated using the SetToken method before they can be used.

    setUrl

    2.x

    Sets the service URL.

    setIntermediateResult

    2.x

    Specifies whether to return intermediate recognition results.

    setPunctuationPrediction

    2.x

    Specifies whether to add punctuation in post-processing.

    setInverseTextNormalization

    2.x

    Specifies whether to perform number-to-text conversion in post-processing.

    setEnableVoiceDetection

    2.x

    Determines whether custom silence detection is enabled.

    setMaxStartSilence

    2.x

    If this duration is exceeded (no voice is detected after recognition starts), the server sends a TaskFailed event to end the current recognition task.

    setMaxEndSilence

    2.x

    If this duration is exceeded, the server sends a RecognitionCompleted event to end the current recognition task. Note that subsequent audio will not be recognized.

    setFormat

    2.x

    Sets the audio data encoding format. Valid values: PCM, OPUS, and OPU. Default value: PCM. We recommend that you use OPUS.

    setSampleRate

    2.x

    Sets the audio sample rate.

    setCustomizationId

    2.x

    Sets a custom model.

    setVocabularyId

    2.x

    Configure General Hotwords.

    setTimeout

    2.x

    Sets the socket receiving timeout period.

    setOutputFormat

    2.x

    Sets the encoding format of the output text. Valid values: UTF-8 and GBK.

    setPayloadParam

    2.x

    Sets parameters. The input parameter is a JSON string.

    setContextParam

    2.x

    Sets custom user parameters. The input parameter is a JSON string.

    AppendHttpHeaderParam

    2.x

    Sets custom HTTP header parameters for the WebSocket handshake phase.

    setAudioAddress

    3.1.13

    Experimental interface. A download link for an audio file that can be accessed over the public network. We recommend that you use Alibaba Cloud OSS.

    setSendTimeout

    3.1.14

    Sets the sending timeout period. Default value: 5000 ms.

    setRecvTimeout

    3.1.14

    Sets the receiving timeout period. Default value: 15000 ms. This takes effect only after you call setEnableRecvTimeout to enable it.

    setEnableRecvTimeout

    3.1.16

    Enables the receiving timeout period. Default value: false. This means the receiving timeout is disabled by default. If enabled, an error is reported if no data is received from the server for a long time.

    getOutputFormat

    3.1.16

    Gets the configured encoding format of the output text.

    setEnableOnMessage

    3.1.16

    Enables the callback for messages returned from the server.

    getTaskId

    3.1.17

    Gets the task_id of the current request.

    start

    2.x

    Starts the SpeechRecognizerRequest.

    stop

    2.x

    Confirms the shutdown with the server and stops the connection normally.

    cancel

    2.x

    Does not confirm the shutdown with the server and closes the connection directly.

    sendAudio

    2.x

    Sends audio data. We recommend that you send 640 to 16,384 bytes of audio data at a time.

C++ SDK error codes

Status code

Status message

Cause

Solution

0

Success

Success

-10

DefaultError

Default error

Not in use.

-11

JsonParseFailed

Incorrect JSON format

Check if the input JSON string is in the correct JSON format.

-12

JsonObjectError

Incorrect JSON object

Retry the operation.

-13

MallocFailed

Malloc failed

Check if the memory is sufficient.

-14

ReallocFailed

Realloc failed

Check if the memory is sufficient.

-15

InvalidInputParam

Invalid input parameter

Not in use.

-50

InvalidLogLevel

Invalid log level

Check the configured log level.

-51

InvalidLogFileSize

Invalid log file size

Check the configured log file size parameter.

-52

InvalidLogFileNum

Invalid number of log files

Check the configured parameter for the number of log files.

-100

EncoderExistent

The NLS encoder already exists

Retry the operation.

-101

EncoderInexistent

The NLS encoder does not exist

We recommend that you re-initialize.

-102

OpusEncoderCreateFailed

Failed to create the Opus encoder

We recommend reinitializing.

-103

OggOpusEncoderCreateFailed

Failed to create the OggOpus encoder

You need to re-initialize.

-104

InvalidEncoderType

Invalid encoder type

OPUS may have been disabled at compile-time but is being used. Alternatively, check ENCODER_TYPE.

-150

EventClientEmpty

The main worker thread is a null pointer and has been released

Re-initialize it by calling startWorkThread().

-151

SelectThreadFailed

Failed to select a worker thread. Not initialized

Re-initialize it by calling startWorkThread().

-160

StartCommandFailed

Failed to send the start command

Retry the operation.

-161

InvokeStartFailed

The request state machine is incorrect, causing start to fail

Check if the current request has not been created or has already been completed.

-162

InvokeSendAudioFailed

The request state machine is incorrect, causing sendAudio to fail

Check if the current request has started (the started event callback has been received) or has already been completed.

-163

InvalidOpusFrameSize

Invalid Opus frame size. The default is 640 bytes

In OPU encoding mode, sendAudio accepts only 640 bytes of data per frame.

-164

InvokeStopFailed

The request state machine is incorrect, causing stop to fail

Check if the current request has not started (the started event callback has not been received) or has already been completed.

-165

InvokeCancelFailed

The request state machine is incorrect, causing stop to fail

Check if the current request has not started (the started event callback has not been received) or has already been completed.

-166

InvokeStControlFailed

The request state machine is incorrect, causing stControl to fail

Check if the current request has not started (the started event callback has not been received) or has already been completed.

-200

NlsEventEmpty

The NLS event is empty

For internal SDK use. The NlsEvent frame is lost.

-201

NewNlsEventFailed

Failed to create NlsEvent

For internal SDK use. Failed to create the NlsEvent frame.

-202

NlsEventMsgEmpty

The message in the NLS event is empty

The message string was found to be empty during parsing by parseJsonMsg().

-203

InvalidNlsEventMsgType

Invalid message type in the NLS event

For internal SDK use. The event type of the NlsEvent frame is invalid.

-204

InvalidNlsEventMsgStatusCode

Invalid message status code in the NLS event

For internal SDK use. The event message status of the NlsEvent frame is invalid.

-205

InvalidNlsEventMsgHeader

Invalid message header in the NLS event

For internal SDK use. The event message header of the NlsEvent frame is invalid.

-250

CancelledExitStatus

cancel has been called

Not in use.

-251

InvalidWorkStatus

Invalid working status

For internal SDK use. The internal status of the current request is invalid.

-252

InvalidNodeQueue

Invalid NodeQueue in workThread

For internal SDK use. The current request to be run is invalid. We recommend that you release the current request and retry.

-300

InvalidRequestParams

Invalid request parameters

The data passed to sendAudio is empty.

-301

RequestEmpty

The request is a null pointer

For internal SDK use. The current request has been released. We recommend that you release the current request and retry.

-302

InvalidRequest

Invalid request

For internal SDK use. The current request has been released. We recommend that you release the current request and retry.

-303

SetParamsEmpty

The input parameter is empty

Check if the input parameter is empty.

-350

GetHttpHeaderFailed

Failed to get the HTTP header

For internal SDK use. Locate the issue based on the feedback in the log.

-351

HttpGotBadStatus

HTTP error status

For internal SDK use. Locate the issue based on the feedback in the log.

-352

WsResponsePackageFailed

Failed to parse the WebSocket response package

For internal SDK use. Locate the issue based on the feedback in the log.

-353

WsResponsePackageEmpty

The parsed WebSocket response package is empty

For internal SDK use. Locate the issue based on the feedback in the log.

-354

WsRequestPackageEmpty

The WebSocket request package is empty

For internal SDK use. Locate the issue based on the feedback in the log.

-355

UnknownWsFrameHeadType

Unknown WebSocket frame header type

For internal SDK use. Locate the issue based on the feedback in the log.

-356

InvalidWsFrameHeaderSize

Invalid WebSocket frame header size

For internal SDK use. Locate the issue based on the feedback in the log.

-357

InvalidWsFrameHeaderBody

Invalid WebSocket frame header body

For internal SDK use. Locate the issue based on the feedback in the log.

-358

InvalidWsFrameBody

Invalid WebSocket frame body

For internal SDK use. Locate the issue based on the feedback in the log.

-359

WsFrameBodyEmpty

The frame data is empty. This is often caused by receiving dirty data

For internal SDK use. Locate the issue based on the feedback in the log.

-400

NodeEmpty

The node is a null pointer

Release the current request and retry.

-401

InvaildNodeStatus

Invalid node status

For internal SDK use. Release the current request and retry.

-402

GetAddrinfoFailed

Address detection through DNS parsing

For internal SDK use. Check if DNS is available in the current environment.

-403

ConnectFailed

Connection failed

Check if the current network is available.

-404

InvalidDnsSource

No DNS on the current device

For internal SDK use. Check if DNS is available in the current environment.

-405

ParseUrlFailed

Invalid URL

Check if the configured URL is valid.

-406

SslHandshakeFailed

SSL handshake failed

For internal SDK use. Check if the current network is available and retry.

-407

SslCtxEmpty

SSL_CTX is empty

For internal SDK use. Check if the current network is available and retry.

-408

SslNewFailed

SSL_new failed

For internal SDK use. Check if the current network is available and retry.

-409

SslSetFailed

Failed to set SSL parameters

For internal SDK use. Check if the current network is available and retry.

-410

SslConnectFailed

SSL_connect failed

For internal SDK use. Check if the current network is available and retry.

-411

SslWriteFailed

Failed to send data over SSL

For internal SDK use. Check if the current network is available and retry.

-412

SslReadSysError

SYSCALL error received when reading data over SSL

For internal SDK use. Check if the current network is available and retry.

-413

SslReadFailed

Failed to read data over SSL

For internal SDK use. Check if the current network is available and retry.

-414

SocketFailed

Failed to create a socket

For internal SDK use. Check if the current network is available and retry.

-415

SetSocketoptFailed

Failed to set socket parameters

For internal SDK use. Check if the current network is available and retry.

-416

SocketConnectFailed

Failed to connect the socket

For internal SDK use. Check if the current network is available and retry.

-417

SocketWriteFailed

Failed to send data over the socket

For internal SDK use. Check if the current network is available and retry.

-418

SocketReadFailed

Failed to read data from the socket

For internal SDK use. Check if the current network is available and retry.

-430

NlsReceiveFailed

Failed to receive NLS frame data

For internal SDK use. Check if the current network is available and retry.

-431

NlsReceiveEmpty

Received NLS frame data is empty

For internal SDK use. Check if the current network is available and retry.

-432

ReadFailed

Failed to receive data

For internal SDK use. Check if the current network is available and retry.

-433

NlsSendFailed

Failed to send NLS data

For internal SDK use. Check if the current network is available and retry.

-434

NewOutputBufferFailed

Failed to create a buffer

For internal SDK use. Check if the memory is sufficient.

-435

NlsEncodingFailed

Audio encoding failed

For internal SDK use. Release the current request and retry.

-436

EventEmpty

The event is empty

For internal SDK use. Release the current request and retry.

-437

EvbufferTooMuch

Too much data in evbuffer

For internal SDK use. The send data cache is full (maximum cache for 16 kHz audio is 320,000; maximum for 8 kHz audio is 160,000). Check if audio data is sent too frequently or if too much data is sent at once.

-438

EvutilSocketFailed

Failed to set evutil parameters

For internal SDK use. Release the current request and retry.

-439

InvalidExitStatus

Invalid exit status

Check if the current request has been canceled.

-450

InvalidAkId

Invalid AccessKey ID for the Alibaba Cloud account

Check if the AccessKey ID of the Alibaba Cloud account is empty.

-451

InvalidAkSecret

Invalid AccessKey secret for the Alibaba Cloud account

Check if the AccessKey secret of the Alibaba Cloud account is empty.

-452

InvalidAppKey

Invalid project AppKey

Check if the AppKey of the Alibaba Cloud project is empty.

-453

InvalidDomain

Invalid domain

Check if the input domain is empty.

-454

InvalidAction

Invalid action

Check if the input action is empty.

-455

InvalidServerVersion

Invalid ServerVersion

Check if the input ServerVersion is empty.

-456

InvalidServerResource

Invalid ServerResource

Check if the input ServerResource is empty.

-457

InvalidRegionId

Invalid RegionId

Check if the input RegionId is empty.

-500

InvalidFileLink

Invalid recorded audio file link

The link for the recorded audio file transcription is empty.

-501

ErrorStatusCode

Error status code

An error was returned for the recorded audio file transcription. See the error code for details.

-502

IconvOpenFailed

Failed to request a conversion descriptor

Failed to convert between UTF-8 and GBK.

-503

IconvFailed

Encoding conversion failed

Failed to convert between UTF-8 and GBK.

-504

ClientRequestFaild

Account client request failed

The recorded audio file transcription request failed.

-999

NlsMaxErrorCode

Other status codes

Status message

Cause

Solution

10000001

NewSslCtxFailed

SSL: couldn't create a context!

We recommend re-initializing.

10000002

DefaultErrorCode

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

Retry the operation.

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

10000003

SysErrorCode

System error.

Handle the error based on the system feedback.

10000004

EmptyUrl

URL: The url is empty.

The input URL is empty. Enter a valid URL.

10000005

InvalidWsUrl

Could not parse WebSocket url:

The input URL format is incorrect. Enter a valid URL.

10000007

JsonStringParseFailed

JSON: Json parse failed.

The JSON format is abnormal. Check the log for the specific error.

10000008

UnknownWsHeadType

WEBSOCKET: unkown head type.

Connection failed. Check if the local DNS resolution is working and the URL is valid.

10000009

HttpConnectFailed

HTTP: connect failed.

Failed to connect to the cloud. Check your network and retry.

10000010

MemNotEnough

Out of memory.

Check if the memory is sufficient.

10000015

SysConnectFailed

connect failed.

Connection failed. Check if the local DNS resolution is working and the URL is valid.

10000100

HttpGotBadStatusWith403

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

The connection was rejected. Check your account, especially if the token has expired.

10000101

EvSendTimeout

Send timeout. socket error:

libevent timed out when sending an event. Check if there are time-consuming tasks in the callback or if high concurrency prevents timely event processing.

10000102

EvRecvTimeout

Recv timeout. socket error:

libevent timed out when receiving an event. Check if there are time-consuming tasks in the callback or if high concurrency prevents timely event processing.

10000103

EvUnknownEvent

Unknown event:

Unknown libevent event. Retry the operation.

10000104

OpNowInProgress

Operation now in progress

The connection is in progress. Retry the operation.

10000105

BrokenPipe

Broken pipe

The pipe cannot be processed. Retry the operation.

10000110

TokenHasExpired

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

Update the token.

10000111

TokenIsInvalid

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

Check the validity of the token.

10000112

NoPrivilegeToVoice

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

You are not authorized to use this voice.

10000113

MissAuthHeader

Gateway:ACCESS_DENIED:Missing authorization header!

Check if your account has the required permissions or if the number of concurrent requests is within the limit.

10000120

Utf8ConvertError

utf8ToGbk failed

UTF-8 transcoding failed. This is often a system issue. Retry the operation.

20000000

SuccessStatusCode

Success

Server response status codes

For more information about service status codes, see Service status codes.

Code example

Note
  • The audio file used in the example has a sample rate of 16000 Hz, and the model is set to the Universal model in the console. If you use other audio files, set the model to one that supports the audio scenario. For more information about model settings, see Manage projects.

  • The example uses the default public network access URL for the short sentence recognition service that is built into the SDK. If you use an Alibaba Cloud ECS instance in the Shanghai region and need to use an internal network access URL, you can set the internal network access URL in the SpeechRecognizerRequest object that you create.

    request->setUrl("ws://nls-gateway-cn-shanghai-internal.aliyuncs.com/ws/v1")
  • For the complete example, see the speechRecognizerDemo.cpp file in the demo folder of the SDK package.

  • Before you call the interface, configure environment variables to read the access credentials. The environment variable names for the AccessKey ID, AccessKey secret, and AppKey of Intelligent Speech Interaction are NLS_AK_ENV, NLS_SK_ENV, and NLS_APPKEY_ENV.

#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <ctime>
#include <string>
#include <iostream>
#include <vector>
#include <fstream>
#include <sys/time.h>
#include <errno.h>
#include "nlsClient.h"
#include "nlsEvent.h"
#include "nlsToken.h"
#include "speechRecognizerRequest.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::LogError;
using AlibabaNls::SpeechRecognizerRequest;

// Custom thread parameters.
struct ParamStruct {
  std::string fileName;
  std::string appkey; 
  std::string token; 
};
// Custom event callback parameters.
struct ParamCallBack {
 public:
  ParamCallBack() {
    pthread_mutex_init(&mtxWord, NULL);
    pthread_cond_init(&cvWord, NULL);
  };
  ~ParamCallBack() {
    pthread_mutex_destroy(&mtxWord);
    pthread_cond_destroy(&cvWord);
  };

  int userId;
  char userInfo[8];
  pthread_mutex_t mtxWord;
  pthread_cond_t cvWord;
};

/**
 * Maintain a global service authentication token and its validity timestamp.
 * Before each service call, check if the token has expired.
 * If it has expired, regenerate a token using the AccessKey ID and AccessKey Secret,
 * and update the global token and its validity timestamp.
 *
 * For more information about how to obtain a token, see https://help.aliyun.com/document_detail/450514.html
 *
 * Note: Do not regenerate a new token before every service call.
 * Regenerate it only when the token is about to expire. All concurrent service calls can share one token.
 */
std::string g_akId = "";
std::string g_akSecret = "";
std::string g_token = "";
long g_expireTime = -1;
int g_sync_timeout = 0;
struct timeval tv;
struct timeval tv1;

// Regenerate a token using the AccessKey ID and AccessKey Secret, and get its expiration timestamp.
int generateToken(std::string akId, std::string akSecret,
                  std::string* token, long* expireTime) {
  NlsToken nlsTokenRequest;
  nlsTokenRequest.setAccessKeyId(akId); 
  nlsTokenRequest.setKeySecret(akSecret); 

  int ret = nlsTokenRequest.applyNlsToken();
  if (ret < 0) {
    // Get the cause of the failure.
    printf("generateToken Failed, error code:%d msg:%s\n",
        ret, nlsTokenRequest.getErrorMsg());
    return ret;
  }
  *token = nlsTokenRequest.getToken();
  *expireTime = nlsTokenRequest.getExpireTime();
  return 0;
}

/**
 * @brief Gets the delay time for sending audio with sendAudio.
 * @param dataSize The size of the data to be sent.
 * @param sampleRate The sample rate, such as 16k or 8k.
 * @param compressRate The data compression ratio. For example, for 16k Opus encoded audio with a 10:1 compression ratio, this value is 10.
                       For uncompressed data, this value is 1.
 * @return The time to sleep after calling sendAudio.
 * @note For 8k PCM encoded data with 16-bit sampling, we recommend sleeping for 100 ms after sending every 1600 bytes.
         For 16k PCM encoded data with 16-bit sampling, we recommend sleeping for 100 ms after sending every 3200 bytes.
         For other encoding formats (such as OPUS), because the decoded data passed to the SDK is still PCM encoded data,
         you need to send 640 bytes and sleep for 20 ms each time, according to the SDK's OPUS/OPU data length limit.
 */
unsigned int getSendAudioSleepTime(int dataSize,
                                   int sampleRate,
                                   int compressRate) { 
  // Only 16-bit sampling is supported.
  const int sampleBytes = 16;     // Only single-channel is supported.
  const int soundChannel = 1;     // The size of the sampled data per second at the current sample rate and bit depth.
  int bytes = (sampleRate * sampleBytes * soundChannel) / 8;     // The size of the sampled data per millisecond at the current sample rate and bit depth.
  int bytesMs = bytes / 1000;     // Divide the size of the data to be sent by the size of the sampled data per millisecond to get the sleep time.
  int sleepMs = (dataSize * compressRate) / bytesMs;
  return sleepMs; 
}

/**
 * @brief Call start(). After a connection is successfully established with the cloud, the SDK's internal thread reports a started event.
 * @param cbEvent The callback event structure. For more information, see nlsEvent.h.
 * @param cbParam Custom callback parameters. Default value: NULL. You can customize parameters as needed.
 * @return
 */
void OnRecognitionStarted(NlsEvent* cbEvent, void* cbParam) {
  ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
  // This demonstrates how to print or use custom user parameters.
  printf("OnRecognitionStarted: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
  // Get the status code of the message. A value of 0 or 20000000 indicates success. Otherwise, an error code is returned.
  // The task_id of the current task. We recommend that you print this for troubleshooting, as it is the unique identifier for the interaction with the server.
  printf("OnRecognitionStarted: status code=%d, task id=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId()); 
  // Get all the information returned by the server.
  //printf("OnRecognitionStarted: all response=%s\n", cbEvent->getAllResponse());

  // Notify the sending thread that start() was successful and it can continue sending data.
  pthread_mutex_lock(&(tmpParam->mtxWord));
  pthread_cond_signal(&(tmpParam->cvWord));
  pthread_mutex_unlock(&(tmpParam->mtxWord));
} 

/**
 * @brief Set the parameter to allow returning intermediate results. When the SDK receives an intermediate result from the cloud,
 *        the SDK's internal thread reports a ResultChanged event.
 * @param cbEvent The callback event structure. For more information, see nlsEvent.h.
 * @param cbParam Custom callback parameters. Default value: NULL. You can customize parameters as needed.
 * @return
 */
void OnRecognitionResultChanged(NlsEvent* cbEvent, void* cbParam) {
  ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
  // This demonstrates how to print or use custom user parameters.
  printf("OnRecognitionResultChanged: %d, %s\n", tmpParam->userId, tmpParam->userInfo);         // The task_id of the current task. We recommend that you print this for troubleshooting, as it is the unique identifier for the interaction with the server.
  printf("OnRecognitionResultChanged: status code=%d, task id=%s, result=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getResult());
  // Get all the information returned by the server.
  //printf("OnRecognitionResultChanged: response=%s\n", cbEvent->getAllResponse());
}

/**
 * @brief When the SDK receives a recognition-ended message from the cloud, the SDK's internal thread reports a Completed event.
 * @note After the Completed event is reported, the SDK internally closes the recognition connection channel.
 *       At this point, calling sendAudio will return a negative value. Stop sending data.
 * @param cbEvent The callback event structure. For more information, see nlsEvent.h.
 * @param cbParam Custom callback parameters. Default value: NULL. You can customize parameters as needed.
 * @return
*/
void OnRecognitionCompleted(NlsEvent* cbEvent, void* cbParam) {
  ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
  // This demonstrates how to print or use custom user parameters.
  printf("OnRecognitionCompleted: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
  // The task_id of the current task. We recommend that you print this for troubleshooting, as it is the unique identifier for the interaction with the server.
  printf("OnRecognitionCompleted: status code=%d, task id=%s, result=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getResult());
  // Get all the information returned by the server.
  //printf("OnRecognitionCompleted: response=%s\n", cbEvent->getAllResponse());
}

/**
 * @brief When an exception occurs during the recognition process, the SDK's internal thread reports a TaskFailed event.
 * @note After the TaskFailed event is reported, the SDK internally closes the recognition connection channel.
 *       At this point, calling sendAudio will return a negative value. Stop sending data.
 * @param cbEvent The callback event structure. For more information, see nlsEvent.h.
 * @param cbParam Custom callback parameters. Default value: NULL. You can customize parameters as needed.
 * @return
 */
void OnRecognitionTaskFailed(NlsEvent* cbEvent, void* cbParam) {
  ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
  // This demonstrates how to print or use custom user parameters.
  printf("OnRecognitionTaskFailed: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
  // The task_id of the current task. We recommend that you print this for troubleshooting, as it is the unique identifier for the interaction with the server.
  printf("OnRecognitionTaskFailed: status code=%d, task id=%s, error message=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getErrorMessage());
  // Get all the information returned by the server.
  //printf("OnRecognitionTaskFailed: response=%s\n", cbEvent->getAllResponse());
}

/**
 * @brief When recognition ends or an exception occurs, the connection channel is closed.
 *        The SDK's internal thread reports a ChannelCloseed event.
 * @param cbEvent The callback event structure. For more information, see nlsEvent.h.
 * @param cbParam Custom callback parameters. Default value: NULL. You can customize parameters as needed.
 * @return
 */
void OnRecognitionChannelClosed(NlsEvent* cbEvent, void* cbParam) {
  ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
  // This demonstrates how to print or use custom user parameters.
  printf("OnRecognitionChannelClosed: %d, %s\n", tmpParam->userId, tmpParam->userInfo);         // Get all the information returned by the server.
  printf("OnRecognitionChannelClosed: response=%s\n", cbEvent->getAllResponse());

  // Notify the sending thread that the final recognition result has been returned and stop() can be called.
  pthread_mutex_lock(&(tmpParam->mtxWord));
  pthread_cond_signal(&(tmpParam->cvWord));
  pthread_mutex_unlock(&(tmpParam->mtxWord));
}

/**
 * @brief Worker thread in short-lived connection mode.
 *        It loops as follows:
 *        createRecognizerRequest           <----|
 *                   |                              |
 *           request->start()                       |
 *                   |                              |
 *           request->sendAudio()                   |
 *                   |                              |
 *           request->stop()                        |
 *                   |                              |
 *           Receive OnRecognitionChannelClosed callback     |
 *                   |                              |
 *           releaseRecognizerRequest(request)  ----|
 */
void* pthreadFunction(void* arg) {
  int sleepMs = 0;
  int ret = 0;
  ParamCallBack *cbParam = NULL;

  // Initialize custom callback parameters. The following two variables are for demonstration purposes only and have no effect in this example.
  // After allocating callback parameters on the heap, release them before exiting the thread.
  cbParam = new ParamCallBack();
  cbParam->userId = rand() % 100;
  strcpy(cbParam->userInfo, "User.");
  // 0: Get the token, configuration file, and other parameters from the custom thread parameters.
  ParamStruct *tst = (ParamStruct *) arg; 
  if (tst == NULL) {
    printf("arg is not valid\n"); 
    delete cbParam;
    return NULL;
  } 
  // Open the audio file to get the data.
  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;
  }
  // 1: Create a SpeechRecognizerRequest object for short sentence recognition.
  SpeechRecognizerRequest *request =
      NlsClient::getInstance()->createRecognizerRequest();
  if (request == NULL) {
    printf("createRecognizerRequest failed\n");
    delete cbParam;
    return NULL;
  }

  // Set the callback function for successful start().
  request->setOnRecognitionStarted(OnRecognitionStarted, cbParam);
  // Set the callback function for recognition exceptions.
  request->setOnTaskFailed(OnRecognitionTaskFailed, cbParam);
  // Set the callback function for when the recognition channel is closed.
  request->setOnChannelClosed(OnRecognitionChannelClosed, cbParam);
  // Set the callback function for intermediate results.
  request->setOnRecognitionResultChanged(OnRecognitionResultChanged, cbParam);
  // Set the callback function for when recognition is completed.
  request->setOnRecognitionCompleted(OnRecognitionCompleted, cbParam);

  // Set the AppKey. This is a required parameter.
  request->setAppKey(tst->appkey.c_str());
  // Set the account verification token. This is a required parameter.
  request->setToken(tst->token.c_str());

  // Set the audio data encoding format. This is an optional parameter. PCM and OPUS are supported. Default value: PCM.
  request->setFormat("opus");
  // Set the audio data sample rate. This is an optional parameter. 16000 and 8000 are supported. Default value: 16000.
  request->setSampleRate(SAMPLE_RATE);
  // Set whether to return intermediate recognition results. This is an optional parameter. Default value: false.
  request->setIntermediateResult(true);
  // Set whether to add punctuation in post-processing. This is an optional parameter. Default value: false.
  request->setPunctuationPrediction(true);
  // Set whether to perform ITN in post-processing. This is an optional parameter. Default value: false.
  request->setInverseTextNormalization(true);
  // Enable voice activity detection. Optional. Default value: False.
  //request->setEnableVoiceDetection(true);
  // Maximum allowed initial silence in milliseconds. Optional.
  // If this is exceeded, the server sends a RecognitionCompleted event to end the current recognition.
  // Note: You must first set enable_voice_detection to true.
  //request->setMaxStartSilence(800);
  // Maximum allowed trailing silence in milliseconds. Optional.
  // If this is exceeded, the server sends a RecognitionCompleted event to end the current recognition.
  // Note: You must first set enable_voice_detection to true.
  //request->setMaxEndSilence(800);
  // Custom language model ID. Optional.
  //request->setCustomizationId("TestId_123");
  // Custom vocabulary ID. Optional.
  //request->setVocabularyId("TestId_456");
  // Used to pass some custom, advanced parameter settings in JSON format: {"key": "value"}.
  //request->setPayloadParam("{\"vad_model\": \"farfield\"}");

  struct timespec outtime;
  struct timeval now;
  /*
   * 2. start() can be a synchronous or asynchronous operation. The default is asynchronous. Because the asynchronous mode has a higher threshold for modification to determine if the request is running successfully through callbacks, and some older versions have synchronous interfaces,
   *    both synchronous and asynchronous calling methods are provided to allow for a smoother SDK upgrade.
   *    Asynchronous case: By default, when setSyncCallTimeout() is not called, the start() call returns immediately.
   *            The return value does not indicate that the request has started successfully. You need to wait for a started event to indicate a successful start, or a TaskFailed event to indicate failure.
   *    Synchronous case: Call setSyncCallTimeout() to set the timeout for the synchronous interface and enable synchronous mode. The start() call does not return immediately.
   *            It returns after an internal success (which also triggers a started event callback) or failure (which also triggers a TaskFailed event callback).
   *            This method is convenient for older SDK versions.
   */
  ret = request->start();
  if (ret < 0) {
    printf("start() failed. may be can not connect server. please check network or firewalld\n");
    NlsClient::getInstance()->releaseRecognizerRequest(request); // start() failed. Release the request object.
    delete cbParam;
    return NULL;
  } else {
    if (g_sync_timeout == 0) {
      /*
       * 2.1. g_sync_timeout is 0, meaning setSyncCallTimeout() was not called by default. start() is called asynchronously.
       *      You need to wait for a started event to indicate a successful start, or a TaskFailed event to indicate failure.
       * 
       * Wait for the started event to be returned to indicate that start() was successful, then send the audio data.
       * The voice server may not be able to process the current request in time, causing no callback to be returned within 10s.
       * After 10s, a TaskFailed callback is returned, so a timeout mechanism is needed.
       */
      printf("wait started callback.\n");

      // The voice server may not be able to process the current request in time, causing no callback to be returned within 10s.
      // After 10s, a TaskFailed callback is returned, so a timeout mechanism is needed.
      gettimeofday(&now, NULL);
      outtime.tv_sec = now.tv_sec + 5;
      outtime.tv_nsec = now.tv_usec * 1000;
      pthread_mutex_lock(&(cbParam->mtxWord));
      if (ETIMEDOUT == pthread_cond_timedwait(&(cbParam->cvWord), &(cbParam->mtxWord), &outtime)) {
        printf("start timeout.\n");
        pthread_mutex_unlock(&(cbParam->mtxWord));
        request->cancel();
        NlsClient::getInstance()->releaseRecognizerRequest(request);
        delete cbParam;
        return NULL;
      }
      pthread_mutex_unlock(&(cbParam->mtxWord));
    } else {
       /*
        * 2.2. g_sync_timeout is greater than 0, meaning setSyncCallTimeout() was called. start() is called synchronously.
        *      A return value of 0 indicates a successful start.
        */ 
    }
  }

  /*
   * 3. Get audio data from the file and send it in a loop.
   */
  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;
    }

    /*
     * 3.1. Send audio data: sendAudio is an asynchronous operation. A negative return value indicates a sending failure, and you need to stop sending.
     *      A value greater than 0 indicates success.
     *      If you want to upload audio data in the traffic-saving Opus format, pass ENCODER_OPU/ENCODER_OPUS as the third parameter.
     *
     * In ENCODER_OPU/ENCODER_OPUS mode, some CPU resources will be used for audio compression.
     */
    ret = request->sendAudio(data, nlen, ENCODER_OPUS); 
    if (ret < 0) {
      // Sending failed. Exit the data sending loop.
      printf("send data fail.\n"); 
      break;
    } 

    /*
     * In actual use, audio data is real-time, so you don't need to use sleep to control the rate. You can send it directly.
     * Here, we use audio data from a file for simulation, so we need to control the rate to simulate a real recording scenario.
     */
    sleepMs = getSendAudioSleepTime(nlen, SAMPLE_RATE, 1); // Get the sleep time based on the data size, sample rate, and data compression ratio.
    /*
     * Audio data sending delay control. No sleep is needed in actual use.
     */
    usleep(sleepMs * 1000);
  } // while

  printf("sendAudio done.\n");
  // 5: Close the audio file.
  fs.close();
  
  /*
   * 4. Notify the cloud that data sending is complete.
   *    stop() can be a synchronous or asynchronous operation. The default is asynchronous. Because the asynchronous mode has a higher threshold for modification to determine if the request is running successfully through callbacks, and some older versions have synchronous interfaces,
   *    both synchronous and asynchronous calling methods are provided to allow for a smoother SDK upgrade.
   *    Asynchronous case: By default, when setSyncCallTimeout() is not called, the stop() call returns immediately.
   *            The return value does not indicate that the request has ended successfully. You need to wait for a closed event to indicate the end.
   *    Synchronous case: Call setSyncCallTimeout() to set the timeout for the synchronous interface and enable synchronous mode. The stop() call does not return immediately.
   *            It returns after the internal work is completed and a closed event callback is triggered.
   *            This method is convenient for older SDK versions.
   */
  ret = request->stop();
  if (ret == 0) {
    if (g_sync_timeout == 0) {
      /*
       * 4.1. g_sync_timeout is 0, meaning setSyncCallTimeout() was not called by default. stop() is called asynchronously.
       *      You need to wait for a closed event to indicate a successful stop, or a TaskFailed event to indicate failure.
       * 
       * Wait for the closed event to be returned to indicate that stop() was successful before releasing.
       * The voice server may not be able to process the current request in time, causing no callback to be returned within 10s.
       * After 10s, a TaskFailed callback is returned, so a timeout mechanism is needed.
       */
      // Wait for the closed event before releasing, otherwise a crash may occur.
      // If you have called setSyncCallTimeout() to enable synchronous calling mode, you do not need to wait for the closed event.
      std::cout << "wait closed callback." << std::endl;
        
      printf("wait closed callback.\n");
    
      // The voice server may not be able to process the current request in time, causing no callback to be returned within 10s.
      // After 10s, a TaskFailed callback is returned with the error message:
      // "Gateway:IDLE_TIMEOUT:Websocket session is idle for too long time, the last directive is 'StopRecognition'!"
      // So a timeout mechanism is needed.
      gettimeofday(&now, NULL);
      outtime.tv_sec = now.tv_sec + 5;
      outtime.tv_nsec = now.tv_usec * 1000;
      // Wait for the closed event before releasing.
      pthread_mutex_lock(&(cbParam->mtxWord));
      if (ETIMEDOUT == pthread_cond_timedwait(&(cbParam->cvWord), &(cbParam->mtxWord), &outtime)) {
        printf("stop timeout\n");
        pthread_mutex_unlock(&(cbParam->mtxWord));
        NlsClient::getInstance()->releaseRecognizerRequest(request);
        delete cbParam;
        return NULL;
      }
      pthread_mutex_unlock(&(cbParam->mtxWord));
    } else {
      /*
       * 4.2. g_sync_timeout is greater than 0, meaning setSyncCallTimeout() was called. stop() is called synchronously.
       *      A return value of 0 indicates a successful start.
       */
    }
  } else {
    printf("stop ret is %d\n", ret);
  }

  /*
   * 5. Release the current request after all work is done.
   *    Please release it after the closed event (to confirm all work is done), otherwise it may disrupt the internal state machine and forcibly unload the running request.
   */
  NlsClient::getInstance()->releaseRecognizerRequest(request);
  delete cbParam;
  return NULL;
}

// Recognize a single audio file.
int speechRecognizerFile(const char* appkey) {
  // Get the current system timestamp to check if the token has expired.
  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 (generateToken(g_akId, g_akSecret, &g_token, &g_expireTime) < 0) {
      return -1;
    } 
  }

  ParamStruct pa;
  pa.token = g_token;
  pa.appkey = appkey;
  pa.fileName = "test0.wav";

  // Start a worker thread for a single recognition task.
  pthread_t pthreadId;
  pthread_create(&pthreadId, NULL, &pthreadFunction, (void *)&pa);
  pthread_join(pthreadId, NULL);
  return 0;
}

// Recognize multiple audio files.
// In the SDK, multi-threading means one thread corresponds to one audio data source, not multiple threads for one audio data source.
// The example code starts two threads to recognize two files simultaneously.
// For free-tier users, the number of concurrent connections cannot exceed 2.
#define AUDIO_FILE_NUMS 2
#define AUDIO_FILE_NAME_LENGTH 32
int speechRecognizerMultFile(const char* appkey) {
  // Get the current system timestamp to check if the token has expired.
  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 (generateToken(g_akId, g_akSecret, &g_token, &g_expireTime) < 0) {
      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]; 
  } 

  // Start 2 worker threads to recognize 2 audio files simultaneously.
  std::vector<pthread_t> pthreadId(AUDIO_FILE_NUMS);
  for (int j = 0; j < AUDIO_FILE_NUMS; j++) {
    pthread_create(&pthreadId[j], NULL, &pthreadFunction, (void *)&(pa[j]));
  }
  for (int j = 0; j < AUDIO_FILE_NUMS; j++) {
    pthread_join(pthreadId[j], NULL);
  }
  return 0;
}

int main(int argc, char* argv[]) {
  printf("Usage: ./demo <your appkey> <your AccessKey ID> <your AccessKey Secret>\n");

  std::string appkey = getenv("NLS_APPKEY_ENV");
  g_akId = getenv("NLS_AK_ENV");
  g_akSecret = getenv("NLS_SK_ENV");

  // Set the SDK output log as needed. Optional.
  // This indicates that the SDK log is output to log-recognizer.txt.
  // LogDebug means all levels of logs are output. LogDebug, LogInfo, LogWarning, and LogError are supported.
  // 400 means a single file is 400 MB. 50 means 50 log files are recorded in a loop.
  int ret = NlsClient::getInstance()->setLogConfig(
      "log-recognizer", LogDebug, 400, 50);
  if (ret < 0) {
    printf("set log failed.\n");
    return -1;
  }

  // Set the socket address type required by the runtime environment. Default value: AF_INET.
  // Must be called before startWorkThread().
  //NlsClient::getInstance()->setAddrInFamily("AF_INET");

  // In a private cloud deployment, you can set a direct IP connection.
  // Must be called before startWorkThread().
  //NlsClient::getInstance()->setDirectHost("106.15.83.44");

  // Some devices may not be able to obtain a usable IP through the SDK's DNS even after setting the DNS.
  // You can call this interface to actively enable the system's getaddrinfo to solve this problem.
  //NlsClient::getInstance()->setUseSysGetAddrInfo(true);

  // g_sync_timeout is 0, meaning setSyncCallTimeout() was not called by default.
  // Asynchronous calling method:
  //   start(): You need to wait for a started event to indicate a successful start, or a TaskFailed event to indicate failure.
  //   stop(): You need to wait for a closed event to indicate that the interaction is complete.
  // Synchronous calling method:
  //   The return of the start()/stop() call indicates that the interaction has started/ended.
  if (g_sync_timeout > 0) {
    NlsClient::getInstance()->setSyncCallTimeout(g_sync_timeout);
  }
    
  // Start the worker thread. This function must be called before creating and starting a request. It can be understood as initializing NlsClient.
  // If the input parameter is negative, it starts the number of available cores in the current system.
  // For concurrency below 200, we recommend an input parameter of 1. For higher concurrency, see the readme for recommendations.
  NlsClient::getInstance()->startWorkThread(1);

  // Recognize a single audio file.
  speechRecognizerFile(appkey.c_str());
  // Concurrently recognize multiple audio files.
  //speechRecognizerMultFile(appkey.c_str());

  // After all tasks are completed, release nlsClient before the process exits.
  // Note that releaseInstance() is not thread-safe. Make sure all requests have stopped before releasing.
  NlsClient::releaseInstance();

  return 0;
}

FAQ

Where can I get the g_akid and g_akSecret used in speechRecognizerDemo.cpp in the C++ SDK?

After I call stop for short sentence recognition in the C++ SDK, the error callback returns status code 40000004. How do I resolve this? The message is "{"header":{"namespace":"Default","name":"TaskFailed","status":40000004,"message_id":"xxxxxxxxxxxxxxxxxxxxxxxxx","task_id":"xxxxxxxxxxxxxxxxxxxxxxxxx","status_text":"Gateway:IDLE_TIMEOUT:Websocket session is idle for too long time, the last directive is 'StopRecognition'!"}}"

This may be because the server received many requests at once, and a single instance could not process them in time. We recommend that you retry the operation.

Why can't I connect to the framework?

The code in the framework is a mix of Objective-C and C++. Therefore, you must use a file with the .mm extension to call it. Also, ensure that the header file path and library file path are correctly set in your project.

Can I use a GCC version higher than 5.0 to compile the speech synthesis and speech recognition features of the C++ SDK (version 3.0 and later)?

Yes, you can. On Linux, GCC 4.8.5 or later is supported. The GCC versions that have been verified to compile and run successfully include 4.8.5, 5.5.0, and 8.4.0.

An ASR request from the C++ SDK fails with a DNS resolution error, causing an exception. The error is "ali-recog-skd.log:AliSpeech_C++SDK(ERROR): GetInetAddressByHostname:252 DNS: resolved timeout.ali-recog-skd.log:AliSpeech_C++SDK(ERROR): start:76 start failed: DNS: resolved timeout..unimrcpserver_current.log: [ERROR] [[./ali/AliRecogChannel.cpp:772,onTaskFailed]]Ali Task start failed Msg :DNS: resolved timeout., start finised." How do I resolve this?

  • For earlier versions (3.0 and earlier): This issue is likely to occur in high-concurrency scenarios or when the computer's DNS is busy. We recommend that you update the SDK to version 3.1.x or restart the request.

  • For later versions (3.0 and later): This issue has been addressed. If it still occurs occasionally, it is because the computer's DNS is busy. You must restart the request.

When I integrate the new C++ SDK into another project and change add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) to add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1) in CMakeLists.txt, the compilation fails. How do I resolve this?

In addition to CMakeLists.txt, you must modify this parameter for the entire project, for example, in config/linux.thirdparty.debug.cmake and config/linux.thirdparty.release.cmake. Search the entire directory for _GLIBCXX_USE_CXX11_ABI and modify it.

What are the differences between the old C++ SDK (NlsSdkCpp2.0) and the new one (NlsSdkCpp3.X)?

In NlsSdkCpp2.0, each request is a thread, and the interfaces are synchronous.

In NlsSdkCpp3.x, event messages are processed uniformly by the third-party library libevent, which provides better concurrency performance. The interfaces are asynchronous.

Does the C++ SDK not support the C11 specification? My project cannot be linked to the SDK. How do I resolve this?

The project defaults to _GLIBCXX_USE_CXX11_ABI=0. You must modify this parameter for the entire project. Search the entire directory for _GLIBCXX_USE_CXX11_ABI and modify it.

The C++ SDK test demo runs successfully, but the integrated project reports a DNS resolution error: "nls-gateway-cn-shanghai.aliyuncs.com dns failed: nodename nor servname provided, or not known". How do I resolve this?

  1. The SDK checks all protocol families (IPv4 and IPv6) enabled on the current device to make DNS resolution requests. The domain name nls-gateway-cn-shanghai.aliyuncs.com does not support IPv6, which causes a resolution error and causes the SDK DNS resolution to fail. You can disable the IPv6 protocol family on the current device. The CppSdk will be improved to make this configurable in a future release.

  2. We recommend that you upgrade to version 3.1.12 or later.

The C++ SDK test demo runs successfully, but the integrated project reports a network connection failure: "[dnsEventCallback:465]Node:0x7f087c001030 ai_canonname: nls-gateway-cn-shanghai.aliyuncs.com.gds.alibabadns.com[dnsEventCallback:477]Node:0x7f087c001030 IpV4:106.15.XX.XX[connectProcess:1329]Node:0x7f087c001030 sockFd:41[connectProcess:1347]Node:0x7f087c001030 new Socket ip:106.15.XX.XX port:443 Fd:41.[socketConnect:1458]Node:0x7f087c001030 Connect failed:Network is unreachable. retry...". How do I resolve this?

This indicates a network connection failure. The log shows that the IP address resolved through DNS cannot be connected. Further checks with Ping confirm that the network is unreachable. This is because local DNS interception causes the SDK's internal libevent evdns_getaddrinfo to retrieve an incorrect IP address.

Solutions:

  • For versions earlier than 3.1.12, you can manually replace evdns_getaddrinfo() with the system's getaddrinfo().

  • For version 3.1.12, you can modify add_definitions(-DNLS_USE_NATIVE_GETADDRINFO) in the CMakeLists.txt file.

  • Version 3.1.12 and later add the setDirectHost() interface. You can perform DNS resolution outside the SDK and then use this interface to set the correct IP address.

  • Version 3.1.13 and later have resolved this issue. If the problem persists at runtime, we recommend that you call the setUseSysGetAddrInfo(true) interface.

What error message is returned if the text passed to the C++ SDK for speech synthesis is not UTF-8 encoded?

If the passed text is not UTF-8 encoded and contains Chinese characters, the call to the start function of the speech synthesis SDK fails. The error message Socket recv failed, errorCode: 0 is returned. An error code of 0 indicates that the server has closed the connection. In this case, you must check whether the passed text is UTF-8 encoded.