Speech Framework 是Apple公司在2016年WWDC上介紹的一個語音識別的API。它是Siri用來做語音識別的框架。在你的應(yīng)用里面可以使用 Speech APIs 來拓展和提高語音識別功能,而不僅僅是單純的使用鍵盤。
Speech APIs的執(zhí)行需要使用一個設(shè)備內(nèi)置的語音識別器和連接到蘋果的服務(wù)器。如果發(fā)現(xiàn)語音識別器是用于一個特定的語言,例如英文、國語等,可以采用 SFSpeechRecognizerDelegate 協(xié)議。
因?yàn)槟愕膽?yīng)用可能需要連接到服務(wù)器進(jìn)行識別,而這涉及到尊重用戶的隱私問題,出于這個原因,我們在啟動語音識別功能之前必須得到用戶的明確許可。
做了一個demo,使用Speech Framework 實(shí)現(xiàn)語音轉(zhuǎn)文字的功能。
上面這個效果圖中的文字是識別我的話轉(zhuǎn)出來的,接下來我們來實(shí)現(xiàn)一下。
1.我們要寫個句子告訴用戶在應(yīng)用中可以如何使用這個語音功能。
例如,在這個例子中寫了這么一句提示的話"Lets you mark an item as finished by saying Done."。
2.在 Info.plist
里面添加兩個鍵值對,分別是Privacy - Speech Recognition Usage Description
(用于請求語音識別) 以及 Privacy - Microphone Usage Description
(用于請求麥克風(fēng)語音輸入授權(quán))。
3.創(chuàng)建 SFSpeechRecognizer
對象,使用 requestAuthorization:
去申請用戶語音識別權(quán)限 。
@property (nonatomic,strong)SFSpeechRecognizer *speechRecognizer;
在viewDidLoad:
中初始化 speechRecognizer
對象,并設(shè)置代理。
// zh-CN 代表是簡體中文
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-CN"];
_speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
//把語音識別的代理設(shè)置為 self
_speechRecognizer.delegate = self;
申請用戶語音識別權(quán)限
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
BOOL isButtonEnable = NO;
//檢查驗(yàn)證的狀態(tài)。如果被授權(quán)了,讓microphone按鈕有效。如果沒有,打印錯誤信息然后讓microphone按鈕失效。
switch (status) {
case SFSpeechRecognizerAuthorizationStatusAuthorized:
{
isButtonEnable = YES;
NSLog(@"用戶授權(quán)語音識別");
}
break;
case SFSpeechRecognizerAuthorizationStatusDenied:
{
isButtonEnable = NO;
NSLog(@"用戶拒絕授權(quán)語音識別");
}
break;
case SFSpeechRecognizerAuthorizationStatusRestricted:
{
isButtonEnable = NO;
NSLog(@"設(shè)備不支持語音識別功能");
}
break;
case SFSpeechRecognizerAuthorizationStatusNotDetermined:
{
isButtonEnable = NO;
NSLog(@"結(jié)果未知 用戶尚未進(jìn)行選擇");
}
break;
}
運(yùn)行后我們會發(fā)現(xiàn)授權(quán)請示如下:
4.在用戶允許通過語音識別和麥克風(fēng)授權(quán)之后,寫一個方發(fā)startRecording
用于語音識別請求。
//實(shí)例化recognitionRequest。在這里我們創(chuàng)建了SFSpeechAudioBufferRecognitionRequest對象。稍后我們利用它把語音數(shù)據(jù)傳到蘋果后臺
_recognitionRequest = [SFSpeechAudioBufferRecognitionRequest new];
//當(dāng)用戶說話的時候讓recognitionRequest報告語音識別的部分結(jié)果
_recognitionRequest.shouldReportPartialResults = YES;
//調(diào)用 speechRecognizer的recognitionTask 方法來開啟語音識別。這個方法有一個completion handler回調(diào)。這個回調(diào)每次都會在識別引擎收到輸入的時候,完善了當(dāng)前識別的信息時候,或者被刪除或者停止的時候被調(diào)用,最后會返回一個最終的文本 (進(jìn)行請求)
_recognitionTask = [_speechRecognizer recognitionTaskWithRequest:_recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
//定義一個布爾值決定識別是否已經(jīng)結(jié)束
BOOL isFinal = NO;
//如果結(jié)果 result 不是nil, 把 textView.text 的值設(shè)置為我們的最優(yōu)文本。如果結(jié)果是最終結(jié)果,設(shè)置 isFinal為true
if (result != nil) {
self.textView.text = result.bestTranscription.formattedString;
isFinal = result.isFinal;
}
//如果沒有錯誤或者結(jié)果是最終結(jié)果,停止 audioEngine(語音輸入)并且停止 recognitionRequest 和 recognitionTask.同時,使Start Recording按鈕有效
if (error != nil || isFinal) {
[self.audioEngine stop];
[inputNode removeTapOnBus:0];
self.recognitionRequest = nil;
self.recognitionTask = nil;
self.microphoneButton.enabled = YES;
}
}];
在開始了recognitionTask之后向 recognitionRequest增加一個語音輸入。Speech Framework 會在語音輸入被加入的同時就開始進(jìn)行解析識別
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
[audioSession setMode:AVAudioSessionModeMeasurement error:nil];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
//檢查 audioEngine(你的設(shè)備)是否有做錄音功能作為語音輸入
AVAudioInputNode *inputNode = [_audioEngine inputNode];
if (!inputNode) {
NSLog(@"Audio engine has no input node");
}
AVAudioFormat *recordingFormat = [inputNode outputFormatForBus:0];
[inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[self.recognitionRequest appendAudioPCMBuffer:buffer];
}];
準(zhǔn)備并且開始audioEngine,并讓textView的文本為 "Say something, I'm listening!"。
[_audioEngine prepare];
[_audioEngine startAndReturnError:nil];
_textView.text = @"Say something, I'm listening!";
我們讓當(dāng)前視圖控制器作為speechRecognizer
的代理,在SFSpeechRecognizerDelegate
中有可選的speechRecognizer:availabilityDidChange:
方法,實(shí)現(xiàn)一下。
//當(dāng)語音識別操作可用性發(fā)生改變時會被調(diào)用
- (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available{
if (available) {
_microphoneButton.enabled = YES;
}
else{
_microphoneButton.enabled = NO;
}
}
下面是一些LocaleIdentifier
,可以參考一下需要的語言。
到此,使用Speech Framework實(shí)現(xiàn)了語音轉(zhuǎn)文字功能實(shí)現(xiàn)了。