本文由簡體中文內容自動轉碼而成。阿里雲不保證此自動轉碼的準確性、完整性及時效性。本文内容請以簡體中文版本為準。

C++ SDK

更新時間:2024-12-18 12:21

本文介紹如何使用阿里雲Intelligent Speech Interaction提供的C++ SDK,包括SDK的安裝方法、SDK程式碼範例以及常見問題等。

SDK下載

說明
  • 當前最新版本:3.1.17,支援Linux、Windows平台。發布日期:2023年08月09日。

  • 使用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

    最新SDK包

    平台

    MD5

    NlsCppSdk_Linux-aarch64_3.1.15_fa30fba.tar.gz

    Linux aarch64

    76c34a3ab397d7285963a139b9270ff4

    NlsCppSdk_Windows_3.1.16_4776504.zip

    Windows

    c428e5cf1295d8933d23a4945683e250

    其中:

    • 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平台為例的範例程式碼工程CMakeList檔案。

  • demo目錄:SDK包中,整合範例程式碼,以Linux平台為例,如下表所示。

  • 檔案名稱

    描述

    檔案名稱

    描述

    speechRecognizerDemo.cpp

    一句話識別樣本。

    speechSynthesizerDemo.cpp

    語音合成樣本。

    speechTranscriberDemo.cpp

    即時語音辨識樣本。

    fileTransferDemo.cpp

    錄音檔案識別樣本。

  • resource目錄:SDK源碼中,Voice Messaging Service範例音頻,可用於功能測試,如下表所示。

  • 檔案名稱

    描述

    檔案名稱

    描述

    • 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.0

    • Glibc 2.5

    • Gcc 4.8.5

  2. 在Linux終端運行如下指令碼。

    1. 進入SDK源碼的根目錄。

    2. 產生SDK庫檔案和可執行程式:srDemo(一句話識別)、stDemo(即時語音辨識)、syDemo(語音合成)、daDemo(語音對話)。

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

      cd build/demo 
      ./stDemo 

Windows平台編譯

推薦直接使用已經編譯好的庫NlsCppSdk_Windows_<version>_<github commit id>.zip進行整合。若有編譯需求,請下載alibabacloud-nls-cpp-sdk<version>-master_<github commit id>.zip並解壓到本地,或從GitHub擷取最新代碼,然後參考其中readme.md的編譯步驟。

