C++ SDK
本文介紹如何使用阿里云智能語音交互提供的C++ SDK,包括SDK的安裝方法、SDK代碼示例以及常見問題等。
SDK下載
當(dāng)前最新版本:3.1.17,支持Linux、Windows平臺(tái)。發(fā)布日期:2023年08月09日。
使用SDK前,請(qǐng)先閱讀接口說明,詳情請(qǐng)參見接口說明。
該版本C++ SDK API 3.1和上一版本API 2.0(已下線)定義有區(qū)別,本文以當(dāng)前版本為例進(jìn)行介紹。
可通過以下兩種方法獲取SDK。
方法一:從GitHub獲取最新源碼,詳細(xì)編譯和運(yùn)行方式可見下文,或查看源碼中的readme.md。
git clone --depth 1 https://github.com/aliyun/alibabacloud-nls-cpp-sdk
方法二:直接從下文表中選取需要的SDK包進(jìn)行下載。其中SDK源碼包為SDK原始代碼,需要通過下文編譯方法生成集成所需的庫(kù)文件。其他對(duì)應(yīng)平臺(tái)的SDK包內(nèi)含相關(guān)庫(kù)文件、頭文件,無需編譯。
最新SDK包
平臺(tái)
MD5
SDK源碼
054d6f9f3226f689dbc68f8ed970fe3b
Linux x86_64
1ebb39ec10993583a645c0de8eebf654
Linux aarch64
76c34a3ab397d7285963a139b9270ff4
Windows
c428e5cf1295d8933d23a4945683e250
其中:
alibabacloud-nls-cpp-sdk<version>-master_<github commit id>.zip為SDK源碼包。
NlsCppSdk_<平臺(tái)>_<版本號(hào)>_<github commit id>.tar.gz為對(duì)應(yīng)平臺(tái)下開發(fā)需要的SDK包,詳見內(nèi)部readme.md。
SDK包文件說明
scripts/build_linux.sh:SDK源碼中,以Linux平臺(tái)為例的示例編譯腳本。
CMakeLists.txt:SDK源碼中,以Linux平臺(tái)為例的示例代碼工程CMakeList文件。
demo目錄:SDK包中,集成示例代碼,以Linux平臺(tái)為例,如下表所示。
resource目錄:SDK源碼中,語音服務(wù)范例音頻,可用于功能測(cè)試,如下表所示。
test0.wav
test1.wav
test2.wav
test3.wav
include:SDK源碼中,SDK頭文件,如下表所示。
文件名
描述
nlsClient.h
SDK實(shí)例。
nlsEvent.h
回調(diào)事件說明。
nlsGlobal.h
SDK全局頭文件。
nlsToken.h
SDK Access Token實(shí)例。
iNlsRequest.h
NLS請(qǐng)求基礎(chǔ)頭文件。
speechRecognizerRequest.h
一句話識(shí)別。
speechSynthesizerRequest.h
語音合成、長(zhǎng)文本語音合成。
speechTranscriberRequest.h
實(shí)時(shí)音頻流識(shí)別。
FileTrans.h
錄音文件識(shí)別。
lib:SDK庫(kù)文件。
readme.md:SDK說明。
release.log:版本說明。
version:版本號(hào)。
文件名 | 描述 |
speechRecognizerDemo.cpp | 一句話識(shí)別示例。 |
speechSynthesizerDemo.cpp | 語音合成示例。 |
speechTranscriberDemo.cpp | 實(shí)時(shí)語音識(shí)別示例。 |
fileTransferDemo.cpp | 錄音文件識(shí)別示例。 |
文件名 | 描述 |
測(cè)試音頻(16k采樣頻率、16bit采樣位數(shù)的音頻文件)。 |
編譯運(yùn)行
Linux平臺(tái)編譯
安裝工具的最低版本要求如下:
CMake 3.0
Glibc 2.5
Gcc 4.8.5
在Linux終端運(yùn)行如下腳本。
進(jìn)入SDK源碼的根目錄。
生成SDK庫(kù)文件和可執(zhí)行程序:srDemo(一句話識(shí)別)、stDemo(實(shí)時(shí)語音識(shí)別)、syDemo(語音合成)、daDemo(語音對(duì)話)。
./scripts/build_linux.sh
查看范例使用方式。
cd build/demo ./syDemo
Windows平臺(tái)編譯
推薦直接使用已經(jīng)編譯好的庫(kù)NlsCppSdk_Windows_<version>_<github commit id>.zip進(jìn)行集成。若有編譯需求,請(qǐng)下載alibabacloud-nls-cpp-sdk<version>-master_<github commit id>.zip并解壓到本地,或從GitHub獲取最新代碼,然后參考其中readme.md的編譯步驟。
關(guān)鍵接口
基礎(chǔ)接口
NlsClient:語音處理客戶端,利用該客戶端可以進(jìn)行一句話識(shí)別、實(shí)時(shí)語音識(shí)別和語音合成的語音處理任務(wù)。該客戶端為線程安全,建議全局僅創(chuàng)建一個(gè)實(shí)例。
接口名
啟用版本
功能描述
getInstance
2.x
獲取(創(chuàng)建)NlsClient實(shí)例。
setLogConfig
2.x
設(shè)置日志文件與存儲(chǔ)路徑。
setDirectHost
3.x
跳過DNS域名解析直接設(shè)置服務(wù)器ipv4地址,若調(diào)用則需要在startWorkThread之前。
setAddrInFamily
3.1.12
設(shè)置套接口地址結(jié)構(gòu)的類型,默認(rèn)為AF_INET僅返回IPV4相關(guān)的地址信息,需要在startWorkThread之前調(diào)用。
setUseSysGetAddrInfo
3.1.13
若libevent的DNS無法滿足,無法完成DNS,可調(diào)用此接口切換成系統(tǒng)的接口,需要在startWorkThread之前調(diào)用。
calculateUtf8Chars
3.1.14
統(tǒng)計(jì)文本內(nèi)容字符數(shù),需要傳入U(xiǎn)TF-8編碼的文本內(nèi)容,其中1個(gè)漢字、1個(gè)英文字母或1個(gè)標(biāo)點(diǎn)均算作1個(gè)字符。
setSyncCallTimeout
3.1.17
設(shè)置同步調(diào)用模式的超時(shí)時(shí)間(ms),0則為關(guān)閉同步模式,默認(rèn)0。此模式start()后收到服務(wù)端結(jié)果再return出去,stop()后收到close()回調(diào)再return出去。
startWorkThread
3.x
啟動(dòng)工作線程數(shù),默認(rèn)1即啟動(dòng)一個(gè)線程,若-1則啟動(dòng)CPU核數(shù)的線程數(shù)。在高并發(fā)的情況下建議選擇-1。可以理解NlsClient實(shí)例初始化,必須調(diào)用。
getVersion
3.x
獲取SDK版本號(hào)。
releaseInstance
2.x
銷毀NlsClient對(duì)象實(shí)例。
CreateSynthesizerRequest
2.x
創(chuàng)建語音合成對(duì)象,線程安全,支持高并發(fā)請(qǐng)求。創(chuàng)建此對(duì)象時(shí)即可通過入?yún)⒋_定是長(zhǎng)文本語音合成還是短文本語音合成。300字以內(nèi)可用短文本語音合成,300字以上可考慮使用長(zhǎng)文本語音合成。字符計(jì)算可調(diào)用接口calculateUtf8Chars。
releaseSynthesizerRequest
2.x
銷毀語音合成對(duì)象,需要在當(dāng)前請(qǐng)求的closed事件后調(diào)用。
NlsToken:創(chuàng)建Token對(duì)象,用于申請(qǐng)獲取TokenId。申請(qǐng)新Token時(shí)需要先獲取有效時(shí)間戳,若超過有效時(shí)間則再申請(qǐng)。若在有效時(shí)間內(nèi)多次申請(qǐng)Token會(huì)導(dǎo)致TokenId錯(cuò)誤而無法使用。
接口名
功能描述
setAccessKeyId
設(shè)置阿里云賬號(hào)AccessKey ID。
setKeySecret
設(shè)置阿里云賬號(hào)AccessKey Secret。
setDomain
設(shè)置域名,非必填。
setServerVersion
設(shè)置API版本,非必填。
setServerResourcePath
設(shè)置服務(wù)路徑,非必填。
setRegionId
設(shè)置服務(wù)的確ID,非必填。
setAction
設(shè)置功能,非必填。
applyNlsToken
申請(qǐng)獲取TokenId。
getToken
獲取TokenId
getExpireTime
獲取Token有效期時(shí)間戳(秒)。
getErrorMsg
獲得錯(cuò)誤信息。
NlsEvent:事件對(duì)象,您可以從中獲取Request狀態(tài)碼、云端返回結(jié)果、失敗信息等。
接口名
功能描述
getStatusCode
獲取狀態(tài)碼,正常情況為0或者20000000,失敗時(shí)對(duì)應(yīng)失敗的錯(cuò)誤碼。
getErrorMessage
在TaskFailed回調(diào)中,獲取NlsRequest操作過程中出現(xiàn)失敗時(shí)的錯(cuò)誤信息。
getTaskId
獲取任務(wù)的TaskId。
getBinaryData
獲取云端返回的二進(jìn)制數(shù)據(jù)。
getAllResponse
獲取云端返回的識(shí)別結(jié)果。
識(shí)別接口
SpeechSynthesizerRequest:語音合成請(qǐng)求對(duì)象,用于語音合成及長(zhǎng)文本語音合成。接口說明以speechSynthesizerRequest.h內(nèi)容為準(zhǔn)。
接口名
啟用版本
功能描述
setOnSynthesisCompleted
2.x
設(shè)置語音合成結(jié)束回調(diào)函數(shù)。
setOnChannelClosed
2.x
設(shè)置通道關(guān)閉回調(diào)函數(shù)。
setOnTaskFailed
2.x
設(shè)置錯(cuò)誤回調(diào)函數(shù)。
setOnBinaryDataReceived
2.x
設(shè)置語音合成二進(jìn)制音頻數(shù)據(jù)接收回調(diào)函數(shù)。
setOnMetaInfo
2.x
設(shè)置文本對(duì)應(yīng)的日志信息接收回調(diào)函數(shù)。
setOnMessage
3.1.16
設(shè)置服務(wù)端response message回調(diào)函數(shù),所有回調(diào)從此回調(diào)輸出由用戶自行解析。非必填。設(shè)置后需setEnableOnMessage啟動(dòng)。
setAppKey
2.x
設(shè)置AppKey。
setToken
2.x
口令認(rèn)證。所有的請(qǐng)求都必須通過SetToken方法認(rèn)證通過,才可以使用。
setUrl
2.x
設(shè)置服務(wù)URL地址。非必填。
setText
2.x
待合成音頻文本內(nèi)容text設(shè)置。300字以內(nèi)可用短文本語音合成,300字以上可考慮使用長(zhǎng)文本語音合成。字符計(jì)算可調(diào)用接口calculateUtf8Chars。
setVoice
2.x
發(fā)音人voice設(shè)置。
setVolume
2.x
音量volume設(shè)置。
setFormat
2.x
輸出音頻編碼格式Format設(shè)置(默認(rèn)是PCM,支持的格式PCM、WAV、MP3)。
setSampleRate
2.x
音頻采樣率設(shè)置。
setSpeechRate
2.x
語速設(shè)置。
setPitchRate
2.x
語調(diào)設(shè)置。
setMethod
2.x
合成方法method設(shè)置,默認(rèn)0。
0:統(tǒng)計(jì)參數(shù)合成:基于統(tǒng)計(jì)參數(shù)的語音合成,優(yōu)點(diǎn)是能適應(yīng)的韻律特征的范圍較寬,合成器比特率低,資源占用小,性能高,音質(zhì)適中。
1:波形拼接合成:基于高質(zhì)量音庫(kù)提取學(xué)習(xí)合成,資源占用相對(duì)較高,音質(zhì)較好,更加貼近真實(shí)發(fā)音,但沒有參數(shù)合成穩(wěn)定。
setEnableSubtitle
2.x
是否開啟字幕功能。
setPayloadParam
2.x
參數(shù)設(shè)置,入?yún)镴SON格式字符串。
setTimeout
2.x
設(shè)置鏈接超時(shí)時(shí)間,默認(rèn)5000ms。
setContextParam
2.x
設(shè)置用戶自定義參數(shù),入?yún)镴SON格式字符串。
AppendHttpHeaderParam
2.x
設(shè)置用戶自定義ws階段http header參數(shù)。
setSendTimeout
3.1.14
設(shè)置發(fā)送超時(shí)時(shí)間,默認(rèn)5000ms。
setEnableOnMessage
3.1.16
設(shè)置開啟服務(wù)器返回消息回調(diào)。
getTaskId
3.1.17
獲得當(dāng)前請(qǐng)求的task_id。
start
2.x
啟動(dòng)SpeechSynthesizerRequest。
cancel
2.x
不會(huì)與服務(wù)端確認(rèn)關(guān)閉,直接關(guān)閉語音合成過程。
C++SDK錯(cuò)誤碼
狀態(tài)碼 | 狀態(tài)消息 | 原因 | 解決方案 |
0 | Success | 成功 | |
-10 | DefaultError | 默認(rèn)錯(cuò)誤 | 暫未使用。 |
-11 | JsonParseFailed | 錯(cuò)誤的JSON格式 | 請(qǐng)檢查傳入的JSON字符串是否符合JSON格式。 |
-12 | JsonObjectError | 錯(cuò)誤的JSON對(duì)象 | 建議重新嘗試。 |
-13 | MallocFailed | Malloc失敗 | 請(qǐng)檢查內(nèi)存是否充足。 |
-14 | ReallocFailed | Realloc失敗 | 請(qǐng)檢查內(nèi)存是否充足。 |
-15 | InvalidInputParam | 傳入無效的參數(shù) | 暫未使用。 |
-50 | InvalidLogLevel | 無效日志級(jí)別 | 請(qǐng)檢查設(shè)置的Log級(jí)別。 |
-51 | InvalidLogFileSize | 無效日志文件大小 | 請(qǐng)檢查設(shè)置的Log文件大小參數(shù)。 |
-52 | InvalidLogFileNum | 無效日志文件數(shù)量 | 請(qǐng)檢查設(shè)置的Log文件數(shù)量參數(shù)。 |
-100 | EncoderExistent | NLS的編碼器已存在 | 建議重新嘗試。 |
-101 | EncoderInexistent | NLS的編碼器不存在 | 建議重新初始化。 |
-102 | OpusEncoderCreateFailed | Opus編碼器創(chuàng)建失敗 | 建議重新初始化。 |
-103 | OggOpusEncoderCreateFailed | OggOpus編碼器創(chuàng)建失敗 | 建議重新初始化。 |
-104 | InvalidEncoderType | encoder類型無效 | 編譯時(shí)可能關(guān)閉OPUS但是又使用,或請(qǐng)檢查ENCODER_TYPE。 |
-150 | EventClientEmpty | 主工作線程空指針,已釋放 | 建議重新初始化,即startWorkThread()。 |
-151 | SelectThreadFailed | 工作線程選擇失敗,未初始化 | 建議重新初始化,即startWorkThread()。 |
-160 | StartCommandFailed | 發(fā)送start命令失敗 | 建議重新嘗試。 |
-161 | InvokeStartFailed | 請(qǐng)求狀態(tài)機(jī)不對(duì),導(dǎo)致start失敗 | 請(qǐng)檢查當(dāng)前請(qǐng)求是否未創(chuàng)建或者已經(jīng)完成。 |
-162 | InvokeSendAudioFailed | 請(qǐng)求狀態(tài)機(jī)不對(duì),導(dǎo)致sendAudio失敗 | 請(qǐng)檢查當(dāng)前請(qǐng)求是否已經(jīng)啟動(dòng)(即收到started事件回調(diào))或者已經(jīng)完成。 |
-163 | InvalidOpusFrameSize | opus幀長(zhǎng)無效,默認(rèn)為640字節(jié) | OPU編碼模式下,sendAudio一幀只接收640字節(jié)數(shù)據(jù)。 |
-164 | InvokeStopFailed | 請(qǐng)求狀態(tài)機(jī)不對(duì),導(dǎo)致stop失敗 | 請(qǐng)檢查當(dāng)前請(qǐng)求是否未啟動(dòng)(即收到started事件回調(diào))或者已經(jīng)完成。 |
-165 | InvokeCancelFailed | 請(qǐng)求狀態(tài)機(jī)不對(duì),導(dǎo)致stop失敗 | 請(qǐng)檢查當(dāng)前請(qǐng)求是否未啟動(dòng)(即收到started事件回調(diào))或者已經(jīng)完成。 |
-166 | InvokeStControlFailed | 請(qǐng)求狀態(tài)機(jī)不對(duì),導(dǎo)致stControl失敗 | 請(qǐng)檢查當(dāng)前請(qǐng)求是否未啟動(dòng)(即收到started事件回調(diào))或者已經(jīng)完成。 |
-200 | NlsEventEmpty | NLS事件為空 | SDK內(nèi)部使用,NlsEvent幀丟失。 |
-201 | NewNlsEventFailed | 創(chuàng)建NlsEvent失敗 | SDK內(nèi)部使用,NlsEvent幀創(chuàng)建失敗。 |
-202 | NlsEventMsgEmpty | NLS事件中消息為空 | parseJsonMsg()進(jìn)行解析時(shí)發(fā)現(xiàn)消息字符串為空。 |
-203 | InvalidNlsEventMsgType | 無效的NLS事件中消息類型 | SDK內(nèi)部使用,NlsEvent幀的事件類型不合法。 |
-204 | InvalidNlsEventMsgStatusCode | 無效的NLS事件中消息狀態(tài)碼 | SDK內(nèi)部使用,NlsEvent幀的事件消息狀態(tài)不合法。 |
-205 | InvalidNlsEventMsgHeader | 無效的NLS事件中消息頭 | SDK內(nèi)部使用,NlsEvent幀的事件消息頭不合法。 |
-250 | CancelledExitStatus | 已調(diào)用cancel | 暫未使用。 |
-251 | InvalidWorkStatus | 無效的工作狀態(tài) | SDK內(nèi)部使用,當(dāng)前請(qǐng)求內(nèi)部狀態(tài)不合法。 |
-252 | InvalidNodeQueue | workThread中NodeQueue無效 | SDK內(nèi)部使用,當(dāng)前待運(yùn)行的請(qǐng)求不合法,建議釋放當(dāng)前請(qǐng)求重新嘗試。 |
-300 | InvalidRequestParams | 請(qǐng)求的入?yún)o效 | sendAudio傳入的數(shù)據(jù)為空。 |
-301 | RequestEmpty | 請(qǐng)求是空指針 | SDK內(nèi)部使用,當(dāng)前請(qǐng)求已經(jīng)釋放,建議釋放當(dāng)前請(qǐng)求重新嘗試。 |
-302 | InvalidRequest | 無效的請(qǐng)求 | SDK內(nèi)部使用,當(dāng)前請(qǐng)求已經(jīng)釋放,建議釋放當(dāng)前請(qǐng)求重新嘗試。 |
-303 | SetParamsEmpty | 設(shè)置傳入的參數(shù)為空 | 請(qǐng)檢查傳入的參數(shù)是否為空。 |
-350 | GetHttpHeaderFailed | 獲得http頭失敗 | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-351 | HttpGotBadStatus | http錯(cuò)誤的狀態(tài) | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-352 | WsResponsePackageFailed | 解析websocket返回包失敗 | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-353 | WsResponsePackageEmpty | 解析websocket返回包為空 | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-354 | WsRequestPackageEmpty | websocket請(qǐng)求包為空 | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-355 | UnknownWsFrameHeadType | 未知websocket幀頭類型 | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-356 | InvalidWsFrameHeaderSize | 無效的websocket幀頭大小 | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-357 | InvalidWsFrameHeaderBody | 無效的websocket幀頭本體 | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-358 | InvalidWsFrameBody | 無效的websocket幀本體 | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-359 | WsFrameBodyEmpty | 幀數(shù)據(jù)為空,常見為收到了臟數(shù)據(jù) | SDK內(nèi)部使用,根據(jù)日志中反饋信息詳細(xì)定位。 |
-400 | NodeEmpty | node為空指針 | 建議釋放當(dāng)前請(qǐng)求重新嘗試。 |
-401 | InvaildNodeStatus | node所處狀態(tài)無效 | SDK內(nèi)部使用,建議釋放當(dāng)前請(qǐng)求重新嘗試。 |
-402 | GetAddrinfoFailed | 通過DNS解析地址識(shí)別 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前環(huán)境的DNS是否可用。 |
-403 | ConnectFailed | 聯(lián)網(wǎng)失敗 | 請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用。 |
-404 | InvalidDnsSource | 當(dāng)前設(shè)備無DNS | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前環(huán)境的DNS是否可用。 |
-405 | ParseUrlFailed | 無效URL | 請(qǐng)檢查設(shè)置的URL是否有效。 |
-406 | SslHandshakeFailed | SSL握手失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-407 | SslCtxEmpty | SSL_CTX未空 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-408 | SslNewFailed | SSL_new失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-409 | SslSetFailed | SSL設(shè)置參數(shù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-410 | SslConnectFailed | SSL_connect失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-411 | SslWriteFailed | SSL發(fā)送數(shù)據(jù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-412 | SslReadSysError | SSL接收數(shù)據(jù)收到SYSCALL錯(cuò)誤 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-413 | SslReadFailed | SSL接收數(shù)據(jù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-414 | SocketFailed | 創(chuàng)建socket失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-415 | SetSocketoptFailed | 設(shè)置socket參數(shù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-416 | SocketConnectFailed | 進(jìn)行socket鏈接失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-417 | SocketWriteFailed | socket發(fā)送數(shù)據(jù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-418 | SocketReadFailed | socket接收數(shù)據(jù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-430 | NlsReceiveFailed | NLS接收幀數(shù)據(jù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-431 | NlsReceiveEmpty | NLS接收幀數(shù)據(jù)為空 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-432 | ReadFailed | 接收數(shù)據(jù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-433 | NlsSendFailed | NLS發(fā)送數(shù)據(jù)失敗 | SDK內(nèi)部使用,請(qǐng)檢查當(dāng)前網(wǎng)絡(luò)環(huán)境是否可用,并再次嘗試。 |
-434 | NewOutputBufferFailed | 創(chuàng)建buffer失敗 | SDK內(nèi)部使用,請(qǐng)檢查內(nèi)存是否充足。 |
-435 | NlsEncodingFailed | 音頻編碼失敗 | SDK內(nèi)部使用,建議釋放當(dāng)前請(qǐng)求重新嘗試。 |
-436 | EventEmpty | event為空 | SDK內(nèi)部使用,建議釋放當(dāng)前請(qǐng)求重新嘗試。 |
-437 | EvbufferTooMuch | evbuffer中數(shù)據(jù)太多 | SDK內(nèi)部使用,發(fā)送數(shù)據(jù)緩存已滿(16K音頻最大緩存320000,8K音頻最大緩存160000),請(qǐng)檢查是否發(fā)送音頻數(shù)據(jù)過頻或一次發(fā)送過多數(shù)據(jù)。 |
-438 | EvutilSocketFailed | evutil設(shè)置參數(shù)失敗 | SDK內(nèi)部使用,建議釋放當(dāng)前請(qǐng)求重新嘗試。 |
-439 | InvalidExitStatus | 無效的退出狀態(tài) | 請(qǐng)檢查是否已經(jīng)cancel了當(dāng)前請(qǐng)求。 |
-450 | InvalidAkId | 阿里云賬號(hào)ak id無效 | 請(qǐng)檢查阿里云賬號(hào)ak id是否為空。 |
-451 | InvalidAkSecret | 阿里云賬號(hào)ak secret無效 | 請(qǐng)檢查阿里云賬號(hào)ak secret是否為空。 |
-452 | InvalidAppKey | 項(xiàng)目appKey無效 | 請(qǐng)檢查阿里云項(xiàng)目appKey是否為空。 |
-453 | InvalidDomain | domain無效 | 請(qǐng)檢查輸入的domain是否為空。 |
-454 | InvalidAction | action無效 | 請(qǐng)檢查輸入的action是否為空。 |
-455 | InvalidServerVersion | ServerVersion無效 | 請(qǐng)檢查輸入的ServerVersion是否為空。 |
-456 | InvalidServerResource | ServerResource無效 | 請(qǐng)檢查輸入的ServerResource是否為空。 |
-457 | InvalidRegionId | RegionId無效 | 請(qǐng)檢查輸入的RegionId是否為空。 |
-500 | InvalidFileLink | 無效的錄音文件鏈接 | 錄音文件轉(zhuǎn)寫文件鏈接為空。 |
-501 | ErrorStatusCode | 錯(cuò)誤的狀態(tài)碼 | 錄音文件轉(zhuǎn)寫返回錯(cuò)誤,詳見錯(cuò)誤碼。 |
-502 | IconvOpenFailed | 申請(qǐng)轉(zhuǎn)換描述失敗 | UTF8與GBK轉(zhuǎn)換失敗。 |
-503 | IconvFailed | 編碼轉(zhuǎn)換失敗 | UTF8與GBK轉(zhuǎn)換失敗。 |
-504 | ClientRequestFaild | 賬號(hào)客戶端請(qǐng)求失敗 | 錄音文件轉(zhuǎn)寫返回失敗。 |
-999 | NlsMaxErrorCode |
其他狀態(tài)碼 | 狀態(tài)消息 | 原因 | 解決方案 |
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 | 系統(tǒng)錯(cuò)誤。 | 根據(jù)系統(tǒng)反饋的錯(cuò)誤信息進(jìn)行處理。 |
10000004 | EmptyUrl | URL: The url is empty. | 傳入的URL為空,請(qǐng)重新填寫正確URL。 |
10000005 | InvalidWsUrl | Could not parse WebSocket url: | 傳入的URL格式錯(cuò)誤,請(qǐng)重新填寫正確URL。 |
10000007 | JsonStringParseFailed | JSON: Json parse failed. | JSON格式異常,請(qǐng)通過日志查看具體的錯(cuò)誤點(diǎn)。 |
10000008 | UnknownWsHeadType | WEBSOCKET: unkown head type. | 聯(lián)網(wǎng)失敗,請(qǐng)檢查本機(jī)DNS解析和URL是否有效。 |
10000009 | HttpConnectFailed | HTTP: connect failed. | 與云端連接失敗,請(qǐng)檢查網(wǎng)絡(luò)后,重試。 |
10000010 | MemNotEnough | 內(nèi)存不足。 | 請(qǐng)檢查內(nèi)存是否充足。 |
10000015 | SysConnectFailed | connect failed. | 聯(lián)網(wǎng)失敗,請(qǐng)檢查本機(jī)DNS解析和URL是否有效。 |
10000100 | HttpGotBadStatusWith403 | Got bad status host=xxxxx line=HTTP/1.1 403 Forbidden | 鏈接被拒,請(qǐng)檢查賬號(hào)特別是token是否過期。 |
10000101 | EvSendTimeout | Send timeout. socket error: | libevent發(fā)送event超時(shí),請(qǐng)檢查回調(diào)中是否有耗時(shí)任務(wù),或并發(fā)過大導(dǎo)致無法及時(shí)處理事件。 |
10000102 | EvRecvTimeout | Recv timeout. socket error: | libevent接收event超時(shí),請(qǐng)檢查回調(diào)中是否有耗時(shí)任務(wù),或并發(fā)過大導(dǎo)致無法及時(shí)處理事件。 |
10000103 | EvUnknownEvent | Unknown event: | 未知的libevent事件,建議重新嘗試。 |
10000104 | OpNowInProgress | Operation now in progress | 鏈接正在進(jìn)行中,建議重新嘗試。 |
10000105 | BrokenPipe | Broken pipe | pipe處理不過來,建議重新嘗試。 |
10000110 | TokenHasExpired | Gateway:ACCESS_DENIED:The token 'xxx' has expired! | 請(qǐng)更新Token。 |
10000111 | TokenIsInvalid | Meta:ACCESS_DENIED:The token 'xxx' is invalid! | 請(qǐng)檢查token的有效性。 |
10000112 | NoPrivilegeToVoice | Gateway:ACCESS_DENIED:No privilege to this voice! (voice: zhinan, privilege: 0) | 此發(fā)音人無權(quán)使用。 |
10000113 | MissAuthHeader | Gateway:ACCESS_DENIED:Missing authorization header! | 請(qǐng)檢查賬號(hào)是否有權(quán)限,或并發(fā)是否在限度內(nèi)。 |
10000120 | Utf8ConvertError | utf8ToGbk failed | utf8轉(zhuǎn)碼失敗,常為系統(tǒng)問題,建議重新嘗試。 |
20000000 | SuccessStatusCode | 成功 |
服務(wù)端響應(yīng)狀態(tài)碼
關(guān)于服務(wù)狀態(tài)碼,請(qǐng)參見服務(wù)狀態(tài)碼。
代碼示例
示例中使用SDK內(nèi)置的默認(rèn)外網(wǎng)訪問服務(wù)URL,如果您使用阿里云上海ECS且需要使用內(nèi)網(wǎng)訪問URL,則在創(chuàng)建speechSynthesizerRequest的對(duì)象中設(shè)置內(nèi)網(wǎng)訪問的URL。
request->setUrl("wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1");
示例中將合成的音頻保存在文件中,如果您需要播放音頻且對(duì)實(shí)時(shí)性要求較高,建議使用流式播放,即邊接收語音數(shù)據(jù)邊播放,減少延時(shí),而無需等待合成結(jié)束后再處理語音流。
完整示例,參見SDK壓縮包中demo目錄的speechSynthesizerDemo.cpp文件。
調(diào)用接口前,需配置環(huán)境變量,通過環(huán)境變量讀取訪問憑證。智能語音交互的AccessKey ID、AccessKey Secret和AppKey的環(huán)境變量名: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 "speechSynthesizerRequest.h"
using namespace AlibabaNlsCommon;
using AlibabaNls::NlsClient;
using AlibabaNls::NlsEvent;
using AlibabaNls::LogDebug;
using AlibabaNls::LogInfo;
using AlibabaNls::LogError;
using AlibabaNls::TtsVersion;
using AlibabaNls::SpeechSynthesizerRequest;
//自定義線程參數(shù)。
struct ParamStruct {
std::string text;
std::string token;
std::string appkey;
std::string audioFile;
};
//自定義事件回調(diào)參數(shù)。
struct ParamCallBack {
public:
ParamCallBack() {
pthread_mutex_init(&mtxWord, NULL);
pthread_cond_init(&cvWord, NULL);
};
~ParamCallBack() {
pthread_mutex_destroy(&mtxWord);
pthread_cond_destroy(&cvWord);
};
std::string binAudioFile;
std::ofstream audioFile;
pthread_mutex_t mtxWord;
pthread_cond_t cvWord;
};
/**
* 全局維護(hù)一個(gè)服務(wù)鑒權(quán)token和其對(duì)應(yīng)的有效期時(shí)間戳,
* 每次調(diào)用服務(wù)之前,首先判斷token是否已經(jīng)過期,
* 如果已經(jīng)過期,則根據(jù)AccessKey ID和AccessKey Secret重新生成一個(gè)token,并更新這個(gè)全局的token和其有效期時(shí)間戳。
*
* 獲取Token具體操作,請(qǐng)參見:http://bestwisewords.com/document_detail/450514.html
*
* 注意:不要每次調(diào)用服務(wù)之前都重新生成新token,只需在token即將過期時(shí)重新生成即可。所有的服務(wù)并發(fā)可共用一個(gè)token。
*/
std::string g_akId = "";
std::string g_akSecret = "";
std::string g_token = "";
long g_expireTime = -1;
/**
* 根據(jù)AccessKey ID和AccessKey Secret重新生成一個(gè)token,并獲取其有效期時(shí)間戳
*/
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 sdk在接收到云端返回合成結(jié)束消息時(shí), sdk內(nèi)部線程上報(bào)Completed事件
* @note 上報(bào)Completed事件之后,SDK內(nèi)部會(huì)關(guān)閉識(shí)別連接通道.
* @param cbEvent 回調(diào)事件結(jié)構(gòu), 詳見nlsEvent.h
* @param cbParam 回調(diào)自定義參數(shù),默認(rèn)為NULL, 可以根據(jù)需求自定義參數(shù)
* @return
*/
void OnSynthesisCompleted(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數(shù)示例。
printf("OnSynthesisCompleted: %s\n", tmpParam->binAudioFile.c_str());
// 獲取消息的狀態(tài)碼,成功為0或者20000000,失敗時(shí)對(duì)應(yīng)失敗的錯(cuò)誤碼。
// 當(dāng)前任務(wù)的task id,方便定位問題,作為和服務(wù)端交互的唯一標(biāo)識(shí)建議輸出。
printf("OnSynthesisCompleted: status code=%d, task id=%s\n", cbEvent->getStatusCode(), cbEvent->getTaskId());
// 獲取服務(wù)端返回的全部信息。
//printf("OnSynthesisCompleted: all response=%s\n", cbEvent->getAllResponse());
}
/**
* @brief 合成過程發(fā)生異常時(shí), sdk內(nèi)部線程上報(bào)TaskFailed事件
* @note 上報(bào)TaskFailed事件之后,SDK內(nèi)部會(huì)關(guān)閉識(shí)別連接通道.
* @param cbEvent 回調(diào)事件結(jié)構(gòu), 詳見nlsEvent.h
* @param cbParam 回調(diào)自定義參數(shù),默認(rèn)為NULL, 可以根據(jù)需求自定義參數(shù)
* @return
*/
void OnSynthesisTaskFailed(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數(shù)示例。
printf("OnSynthesisTaskFailed: %s\n", tmpParam->binAudioFile.c_str());
// 當(dāng)前任務(wù)的task id。
printf("OnSynthesisTaskFailed: status code=%d, task id=%s, error message=%s\n",
cbEvent->getStatusCode(), cbEvent->getTaskId(), cbEvent->getErrorMessage());
}
/**
* @brief 文本上報(bào)服務(wù)端之后, 收到服務(wù)端返回的二進(jìn)制音頻數(shù)據(jù), SDK內(nèi)部線程通過BinaryDataRecved事件上報(bào)給用戶
* @param cbEvent 回調(diào)事件結(jié)構(gòu), 詳見nlsEvent.h
* @param cbParam 回調(diào)自定義參數(shù),默認(rèn)為NULL, 可以根據(jù)需求自定義參數(shù)
* @return
* @notice 此處切記不可做block操作,只可做音頻數(shù)據(jù)轉(zhuǎn)存. 若在此回調(diào)中做過多操作,
* 會(huì)阻塞后續(xù)的數(shù)據(jù)回調(diào)和completed事件回調(diào).
*/
void OnBinaryDataRecved(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數(shù)示例。
printf("OnBinaryDataRecved: %s\n", tmpParam->binAudioFile.c_str());
const std::vector<unsigned char>& data = cbEvent->getBinaryData(); // getBinaryData() :獲取文本合成的二進(jìn)制音頻數(shù)據(jù)。
printf("OnBinaryDataRecved: status code=%d, task id=%s, data size=%d\n",
cbEvent->getStatusCode(), cbEvent->getTaskId(), data.size());
// 以追加形式將二進(jìn)制音頻數(shù)據(jù)寫入文件。
if (data.size() > 0) {
tmpParam->audioFile.write((char*)&data[0], data.size());
}
}
/**
* @brief 返回 tts 文本對(duì)應(yīng)的日志信息,增量返回對(duì)應(yīng)的字幕信息
* @param cbEvent 回調(diào)事件結(jié)構(gòu), 詳見nlsEvent.h
* @param cbParam 回調(diào)自定義參數(shù),默認(rèn)為NULL, 可以根據(jù)需求自定義參數(shù)
* @return
*/
void OnMetaInfo(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數(shù)示例。
printf("OnBinaryDataRecved: %s\n", tmpParam->binAudioFile.c_str());
printf("OnMetaInfo: task id=%s, respose=%s\n", cbEvent->getTaskId(), cbEvent->getAllResponse());
}
/**
* @brief 識(shí)別結(jié)束或發(fā)生異常時(shí),會(huì)關(guān)閉連接通道, sdk內(nèi)部線程上報(bào)ChannelCloseed事件
* @param cbEvent 回調(diào)事件結(jié)構(gòu), 詳見nlsEvent.h
* @param cbParam 回調(diào)自定義參數(shù),默認(rèn)為NULL, 可以根據(jù)需求自定義參數(shù)
* @return
*/
void OnSynthesisChannelClosed(NlsEvent* cbEvent, void* cbParam) {
ParamCallBack* tmpParam = (ParamCallBack*)cbParam;
// 演示如何打印/使用用戶自定義參數(shù)示例。
printf("OnSynthesisChannelClosed: %s\n", tmpParam->binAudioFile.c_str());
printf("OnSynthesisChannelClosed: %s\n", cbEvent->getAllResponse());
//通知發(fā)送線程, 最終識(shí)別結(jié)果已經(jīng)返回, 可以調(diào)用stop()
pthread_mutex_lock(&(tmpParam->mtxWord));
pthread_cond_signal(&(tmpParam->cvWord));
pthread_mutex_unlock(&(tmpParam->mtxWord));
}
/**
* @brief 短鏈接模式下工作線程
* 以 createSynthesizerRequest <----|
* | |
* request->start() |
* | |
* 收到OnSynthesisChannelClosed回調(diào) |
* | |
* releaseSynthesizerRequest(request) ----|
* 進(jìn)行循環(huán)。
*/
void* pthreadFunc(void* arg) {
// 0: 從自定義線程參數(shù)中獲取token, 配置文件等參數(shù).
ParamStruct* tst = (ParamStruct*)arg;
if (tst == NULL) {
std::cout << "arg is not valid." << std::endl;
return NULL;
}
// 1: 初始化自定義回調(diào)參數(shù)
ParamCallBack* cbParam = new ParamCallBack();
cbParam->binAudioFile = tst->audioFile;
cbParam->audioFile.open(cbParam->binAudioFile.c_str(), std::ios::binary | std::ios::out);
/*
* 1. 創(chuàng)建語音識(shí)別SpeechSynthesizerRequest對(duì)象.
*
* 默認(rèn)為實(shí)時(shí)短文本語音合成請(qǐng)求, 支持一次性合成300字符以內(nèi)的文字,
* 其中1個(gè)漢字、1個(gè)英文字母或1個(gè)標(biāo)點(diǎn)均算作1個(gè)字符,
* 超過300個(gè)字符的內(nèi)容將會(huì)報(bào)錯(cuò)(或者截?cái)?.
* 一次性合成超過300字符可考慮長(zhǎng)文本語音合成功能.
*
* 實(shí)時(shí)短文本語音合成文檔詳見: http://bestwisewords.com/document_detail/84435.html
* 長(zhǎng)文本語音合成文檔詳見: http://bestwisewords.com/document_detail/130509.html
*/
TtsVersion tts_version = AlibabaNls::ShortTts;
int chars_cnt = NlsClient::getInstance()->calculateUtf8Chars(tst->text.c_str());
if (chars_cnt > 300) {
tts_version = AlibabaNls::LongTts;
}
// 2:創(chuàng)建語音識(shí)別SpeechSynthesizerRequest對(duì)象
SpeechSynthesizerRequest* request =
NlsClient::getInstance()->createSynthesizerRequest(tts_version);
if (request == NULL) {
printf("createSynthesizerRequest failed.\n");
cbParam->audioFile.close();
delete cbParam;
return NULL;
}
// 設(shè)置音頻合成結(jié)束回調(diào)函數(shù)
request->setOnSynthesisCompleted(OnSynthesisCompleted, cbParam);
// 設(shè)置音頻合成通道關(guān)閉回調(diào)函數(shù)
request->setOnChannelClosed(OnSynthesisChannelClosed, cbParam);
// 設(shè)置異常失敗回調(diào)函數(shù)
request->setOnTaskFailed(OnSynthesisTaskFailed, cbParam);
// 設(shè)置文本音頻數(shù)據(jù)接收回調(diào)函數(shù)
request->setOnBinaryDataReceived(OnBinaryDataRecved, cbParam);
// 設(shè)置字幕信息
request->setOnMetaInfo(OnMetaInfo, cbParam);
request->setAppKey(tst->appkey.c_str());
// 設(shè)置賬號(hào)校驗(yàn)token, 必填參數(shù)
request->setToken(tst->token.c_str());
// 設(shè)置待合成文本, 必填參數(shù). 文本內(nèi)容必須為UTF-8編碼
// 一次性合成超過300字符可考慮長(zhǎng)文本語音合成功能.
// 長(zhǎng)文本語音合成文檔詳見: http://bestwisewords.com/document_detail/130509.html
request->setText(tst->text.c_str());
// 發(fā)音人, 包含"xiaoyun", "ruoxi", "xiaogang"等. 可選參數(shù), 默認(rèn)是xiaoyun
request->setVoice("siqi");
// 訪問個(gè)性化音色,訪問的Voice必須是個(gè)人定制音色
//request->setPayloadParam("{\"enable_ptts\":true}");
// 音量, 范圍是0~100, 可選參數(shù), 默認(rèn)50
request->setVolume(50);
// 音頻編碼格式, 可選參數(shù), 默認(rèn)是wav. 支持的格式pcm, wav, mp3
request->setFormat("wav");
// 音頻采樣率, 包含8000, 16000. 可選參數(shù), 默認(rèn)是16000
request->setSampleRate(16000);
// 語速, 范圍是-500~500, 可選參數(shù), 默認(rèn)是0
request->setSpeechRate(0);
// 語調(diào), 范圍是-500~500, 可選參數(shù), 默認(rèn)是0
request->setPitchRate(0);
// 開啟字幕
request->setEnableSubtitle(true);
// 3: start()為異步操作。成功則開始返回BinaryRecv事件。失敗返回TaskFailed事件。
int ret = request->start();
if (ret < 0) {
printf("start() failed. may be can not connect server. please check network or firewalld\n");
NlsClient::getInstance()->releaseSynthesizerRequest(request); // start()失敗,釋放request對(duì)象
cbParam->audioFile.close();
delete cbParam;
return NULL;
}
struct timeval now;
struct timespec outtime;
// 4: 通知云端數(shù)據(jù)發(fā)送結(jié)束.
// stop()為無意義接口,調(diào)用與否都會(huì)跑完全程,均需等待closed事件回調(diào).
// cancel()立即停止工作, 且不會(huì)有回調(diào)返回, 失敗返回TaskFailed事件。
//ret = request->cancel();
ret = request->stop();
if (ret == 0) {
printf("wait closed callback.\n");
// 語音服務(wù)器存在來不及處理當(dāng)前請(qǐng)求, 10s內(nèi)不返回任何回調(diào)的問題,
// 然后在10s后返回一個(gè)TaskFailed回調(diào), 所以需要設(shè)置一個(gè)超時(shí)機(jī)制.
gettimeofday(&now, NULL);
outtime.tv_sec = now.tv_sec + 30;
outtime.tv_nsec = now.tv_usec * 1000;
// 等待closed事件后再進(jìn)行釋放, 否則會(huì)出現(xiàn)崩潰
pthread_mutex_lock(&(cbParam->mtxWord));
if (ETIMEDOUT == pthread_cond_timedwait(&(cbParam->cvWord), &(cbParam->mtxWord), &outtime)) {
printf("synthesis timeout.\n");
}
pthread_mutex_unlock(&(cbParam->mtxWord));
}
NlsClient::getInstance()->releaseSynthesizerRequest(request);
cbParam->audioFile.close();
delete cbParam;
return NULL;
}
// 合成單個(gè)文本數(shù)據(jù)
int speechSynthesizerFile(const char* appkey) {
//獲取當(dāng)前系統(tǒng)時(shí)間戳,判斷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.text = "今天天氣很棒,適合去戶外旅行.";
pa.audioFile = "syAudio.wav";
// 啟動(dòng)一個(gè)工作線程,用于單次識(shí)別。
pthread_t pthreadId;
pthread_create(&pthreadId, NULL, &pthreadFunc, (void *)&pa);
pthread_join(pthreadId, NULL);
return 0;
}
// 合成多個(gè)文本數(shù)據(jù)。
// SDK多線程指一個(gè)文本數(shù)據(jù)對(duì)應(yīng)一個(gè)線程,非一個(gè)文本數(shù)據(jù)對(duì)應(yīng)多個(gè)線程。
// 示例代碼為同時(shí)開啟2個(gè)線程合成2個(gè)文件。
// 免費(fèi)用戶并發(fā)連接不能超過2個(gè)。
#define AUDIO_TEXT_NUMS 2
#define AUDIO_TEXT_LENGTH 64
#define AUDIO_FILE_NAME_LENGTH 32
int speechTranscriberMultFile(const char* appkey) {
//獲取當(dāng)前系統(tǒng)時(shí)間戳判斷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;
}
}
const char syAudioFiles[AUDIO_TEXT_NUMS][AUDIO_FILE_NAME_LENGTH] =
{
"syAudio0.wav",
"syAudio1.wav"
};
const char texts[AUDIO_TEXT_NUMS][AUDIO_TEXT_LENGTH] =
{
"今日天氣真不錯(cuò),我想去操作踢足球.",
"明天有大暴雨,還是宅在家里看電影吧."
};
ParamStruct pa[AUDIO_TEXT_NUMS];
for (int i = 0; i < AUDIO_TEXT_NUMS; i ++) {
pa[i].token = g_token;
pa[i].appkey = appkey;
pa[i].text = texts[i];
pa[i].audioFile = syAudioFiles[i];
}
std::vector<pthread_t> pthreadId(AUDIO_TEXT_NUMS); // 啟動(dòng)工作線程,同時(shí)識(shí)別音頻文件。
for (int j = 0; j < AUDIO_TEXT_NUMS; j++) {
pthread_create(&pthreadId[j], NULL, &pthreadFunc, (void *)&(pa[j]));
}
for (int j = 0; j < AUDIO_TEXT_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");
// 根據(jù)需要設(shè)置SDK輸出日志。可選。
// 此處表示SDK日志輸出至log-synthesizer.txt。
// LogDebug表示輸出所有級(jí)別日志,支持LogDebug、LogInfo、LogWarning、LogError。
// 400表示單個(gè)文件400MB。50表示50個(gè)日志文件循環(huán)記錄。
int ret = NlsClient::getInstance()->setLogConfig(
"log-synthesizer", LogDebug, 400, 50);
if (ret < 0) {
printf("set log failed.\n");
return -1;
}
// 設(shè)置運(yùn)行環(huán)境需要的套接口地址類型, 默認(rèn)為AF_INET
// 必須在startWorkThread()前調(diào)用
//AlibabaNls::NlsClient::getInstance()->setAddrInFamily("AF_INET");
// 私有云部署的情況下可進(jìn)行直連IP的設(shè)置
// 必須在startWorkThread()前調(diào)用
//NlsClient::getInstance()->setDirectHost("106.15.83.44");
// 存在部分設(shè)備在設(shè)置了dns后仍然無法通過SDK的dns獲取可用的IP,
// 可調(diào)用此接口主動(dòng)啟用系統(tǒng)的getaddrinfo來解決這個(gè)問題.
//NlsClient::getInstance()->setUseSysGetAddrInfo(true);
// 啟動(dòng)工作線程, 在創(chuàng)建請(qǐng)求和啟動(dòng)前必須調(diào)用此函數(shù), 可理解為對(duì)NlsClient的初始化
// 入?yún)樨?fù)時(shí), 啟動(dòng)當(dāng)前系統(tǒng)中可用的核數(shù)。
// 200并發(fā)以下推薦入?yún)?, 更高并發(fā)入?yún)⑼扑]可看readme。
NlsClient::getInstance()->startWorkThread(1);
// 合成單個(gè)文本
speechSynthesizerFile(appkey.c_str());
// 合成單個(gè)文本
//speechSynthesizerMultFile(appkey.c_str());
// 所有工作完成,進(jìn)程退出前,釋放nlsClient。
// 請(qǐng)注意releaseInstance()非線程安全, 需要確認(rèn)所有請(qǐng)求都停止工作才可釋放。
NlsClient::releaseInstance();
return 0;
}