本文介紹如何使用阿里云智能語音服務提供的iOS NUI SDK,包括SDK下載安裝、關鍵接口及代碼示例。
前提條件
下載安裝
- 說明
請下載后在樣例初始化代碼中替換您的阿里云賬號信息、Appkey和Token才可運行。
為方便集成,2.5.14版本后iOS接口使用純Object-C接口,不再使用C++混合接口。
對象
說明
智能語音交互移動端SDK
智能語音交互移動端SDK
阿里云計算有限公司
阿里云計算有限公司
SDK版本
2.6.3-01B
SDK更新時間
2024-12-19
SDK整合包大小
17.3MB
SDK整合包MD5值
edf1a1a770bf869b738ee89ab43d88aa
隱私政策
SDK整合包下載
類別
兼容范圍
系統
最低支持iOS9。
架構
arm64,x86_64
此SDK還包含如下功能,若未支持您想要的功能,請前往對應文檔獲取SDK。
功能
是否支持
一句話識別
是
實時語音識別
是
語音合成
是
實時長文本語音合成
是
流式文本語音合成
是
離線語音合成
否
錄音文件識別極速版
是
喚醒及命令詞
否
聽悟實時推流
是
解壓ZIP包,將zip包中的nuisdk.framework添加到您的工程中,并在工程Build Phases的Link Binary With Libraries中添加nuisdk.framework。
使用Xcode打開此工程,工程中提供了參考代碼以及一些直接可使用的工具類,例如音頻播放錄制和文件操作,您可以直接復制源碼到您的實際工程進行使用。其中一句話識別示例代碼為SpeechRecognizerViewController。替換Appkey和Token后可直接運行。
SDK關鍵接口
nui_initialize:初始化SDK。
/** * 初始化SDK,SDK為單例,請先釋放后再次進行初始化。請勿在UI線程調用,可能引起阻塞。 * @param parameters: 初始化參數,參見接口說明文檔:http://bestwisewords.com/zh/isi/developer-reference/overview-3 * @param level: log打印級別,值越小打印越多 * @param save_log: 是否保存log為文件,存儲目錄為parameter中的debug_path字段值。注意,log文件無上限,請注意持續存儲導致磁盤存滿。 * @return 參見錯誤碼 */ -(NuiResultCode) nui_initialize:(const char *)parameters logLevel:(NuiSdkLogLevel)level saveLog:(BOOL)save_log;
nui_set_params:以JSON格式設置SDK參數。
/** * 以JSON格式設置參數 * @param params: 參數信息請參見接口說明文檔:http://bestwisewords.com/zh/isi/developer-reference/overview-3 * @return 參見錯誤碼 */ -(NuiResultCode) nui_set_params:(const char *)params;
nui_dialog_start:開始識別。
/** * 開始識別 * @param vad_mode: 多種模式,對于識別場景,請使用P2T * @param dialog_params: 設置識別參數,可不設置 * @return 參見錯誤碼 */ -(NuiResultCode) nui_dialog_start:(NuiVadMode)vad_mode dialogParam:(const char *)dialog_params;
nui_dialog_cancel:結束識別。
/** * 結束識別,調用該接口后,服務端將返回最終識別結果并結束任務 * @param force: 是否強制結束而忽略最終結果,false或NO表示停止但是等待完整結果返回 * @return 參見錯誤碼 */ -(NuiResultCode) nui_dialog_cancel:(BOOL)force;
nui_release:釋放SDK。
/** * 釋放SDK資源 * @return 參見錯誤碼 */ -(NuiResultCode) nui_release;
nui_get_version:獲得當前SDK版本信息。
/** * 獲得當前SDK版本信息 * @return 字符串形式的SDK版本信息 */ -(const char*) nui_get_version;
nui_get_all_response:獲得當前事件回調的完整信息。
/** * 獲得當前事件回調的完整信息 * @return json字符串形式的完整事件信息 */ -(const char*) nui_get_all_response;
NeoNuiSdkDelegate:事件代理
onNuiEventCallback:SDK事件回調。
/** * SDK主要事件回調 * @param event: 回調事件,參見如下事件列表 * @param dialog: 會話編號(暫不支持) * @param wuw: 語音喚醒功能使用(暫不支持) * @param asr_result: 語音識別結果 * @param finish: 本輪識別是否結束標志 * @param resultCode: 參見錯誤碼,在出現EVENT_ASR_ERROR事件時有效 */ -(void) onNuiEventCallback:(NuiCallbackEvent)nuiEvent dialog:(long)dialog kwsResult:(const char *)wuw asrResult:(const char *)asr_result ifFinish:(BOOL)finish retCode:(int)code;
NuiCallbackEvent事件列表:
名稱
說明
EVENT_VAD_START
檢測到人聲起點。
EVENT_VAD_END
檢測到人聲尾點。
EVENT_ASR_PARTIAL_RESULT
語音識別中間結果。
EVENT_ASR_RESULT
語音識別最終結果。
EVENT_ASR_ERROR
根據錯誤碼信息判斷出錯原因。
EVENT_MIC_EEROR
錄音錯誤,表示SDK連續2秒未收到任何音頻,可檢查錄音系統是否正常。
onNuiNeedAudioData:獲取音頻
/** * 開始識別時,此回調被連續調用,App需要在回調中進行語音數據填充 * @param audioData: 填充語音的存儲區 * @param len: 需要填充語音的字節數 * @return 實際填充的字節數 */ -(int) onNuiNeedAudioData:(char *)audioData length:(int)len;
onNuiAudioStateChanged:根據音頻狀態進行錄音功能的開關。
/** * 當start/stop/cancel等接口調用時,SDK通過此回調通知App進行錄音的開關操作 * @param state:錄音需要的狀態(打開/關閉) */ -(void) onNuiAudioStateChanged:(NuiAudioState)state;
onNuiRmsChanged:音頻能量事件。
/** * SDK主要事件回調 * @param rms: 語音能量值,范圍為-160至0 */ -(void) onNuiRmsChanged:(float) rms;
調用步驟
初始化SDK、錄音實例。
根據業務需求配置參數。
調用nui_dialog_start開始識別。
根據音頻狀態回調onNuiAudioStateChanged,打開錄音機。
在onNuiNeedAudioData回調中提供錄音數據。
在EVENT_ASR_PARTIAL_RESULT事件回調中獲取識別結果。
調用nui_dialog_cancel結束識別。
結束調用,使用release接口釋放SDK資源。
代碼示例
接口默認采用get_instance方式獲得單例,您如果有多例需求,也可以直接alloc對象進行使用。
NUI SDK初始化
BOOL save_log = NO;
NSString * initParam = [self genInitParams];
[_nui nui_initialize:[initParam UTF8String] logLevel:LOG_LEVEL_VERBOSE saveLog:save_log];
其中,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 *ticketJsonDict = [NSMutableDictionary dictionary];
//獲取賬號訪問憑證:
// getTicket為示例工程中提供了多種可能的方式,請選擇適合自身業務的安全方式
//
//鄭重提示:
// 語音交互服務需要先準備好賬號,并開通相關服務。具體步驟請查看:
// 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:ticketJsonDict Type:get_token_from_server_for_online_features];
if ([ticketJsonDict objectForKey:@"token"] != nil) {
NSString *tokenValue = [ticketJsonDict objectForKey:@"token"];
if ([tokenValue length] == 0) {
TLog(@"The 'token' key exists but the value is empty.");
}
} else {
TLog(@"The 'token' key does not exist.");
}
[ticketJsonDict setObject:@"wss://nls-gateway.cn-shanghai.aliyuncs.com:443/ws/v1" forKey:@"url"]; // 默認
//工作目錄路徑,SDK從該路徑讀取配置文件
[ticketJsonDict setObject:bundlePath forKey:@"workspace"]; // 必填
//當初始化SDK時的save_log參數取值為true時,該參數生效。表示是否保存音頻debug,該數據保存在debug目錄中,需要確保debug_path有效可寫
[ticketJsonDict setObject:save_wav ? @"true" : @"false" forKey:@"save_wav"];
//debug目錄,當初始化SDK時的save_log參數取值為true時,該目錄用于保存中間音頻文件
[ticketJsonDict setObject:debug_path forKey:@"debug_path"];
//AsrCloud = 4 // 在線一句話識別可以選這個
[ticketJsonDict setObject:@"4" forKey:@"service_mode"]; // 必填
NSString *id_string = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
TLog(@"id: %s", [id_string UTF8String]);
[ticketJsonDict setObject:id_string forKey:@"device_id"]; // 必填, 推薦填入具有唯一性的id, 方便定位問題
NSData *data = [NSJSONSerialization dataWithJSONObject:ticketJsonDict options:NSJSONWritingPrettyPrinted error:nil];
NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return jsonStr;
}
參數設置
以JSON字符串形式進行設置。
-(NSString*) genParams {
NSMutableDictionary *nls_config = [NSMutableDictionary dictionary];
[nls_config setValue:@YES forKey:@"enable_intermediate_result"]; // 必填
//參數可根據實際業務進行配置
//接口說明可見: http://bestwisewords.com/document_detail/173298.html
//查看 2.開始識別
//由于對外的SDK(01B版本)不帶有本地VAD模塊(僅帶有喚醒功能(029版本)的SDK具有VAD模塊),
//若要使用VAD模式,則需要設置nls_config參數啟動在線VAD模式(見genParams())
//
//模式說明:
//若使用P2T模式,即按下開始說話,放開結束說話的模式,則不啟動enable_voice_detection。
//若使用VAD模式,即自動判斷用戶說完一句話,則啟動enable_voice_detection。
//[nls_config setValue:@YES forKey:@"enable_voice_detection"];
//[nls_config setValue:@10000 forKey:@"max_start_silence"];
//[nls_config setValue:@800 forKey:@"max_end_silence"];
//[nls_config setValue:@"<更新token>" forKey:@"token"];
//[nls_config setValue:@YES forKey:@"enable_punctuation_prediction"];
//[nls_config setValue:@YES forKey:@"enable_inverse_text_normalization"];
//[nls_config setValue:@16000 forKey:@"sample_rate"];
//[nls_config setValue:@"opus" forKey:@"sr_format"];
NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
[dictM setObject:nls_config forKey:@"nls_config"];
[dictM setValue:@(SERVICE_TYPE_ASR) forKey:@"service_type"]; // 必填
//如果有HttpDns則可進行設置
//[dictM setObject:[_utils getDirectIp] forKey:@"direct_ip"];
/*若文檔中不包含某些參數,但是此功能支持這個參數,可以用如下萬能接口設置參數*/
//NSMutableDictionary *extend_config = [NSMutableDictionary dictionary];
//[extend_config setValue:@YES forKey:@"custom_test"];
//[dictM setObject:extend_config forKey:@"extend_config"];
NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil];
NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return jsonStr;
}
NSString * parameters = [self genParams];
[_nui nui_set_params:[parameters UTF8String]];
開始識別
通過nui_dialog_start接口開啟監聽。
-(NSString*) genDialogParams {
NSMutableDictionary *dialog_params = [NSMutableDictionary dictionary];
// 運行過程中可以在nui_dialog_start時更新臨時參數,尤其是更新過期token
// 注意: 若下一輪對話不再設置參數,則繼續使用初始化時傳入的參數
// [dialog_params setValue:@"" forKey:@"app_key"];
// [dialog_params setValue:@"" forKey:@"token"];
NSData *data = [NSJSONSerialization dataWithJSONObject:dialog_params options:NSJSONWritingPrettyPrinted error:nil];
NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return jsonStr;
}
//若需要修改token等參數, 可詳見genDialogParams()
NSString * parameters = [self genDialogParams];
//若要使用VAD模式,則需要設置nls_config參數啟動在線VAD模式(見genParams())
[_nui nui_dialog_start:MODE_P2T dialogParam:[parameters UTF8String]];
回調處理
onNuiAudioStateChanged:錄音狀態回調,SDK內部維護錄音狀態,調用時根據該狀態的回調進行錄音機的開關操作。
-(void)onNuiAudioStateChanged:(NuiAudioState)state{ TLog(@"onNuiAudioStateChanged state=%u", state); if (state == STATE_CLOSE || state == STATE_PAUSE) { // 舊版本示例工程提供的錄音模塊,僅做參考,可根據自身業務重寫錄音模塊。 // [_voiceRecorder stop:YES]; // 新版本示例工程提供了新的錄音模塊,僅做參考,可根據自身業務重寫錄音模塊。 [_audioController stopRecorder:NO]; } else if (state == STATE_OPEN){ self.recordedVoiceData = [NSMutableData data]; // 舊版本示例工程提供的錄音模塊,僅做參考,可根據自身業務重寫錄音模塊。 // [_voiceRecorder start]; // 新版本示例工程提供了新的錄音模塊,僅做參考,可根據自身業務重寫錄音模塊。 [_audioController startRecorder]; } }
onNuiNeedAudioData:錄音數據回調,在該回調中填充錄音數據。
-(int)onNuiNeedAudioData:(char *)audioData length:(int)len { static int emptyCount = 0; @autoreleasepool { @synchronized(_recordedVoiceData){ if (_recordedVoiceData.length > 0) { int recorder_len = 0; if (_recordedVoiceData.length > len) recorder_len = len; else recorder_len = _recordedVoiceData.length; NSData *tempData = [_recordedVoiceData subdataWithRange:NSMakeRange(0, recorder_len)]; [tempData getBytes:audioData length:recorder_len]; tempData = nil; NSInteger remainLength = _recordedVoiceData.length - recorder_len; NSRange range = NSMakeRange(recorder_len, remainLength); [_recordedVoiceData setData:[_recordedVoiceData subdataWithRange:range]]; emptyCount = 0; return recorder_len; } else { if (emptyCount++ >= 50) { TLog(@"_recordedVoiceData length = %lu! empty 50times.", (unsigned long)_recordedVoiceData.length); emptyCount = 0; } return 0; } } } return 0; }
onNuiEventCallback:NUI SDK事件回調,請勿在事件回調中調用SDK的接口,可能引起死鎖。
-(void)onNuiEventCallback:(NuiCallbackEvent)nuiEvent dialog:(long)dialog kwsResult:(const char *)wuw asrResult:(const char *)asr_result ifFinish:(bool)finish retCode:(int)code { TLog(@"onNuiEventCallback event %d finish %d", nuiEvent, finish); if (nuiEvent == EVENT_ASR_PARTIAL_RESULT || nuiEvent == EVENT_ASR_RESULT) { // asr_result在此包含task_id,task_id有助于排查問題,請用戶進行記錄保存。 TLog(@"ASR RESULT %s finish %d", asr_result, finish); NSString *result = [NSString stringWithUTF8String:asr_result]; } else if (nuiEvent == EVENT_ASR_ERROR) { // asr_result在EVENT_ASR_ERROR中為錯誤信息,搭配錯誤碼code和其中的task_id更易排查問題,請用戶進行記錄保存。 TLog(@"EVENT_ASR_ERROR error[%d], error mesg[%s]", code, asr_result); // 可通過nui_get_all_response獲得完整的信息 const char *response = [_nui nui_get_all_response]; if (response != NULL) { TLog(@"GET ALL RESPONSE: %s", response); } } else if (nuiEvent == EVENT_MIC_ERROR) { TLog(@"MIC ERROR"); // 舊版本示例工程提供的錄音模塊,僅做參考,可根據自身業務重寫錄音模塊。 // [_voiceRecorder stop:YES]; // [_voiceRecorder start]; // 新版本示例工程提供了新的錄音模塊,僅做參考,可根據自身業務重寫錄音模塊。 [_audioController stopRecorder:NO]; [_audioController startRecorder]; } //finish 為真(可能是發生錯誤,也可能是完成識別)表示一次任務生命周期結束,可以開始新的識別 if (finish) { } return; }
結束識別
[_nui nui_dialog_cancel:NO];
常見問題
iOS SDK使用一句話識別功能,集成nuisdk.framework,按照文檔在工程Build Phases的Link Binary With Libraries中添加nuisdk.framework,在編譯配置的General > Frameworks, Libraries, and Embedded Content中配置nuisdk.framework為Embed & Sign,但.m中仍提示找不到 nuisdk.framework/Headers/NeoNui.h如何解決?
請檢查頭文件#import <nuisdk/NeoNui.h>是否按照文檔正常導入。
是否有Android和iOS的SDK,能否用在專有云環境下?
有SDK,在專有云安裝包里默認不提供,可以通過阿里云幫助中心對應的服務文檔中下載,如實時語音識別的Android SDK和iOS SDK。移動端SDK可以調用公共云ASR、TTS服務,也可以用在專有云環境下。
iOS是否支持后臺處理?
SDK本身不限制前后臺,iOS SDK的樣例工程默認僅支持前臺處理,如果您需要支持后臺處理,可以做如下修改:
在工程Info.list中添加Required background modes配置,并在該配置下添加Item,Value設置為App plays audio or streams audio/video using AirPlay。
在錄音模塊中進入后臺時,不停止錄音。亦即NLSVoiceRecorder.m中_appResignActive接口中不做停止錄音調用。
下載語音交互iOS SDK至本地靜態庫,運行Demo程序測試代碼時,模擬器可以正常運行,真機無法運行,報錯“Reason: no suitable image found. Did find:xxx”如何解決?
建議您刪除手機上對應的APP后,執行xcode clean
,并重新嘗試運行。除此以外,還需檢查簽名的正確性,如果簽名不正確,需撤銷原來的inHouse證書,重新制作新的證書和provisioning profile,并將代碼重新簽名,再次打包。
iOS端集成nuisdk運行報mic錯誤如何處理?
請檢查當前錄音設備是否被占用。
使用智能語音服務集成iOS SDK,接入nuisdk.framework后,導入頭文件#import "nuisdk.framework/Headers/NeoNui.h"后項目報錯如何解決?
一般情況下是SDK導入有問題導致,請您確認下圖參數是否已勾選,如果已勾選,建議您將頭文件導入方式換為#import <nuisdk/NeoNui.h>
。
按照文檔使用SDK接入后報錯“/Users/admin/FlashTranscription_iOS/Fc_ASR.xcodeproj Building for iOS, but the linked and embedded framework 'nuisdk.framework' was built for iOS + iOS Simulator."”如何解決?
可能因為版本過高導致,建議您修改項目配置Validate Workspace為Yes后,重新編譯。
使用集成語音服務iOS SDK,集成flutter_plugin時報錯“Undefined symbols for architecture arm64: "std::__1::mutex::~mutex()", referenced from: ___cxx_global_var_init in libflutter_tts.a(ringBuf.o)”如何解決?
您可以打開iOS工程下的Podfile文件,修改post_install do |installer|
部分的代碼,再次執行構建即可成功。
TRTC實時音視頻和語音識別結合,當同時調用麥克風時可能會發生沖突,導致有一方沒有聲音如何解決?
建議嘗試TRTC的音視頻流,使用localStream.getAudioTrack
獲取MediaStreamTrack
對象,并轉換為符合ASR標準的音頻流,然后通過語音識別SDK發起請求。
使用App集成iOS SDK,提交到App store失敗,提示“Unsupported Architectures. The executable for AliYunSmart.app/Frameworks/nuisdk.framework contains unsupported architectures '[x86_ _64, i386]'. With error code”如何解決?
可能是模擬器架構影響,您可以參考如下方法查看framework版本并移除framework模擬器架構。
進入framework目錄。
輸入命令
lipo -info xxxFramework
,查看framework的架構版本,如果含有模擬器打包需要把模擬器架構移除。
使用集成語音服務iOS SDK,接入nuisdk.framework后報錯,要修改Legacy Build system才可以運行,如何解決?
建議您修改項目配置Validate Workspace為Yes后,重新編譯。