使用iOS语言识别以及语言合成遇到的坑

语音识别

坑一、授权的几个枚举一定要注意千万别写错了,细心点莫有问题!!

语音合成

iOS7.0 后苹果推出的
神坑、在设置AVAudioSession的分类是一定要注意其类型。

/*  使用这一类别的背景声音,如雨,汽车引擎噪音等。混合与其他音乐。 */
AVAudioSessionCategoryAmbient;
/*  使用这个类别作为背景声音。其他音乐也会停止演奏。*/
AVAudioSessionCategorySoloAmbient;
/* 用这一类别来播放音乐。*/
AVAudioSessionCategoryPlayback;
/*  在录制音频时使用这个类别.*/
AVAudioSessionCategoryRecord;
/*  在录制和回放音频时使用这一类别。 */
AVAudioSessionCategoryPlayAndRecord;
/* 当使用硬件编解码器或信号处理器时,请使用这一类别不播放或录制音频。 */
AVAudioSessionCategoryAudioProcessing
//设置方法,因为我们还需要识别播放,所以选择这个AVAudioSessionCategoryPlayAndRecord类型,使用别的播放会报错 Failure starting audio queue
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];

注意:使用AVAudioSessionCategoryPlayAndRecord类型默认是听筒播放,设置为扬声器有两种方法:

方法一:可以用该方法来实现听筒和扬声器切换播放
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
方法二
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];

1、获取权限,将下面的代码放到Info.plist中

<key>NSMicrophoneUsageDescription</key> <string>App需要您的同意,才能访问麦克风</string> <key>NSSpeechRecognitionUsageDescription</key> <string>App需要您的同意,才能使用语音识别技术</string>

2、几个注意

//请求授权使用的枚举
//SFSpeechRecognizerAuthorizationStatusNotDetermined  : 语音识别未授权
//SFSpeechRecognizerAuthorizationStatusDenied :用户未授权使用语音识别
//SFSpeechRecognizerAuthorizationStatusRestricted :语音识别在这台设备上受到限制
//SFSpeechRecognizerAuthorizationStatusAuthorized :已授权

详解AVAudioSession参考:(http://www.jianshu.com/p/331a4455ba7f

3、全部代码

//
//  SpeechRecognitionViewController.m
//  SpeechRecognition
//
//  Created by 李东 on 2017/8/22.
//  Copyright © 2017年 LD. All rights reserved.
//

#import "SpeechRecognitionViewController.h"
#import <Speech/Speech.h>
#import <AVFoundation/AVFoundation.h>

@interface SpeechRecognitionViewController () <SFSpeechRecognizerDelegate>
//开始录音按钮
@property (weak, nonatomic) IBOutlet UIButton *recordButton;
//展示结果
@property (weak, nonatomic) IBOutlet UILabel *showResults;
//语音识别器
@property (nonatomic, strong) SFSpeechRecognizer *speechRecognizer;
// 语音识别任务,可监控识别进度。通过他可以取消或终止当前的语音识别任务
@property (nonatomic, strong) SFSpeechRecognitionTask *speechRecognitionTask;
// 语音引擎,负责提供录音输入
@property (nonatomic,strong) AVAudioEngine *audioEngine;
//从任意缓存中获取语音的识别请求
// 发起语音识别请求,为语音识别器指定一个音频输入源,这里是在音频缓冲器中提供的识别语音。
// SFSpeechAudioBufferRecognitionRequest 从任意缓存中获取语音的识别请求
// SFSpeechRecognitionRequest  从音频源识别语音的请求。
// SFSpeechURLRecognitionRequest 在录制的音频文件中识别语音的请求。
@property (nonatomic,strong) SFSpeechAudioBufferRecognitionRequest *recognitionRequest;
//语音合成器,负责文本转语音的播放
@property (nonatomic, strong) AVSpeechSynthesizer * avSS;


@end

@implementation SpeechRecognitionViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _recordButton.enabled = NO;
    // Do any additional setup after loading the view from its nib.
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    //请求授权,使用的枚举
    //SFSpeechRecognizerAuthorizationStatusNotDetermined  : 语音识别未授权
    //SFSpeechRecognizerAuthorizationStatusDenied :用户未授权使用语音识别
    //SFSpeechRecognizerAuthorizationStatusRestricted :语音识别在这台设备上受到限制
    //SFSpeechRecognizerAuthorizationStatusAuthorized :已授权
    __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;
            }
        });
    }];
}

