本文介紹如何使用阿里雲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
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源碼中,Voice Messaging Service範例音頻,可用於功能測試,如下表所示。
test0.wav
test1.wav
test2.wav
test3.wav
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:版本號碼。
檔案名稱 | 描述 |
檔案名稱 | 描述 |
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 ./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_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 "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;
}