關鍵介面

  • 基礎介面

    • NlsClient:語音處理用戶端,利用該用戶端可以進行一句話識別、即時語音辨識和語音合成的語音處理任務。該用戶端為安全執行緒,建議全域僅建立一個執行個體。

      介面名

      啟用版本

      功能描述

      介面名

      啟用版本

      功能描述

      getInstance

      2.x

      擷取(建立)NlsClient執行個體。

      setLogConfig

      2.x

      設定記錄檔與儲存路徑。

      setDirectHost

      3.x

      跳過DNS網域名稱解析直接設定伺服器ipv4地址,若調用則需要在startWorkThread之前。

      setAddrInFamily

      3.1.12

      設定套介面地址結構的類型,預設為AF_INET僅返回IPV4相關的地址資訊,需要在startWorkThread之前調用。

      setUseSysGetAddrInfo

      3.1.13

      若libevent的DNS無法滿足,無法完成DNS,可調用此介面切換成系統的介面,需要在startWorkThread之前調用。

      setSyncCallTimeout

      3.1.17

      設定同步調用模式的逾時時間(ms),0則為關閉同步模式,預設0。此模式start()後收到服務端結果再return出去,stop()後收到close()回調再return出去。

      startWorkThread

      3.x

      啟動背景工作執行緒數,預設1即啟動一個線程,若-1則啟動CPU核心數的線程數。在高並發的情況下建議選擇-1。可以理解NlsClient執行個體初始化,必須調用。

      releaseInstance

      3.x

      銷毀NlsClient對象執行個體。

      getVersion

      2.x

      擷取SDK版本號碼。

      createTranscriberRequest

      2.x

      建立即時語音辨識對象,安全執行緒,支援高並發請求。

      releaseTranscriberRequest

      2.x

      銷毀即時語音辨識對象,需要在當前請求的closed事件後調用。

    • NlsToken:建立Token對象,用於申請擷取TokenId。申請新Token時需要先擷取有效時間戳記,若超過有效時間則再申請。若在有效時間內多次申請Token會導致TokenId錯誤而無法使用。

      介面名

      功能描述

      介面名

      功能描述

      setAccessKeyId

      設定阿里雲帳號AccessKey ID。

      setKeySecret

      設定阿里雲帳號AccessKey Secret。

      setDomain

      設定網域名稱,非必填。

      setServerVersion

      設定API版本,非必填。

      setServerResourcePath

      設定服務路徑,非必填。

      setRegionId

      設定服務的確ID,非必填。

      setAction

      設定功能,非必填。

      applyNlsToken

      申請擷取TokenId。

      getToken

      擷取TokenId。

      getExpireTime

      擷取Token有效期間時間戳記(秒)。

      getErrorMsg

      獲得錯誤資訊。

    • NlsEvent:事件對象,您可以從中擷取Request狀態代碼、雲端返回結果、失敗資訊等。

      介面名

      功能描述

      介面名

      功能描述

      getStatusCode

      擷取狀態代碼,正常情況為0或者20000000,失敗時對應失敗的錯誤碼。

      getErrorMessage

      在TaskFailed回調中,擷取NlsRequest操作過程中出現失敗時的錯誤資訊。

      getTaskId

      擷取任務的TaskId。

      getAllResponse

      擷取雲端返回的識別結果。

      getResult

      擷取中間識別結果和最終結果。

      getSentenceIndex

      擷取即時語音檢測的句子編號。

      getSentenceTime

      擷取即時語音檢測的句子的音頻時間長度,單位是毫秒。

      getSentenceBeginTime

      對應的SentenceBegin事件的時間,單位是毫秒。

  • 識別介面

    SpeechTranscriberRequest:即時語音辨識請求對象,用於長語音即時識別。介面說明以SpeechTranscriberRequest.h內容為準。

    介面名

    啟用版本

    功能描述

    介面名

    啟用版本

    功能描述

    setOnTaskFailed

    2.x

    設定錯誤回呼函數。

    setOnTranscriptionStarted

    2.x

    設定即時音頻流識別開始回呼函數。

    setOnSentenceBegin

    2.x

    設定一句話開始回調。

    setOnSentenceEnd

    2.x

    設定一句話結束回呼函數。

    setOnTranscriptionResultChanged

    2.x

    設定即時音頻流識別中間結果回呼函數。

    setOnTranscriptionCompleted

    2.x

    設定服務端結束服務回呼函數。

    setOnChannelClosed

    2.x

    設定通道關閉回呼函數。

    setOnMessage

    3.1.16

    設定服務端response message回呼函數,所有回調從此回調輸出由使用者自行解析。非必填。設定後需setEnableOnMessage啟動。

    setAppKey

    2.x

    設定AppKey。

    setToken

    2.x

    口令認證。所有的請求都必須通過SetToken方法認證通過,才可以使用。

    setUrl

    2.x

    設定服務URL地址。

    setIntermediateResult

    2.x

    設定是否返回中間識別結果。

    setPunctuationPrediction

    2.x

    設定是否在後處理中添加標點。

    setInverseTextNormalization

    2.x

    設定是否在後處理中執行數字轉換。

    setFormat

    2.x

    設定音頻資料編碼格式(PCM、OPUS、OPU,預設是PCM,推薦OPUS)。

    setSampleRate

    2.x

    音頻採樣率設定。

    setSemanticSentenceDetection

    2.x

    設定是否使用語義斷句。

    setMaxSentenceSilence

    2.x

    設定vad閾值。

    setCustomizationId

    2.x

    設定定製模型。

    setVocabularyId

    2.x

    使用該介面也可以把專案和熱詞關聯起來。如果同時配置了控制台熱詞和SDK,則SDK配置優先順序最高,將會覆蓋控制台熱詞配置。

    setTimeout

    2.x

    設定連結逾時時間,預設5000ms。

    setSessionId

    2.x

    設定Session ID。

    setOutputFormat

    2.x

    設定輸出文本的編碼格式,編碼格式UTF-8 or GBK。

    setPayloadParam

    2.x

    參數設定,入參為JSON格式字串。

    setContextParam

    2.x

    設定使用者自訂參數,入參為JSON格式字串。

    AppendHttpHeaderParam

    2.x

    設定使用者自訂ws階段http header參數。

    setSendTimeout

    3.1.14

    設定發送逾時時間,預設5000ms。

    setRecvTimeout

    3.1.14

    設定接收逾時時間, 預設15000ms,需setEnableRecvTimeout開啟後生效。

    setEnableRecvTimeout

    3.1.16

    設定開啟接收逾時時間,預設false,即預設關閉接收逾時時間,開啟後長時間未收服務端則報錯。

    getOutputFormat

    3.1.16

    獲得設定的輸出文本的編碼格式。

    setEnableOnMessage

    3.1.16

    設定開啟伺服器返回訊息回調。

    getTaskId

    3.1.17

    獲得當前請求的task_id。

    start

    2.x

    啟動SpeechTranscriberRequest。

    stop

    2.x

    會與服務端確認關閉,正常停止即時音頻流識別操作。

    cancel

    2.x

    不會與服務端確認關閉,直接關閉即時音頻流識別過程。

    control

    2.x

    要求服務端更新識別參數。

    sendAudio

    2.x

    發送語音資料。建議一次發送音頻資料640~16384位元組。

