Speech Framework 是Apple公司在2016年WWDC上介绍的一个语音识别的API。它是Siri用来做语音识别的框架。在你的应用里面可以使用 Speech APIs 来拓展和提高语音识别功能,而不仅仅是单纯的使用键盘。
Speech APIs的执行需要使用一个设备内置的语音识别器和连接到苹果的服务器。如果发现语音识别器是用于一个特定的语言,例如英文、国语等,可以采用 SFSpeechRecognizerDelegate 协议。
因为你的应用可能需要连接到服务器进行识别,而这涉及到尊重用户的隐私问题,出于这个原因,我们在启动语音识别功能之前必须得到用户的明确许可。
做了一个demo,使用Speech Framework 实现语音转文字的功能。
上面这个效果图中的文字是识别我的话转出来的,接下来我们来实现一下。
1.我们要写个句子告诉用户在应用中可以如何使用这个语音功能。
例如,在这个例子中写了这么一句提示的话"Lets you mark an item as finished by saying Done."。
2.在 Info.plist
里面添加两个键值对,分别是Privacy - Speech Recognition Usage Description
(用于请求语音识别) 以及 Privacy - Microphone Usage Description
(用于请求麦克风语音输入授权)。
3.创建 SFSpeechRecognizer
对象,使用 requestAuthorization:
去申请用户语音识别权限 。
@property (nonatomic,strong)SFSpeechRecognizer *speechRecognizer;
在viewDidLoad:
中初始化 speechRecognizer
对象,并设置代理。
// zh-CN 代表是简体中文
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-CN"];
_speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
//把语音识别的代理设置为 self
_speechRecognizer.delegate = self;
申请用户语音识别权限
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
BOOL isButtonEnable = NO;
//检查验证的状态。如果被授权了,让microphone按钮有效。如果没有,打印错误信息然后让microphone按钮失效。
switch (status) {
case SFSpeechRecognizerAuthorizationStatusAuthorized:
{
isButtonEnable = YES;
NSLog(@"用户授权语音识别");
}
break;
case SFSpeechRecognizerAuthorizationStatusDenied:
{
isButtonEnable = NO;
NSLog(@"用户拒绝授权语音识别");
}
break;
case SFSpeechRecognizerAuthorizationStatusRestricted:
{
isButtonEnable = NO;
NSLog(@"设备不支持语音识别功能");
}
break;
case SFSpeechRecognizerAuthorizationStatusNotDetermined:
{
isButtonEnable = NO;
NSLog(@"结果未知 用户尚未进行选择");
}
break;
}
运行后我们会发现授权请示如下:
4.在用户允许通过语音识别和麦克风授权之后,写一个方发startRecording
用于语音识别请求。
//实例化recognitionRequest。在这里我们创建了SFSpeechAudioBufferRecognitionRequest对象。稍后我们利用它把语音数据传到苹果后台
_recognitionRequest = [SFSpeechAudioBufferRecognitionRequest new];
//当用户说话的时候让recognitionRequest报告语音识别的部分结果
_recognitionRequest.shouldReportPartialResults = YES;
//调用 speechRecognizer的recognitionTask 方法来开启语音识别。这个方法有一个completion handler回调。这个回调每次都会在识别引擎收到输入的时候,完善了当前识别的信息时候,或者被删除或者停止的时候被调用,最后会返回一个最终的文本 (进行请求)
_recognitionTask = [_speechRecognizer recognitionTaskWithRequest:_recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
//定义一个布尔值决定识别是否已经结束
BOOL isFinal = NO;
//如果结果 result 不是nil, 把 textView.text 的值设置为我们的最优文本。如果结果是最终结果,设置 isFinal为true
if (result != nil) {
self.textView.text = result.bestTranscription.formattedString;
isFinal = result.isFinal;
}
//如果没有错误或者结果是最终结果,停止 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 会在语音输入被加入的同时就开始进行解析识别
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
[audioSession setMode:AVAudioSessionModeMeasurement error:nil];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
//检查 audioEngine(你的设备)是否有做录音功能作为语音输入
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];
}];
准备并且开始audioEngine,并让textView的文本为 "Say something, I'm listening!"。
[_audioEngine prepare];
[_audioEngine startAndReturnError:nil];
_textView.text = @"Say something, I'm listening!";
我们让当前视图控制器作为speechRecognizer
的代理,在SFSpeechRecognizerDelegate
中有可选的speechRecognizer:availabilityDidChange:
方法,实现一下。
//当语音识别操作可用性发生改变时会被调用
- (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available{
if (available) {
_microphoneButton.enabled = YES;
}
else{
_microphoneButton.enabled = NO;
}
}
下面是一些LocaleIdentifier
,可以参考一下需要的语言。
到此,使用Speech Framework实现了语音转文字功能实现了。