本文介紹如何使用阿里云智能語音交互提供的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源碼
054d6f9f3226f689dbc68f8ed970fe3b
Linux x86_64
1ebb39ec10993583a645c0de8eebf654
Linux aarch64
76c34a3ab397d7285963a139b9270ff4
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平臺為例,如下表所示。
resource目錄:SDK源碼中,語音服務范例音頻,可用于功能測試,如下表所示。
test0.wav
test1.wav
test2.wav
test3.wav
include:SDK源碼中,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:版本號。
文件名 | 描述 |
speechRecognizerDemo.cpp | 一句話識別示例。 |
speechSynthesizerDemo.cpp | 語音合成示例。 |
speechTranscriberDemo.cpp | 實時語音識別示例。 |
fileTransferDemo.cpp | 錄音文件識別示例。 |
文件名 | 描述 |
測試音頻(16k采樣頻率、16bit采樣位數的音頻文件)。 |
編譯運行
Linux平臺編譯
安裝工具的最低版本要求如下:
CMake 3.0
Glibc 2.5
Gcc 4.8.5
在Linux終端運行如下腳本。
進入SDK源碼的根目錄。
生成SDK庫文件和可執行程序:srDemo(一句話識別)、stDemo(實時語音識別)、syDemo(語音合成)、daDemo(語音對話)。
./scripts/build_linux.sh
查看范例使用方式。
cd build/demo ./srDemo
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
獲?。▌摻ǎ㎞lsClient實例。
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??梢岳斫鉃镹lsClient實例初始化,必須調用。
releaseInstance
3.x
銷毀NlsClient對象實例。
getVersion
2.x
獲取SDK版本號。
createRecognizerRequest
2.x
創建一句話識別對象,線程安全,支持高并發請求。
releaseRecognizerRequest
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
獲取中間識別結果和最終結果。
識別接口
SpeechRecognizerRequest:一句話識別請求對象,用于短語音識別。接口說明以speechRecognizerRequest.h內容為準。
接口名
啟用版本
功能描述
setOnTaskFailed
2.x
設置錯誤回調函數。
setOnRecognitionStarted
2.x
設置一句話識別開始回調函數。
setOnRecognitionResultChanged
2.x
設置一句話識別中間結果回調函數。
setOnRecognitionCompleted
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
設置是否在后處理中執行數字轉換。
setEnableVoiceDetection
2.x
設置是否啟動自定義靜音檢測。
setMaxStartSilence
2.x
超出后(即開始識別后多長時間沒有檢測到聲音)服務端將會發送TaskFailed事件,結束本次識別。
setMaxEndSilence
2.x
超出時長服務端會發送RecognitionCompleted事件,結束本次識別(需要注意后續的語音將不會進行識別)。
setFormat
2.x
設置音頻數據編碼格式(PCM、OPUS、OPU,默認是PCM,推薦OPUS)。
setSampleRate
2.x
音頻采樣率設置。
setCustomizationId
2.x
設置定制模型。
setVocabularyId
2.x
設置泛熱詞。
setTimeout
2.x
設置Socket接收超時時間。
setOutputFormat
2.x
設置輸出文本的編碼格式,編碼格式UTF-8 or GBK。
setPayloadParam
2.x
參數設置,入參為JSON格式字符串。
setContextParam
2.x
設置用戶自定義參數,入參為JSON格式字符串。
AppendHttpHeaderParam
2.x
設置用戶自定義ws階段http header參數。
setAudioAddress
3.1.13
實驗接口??赏ㄟ^公網訪問的音頻文件下載鏈接,音頻文件下載鏈接,推薦使用阿里云OSS。
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
啟動SpeechRecognizerRequest。
stop
2.x
會與服務端確認關閉,正常停止鏈接操作。
cancel
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 | 主工作線程空指針,已釋放 | 建議重新初始化,即startWorkThread()。 |
-151 | SelectThreadFailed | 工作線程選擇失敗,未初始化 | 建議重新初始化,即startWorkThread()。 |
-160 | StartCommandFailed | 發送start命令失敗 | 建議重新嘗試。 |
-161 | InvokeStartFailed | 請求狀態機不對,導致start失敗 | 請檢查當前請求是否未創建或者已經完成。 |
-162 | InvokeSendAudioFailed | 請求狀態機不對,導致sendAudio失敗 | 請檢查當前請求是否已經啟動(即收到started事件回調)或者已經完成。 |
-163 | InvalidOpusFrameSize | opus幀長無效,默認為640字節 | OPU編碼模式下,sendAudio一幀只接收640字節數據。 |
-164 | InvokeStopFailed | 請求狀態機不對,導致stop失敗 | 請檢查當前請求是否未啟動(即收到started事件回調)或者已經完成。 |
-165 | InvokeCancelFailed | 請求狀態機不對,導致stop失敗 | 請檢查當前請求是否未啟動(即收到started事件回調)或者已經完成。 |
-166 | InvokeStControlFailed | 請求狀態機不對,導致stControl失敗 | 請檢查當前請求是否未啟動(即收到started事件回調)或者已經完成。 |
-200 | NlsEventEmpty | NLS事件為空 | SDK內部使用,NlsEvent幀丟失。 |
-201 | NewNlsEventFailed | 創建NlsEvent失敗 | SDK內部使用,NlsEvent幀創建失敗。 |
-202 | NlsEventMsgEmpty | NLS事件中消息為空 | parseJsonMsg()進行解析時發現消息字符串為空。 |
-203 | InvalidNlsEventMsgType | 無效的NLS事件中消息類型 | SDK內部使用,NlsEvent幀的事件類型不合法。 |
-204 | InvalidNlsEventMsgStatusCode | 無效的NLS事件中消息狀態碼 | SDK內部使用,NlsEvent幀的事件消息狀態不合法。 |
-205 | InvalidNlsEventMsgHeader | 無效的NLS事件中消息頭 | SDK內部使用,NlsEvent幀的事件消息頭不合法。 |
-250 | CancelledExitStatus | 已調用cancel | 暫未使用。 |
-251 | InvalidWorkStatus | 無效的工作狀態 | SDK內部使用,當前請求內部狀態不合法。 |
-252 | InvalidNodeQueue | workThread中NodeQueue無效 | SDK內部使用,當前待運行的請求不合法,建議釋放當前請求重新嘗試。 |
-300 | InvalidRequestParams | 請求的入參無效 | sendAudio傳入的數據為空。 |
-301 | RequestEmpty | 請求是空指針 | SDK內部使用,當前請求已經釋放,建議釋放當前請求重新嘗試。 |
-302 | InvalidRequest | 無效的請求 | SDK內部使用,當前請求已經釋放,建議釋放當前請求重新嘗試。 |
-303 | SetParamsEmpty | 設置傳入的參數為空 | 請檢查傳入的參數是否為空。 |
-350 | GetHttpHeaderFailed | 獲得http頭失敗 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-351 | HttpGotBadStatus | http錯誤的狀態 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-352 | WsResponsePackageFailed | 解析websocket返回包失敗 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-353 | WsResponsePackageEmpty | 解析websocket返回包為空 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-354 | WsRequestPackageEmpty | websocket請求包為空 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-355 | UnknownWsFrameHeadType | 未知websocket幀頭類型 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-356 | InvalidWsFrameHeaderSize | 無效的websocket幀頭大小 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-357 | InvalidWsFrameHeaderBody | 無效的websocket幀頭本體 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-358 | InvalidWsFrameBody | 無效的websocket幀本體 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-359 | WsFrameBodyEmpty | 幀數據為空,常見為收到了臟數據 | SDK內部使用,根據日志中反饋信息詳細定位。 |
-400 | NodeEmpty | node為空指針 | 建議釋放當前請求重新嘗試。 |
-401 | InvaildNodeStatus | node所處狀態無效 | SDK內部使用,建議釋放當前請求重新嘗試。 |
-402 | GetAddrinfoFailed | 通過DNS解析地址識別 | SDK內部使用,請檢查當前環境的DNS是否可用。 |
-403 | ConnectFailed | 聯網失敗 | 請檢查當前網絡環境是否可用。 |
-404 | InvalidDnsSource | 當前設備無DNS | SDK內部使用,請檢查當前環境的DNS是否可用。 |
-405 | ParseUrlFailed | 無效URL | 請檢查設置的URL是否有效。 |
-406 | SslHandshakeFailed | SSL握手失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-407 | SslCtxEmpty | SSL_CTX未空 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-408 | SslNewFailed | SSL_new失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-409 | SslSetFailed | SSL設置參數失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-410 | SslConnectFailed | SSL_connect失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-411 | SslWriteFailed | SSL發送數據失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-412 | SslReadSysError | SSL接收數據收到SYSCALL錯誤 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-413 | SslReadFailed | SSL接收數據失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-414 | SocketFailed | 創建socket失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-415 | SetSocketoptFailed | 設置socket參數失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-416 | SocketConnectFailed | 進行socket鏈接失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-417 | SocketWriteFailed | socket發送數據失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-418 | SocketReadFailed | socket接收數據失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-430 | NlsReceiveFailed | NLS接收幀數據失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-431 | NlsReceiveEmpty | NLS接收幀數據為空 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-432 | ReadFailed | 接收數據失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-433 | NlsSendFailed | NLS發送數據失敗 | SDK內部使用,請檢查當前網絡環境是否可用,并再次嘗試。 |
-434 | NewOutputBufferFailed | 創建buffer失敗 | SDK內部使用,請檢查內存是否充足。 |
-435 | NlsEncodingFailed | 音頻編碼失敗 | SDK內部使用,建議釋放當前請求重新嘗試。 |
-436 | EventEmpty | event為空 | SDK內部使用,建議釋放當前請求重新嘗試。 |
-437 | EvbufferTooMuch | evbuffer中數據太多 | SDK內部使用,發送數據緩存已滿(16K音頻最大緩存320000,8K音頻最大緩存160000),請檢查是否發送音頻數據過頻或一次發送過多數據。 |
-438 | EvutilSocketFailed | evutil設置參數失敗 | SDK內部使用,建議釋放當前請求重新嘗試。 |
-439 | InvalidExitStatus | 無效的退出狀態 | 請檢查是否已經cancel了當前請求。 |
-450 | InvalidAkId | 阿里云賬號ak id無效 | 請檢查阿里云賬號ak id是否為空。 |
-451 | InvalidAkSecret | 阿里云賬號ak secret無效 | 請檢查阿里云賬號ak secret是否為空。 |
-452 | InvalidAppKey | 項目appKey無效 | 請檢查阿里云項目appKey是否為空。 |
-453 | InvalidDomain | domain無效 | 請檢查輸入的domain是否為空。 |
-454 | InvalidAction | action無效 | 請檢查輸入的action是否為空。 |
-455 | InvalidServerVersion | ServerVersion無效 | 請檢查輸入的ServerVersion是否為空。 |
-456 | InvalidServerResource | ServerResource無效 | 請檢查輸入的ServerResource是否為空。 |
-457 | InvalidRegionId | RegionId無效 | 請檢查輸入的RegionId是否為空。 |
-500 | InvalidFileLink | 無效的錄音文件鏈接 | 錄音文件轉寫文件鏈接為空。 |
-501 | ErrorStatusCode | 錯誤的狀態碼 | 錄音文件轉寫返回錯誤,詳見錯誤碼。 |
-502 | IconvOpenFailed | 申請轉換描述失敗 | UTF8與GBK轉換失敗。 |
-503 | IconvFailed | 編碼轉換失敗 | UTF8與GBK轉換失敗。 |
-504 | ClientRequestFaild | 賬號客戶端請求失敗 | 錄音文件轉寫返回失敗。 |
-999 | NlsMaxErrorCode |
其他狀態碼 | 狀態消息 | 原因 | 解決方案 |
10000001 | NewSslCtxFailed | SSL: couldn't create a context! | 建議重新初始化。 |
10000002 | DefaultErrorCode | return of SSL_read: error:00000000:lib(0):func(0):reason(0) | 建議重新嘗試。 |
return of SSL_read: error:140E0197:SSL routines:SSL_shutdown:shutdown while in init | |||
10000003 | SysErrorCode | 系統錯誤。 | 根據系統反饋的錯誤信息進行處理。 |
10000004 | EmptyUrl | URL: The url is empty. | 傳入的URL為空,請重新填寫正確URL。 |
10000005 | InvalidWsUrl | Could not parse WebSocket url: | 傳入的URL格式錯誤,請重新填寫正確URL。 |
10000007 | JsonStringParseFailed | JSON: Json parse failed. | JSON格式異常,請通過日志查看具體的錯誤點。 |
10000008 | UnknownWsHeadType | WEBSOCKET: unkown head type. | 聯網失敗,請檢查本機DNS解析和URL是否有效。 |
10000009 | HttpConnectFailed | HTTP: connect failed. | 與云端連接失敗,請檢查網絡后重試。 |
10000010 | MemNotEnough | 內存不足。 | 請檢查內存是否充足。 |
10000015 | SysConnectFailed | connect failed. | 聯網失敗,請檢查本機DNS解析和URL是否有效。 |
10000100 | HttpGotBadStatusWith403 | Got bad status host=xxxxx line=HTTP/1.1 403 Forbidden | 鏈接被拒,請檢查賬號特別是token是否過期。 |
10000101 | EvSendTimeout | Send timeout. socket error: | libevent發送event超時,請檢查回調中是否有耗時任務或并發過大導致無法及時處理事件。 |
10000102 | EvRecvTimeout | Recv timeout. socket error: | libevent接收event超時,請檢查回調中是否有耗時任務,或并發過大導致無法及時處理事件。 |
10000103 | EvUnknownEvent | Unknown event: | 未知的libevent事件,建議重新嘗試。 |
10000104 | OpNowInProgress | Operation now in progress | 鏈接正在進行中,建議重新嘗試。 |
10000105 | BrokenPipe | Broken pipe | pipe處理不過來,建議重新嘗試。 |
10000110 | TokenHasExpired | Gateway:ACCESS_DENIED:The token 'xxx' has expired! | 請更新Token。 |
10000111 | TokenIsInvalid | Meta:ACCESS_DENIED:The token 'xxx' is invalid! | 請檢查token的有效性。 |
10000112 | NoPrivilegeToVoice | Gateway:ACCESS_DENIED:No privilege to this voice! (voice: zhinan, privilege: 0) | 此發音人無權使用。 |
10000113 | MissAuthHeader | Gateway:ACCESS_DENIED:Missing authorization header! | 請檢查賬號是否有權限,或并發是否在限度內。 |
10000120 | Utf8ConvertError | utf8ToGbk failed | utf8轉碼失敗,常為系統問題,建議重新嘗試。 |
20000000 | SuccessStatusCode | 成功 |
服務端響應狀態碼
關于服務狀態碼,請參見服務狀態碼。
代碼示例
示例中使用的音頻文件為16000Hz采樣率,管控臺設置的模型為通用模型。如果使用其他音頻,請設置為支持該音頻場景的模型。關于模型設置,請參見管理項目。
示例中使用了SDK內置的默認一句話識別服務的外網訪問服務URL,如果您使用阿里云上海ECS且需要使用內網訪問URL,則在創建SpeechRecognizerRequest的對象中設置內網訪問的URL。
request->setUrl("ws://nls-gateway-cn-shanghai-internal.aliyuncs.com/ws/v1")
完整示例,參見SDK壓縮包中demo目錄的speechRecognizerDemo.cpp文件。
調用接口前,需配置環境變量,通過環境變量讀取訪問憑證。智能語音交互的AccessKey ID、AccessKey Secret和AppKey的環境變量名:NLS_AK_ENV、NLS_SK_ENV、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;
//自定義線程參數。
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具體操作,請參見:http://bestwisewords.com/document_detail/450514.html
*
* 注意:不要每次調用服務之前都重新生成新token,
* 只需在token即將過期時重新生成即可。所有的服務并發可共用一個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;
//根據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 OnRecognitionStarted(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數。
printf("OnRecognitionStarted: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
// 獲取消息的狀態碼,成功為0或者20000000,失敗時對應失敗的錯誤碼。
// 當前任務的task id,方便定位問題,作為和服務端交互的唯一標識建議輸出。
printf("OnRecognitionStarted: status code=%d, task id=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId());
// 獲取服務端返回的全部信息
//printf("OnRecognitionStarted: all response=%s\n", cbEvent->getAllResponse());
// 通知發送線程start()成功, 可以繼續發送數據
pthread_mutex_lock(&(tmpParam->mtxWord));
pthread_cond_signal(&(tmpParam->cvWord));
pthread_mutex_unlock(&(tmpParam->mtxWord));
}
/**
* @brief 設置允許返回中間結果參數, sdk在接收到云端返回到中間結果時,
* sdk內部線程上報ResultChanged事件
* @param cbEvent 回調事件結構, 詳見nlsEvent.h
* @param cbParam 回調自定義參數,默認為NULL, 可以根據需求自定義參數
* @return
*/
void OnRecognitionResultChanged(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數。
printf("OnRecognitionResultChanged: %d, %s\n", tmpParam->userId, tmpParam->userInfo); // 當前任務的task id,方便定位問題,作為和服務端交互的唯一標識建議輸出。
printf("OnRecognitionResultChanged: status code=%d, task id=%s, result=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getResult());
// 獲取服務端返回的全部信息
//printf("OnRecognitionResultChanged: response=%s\n", cbEvent->getAllResponse());
}
/**
* @brief sdk在接收到云端返回識別結束消息時, sdk內部線程上報Completed事件
* @note 上報Completed事件之后, SDK內部會關閉識別連接通道.
* 此時調用sendAudio會返回負值, 請停止發送.
* @param cbEvent 回調事件結構, 詳見nlsEvent.h
* @param cbParam 回調自定義參數,默認為NULL, 可以根據需求自定義參數
* @return
*/
void OnRecognitionCompleted(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數。
printf("OnRecognitionCompleted: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
// 當前任務的task id,方便定位問題,作為和服務端交互的唯一標識建議輸出。
printf("OnRecognitionCompleted: status code=%d, task id=%s, result=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getResult());
// 獲取服務端返回的全部信息。
//printf("OnRecognitionCompleted: response=%s\n", cbEvent->getAllResponse());
}
/**
* @brief 識別過程發生異常時, sdk內部線程上報TaskFailed事件
* @note 上報TaskFailed事件之后, SDK內部會關閉識別連接通道.
* 此時調用sendAudio會返回負值, 請停止發送.
* @param cbEvent 回調事件結構, 詳見nlsEvent.h
* @param cbParam 回調自定義參數,默認為NULL, 可以根據需求自定義參數
* @return
*/
void OnRecognitionTaskFailed(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數。
printf("OnRecognitionTaskFailed: %d, %s\n", tmpParam->userId, tmpParam->userInfo);
// 當前任務的task id,方便定位問題,作為和服務端交互的唯一標識建議輸出。
printf("OnRecognitionTaskFailed: status code=%d, task id=%s, error message=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getErrorMessage());
// 獲取服務端返回的全部信息。
//printf("OnRecognitionTaskFailed: response=%s\n", cbEvent->getAllResponse());
}
/**
* @brief 識別結束或發生異常時,會關閉連接通道,
* sdk內部線程上報ChannelCloseed事件
* @param cbEvent 回調事件結構, 詳見nlsEvent.h
* @param cbParam 回調自定義參數,默認為NULL, 可以根據需求自定義參數
* @return
*/
void OnRecognitionChannelClosed(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數。
printf("OnRecognitionChannelClosed: %d, %s\n", tmpParam->userId, tmpParam->userInfo); // 獲取服務端返回的全部信息。
printf("OnRecognitionChannelClosed: response=%s\n", cbEvent->getAllResponse());
//通知發送線程, 最終識別結果已經返回, 可以調用stop()
pthread_mutex_lock(&(tmpParam->mtxWord));
pthread_cond_signal(&(tmpParam->cvWord));
pthread_mutex_unlock(&(tmpParam->mtxWord));
}
/**
* @brief 短鏈接模式下工作線程
* 以 createRecognizerRequest <----|
* | |
* request->start() |
* | |
* request->sendAudio() |
* | |
* request->stop() |
* | |
* 收到OnRecognitionChannelClosed回調 |
* | |
* releaseRecognizerRequest(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: 創建一句話識別SpeechRecognizerRequest對象。
SpeechRecognizerRequest *request =
NlsClient::getInstance()->createRecognizerRequest();
if (request == NULL) {
printf("createRecognizerRequest failed\n");
delete cbParam;
return NULL;
}
// 設置start()成功回調函數
request->setOnRecognitionStarted(OnRecognitionStarted, cbParam);
// 設置異常識別回調函數
request->setOnTaskFailed(OnRecognitionTaskFailed, cbParam);
// 設置識別通道關閉回調函數
request->setOnChannelClosed(OnRecognitionChannelClosed, cbParam);
// 設置中間結果回調函數
request->setOnRecognitionResultChanged(OnRecognitionResultChanged, cbParam);
// 設置識別結束回調函數
request->setOnRecognitionCompleted(OnRecognitionCompleted, cbParam);
// 設置appKey。必填參數。
request->setAppKey(tst->appkey.c_str());
// 設置賬號校驗token, 必填參數
request->setToken(tst->token.c_str());
// 設置音頻數據編碼格式??蛇x參數,目前支持PCM/OPUS,默認為PCM。
request->setFormat("opus");
// 設置音頻數據采樣率??蛇x參數,目前支持16000/8000。默認為16000。
request->setSampleRate(SAMPLE_RATE);
// 設置是否返回中間識別結果。可選參數,默認false。
request->setIntermediateResult(true);
// 設置是否在后處理中添加標點??蛇x參數,默認false。
request->setPunctuationPrediction(true);
// 設置是否在后處理中執行ITN??蛇x參數,默認false。
request->setInverseTextNormalization(true);
// 是否啟動語音檢測??蛇x,默認為False。
//request->setEnableVoiceDetection(true);
// 允許的最大開始靜音, 可選, 單位是毫秒,
// 超出后服務端將會發送RecognitionCompleted事件, 結束本次識別.
// 注意: 需要先設置enable_voice_detection為true
//request->setMaxStartSilence(800);
// 允許的最大結束靜音, 可選, 單位是毫秒,
// 超出后服務端將會發送RecognitionCompleted事件, 結束本次識別.
// 注意: 需要先設置enable_voice_detection為true
//request->setMaxEndSilence(800);
// 定制語言模型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()->releaseRecognizerRequest(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()成功, 然后再發送音頻數據。
* 語音服務器存在來不及處理當前請求的情況, 10s內不返回任何回調的問題,
* 然后在10s后返回一個TaskFailed回調, 所以需要設置一個超時機制。
*/
printf("wait started callback.\n");
// 語音服務器存在來不及處理當前請求, 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()->releaseRecognizerRequest(request);
delete cbParam;
return NULL;
}
pthread_mutex_unlock(&(cbParam->mtxWord));
} else {
/*
* 2.2. g_sync_timeout大于0,即調用了setSyncCallTimeout(),同步方式調用start()
* 返回值0即表示啟動成功。
*/
}
}
/*
* 3. 從文件取音頻數據循環發送音頻
*/
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. 發送音頻數據: 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()成功, 然后才可釋放。
* 語音服務器存在來不及處理當前請求的情況, 10s內不返回任何回調的問題,
* 然后在10s后返回一個TaskFailed回調, 所以需要設置一個超時機制。
*/
// 等待closed事件后再進行釋放, 否則會出現崩潰
// 若調用了setSyncCallTimeout()啟動了同步調用模式, 則可以不等待closed事件。
std::cout << "wait closed callback." << std::endl;
printf("wait closed callback.\n");
// 語音服務器存在來不及處理當前請求, 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()->releaseRecognizerRequest(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()->releaseRecognizerRequest(request);
delete cbParam;
return NULL;
}
// 識別單個音頻數據
int speechRecognizerFile(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 speechRecognizerMultFile(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輸出日志??蛇x。
// 此處表示SDK日志輸出至log-recognizer.txt。
// LogDebug表示輸出所有級別日志,支持LogDebug、LogInfo、LogWarning、LogError。
// 400表示單個文件400MB。50表示50個日志文件循環記錄。
int ret = NlsClient::getInstance()->setLogConfig(
"log-recognizer", 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);
// 識別單個音頻數據
speechRecognizerFile(appkey.c_str());
// 并發識別多個音頻數據
//speechRecognizerMultFile(appkey.c_str());
// 所有工作完成,進程退出前,釋放nlsClient。
// 請注意releaseInstance()非線程安全, 需要確認所有請求都停止工作才可釋放。
NlsClient::releaseInstance();
return 0;
}