C++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編碼器建立失敗

建議重新初始化。

-104

InvalidEncoderType

encoder類型無效

編譯時間可能關閉OPUS但是又使用,或請檢查ENCODER_TYPE。

-150

EventClientEmpty

主背景工作執行緒null 指標,已釋放

建議重新初始化,即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

請求是null 指標

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

成功

服務端響應狀態代碼

關於服務狀態代碼,請參見API reference

程式碼範例

說明
  • 樣本中使用的音頻檔案為16000 Hz採樣率,管控台設定的模型為通用模型。如果使用其他音頻,請設定為支援該音頻情境的模型。關於模型設定,請參見Manage projects

  • 樣本中使用了SDK內建的預設即時語音辨識服務的外網訪問服務端URL,如果您使用阿里雲上海ECS且需要使用內網訪問服務端URL,則在建立speechTranscriberRequest的對象中設定內網訪問的URL。

    request->setUrl("ws://nls-gateway-cn-shanghai-internal.aliyuncs.com/ws/v1");
  • 完整樣本,參見SDK壓縮包中Demo目錄的speechTranscriberDemo.cpp檔案。

  • 調用介面前,需配置環境變數,通過環境變數讀取存取憑證。Intelligent Speech Interaction的AccessKey ID、AccessKey Secret和AppKey的環境變數名:NLS_AK_ENVNLS_SK_ENVNLS_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 "speechTranscriberRequest.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::SpeechTranscriberRequest;

//自訂線程參數。
struct ParamStruct {
  std::string fileName;
  std::string appkey; 
  std::string token; 
};
//自訂事件回調參數。
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;
};

/**
 * 全域維護一個服務鑒權token和其對應的有效期間時間戳記,
 * 每次調用服務之前,首先判斷token是否已經到期,
 * 如果已經到期,則根據AccessKey ID和AccessKey Secret重建一個token,
 * 並更新這個全域的token和其有效期間時間戳記。
 *
 * 擷取Token具體操作,請參見:https://help.aliyun.com/document_detail/450514.html
 *
 * 注意:不要每次調用服務之前都重建新token,
 * 只需在token即將到期時重建即可。所有的服務並發可共用一個token。
 * Intelligent Speech Interaction的AccessKey ID、AccessKey Secret和AppKey的環境變數名:NLS_AK_ENV、NLS_SK_ENV、NLS_APPKEY_ENV
 */
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;

/**
 * 根據AccessKey ID和AccessKey Secret重建一個token,
 * 並擷取其有效期間時間戳記
 */
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) {
    // 擷取失敗原因。
    printf("generateToken Failed, error code:%d msg:%s\n",
        ret, nlsTokenRequest.getErrorMsg());
    return ret;
  }
  *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, 可以根據需求自訂參數
 * @return
 */
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());

  // 通知發送線程start()成功, 可以繼續發送資料
  pthread_mutex_lock(&(tmpParam->mtxWord));
  pthread_cond_signal(&(tmpParam->cvWord));
  pthread_mutex_unlock(&(tmpParam->mtxWord));
} 

/**
 * @brief 服務端檢測到了一句話的開始, sdk內部線程上報SentenceBegin事件
 * @param cbEvent 回調事件結構, 詳見nlsEvent.h
 * @param cbParam 回調自訂參數,預設為NULL, 可以根據需求自訂參數
 * @return
*/
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, 可以根據需求自訂參數
 * @return
*/
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在接收到雲端返回到最新結果時,
 *        sdk內部線程上報ResultChanged事件
 * @param cbEvent 回調事件結構, 詳見nlsEvent.h
 * @param cbParam 回調自訂參數,預設為NULL, 可以根據需求自訂參數
 * @return
