一铭若、引言
??????? iOS10系統(tǒng)是一個(gè)較有突破性的系統(tǒng),其在Message递览,Notification等方面都開放了很多實(shí)用性的開發(fā)接口奥喻。本篇博客將主要探討iOS10中新引入的SpeechFramework框架。有個(gè)這個(gè)框架非迹,開發(fā)者可以十分容易的為自己的App添加語音識(shí)別功能环鲤,不需要再依賴于其他第三方的語音識(shí)別服務(wù),并且憎兽,Apple的Siri應(yīng)用的強(qiáng)大也證明了Apple的語音服務(wù)是足夠強(qiáng)大的冷离,不通過第三方,也大大增強(qiáng)了用戶的安全性纯命。
二西剥、SpeechFramework框架中的重要類
??????? SpeechFramework框架比較輕量級(jí),其中的類并不十分冗雜亿汞,在學(xué)習(xí)SpeechFramework框架前瞭空,我們需要對(duì)其中類與類與類之間的關(guān)系有個(gè)大致的熟悉了解。
SFSpeechRecognizer:這個(gè)類是語音識(shí)別的操作類疗我,用于語音識(shí)別用戶權(quán)限的申請(qǐng)咆畏,語言環(huán)境的設(shè)置,語音模式的設(shè)置以及向Apple服務(wù)發(fā)送語音識(shí)別的請(qǐng)求吴裤。
SFSpeechRecognitionTask:這個(gè)類是語音識(shí)別服務(wù)請(qǐng)求任務(wù)類旧找,每一個(gè)語音識(shí)別請(qǐng)求都可以抽象為一個(gè)SFSpeechRecognitionTask實(shí)例,其中SFSpeechRecognitionTaskDelegate協(xié)議中約定了許多請(qǐng)求任務(wù)過程中的監(jiān)聽方法麦牺。
SFSpeechRecognitionRequest:語音識(shí)別請(qǐng)求類钮蛛,需要通過其子類來進(jìn)行實(shí)例化。
SFSpeechURLRecognitionRequest:通過音頻URL來創(chuàng)建語音識(shí)別請(qǐng)求剖膳。
SFSpeechAudioBufferRecognitionRequest:通過音頻流來創(chuàng)建語音識(shí)別請(qǐng)求魏颓。
SFSpeechRecognitionResult:語音識(shí)別請(qǐng)求結(jié)果類。
SFTranscription:語音轉(zhuǎn)換后的信息類吱晒。
SFTranscriptionSegment:語音轉(zhuǎn)換中的音頻節(jié)點(diǎn)類甸饱。
??????? 了解了上述類的作用于其之間的聯(lián)系,使用SpeechFramework框架將十分容易枕荞。
三柜候、申請(qǐng)用戶語音識(shí)別權(quán)限與進(jìn)行語音識(shí)別請(qǐng)求
??????? 開發(fā)者若要在自己的App中使用語音識(shí)別功能搞动,需要獲取用戶的同意。首先需要在工程的Info.plist文件中添加一個(gè)Privacy-Speech Recognition Usage Description鍵渣刷,其實(shí)需要對(duì)應(yīng)一個(gè)String類型的值鹦肿,這個(gè)值將會(huì)在系統(tǒng)獲取權(quán)限的警告框中顯示,Info.plist文件如下圖所示:
使用SFSpeechRecognize類的requestAuthorization方法來進(jìn)行用戶權(quán)限的申請(qǐng)辅柴,用戶的反饋結(jié)果會(huì)在這個(gè)方法的回調(diào)block中傳入箩溃,如下:
//申請(qǐng)用戶語音識(shí)別權(quán)限
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
}];
SFSpeechRecognizerAuthorzationStatus枚舉中定義了用戶的反饋結(jié)果,如下:
typedefNS_ENUM(NSInteger, SFSpeechRecognizerAuthorizationStatus) {
?//結(jié)果未知 用戶尚未進(jìn)行選擇
?SFSpeechRecognizerAuthorizationStatusNotDetermined,
?//用戶拒絕授權(quán)語音識(shí)別
?SFSpeechRecognizerAuthorizationStatusDenied,
?//設(shè)備不支持語音識(shí)別功能
?SFSpeechRecognizerAuthorizationStatusRestricted,
?//用戶授權(quán)語音識(shí)別
?SFSpeechRecognizerAuthorizationStatusAuthorized,
};
??????? 如果申請(qǐng)用戶語音識(shí)別權(quán)限成功碌嘀,開發(fā)者可以通過SFSpeechRecognizer操作類來進(jìn)行語音識(shí)別請(qǐng)求涣旨,示例如下:
//創(chuàng)建語音識(shí)別操作類對(duì)象
SFSpeechRecognizer * rec = [[SFSpeechRecognizer alloc]init];
//通過一個(gè)音頻路徑創(chuàng)建音頻識(shí)別請(qǐng)求
SFSpeechRecognitionRequest * request = [[SFSpeechURLRecognitionRequest alloc]initWithURL:[[NSBundle mainBundle] URLForResource:@"7011"withExtension:@"m4a"]];
//進(jìn)行請(qǐng)求
[rec recognitionTaskWithRequest:request resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
?//打印語音識(shí)別的結(jié)果字符串
?NSLog(@"%@",result.bestTranscription.formattedString);
}];
四、深入SFSpeechRecognizer類
??????? SFSpeechRecognizer類的主要作用是申請(qǐng)權(quán)限股冗,配置參數(shù)與進(jìn)行語音識(shí)別請(qǐng)求霹陡。其中比較重要的屬性與方法如下:
//獲取當(dāng)前用戶權(quán)限狀態(tài)
+ (SFSpeechRecognizerAuthorizationStatus)authorizationStatus;
//申請(qǐng)語音識(shí)別用戶權(quán)限
+ (void)requestAuthorization:(void(^)(SFSpeechRecognizerAuthorizationStatus status))handler;
//獲取所支持的所有語言環(huán)境
+ (NSSet *)supportedLocales;
//初始化方法 需要注意 這個(gè)初始化方法將默認(rèn)以設(shè)備當(dāng)前的語言環(huán)境作為語音識(shí)別的語言環(huán)境
- (nullable instancetype)init;
//初始化方法 設(shè)置一個(gè)特定的語言環(huán)境
- (nullable instancetype)initWithLocale:(NSLocale *)locale NS_DESIGNATED_INITIALIZER;
//語音識(shí)別是否可用
@property (nonatomic, readonly, getter=isAvailable) BOOLavailable;
//語音識(shí)別操作類協(xié)議代理
@property (nonatomic, weak) id delegate;
//設(shè)置語音識(shí)別的配置參數(shù) 需要注意 在每個(gè)語音識(shí)別請(qǐng)求中也有這樣一個(gè)屬性 這里設(shè)置將作為默認(rèn)值
//如果SFSpeechRecognitionRequest對(duì)象中也進(jìn)行了設(shè)置 則會(huì)覆蓋這里的值
/*
typedef NS_ENUM(NSInteger, SFSpeechRecognitionTaskHint) {
?SFSpeechRecognitionTaskHintUnspecified = 0,? // 無定義
?SFSpeechRecognitionTaskHintDictation = 1,? // 正常的聽寫風(fēng)格
?SFSpeechRecognitionTaskHintSearch = 2,?? // 搜索風(fēng)格
?SFSpeechRecognitionTaskHintConfirmation = 3, // 短語風(fēng)格
};
*/
@property (nonatomic) SFSpeechRecognitionTaskHint defaultTaskHint;
//使用回調(diào)Block的方式進(jìn)行語音識(shí)別請(qǐng)求 請(qǐng)求結(jié)果會(huì)在Block中傳入
- (SFSpeechRecognitionTask *)recognitionTaskWithRequest:(SFSpeechRecognitionRequest *)request
???????????resultHandler:(void(^)(SFSpeechRecognitionResult * __nullable result, NSError * __nullable error))resultHandler;
//使用代理回調(diào)的方式進(jìn)行語音識(shí)別請(qǐng)求
- (SFSpeechRecognitionTask *)recognitionTaskWithRequest:(SFSpeechRecognitionRequest *)request
????????????delegate:(id )delegate;
//設(shè)置請(qǐng)求所占用的任務(wù)隊(duì)列
@property (nonatomic, strong) NSOperationQueue *queue;
SFSpeechRecognizerDelegate協(xié)議中只約定了一個(gè)方法,如下:
//當(dāng)語音識(shí)別操作可用性發(fā)生改變時(shí)會(huì)被調(diào)用
- (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available;
??????? 通過Block回調(diào)的方式進(jìn)行語音識(shí)別請(qǐng)求十分簡(jiǎn)單止状,如果使用代理回調(diào)的方式烹棉,開發(fā)者需要實(shí)現(xiàn)SFSpeechRecognitionTaskDelegate協(xié)議中的相關(guān)方法,如下:
//當(dāng)開始檢測(cè)音頻源中的語音時(shí)首先調(diào)用此方法
- (void)speechRecognitionDidDetectSpeech:(SFSpeechRecognitionTask *)task;
//當(dāng)識(shí)別出一條可用的信息后 會(huì)調(diào)用
/*
需要注意怯疤,apple的語音識(shí)別服務(wù)會(huì)根據(jù)提供的音頻源識(shí)別出多個(gè)可能的結(jié)果 每有一條結(jié)果可用 都會(huì)調(diào)用此方法
*/
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription;
//當(dāng)識(shí)別完成所有可用的結(jié)果后調(diào)用
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult;
//當(dāng)不再接受音頻輸入時(shí)調(diào)用 即開始處理語音識(shí)別任務(wù)時(shí)調(diào)用
- (void)speechRecognitionTaskFinishedReadingAudio:(SFSpeechRecognitionTask *)task;
//當(dāng)語音識(shí)別任務(wù)被取消時(shí)調(diào)用
- (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task;
//語音識(shí)別任務(wù)完成時(shí)被調(diào)用
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishSuccessfully:(BOOL)successfully;
SFSpeechRecognitionTask類中封裝了屬性和方法如下:
//此任務(wù)的當(dāng)前狀態(tài)
/*
typedef NS_ENUM(NSInteger, SFSpeechRecognitionTaskState) {
?SFSpeechRecognitionTaskStateStarting = 0,? // 任務(wù)開始
?SFSpeechRecognitionTaskStateRunning = 1,? // 任務(wù)正在運(yùn)行
?SFSpeechRecognitionTaskStateFinishing = 2,? // 不在進(jìn)行音頻讀入 即將返回識(shí)別結(jié)果
?SFSpeechRecognitionTaskStateCanceling = 3,? // 任務(wù)取消
?SFSpeechRecognitionTaskStateCompleted = 4,? // 所有結(jié)果返回完成
};
*/
@property (nonatomic, readonly) SFSpeechRecognitionTaskState state;
//音頻輸入是否完成
@property (nonatomic, readonly, getter=isFinishing) BOOLfinishing;
//手動(dòng)完成音頻輸入 不再接收音頻
- (void)finish;
//任務(wù)是否被取消
@property (nonatomic, readonly, getter=isCancelled) BOOLcancelled;
//手動(dòng)取消任務(wù)
- (void)cancel;
關(guān)于音頻識(shí)別請(qǐng)求類浆洗,除了可以使用SFSpeechURLRecognitionRequest類來進(jìn)行創(chuàng)建外,還可以使用SFSpeechAudioBufferRecognitionRequest類來進(jìn)行創(chuàng)建:
@interface SFSpeechAudioBufferRecognitionRequest : SFSpeechRecognitionRequest
@property (nonatomic, readonly) AVAudioFormat *nativeAudioFormat;
//拼接音頻流
- (void)appendAudioPCMBuffer:(AVAudioPCMBuffer *)audioPCMBuffer;
- (void)appendAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer;
//完成輸入
- (void)endAudio;
@end
五集峦、語音識(shí)別結(jié)果類SFSpeechRecognitionResult
SFSpeechRecognitionResult類是語音識(shí)別結(jié)果的封裝伏社,其中包含了許多套平行的識(shí)別信息,其每一份識(shí)別信息都有可信度屬性來描述其準(zhǔn)確程度塔淤。SFSpeechRecognitionResult類中屬性如下:
//識(shí)別到的多套語音轉(zhuǎn)換信息數(shù)組 其會(huì)按照準(zhǔn)確度進(jìn)行排序
@property (nonatomic, readonly, copy) NSArray *transcriptions;
//準(zhǔn)確性最高的識(shí)別實(shí)例
@property (nonatomic, readonly, copy) SFTranscription *bestTranscription;
//是否已經(jīng)完成 如果YES 則所有所有識(shí)別信息都已經(jīng)獲取完成
@property (nonatomic, readonly, getter=isFinal) BOOLfinal;
SFSpeechRecognitionResult類只是語音識(shí)別結(jié)果的一個(gè)封裝摘昌,真正的識(shí)別信息定義在SFTranscription類中,SFTranscription類中屬性如下:
//完整的語音識(shí)別準(zhǔn)換后的文本信息字符串
@property (nonatomic, readonly, copy) NSString *formattedString;
//語音識(shí)別節(jié)點(diǎn)數(shù)組
@property (nonatomic, readonly, copy) NSArray *segments;
當(dāng)對(duì)一句完整的話進(jìn)行識(shí)別時(shí)凯沪,Apple的語音識(shí)別服務(wù)實(shí)際上會(huì)把這句語音拆分成若干個(gè)音頻節(jié)點(diǎn)第焰,每個(gè)節(jié)點(diǎn)可能為一個(gè)單詞买优,SFTranscription類中的segments屬性就存放這些節(jié)點(diǎn)妨马。SFTranscriptionSegment類中定義的屬性如下:
//當(dāng)前節(jié)點(diǎn)識(shí)別后的文本信息
@property (nonatomic, readonly, copy) NSString *substring;
//當(dāng)前節(jié)點(diǎn)識(shí)別后的文本信息在整體識(shí)別語句中的位置
@property (nonatomic, readonly) NSRange substringRange;
//當(dāng)前節(jié)點(diǎn)的音頻時(shí)間戳
@property (nonatomic, readonly) NSTimeInterval timestamp;
//當(dāng)前節(jié)點(diǎn)音頻的持續(xù)時(shí)間
@property (nonatomic, readonly) NSTimeInterval duration;
//可信度/準(zhǔn)確度 0-1之間
@property (nonatomic, readonly) floatconfidence;
//關(guān)于此節(jié)點(diǎn)的其他可能的識(shí)別結(jié)果
@property (nonatomic, readonly) NSArray *alternativeSubstrings;