本文介紹了如何使用阿里云離線語音合成服務提供的iOS NUI SDK,包括下載安裝SDK和語音包、SDK關鍵接口及代碼示例。
前提條件
下載安裝
- 說明
下載后在樣例初始化代碼中替換您的阿里云賬號信息、Appkey才可運行。為方便集成,2.5.14版本后iOS接口使用純Object-C接口,不再使用C++混合接口。
類別
兼容范圍
系統
最低支持iOS9
架構
arm64,x86_64
此SDK還包含如下功能,若未支持您想要的功能,請前往對應文檔獲取SDK。
功能
是否支持
一句話識別
是
實時語音識別
是
語音合成
是
實時長文本語音合成
是
流式文本語音合成
是
離線語音合成
是
錄音文件識別極速版
是
喚醒及命令詞
否
聽悟實時推流
是
下載語音包,詳情請參見接口說明中的語音包列表。
重要SDK和語音包是完全獨立的,下載SDK后并不能直接使用,需要下載語音包,并設置語音包存放路徑。
解壓ZIP包。
將ZIP包中的nuisdk.framework添加到您的工程中,并在工程Build Phases的Link Binary With Libraries中添加nuisdk.framework。
使用Xcode打開此工程。
工程中提供了參考代碼以及一些直接可使用的工具類,例如音頻播放錄制和文件操作,您可以直接復制源碼到您的實際工程進行使用。其中語音合成示例代碼在LocalTTSViewController類中。替換appkey和token后可直接運行。
SDK關鍵接口
nui_tts_initialize:初始化SDK。
/** * 初始化SDK,離線合成暫不支持多實例,請先釋放后再次進行初始化。請勿在UI線程調用,意外下可能引起阻塞。 * 初始化是耗時操作,不需要合成一個任務就進行該操作;在啟動和退出時進行一次即可。 * @param parameters: 初始化參數,參考接口說明。 :http://bestwisewords.com/zh/isi/developer-reference/sdk-reference-11 * @param level: log打印級別,值越小打印越多 * @param save_log: 是否保存log為文件,存儲目錄為parameter中的debug_path字段值。注意,log文件無上限,請注意持續存儲導致磁盤存滿。 * @return 參考錯誤碼:http://bestwisewords.com/document_detail/459864.html */ -(int) nui_tts_initialize:(const char *)parameters logLevel:(NuiSdkLogLevel)level saveLog:(BOOL)save_log;
nui_tts_play:開始播放。
/** * 開始播放,該接口異步執行 * @param priority: 任務優先級,請使用"1"。 * @param taskid: 任務ID,可傳入32個字節的uuid或者傳入空內容由SDK自動生成。 * @param text: 要播放的文本內容。 * @return 參考錯誤碼。 */ -(int) nui_tts_play:(const char *)priority taskId:(const char *)taskid text:(const char *)text;
nui_tts_cancel:取消播放。
/** * 取消合成任務 * @param taskid: 傳入想要停止的任務ID,如果為空則取消所有任務。 * @return 參考錯誤碼。 */ -(int) nui_tts_cancel:(const char *)taskid;
nui_tts_pause:暫停播放。
/** * 暫停 * @return 參考錯誤碼。 */ -(int) nui_tts_pause;
nui_tts_resume:恢復播放。
/** * 恢復暫停的任務 * @return 參考錯誤碼。 */ -(int) nui_tts_resume;
nui_tts_set_param:設置語音合成參數。
/** * 以鍵值對形式設置參數 * @param param: 參數名,參考接口說明:http://bestwisewords.com/zh/isi/developer-reference/sdk-reference-11 * @param value: 參數值,參考接口說明:http://bestwisewords.com/zh/isi/developer-reference/sdk-reference-11 * @return 參考錯誤碼 */ -(int) nui_tts_set_param:(const char *)param value:(const char *)value;
nui_tts_get_param:獲取參數。
/** * 獲取參數值 * @param param: 參數名,參考接口說明:http://bestwisewords.com/zh/isi/developer-reference/sdk-reference-11 * @return 參數值 */ -(const char *) nui_tts_get_param:(const char *)param;
nui_tts_release:釋放SDK資源。
/** * 釋放SDK * @return 參考錯誤碼。 */ -(int) nui_tts_release;
NeoNuiTtsDelegate事件代理
onNuiTtsUserdataCallback:在回調中提供音頻數據。
/** * 當開始識別時,此回調被連續調用,App需要在回調中進行語音數據填充。 * @param info: 在使用時間戳功能時返回時間戳結果,JSON格式。 * @param info_len: info字段的數據長度。 * @param buffer: 合成的語音數據。 * @param len: 合成的語音長度。 * @param taskid: 本次合成的任務ID。 */ - (void)onNuiTtsUserdataCallback:(char*)info infoLen:(int)info_len buffer:(char*)buffer len:(int)len taskId:(char*)task_id;
onNuiTtsEventCallback: 事件回調。
/** * SDK主要事件回調 * @param event: 回調事件,參考接口說明:http://bestwisewords.com/zh/isi/developer-reference/sdk-reference-11 * @param taskid: 本次合成的任務id * @param code: 參考錯誤碼,TTS_EVENT_ERROR時有效 */ - (void)onNuiTtsEventCallback:(NuiSdkTtsEvent)event taskId:(char*)taskid code:(int)code;
NuiSdkTtsEvent事件列表:
名稱
說明
TTS_EVENT_START
語音合成開始,準備播放。
TTS_EVENT_END
語音合成結束,合成數據已全部拋出,但并不表示播放結束。
TTS_EVENT_CANCEL
取消語音合成。
TTS_EVENT_PAUSE
語音合成暫停。
TTS_EVENT_RESUME
語音合成恢復。
TTS_EVENT_ERROR
語音合成發生錯誤。
調用步驟
初始化SDK和播放組件。
根據業務需要設置參數。
調用nui_tts_play進行播放。
在合成數據回調中,將數據寫入播放器進行播放,建議使用流式播放。
收到語音合成結束的回調。
代碼示例
語音合成初始化。
// 一次初始化成功,可以反復調用合成和參數設置接口,不需要頻繁初始化和釋放,減少耗時 NSString * initParam = [self genInitParams]; [_nui nui_tts_initialize:[initParam UTF8String] logLevel:LOG_LEVEL_VERBOSE saveLog:true]; if (retcode != 0) { // 初始化失敗,通過"error_msg"查看詳細的錯誤信息,離線語音合成FAQ文檔中已列出常見錯誤。 const char *errmsg = [_nui nui_tts_get_param: "error_msg"]; TLog(@"init failed. retcode:%d. errmsg:%s", retcode, errmsg); // 初始化失敗不需要再調用參數設置和合成接口 return; }
其中,genInitParams生成為String JSON字符串,包含資源目錄和用戶信息。其中用戶信息包含如下字段。
-(NSString *)genInitParams { NSString *strResourcesBundle = [[NSBundle mainBundle] pathForResource:@"Resources" ofType:@"bundle"]; NSString *bundlePath = [[NSBundle bundleWithPath:strResourcesBundle] resourcePath]; NSString *debug_path = [_utils createDir]; NSMutableDictionary *dictM = [NSMutableDictionary dictionary]; //鄭重提示: // 語音交互服務需要先準備好賬號,并開通相關服務。具體步驟請查看: // http://bestwisewords.com/zh/isi/getting-started/start-here // //原始賬號: // 賬號(子賬號)信息主要包括AccessKey ID(后續簡稱為ak_id)和AccessKey Secret(后續簡稱為ak_secret)。 // 此賬號信息一定不可存儲在app代碼中或移動端側,以防賬號信息泄露造成資費損失。 // //STS臨時憑證: // 由于賬號信息下發給客戶端存在泄露的可能,阿里云提供的一種臨時訪問權限管理服務STS(Security Token Service)。 // STS是由賬號信息ak_id和ak_secret,通過請求生成臨時的sts_ak_id/sts_ak_secret/sts_token // (為了區別原始賬號信息和STS臨時憑證, 命名前綴sts_表示STS生成的臨時憑證信息) //什么是STS:http://bestwisewords.com/zh/ram/product-overview/what-is-sts //STS SDK概覽:http://bestwisewords.com/zh/ram/developer-reference/sts-sdk-overview //STS Python SDK調用示例:http://bestwisewords.com/zh/ram/developer-reference/use-the-sts-openapi-example // //賬號需求說明: // 若使用離線功能(離線語音合成、喚醒), 則必須app_key、ak_id和ak_secret,或app_key、sts_ak_id、sts_ak_secret和sts_token // 若使用在線功能(語音合成、實時轉寫、一句話識別、錄音文件轉寫等), 則只需app_key和token //獲取賬號訪問憑證: [_utils getTicket:dictM Type:get_sts_access_from_server_for_offline_features]; //請參照阿里云官網獲取鑒權信息獲取配額 // http://bestwisewords.com/document_detail/251488.html?spm=a2c4g.11186623.6.638.1f0d530eut95Jn // 如果配額已耗盡,請聯系客戶擴大配額 // 如果合成失敗,通常是由于鑒權失敗,可以參照阿里云官網Q&A部分 // http://bestwisewords.com/document_detail/204191.html?spm=a2c4g.11186623.6.657.3cde7340qMll1h ,根據錯誤日志判別導致鑒權失敗的原因 //工作目錄路徑,SDK從該路徑讀取配置文件 [dictM setObject:bundlePath forKey:@"workspace"]; // 如果需要保存調試日志到文件,初始化的時候加入該字段;不要保存日志,該字段刪除 // 日志文件是追加的方式存儲的,下次初始化時并不會將老日志沖掉重寫 // 另外,在開啟保存日志文件時,可以動態的通過接口nui_tts_set_param將日志等級設置成最高值,保證日志不寫入文件,等需要寫入時再動態設置成較低的等級 [dictM setObject:debug_path forKey:@"debug_path"]; TLog(@"debug_path:%@", debug_path); TLog(@"workspace:%@", bundlePath); [dictM setObject:@"wss://nls-gateway.cn-shanghai.aliyuncs.com:443/ws/v1" forKey:@"url"]; // 設置成本地語音合成模式, 這個設置很重要, 遺漏會導致無法運行 [dictM setObject:@"0" forKey:@"mode_type"]; // 必填 // 特別說明: 鑒權所用的id是由以下device_id,與手機內部的一些唯一碼進行組合加密生成的。 // 更換手機或者更換device_id都會導致重新鑒權計費。 // 此外, 以下device_id請設置有意義且具有唯一性的id, 比如用戶賬號(手機號、IMEI等), // 傳入相同或隨機變換的device_id會導致鑒權失敗或重復收費。 // NSString *id_string = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]; 并不能保證生成不變的device_id,請不要使用 [dictM setObject:@"empty_device_id" forKey:@"device_id"]; // 必填 NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil]; NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; return jsonStr; }
根據需求設置參數。
//加載語音包:已購買的語音包,可以放在任意位置,以aijia為例,該語音包位于Documents/voices/下,設置命令為“Documents/voices/aijia” NSString *cmd = [NSString stringWithFormat:@"%@/aijia", myvoicedir]; [self.nui nui_tts_set_param:"extend_font_name" value:[cmd UTF8String]];
啟動語音合成。
//建議同一時間單示例啟動一個task進行語音合成,單實例多task易出異常。 [self.nui nui_tts_play:"1" taskId:"" text:[content UTF8String]];
取消語音合成
//如果上個任務沒有合成完畢,手動取消,開始合成新的任務。 //建議同一時間單示例啟動一個task進行語音合成,單實例多task易在cancel時出異常。 [self.nui nui_tts_cancel:NULL];
回調處理。
onNuiTtsEventCallback:語音合成事件回調,根據語音合成狀態控制播放器。
- (void)onNuiTtsEventCallback:(NuiSdkTtsEvent)event taskId:(char*)taskid code:(int)code { TLog(@"onNuiTtsEventCallback event[%d]", event); if (event == TTS_EVENT_START) { TLog(@"onNuiTtsEventCallback TTS_EVENT_START"); loop_in = TTS_EVENT_START; // 舊版本示例工程提供的播放器,僅做參考,可根據自身業務重寫播放器。 // [self->_voicePlayer play]; // 新版本示例工程提供了新的播放器,僅做參考,可根據自身業務重寫播放器。 [_audioController startPlayer]; } else if (event == TTS_EVENT_END || event == TTS_EVENT_CANCEL || event == TTS_EVENT_ERROR) { loop_in = event; if (event == TTS_EVENT_END) { TLog(@"onNuiTtsEventCallback TTS_EVENT_END"); // 舊版本示例工程提供的播放器,僅做參考,可根據自身業務重寫播放器。 // 注意這里的event事件是指語音合成完成,而非播放完成,播放完成需要由voicePlayer對象來進行通知 // [self->_voicePlayer drain]; // 新版本示例工程提供了新的播放器,僅做參考,可根據自身業務重寫播放器。 // 注意這里的event事件是指語音合成完成,而非播放完成,播放完成需要由audioController對象來進行通知 [_audioController drain]; } else { // 舊版本示例工程提供的播放器,僅做參考,可根據自身業務重寫播放器。 // 取消播報、或者發生異常時終止播放 // [self->_voicePlayer stop]; // 新版本示例工程提供了新的播放器,僅做參考,可根據自身業務重寫播放器。 // 取消播報、或者發生異常時終止播放 [_audioController stopPlayer]; } if (event == TTS_EVENT_ERROR) { const char *errmsg = [_nui nui_tts_get_param: "error_msg"]; TLog(@"tts get errmsg:%s", errmsg); } } }
onNuiTtsUserdataCallback:語音合成數據回調,將回調中的合成數據寫入播放器進行播放。
- (void)onNuiTtsUserdataCallback:(char*)info infoLen:(int)info_len buffer:(char*)buffer len:(int)len taskId:(char*)task_id { TLog(@"onNuiTtsUserdataCallback info ..."); if (info_len > 0) { TLog(@"onNuiTtsUserdataCallback info text %s. index %d.", info, info_len); } if (len > 0) { // 舊版本示例工程提供的播放器,僅做參考,可根據自身業務重寫播放器。 // [_voicePlayer write:(char*)buffer Length:(unsigned int)len]; // 新版本示例工程提供了新的播放器,僅做參考,可根據自身業務重寫播放器。 [_audioController write:(char*)buffer Length:(unsigned int)len]; } }