*/
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會返回負值, 請停止發送.
 * @param cbEvent 回調事件結構, 詳見nlsEvent.h
 * @param cbParam 回調自訂參數,預設為NULL, 可以根據需求自訂參數
 * @return
*/
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(), sendAudio(), stop())發生異常時, sdk內部線程上報TaskFailed事件
 * @note 上報TaskFailed事件之後, SDK內部會關閉識別串連通道. 此時調用sendAudio會返回負值, 請停止發送
 * @param cbEvent 回調事件結構, 詳見nlsEvent.h
 * @param cbParam 回調自訂參數,預設為NULL, 可以根據需求自訂參數
 * @return
 */
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內部線程上報ChannelCloseed事件
 * @param cbEvent 回調事件結構, 詳見nlsEvent.h
 * @param cbParam 回調自訂參數,預設為NULL, 可以根據需求自訂參數
 * @return
 */
void onChannelClosed(NlsEvent* cbEvent, void* cbParam) {     
  ParamCallBack* tmpParam = (ParamCallBack*)cbParam;     
  // 示範如何列印/使用使用者自訂參數。
  printf("onChannelClosed: %d, %s\n", tmpParam->userId, tmpParam->userInfo); // 擷取服務端返回的全部資訊。
  printf("onChannelClosed: response=%s\n", cbEvent->getAllResponse());

  //通知發送線程, 最終識別結果已經返回, 可以調用stop()
  pthread_mutex_lock(&(tmpParam->mtxWord));
  pthread_cond_signal(&(tmpParam->cvWord));
  pthread_mutex_unlock(&(tmpParam->mtxWord));
}

/**
 * @brief 短連結模式下背景工作執行緒
 *        以 createTranscriberRequest           <----|
 *                   |                               |
 *           request->start()                        |
 *                   |                               |
 *           request->sendAudio()                    |
 *                   |                               |
 *           request->stop()                         |
 *                   |                               |
 *           收到onChannelClosed回調                 |
 *                   |                               |
 *           releaseTranscriberRequest(request)  ----|
 *        進行迴圈。
 */
