iOS原生语音识别使用的正确姿势

作者: b9bd2a64f47e | 来源:发表于2016-12-09 23:19 被阅读7446次

语音识别技术这几年在移动App上的应用越来越广,各种第三方语音识别SDK也是层出不穷,例如科大讯飞、百度语音等,同时引入语音识别技术也是一个提高App逼格的好方法😁。所以今年的WWDC上,苹果开放了他的语音识别的API 视频在这。有了语音识别技术我们开发者就可以开发出像Siri这样炫酷的应用。我们最近也要上这个功能,所以调研一些这方面的东西。本文主要介绍iOS语音识别SDK的用法。

  • 首先需要在plist文件中申请语音识别和麦克风使用权限:


  • 引入头文件
#import <Speech/Speech.h>
#import <AVFoundation/AVFoundation.h>
  • 申请权限
 - (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    __weak typeof(self) weakSelf = self;
    [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
        dispatch_async(dispatch_get_main_queue(), ^{
            switch (status) {
                case SFSpeechRecognizerAuthorizationStatusNotDetermined:
                    weakSelf.recordButton.enabled = NO;
                    [weakSelf.recordButton setTitle:@"语音识别未授权" forState:UIControlStateDisabled];
                    break;
                case SFSpeechRecognizerAuthorizationStatusDenied:
                    weakSelf.recordButton.enabled = NO;
                    [weakSelf.recordButton setTitle:@"用户未授权使用语音识别" forState:UIControlStateDisabled];
                    break;
                case SFSpeechRecognizerAuthorizationStatusRestricted:
                    weakSelf.recordButton.enabled = NO;
                    [weakSelf.recordButton setTitle:@"语音识别在这台设备上受到限制" forState:UIControlStateDisabled];
                    
                    break;
                case SFSpeechRecognizerAuthorizationStatusAuthorized:
                    weakSelf.recordButton.enabled = YES;
                    [weakSelf.recordButton setTitle:@"开始录音" forState:UIControlStateNormal];
                    break;
                    
                default:
                    break;
            }
  
        });
    }];
}
  • 核心代码
    • 识别实时音频流,如下
   - (void)startRecording{
        if (_recognitionTask) {
           [_recognitionTask cancel];
            _recognitionTask = nil;
         }
    
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *error;
    [audioSession setCategory:AVAudioSessionCategoryRecord error:&error];
    NSParameterAssert(!error);
    [audioSession setMode:AVAudioSessionModeMeasurement error:&error];
    NSParameterAssert(!error);
    [audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
    NSParameterAssert(!error);
    
    _recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
    AVAudioInputNode *inputNode = self.audioEngine.inputNode;
    NSAssert(inputNode, @"录入设备没有准备好");
    NSAssert(_recognitionRequest, @"请求初始化失败");
    _recognitionRequest.shouldReportPartialResults = YES;
    __weak typeof(self) weakSelf = self;
    _recognitionTask = [self.speechRecognizer recognitionTaskWithRequest:_recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        BOOL isFinal = NO;
        if (result) {
            strongSelf.resultStringLable.text = result.bestTranscription.formattedString;
            isFinal = result.isFinal;
        }
        if (error || isFinal) {
            [self.audioEngine stop];
            [inputNode removeTapOnBus:0];
            strongSelf.recognitionTask = nil;
            strongSelf.recognitionRequest = nil;
            strongSelf.recordButton.enabled = YES;
            [strongSelf.recordButton setTitle:@"开始录音" forState:UIControlStateNormal];
        }
     
    }];
    
    AVAudioFormat *recordingFormat = [inputNode outputFormatForBus:0];
//在添加tap之前先移除上一个  不然有可能报"Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio',"之类的错误
    [inputNode removeTapOnBus:0];
    [inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (strongSelf.recognitionRequest) {
            [strongSelf.recognitionRequest appendAudioPCMBuffer:buffer];
        }
    }];
    
    [self.audioEngine prepare];
    [self.audioEngine startAndReturnError:&error];
     NSParameterAssert(!error);
    self.resultStringLable.text = @"正在录音。。。";
}
   - (SFSpeechRecognizer *)speechRecognizer{
    if (!_speechRecognizer) {
        //要为语音识别对象设置语言,这里设置的是中文
        NSLocale *local =[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"];
        
        _speechRecognizer =[[SFSpeechRecognizer alloc] initWithLocale:local];
        _speechRecognizer.delegate = self;
    }
    return _speechRecognizer;
}
  • 识别本地音频文件,如下
   - (IBAction)recognizeLocalAudioFile:(UIButton *)sender {   
//此处设置支持的语言
 NSLocale *local =[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"];
    SFSpeechRecognizer *localRecognizer =[[SFSpeechRecognizer alloc] initWithLocale:local];
    NSURL *url =[[NSBundle mainBundle] URLForResource:@"录音.m4a" withExtension:nil];
    if (!url) return;
    SFSpeechURLRecognitionRequest *res =[[SFSpeechURLRecognitionRequest alloc] initWithURL:url];
    __weak typeof(self) weakSelf = self;
    [localRecognizer recognitionTaskWithRequest:res resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
        if (error) {
            NSLog(@"语音识别解析失败,%@",error);
        }
        else
        {
            weakSelf.resultStringLable.text = result.bestTranscription.formattedString;
        }
    }];
}
  • 注意
  • iOS语音识别Api只支持iOS10SDK以及以后的版本,开发工具至少要Xcode8.0。
  • 本文的Demo在这里下载,要看效果的话要在真机上运行。
  • 谢谢阅读此文,希望它能对你有用。

2018-03-30 更新:修复iOS11状态栏菊花一直有的bug。。。。

相关文章

网友评论

  • s超s:识别的文字没有标点符号怎么办
  • cb1834dc35e9:你好,真机设备iPad air2系统iOS11.4可以,iphone6系统11.3识别不了语音求解。
    cb1834dc35e9:iphone6 联网条件下可以识别,离线不行,ipad都可以。
  • XP_Swf:完全复制粘贴过来的 开始语音识别就挂了 识别本地的也一样 求解?
    b9bd2a64f47e:文章更新了,看看最后
    b9bd2a64f47e:系统版本是多少?
  • 9db7176081e9:录音没有识别 只是停止录音,然后识别结果那什么都没有
    b9bd2a64f47e:@zn_1ea9 我在iOS11 和iOS 10 上试了下,没复现这个问题。你的系统版本是多少?说话的时候离麦克风多近?
  • 张科_Zack:楼主本地语音文件识别失败 菊花一直转 ,调用 cancel 也取消不了
    张科_Zack:@星星Y灬 目前换没有
    b9bd2a64f47e:@张科_dbb8 问题解决了吗?
    张科_Zack:我在 您demo 基础上测试的,如果是SFSpeechAudioBufferRecognitionRequest 实时识别的,cancel 就管用,如果 是语音文件识别 cancel 后菊花还是一直在转
  • 5f11c1252322:请问识别文件的话需要联网吗,还是离线识别的?
  • 0206b277d36d:你好 ,你这个打开关闭语音识别以后,状态栏小菊花一直转....我试过几个方法 关不掉,请您看看 谢谢!
    b9bd2a64f47e:@Coder_LiSir :+1: 我也是stop的时候加了task cancel。
    0206b277d36d:@星星Y灬 好的 谢谢,我下一个,开始我自己后面加了一个 task cancel 方法,好像也没出现这个问题了
    b9bd2a64f47e:看了下 在iOS11上确实有这个问题,我更新demo了,你下载下
  • f6102da5268d:想知道能一边录音成音频文件, 一边识别吗?
    看了一下category,好像会有冲突呀.
  • 无效_昵称已经被使用:10.0才能用 没啥软用啊
    b9bd2a64f47e:10以上的系统已经占到70%,11还没发布呢。APP可以10为界限分别处理啊。。目前很多APP用了原生的语音识别库,过两年估计就支持10以上的了。再者至少可以拿来和其他框架比较下准确率,多一个选择
  • 码农淏:拿走了,谢谢
  • 356a6ddcce5c:你githup 上的demo怎么下载不了啊 :sob:
    356a6ddcce5c:@星星Y灬 可以了 谢谢!!!当时可能网络问题
    b9bd2a64f47e:gitHub 上的其他项目可以下载吗
    b9bd2a64f47e:刚试了下 可以啊,有截图吗,提示啥啊:sweat:
  • 5e99e81683aa:*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: _recordingTap == nil'

    运行的时候一说话会报这样的错误。。。求解啊大神
    5e99e81683aa:@星星Y灬 好的。。我试试
    b9bd2a64f47e:我更新了文章,你看看最新的,加了行代码:[inputNode removeTapOnBus:0]; 自己看吧
  • 出门右转掘金见:请问如果要在中文里插入英文可以吗
  • 早已变旧的时光:-(void)finishRec
    {
    if (self.audioEngine.isRunning)
    {
    [self.audioEngine stop];
    if (_recognitionRequest) {
    [_recognitionRequest endAudio];
    }
    NSLog(@"正在停止");
    }
    }
    大哥为啥我这么结束会崩啊。。😖
    0206b277d36d:请问开启了语音识别 关闭以后,小菊花还一直转 取消不了,这个怎么解决呢
    早已变旧的时光:@啟星 是啊,我知道了。。。
    -(void)finishRec
    {
    if (_recognitionTask) {
    [_recognitionTask cancel];
    _recognitionTask = nil;
    }
    if (self.audioEngine.isRunning)
    {

    [self.audioEngine stop];
    if (_recognitionRequest) {
    [_recognitionRequest endAudio];
    }
    NSLog(@"正在停止");
    }

    }
    我这样写就好了。。
    b9bd2a64f47e:@早已变旧的时光 是真机吗
  • kongkk: 我的项目中除了导入上面两个头文件之外,还得在项目的Build Phases中的Link Binary With Libraries中添加Speech.framework库才能编译通过,不然提示找不到SFSpeechRecognizer这个类,估计是新加的吧。
    b9bd2a64f47e:@蜡泪再塑 正常情况下,xcode会自动链接的不需要手动加的。当然也有其他情况,可能是你的xcode设置了什么。。。。。能用就好,不必纠结这个,有时候xcode也有bug
  • 4090dea7ba26:能识别其他国家语言吗?除了中文和英文,像日语,韩语……
    kongkk:我的项目中除了导入上面两个头文件之外,还得在项目的Build Phases中的Link Binary With Libraries中添加Speech.framework库才能编译通过,不然提示找不到SFSpeechRecognizer这个类,估计是新加的吧。
    b9bd2a64f47e:世界上大部分语言都支持,好像是50多种,可以自己设置,文中有示例代码。
  • Rchongg:原生的识别率咋样
    0206b277d36d:请问下 开启了语音识别 状态栏小菊花一直转怎么解决呢?
    顾顾314:请问有没有静默时间?比如我说了一句话,暂停10s 不再说话,此时录音自动停止.
    b9bd2a64f47e:@Rchongg 跟科大讯飞对比了一下,发现跟科大讯飞不相上下,现在的语音识别SDK识别率大都在90%以上,差个1%、4%的感受不出来,你也可以下载文末的Demo感受一下

本文标题:iOS原生语音识别使用的正确姿势

本文链接:https://www.haomeiwen.com/subject/vijymttx.html