//录音按钮点击方法
- (IBAction)recordButtonClick:(UIButton *)sender {
    if (self.audioEngine.isRunning) {
        // 停止录音
        [self.audioEngine stop];
        if (_recognitionRequest) {
            [_recognitionRequest endAudio];
        }
        self.recordButton.enabled = NO;
        [self.recordButton setTitle:@"正在停止。。。" forState: UIControlStateDisabled];
    } else {
        [self startRecording];
        [self.recordButton setTitle:@"停止录音" forState:UIControlStateNormal];
    }
    
}
//播放识别后的文本
- (IBAction)stratPlaySpeech:(id)sender {
    
    [self readingAloudWithString:self.showResults.text language:@"zh-CN"];
    
}
//设置为扬声器播放
- (IBAction)setupeRceiver:(id)sender {
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
}
//设置听筒播放
- (IBAction)setupSpeaker:(id)sender {
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
}

//开始录音方法
- (void)startRecording {
    //判断上一个任务是否还在,制空
    if (_speechRecognitionTask) {
        [_speechRecognitionTask cancel];
        _speechRecognitionTask = nil;
    }
    //创建录音session
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *error;
    //设置会话的类别,默认是听筒播放
    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
    //设置为扬声器播放
    //[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
    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;
    _speechRecognitionTask = [self.speechRecognizer recognitionTaskWithRequest:_recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        BOOL isFinall = NO;
        if (result) {
            //拿到全部的结果
//            NSLog(@"%@", result);
//            NSLog(@"%@", result.bestTranscription.formattedString);
            //strongSelf.showResults.text = result.bestTranscription.formattedString;
            //根据result.isFinal判断是不是最后的结果
            isFinall = result.isFinal;
            if (result.isFinal) {
                NSLog(@"我是最后的结果");
                strongSelf.showResults.text = result.bestTranscription.formattedString;
            }
        }
        if (error || isFinall) {
            [strongSelf.audioEngine stop];
            [inputNode removeTapOnBus:0];
            strongSelf.recognitionRequest = nil;
            strongSelf.speechRecognitionTask = 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.showResults.text = @"正在录音。。。";
    
}
//使用系统的语音合成
- (void)readingAloudWithString:(NSString *)str language: (NSString *)language{
    //说话的内容
    AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:str];
    //语调0.5到2,默认1
    utterance.pitchMultiplier = 1;
    //语速 0到1,默认是0.5
    utterance.rate = 0.5;
    //音量
    utterance.volume = 1;
    
    AVSpeechSynthesisVoice *voiceType = [AVSpeechSynthesisVoice voiceWithLanguage:language];
    
    utterance.voice = voiceType;
    [self.avSS speakUtterance:utterance];
    
}


#pragma mark - 懒加载

//语音合成器
- (AVSpeechSynthesizer *)avSS {
    if (!_avSS) {
        _avSS = [[AVSpeechSynthesizer alloc] init];
        _avSS.delegate = self;
    }
    return _avSS;
}
//语音引擎,负责提供录音输入
- (AVAudioEngine *)audioEngine {
    if (!_audioEngine) {
        _audioEngine = [[AVAudioEngine alloc] init];
    }
    return _audioEngine;
}
//懒加载语音识别器
- (SFSpeechRecognizer *)speechRecognizer {
    if (!_speechRecognizer) {
        //为识别语音设置语言这里暂时设置为中文
        NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-CN"];
        _speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
        _speechRecognizer.delegate = self;
    }
    return _speechRecognizer;
}


#pragma mark - SFSpeechRecognizerDelegate

- (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available {
    if (available) {
        self.recordButton.enabled = YES;
        [self.recordButton setTitle:@"开始录音" forState: UIControlStateNormal];
    } else {
        self.recordButton.enabled = NO;
        [self.recordButton setTitle:@"语音识别不可用" forState:UIControlStateDisabled];
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

详细的语音合成下篇文章给大家介绍,有问题希望大家积极留言,刚刚加入简书,希望大家多多支持。dmeo地址就不留了,整个代码复制就能运行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容