void* pthreadFunction(void* arg) {
  int sleepMs = 0;
  int ret = 0;
  ParamCallBack *cbParam = NULL;

  //初始化自訂回調參數,以下兩變數僅作為樣本表示參數傳遞,在樣本中不起任何作用。
  //回調參數在堆中分配之後,請在退出線程前釋放。
  cbParam = new ParamCallBack();
  cbParam->userId = rand() % 100;
  strcpy(cbParam->userInfo, "User.");
  // 0:從自訂線程參數中擷取token,設定檔等參數。
  ParamStruct *tst = (ParamStruct *) arg; 
  if (tst == NULL) {
    printf("arg is not valid\n"); 
    delete cbParam;
    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;
  }
  /*
   * 1. 建立即時音頻流識別SpeechTranscriberRequest對象
   */
  SpeechTranscriberRequest* request =
      NlsClient::getInstance()->createTranscriberRequest();
  if (request == NULL) {
    printf("createTranscriberRequest failed\n");
    delete cbParam;
    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);

  // 設定appKey。必填參數。
  request->setAppKey(tst->appkey.c_str());
  // 設定帳號校正token, 必填參數
  request->setToken(tst->token.c_str());

  // 設定音頻資料編碼格式。選擇性參數,目前支援PCM/OPUS,預設為PCM。
  request->setFormat("opus");
  // 設定音頻資料採樣率。選擇性參數,目前支援16000/8000。預設為16000。
  request->setSampleRate(SAMPLE_RATE);
  // 設定是否返回中間識別結果。選擇性參數,預設false。
  request->setIntermediateResult(true);
  // 設定是否在後處理中添加標點。選擇性參數,預設false。
  request->setPunctuationPrediction(true);
  // 設定是否在後處理中執行ITN。選擇性參數,預設false。
  request->setInverseTextNormalization(true);

  // 語音斷句檢測閾值,一句話之後靜音長度超過該值,即本句結束,合法參數範圍200ms~2000ms,預設值800ms。
  //request->setMaxSentenceSilence(800);
  // 語義斷句,啟動此功能語音斷句檢測功能不會生效。此功能必須開啟中間識別結果。
  //request->setSemanticSentenceDetection(true);
  // 定製語言模型id,可選。
  //request->setCustomizationId("TestId_123");
  // 定製泛熱詞id,可選。
  //request->setVocabularyId("TestId_456");
  // 用於傳遞某些定製化、進階參數設定,參數格式為JSON格式:{"key": "value"}。
  //request->setPayloadParam("{\"vad_model\": \"farfield\"}");

  struct timespec outtime;
  struct timeval now;
  /*
   * 2. start()為同步/非同步兩種操作,預設非同步。由於非同步模式通過回調判斷request是否成功運行有修改門檻,且部分舊版本為同步介面。
   *    為了能較為平滑的更新升級SDK,提供了同步/非同步兩種調用方式。
   *    非同步情況:預設未調用setSyncCallTimeout()的時候,start()調用立即返回,
   *            且傳回值並不代表request成功開始工作,需要等待返回started事件表示成功啟動,或返回TaskFailed事件表示失敗。
   *    同步情況:調用setSyncCallTimeout()設定同步介面的逾時時間,並啟動同步模式。start()調用後不會立即返回,
   *            直到內部得到成功(同時也會觸發started事件回調)或失敗(同時也會觸發TaskFailed事件回調)後返回。
   *            此方法方便舊版本SDK
   */
  ret = request->start();
  if (ret < 0) {
    printf("start() failed. may be can not connect server. please check network or firewalld\n");
    NlsClient::getInstance()->releaseTranscriberRequest(request); // start()失敗,釋放request對象。
    delete cbParam;
    return NULL;
  } else {
    if (g_sync_timeout == 0) {
      /*
       * 2.1. g_sync_timeout等於0,即預設未調用setSyncCallTimeout(),非同步方式調用start()
       *      需要等待返回started事件表示成功啟動,或返回TaskFailed事件表示失敗。
       * 
       * 等待started事件返回表示start()成功, 然後再發送音頻資料。
       * Voice Messaging Service器存在來不及處理當前請求的情況, 10s內不返回任何回調的問題,
       * 然後在10s後返回一個TaskFailed回調, 所以需要設定一個逾時機制。
       */
      // 等待started事件返回, 再發送
      printf("wait started callback.\n");
    
      // Voice Messaging Service器存在來不及處理當前請求, 10s內不返回任何回調的問題,
      // 然後在10s後返回一個TaskFailed回調, 所以需要設定一個逾時機制.
      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()->releaseTranscriberRequest(request);
        delete cbParam;
        return NULL;
      }
      pthread_mutex_unlock(&(cbParam->mtxWord));
    } else {
      /*
       * 2.2. g_sync_timeout大於0,即調用了setSyncCallTimeout(),同步方式調用start()
       *      傳回值0即表示啟動成功。
       */
    }
  }

  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. 發送音頻資料: sendAudio為非同步作業, 返回負值表示發送失敗, 需要停止發送;
     *      返回大於0 為成功. 
     *      若希望用省流量的opus格式上傳音頻資料, 則第三參數傳入ENCODER_OPU/ENCODER_OPUS
     *
     * ENCODER_OPU/ENCODER_OPUS模式時, 會佔用一定的CPU進行音頻壓縮
     */
    ret = request->sendAudio(data, nlen, ENCODER_OPUS); 
    if (ret < 0) {
      // 發送失敗,退出迴圈資料發送。
      printf("send data fail.\n"); 
      break;
    } 

    /*
     * 實際使用中, 語音資料是即時的, 不用sleep控制速率, 直接發送即可.
     * 此處是用語音資料來自檔案的方式進行類比, 故發送時需要控制速率來類比真實錄音情境.
     */
    sleepMs = getSendAudioSleepTime(nlen, SAMPLE_RATE, 1); // 根據發送資料大小、採樣率、資料壓縮比來擷取sleep時間。
    /*
     * 語音資料發送延時控制, 實際使用中無需sleep.
     */
    usleep(sleepMs * 1000);
  } // while

  printf("sendAudio done.\n");
  //5: 關閉音頻檔案
  fs.close();
  
  /*
   * 4. 通知雲端資料發送結束.
   *    stop()為同步/非同步兩種操作,預設非同步。由於非同步模式通過回調判斷request是否成功運行有修改門檻,且部分舊版本為同步介面。
   *    為了能較為平滑的更新升級SDK,提供了同步/非同步兩種調用方式。
   *    非同步情況:預設未調用setSyncCallTimeout()的時候,stop()調用立即返回,
   *            且傳回值並不代表request成功結束,需要等待返回closed事件表示結束。
   *    同步情況:調用setSyncCallTimeout()設定同步介面的逾時時間,並啟動同步模式。stop()調用後不會立即返回,
   *            直到內部完成工作,並觸發closed事件回調後返回。
   *            此方法方便舊版本SDK。
   */
  ret = request->stop();
  if (ret == 0) {
      if (g_sync_timeout == 0) {
        /*
         * 4.1. g_sync_timeout等於0,即預設未調用setSyncCallTimeout(),非同步方式調用stop()
         *      需要等待返回closed事件表示成功停止,或返回TaskFailed事件表示失敗。
         * 
         * 等待closed事件返回表示stop()成功, 然後才可釋放。
         * Voice Messaging Service器存在來不及處理當前請求的情況, 10s內不返回任何回調的問題,
         * 然後在10s後返回一個TaskFailed回調, 所以需要設定一個逾時機制。
         */
        // 等待closed事件後再進行釋放, 否則會出現崩潰
        // 若調用了setSyncCallTimeout()啟動了同步調用模式, 則可以不等待closed事件。
        printf("wait closed callback.\n");
        
        // Voice Messaging Service器存在來不及處理當前請求, 10s內不返回任何回調的問題,
        // 然後在10s後返回一個TaskFailed回調, 錯誤資訊為:
        // "Gateway:IDLE_TIMEOUT:Websocket session is idle for too long time, the last directive is 'StopRecognition'!"
        // 所以需要設定一個逾時機制.
        gettimeofday(&now, NULL);
        outtime.tv_sec = now.tv_sec + 5;
        outtime.tv_nsec = now.tv_usec * 1000;
        // 等待closed事件後再進行釋放
        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()->releaseTranscriberRequest(request);
          delete cbParam;
          return NULL;
        }
        pthread_mutex_unlock(&(cbParam->mtxWord));
      } else {
        /*
         * 4.2. g_sync_timeout大於0,即調用了setSyncCallTimeout(),同步方式調用stop()
         *      傳回值0即表示啟動成功。
         */
      }
  } else {
    printf("stop ret is %d\n", ret);
  }

  /*
   * 5. 完成所有工作後釋放當前請求。
   *    請在closed事件(確定完成所有工作)後再釋放, 否則容易破壞內部狀態機器, 會強制卸載正在啟動並執行請求。
   */
  NlsClient::getInstance()->releaseTranscriberRequest(request);
  delete cbParam;
  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 (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";

  // 啟動一個背景工作執行緒,用於單次識別。
  pthread_t pthreadId;
  pthread_create(&pthreadId, NULL, &pthreadFunction, (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 (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]; 
  } 

  // 啟動2個背景工作執行緒,同時識別2個音頻檔案。
  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");

  // 根據需要設定SDK輸出日誌。可選。
  // 此處表示SDK日誌輸出至log-transcriber.txt。
  // LogDebug表示輸出所有層級日誌,支援LogDebug、LogInfo、LogWarning、LogError。
  // 400表示單個檔案400MB。50表示50個記錄檔迴圈記錄。
  int ret = NlsClient::getInstance()->setLogConfig(
      "log-transcriber", LogDebug, 400, 50);
  if (ret < 0) {
    printf("set log failed.\n");
    return -1;
  }

  // 設定運行環境需要的套介面地址類型, 預設為AF_INET
  // 必須在startWorkThread()前調用
  //NlsClient::getInstance()->setAddrInFamily("AF_INET");
    
  // 私人雲端部署的情況下可進行直連IP的設定
  // 必須在startWorkThread()前調用
  //NlsClient::getInstance()->setDirectHost("106.15.83.44");

  // 存在部分裝置在設定了dns後仍然無法通過SDK的dns擷取可用的IP,
  // 可調用此介面主動啟用系統的getaddrinfo來解決這個問題.
  //NlsClient::getInstance()->setUseSysGetAddrInfo(true);

  // g_sync_timeout等於0,即預設未調用setSyncCallTimeout()
  // 非同步方式調用
  //   start(): 需要等待返回started事件表示成功啟動,或返回TaskFailed事件表示失敗。
  //   stop(): 需要等待返回closed事件則表示完成此次互動。
  // 同步方式調用
  //   start()/stop() 調用返回即表示互動啟動/結束。
  if (g_sync_timeout > 0) {
    NlsClient::getInstance()->setSyncCallTimeout(g_sync_timeout);
  }

  // 啟動背景工作執行緒, 在建立請求和啟動前必須調用此函數, 可理解為對NlsClient的初始化
  // 入參為負時, 啟動當前系統中可用的核心數。
  // 200並發以下推薦入參為1, 更高並發入參推薦可看readme。
  NlsClient::getInstance()->startWorkThread(1);

  // 識別單個音頻資料
  speechTranscriberFile(appkey.c_str());
  // 並發識別多個音頻資料
  //speechTranscriberMultFile(appkey.c_str());

  // 所有工作完成,進程退出前,釋放nlsClient。
  // 請注意releaseInstance()非安全執行緒, 需要確認所有請求都停止工作才可釋放。
  NlsClient::releaseInstance();

  return 0;
}

常見問題

C++ SDK調用智能即時語音解析介面失敗,提示 {"TaskFailed":"connect failed."} {"channeclClosed": "nls request finished."}如何解決?

  1. C++ SDK3.0及以前的版本有小機率出現這個問題,無需特別關注;3.1及以後版本出現這個問題可能是運行環境的網路問題導致,建議您檢查本網環境。

  2. 如果沒有返回TaskId,說明在串連過程中直接斷開,即時語音互動不需要重複調用介面,重複調用會有並發上限和逾時時間,並發超過限制會直接返回超過限制,WebSocket串連超過10秒沒有音頻就會自動斷開,但是會返回TaskId。

  3. 這種情況一般是由於當時網路擁堵造成的,建議您使用Windows系統中Wireshark抓包工具的安裝使用方法查看分析實際發送的包是否重傳了tcp retransmission,可以在用戶端使用traceroute命令或者使用MTR工具到nls-gateway-cn-shanghai.aliyuncs.com進行鏈路測試,判斷從用戶端到介面服務之間網路是否不穩定。

C++ SDK即時語音辨識報錯,提示status_text:Gateway:IDLE_TIMEOUT:Websocket session is idle for too long time, the last directive is 'StartTranscription'!如何解決?

  1. 因為超過10秒沒有發送資料到服務端,空閑逾時自動斷連。同時請檢查URI是否正確,wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1。如果發生這種情況,可以增加重試機制再次請求。

  2. 也可能服務端瞬間收到大量請求導致單個執行個體無法及時處理,建議重試。

C++ SDK調用即時語音辨識,整合在mrcp裡面使用,部分情況下建立多個識別通道時會返回10000002如何解決?

錯誤碼10000002是OpenSSL官方錯誤描述,Resource temporarily unavailable一般是建連後未發送資料到服務端導致WebSocket逾時,下一個發送的指令是StartTranscription

C++ SDK(3.0及以後版本)使用語音合成和語音辨識功能,可以提高GCC5.0以上的編譯版本嗎?

可以。Linux下支援GCC 4.8.5或以上版本。目前已驗證且順利編譯啟動並執行GCC版本包括4.8.5、5.5.0、8.4.0。

為什麼串連不到framework?

framework中代碼採用Objective-C和C++混合編寫而成,所以需要使用.mm尾碼檔案進行調用,同時請確保工程的標頭檔路徑與庫檔案路徑設定正確。

C++ SDK ASR請求有DNS解析失敗的情況導致異常,報錯“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."”如何解決?

  • 舊版(3.0及以前版本):在高並發或者電腦DNS忙碌的情況下容易出現以上問題,建議您更新到3.1.X版本,或進行再次重啟請求。

  • 新版(3.0及以後版本):已經對此問題進行防禦,若仍然偶現此問題,則為電腦DNS忙碌,需要再次重啟請求。

C++ SDK(新)整合到其他專案中時,將CMakeLists.txt中的add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) 修改為add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)後編譯不通過如何解決?

除了CMakeLists.txt,全工程都需要修改該參數,例如config/linux.thirdparty.debug.cmakeconfig/linux.thirdparty.release.cmake,請在全目錄搜尋_GLIBCXX_USE_CXX11_ABI進行修改。

C++ SDK在Windows上使用,報錯缺少nlsCommonSdk.dll如何解決?

3.1及以後版本無nlsCommonSdk.dll。

C++ SDK舊版NlsSdkCpp2.0和新版NlsSdkCpp3.X的區別是什嗎?

NlsSdkCpp2.0版本的SDK每一個請求為一個線程,且介面為同步介面。

NlsSdkCpp3.X版本的SDK內部由第三方庫libevent統一處理事件訊息,並發效能更強,且介面為非同步介面。

C++版的SDK不支援實現C11規範嗎? 現在導致專案無法連結SDK該如何解決?

工程預設為_GLIBCXX_USE_CXX11_ABI=0,全工程都需要修改該參數,請在全目錄搜尋_GLIBCXX_USE_CXX11_ABI進行修改。

C++ SDK測試Demo成功,整合專案報錯,DNS解析失敗,報錯“nls-gateway-cn-shanghai.aliyuncs.com dns failed: nodename nor servname provided, or not known”如何解決?

  1. SDK中會查看當前裝置開啟的所有協議族(IPv4、IPv6)進行DNS解析請求,nls-gateway-cn-shanghai.aliyuncs.com不支援 IPv6,返回解析錯誤,從而導致SDK DNS解析失敗退出。可禁用當前裝置的IPv6協議族,後續CppSdk產品改進對這方面進行可配置處理。

  2. 建議您升級到3.1.12及以後版本。

C++ SDK測試Demo可以成功,整合專案報錯,網路連結失敗,報錯“[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...”如何解決?

以上現象為無法串連網路,查看日誌發現DNS網域名稱解析出來的IP連結不成功,進一步通過Ping判斷網路不通。由於本地攔截DNS解析,導致SDK內部libeventevdns_getaddrinfo獲得錯誤的IP。

解決辦法:

  • 3.1.12版本以前可將evdns_getaddrinfo()手動替換成系統的getaddrinfo()。

  • 3.1.12版本可在CMakeLists.txt中修改add_definitions(-DNLS_USE_NATIVE_GETADDRINFO)

  • 3.1.12及以後版本增加setDirectHost()介面,您可以在SDK外部進行DNS解析,擷取正確IP後通過該介面設入。

  • 3.1.13及以後版本已解決此問題,若運行時仍存在上述問題,建議調用介面setUseSysGetAddrInfo(true)。

C++ SDK語音合成時傳入的文本沒有採用UTF-8編碼會有什麼錯誤資訊?

如果傳入的文本沒有採用UTF-8編碼,在文本中含有中文字元時,語音合成SDK調用start函數會失敗,返回錯誤資訊Socket recv failed, errorCode: 0。錯誤碼為0表示服務端已經關閉了串連,此時應檢查傳入的文本是否採用UTF-8編碼。

  • 本頁導讀 (1, M)
  • SDK下載
  • SDK包檔案說明
  • 編譯運行
  • Linux平台編譯
  • Windows平台編譯
  • 關鍵介面
  • C++SDK錯誤碼
  • 服務端響應狀態代碼
  • 程式碼範例
  • 常見問題
  • C++ SDK調用智能即時語音解析介面失敗,提示 {"TaskFailed":"connect failed."} {"channeclClosed": "nls request finished."}如何解決?
  • C++ SDK即時語音辨識報錯,提示status_text:Gateway:IDLE_TIMEOUT:Websocket session is idle for too long time, the last directive is 'StartTranscription'!如何解決?
  • C++ SDK調用即時語音辨識,整合在mrcp裡面使用,部分情況下建立多個識別通道時會返回10000002如何解決?
  • C++ SDK(3.0及以後版本)使用語音合成和語音辨識功能,可以提高GCC5.0以上的編譯版本嗎?
  • 為什麼串連不到framework?
  • C++ SDK ASR請求有DNS解析失敗的情況導致異常,報錯“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."”如何解決?
  • C++ SDK(新)整合到其他專案中時,將CMakeLists.txt中的add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) 修改為add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)後編譯不通過如何解決?
  • C++ SDK在Windows上使用,報錯缺少nlsCommonSdk.dll如何解決?
  • C++ SDK舊版NlsSdkCpp2.0和新版NlsSdkCpp3.X的區別是什嗎?
  • C++版的SDK不支援實現C11規範嗎? 現在導致專案無法連結SDK該如何解決?
  • C++ SDK測試Demo成功,整合專案報錯,DNS解析失敗,報錯“nls-gateway-cn-shanghai.aliyuncs.com dns failed: nodename nor servname provided, or not known”如何解決?
  • C++ SDK測試Demo可以成功,整合專案報錯,網路連結失敗,報錯“[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...”如何解決?
  • C++ SDK語音合成時傳入的文本沒有採用UTF-8編碼會有什麼錯誤資訊?
文檔反饋