之前做的项目中有语音识别的需求, 是用讯飞语音SDK实现的。 有很多服务商提供声音转文字的服务,有收费的有免费。
2016年苹果在发布的上iOS10增加了一个语音识别功能,并且将其封装到了SpeechFramework库中。苹果手机上Siri的语音识别就是基于Speech实现的。
下面就开始动手敲代码实践录音和Speech的用法吧
1. 引入Speech 和AVFoundation
#import <AVFoundation/AVFoundation.h> // 录音
#import <Speech/Speech.h> // 语音识别
2. 申请用户权限
想要使用录音和语音识别功能必须先配置info.plist文件,在其中增加麦克风和语音识别授权属性
<key>NSMicrophoneUsageDescription</key>
<string>App需要您的同意,才能使用麦克风</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>App需要您的同意,才能使用语音识别</string>
加完之后是这样的
3. 录音
- 激活AVAudioSession
_session = [AVAudioSession sharedInstance];
NSError *categoryError = nil;
//设置为播放和录音状态,以便可以在录制完之后播放录音
[_session setCategory:AVAudioSessionCategoryPlayAndRecord error:&categoryError];
if (_session) {
[_session setActive:YES error:nil]; // 此处手动激活
}
else {
NSLog(@"Error creating session: %@",[categoryError description]);
}
- 创建录音器, 设置代理(可以监听录制的状态)
- (void)createAudioRecorder
{
// 实例化录音器对象
NSError *errorRecord = nil;
_recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL fileURLWithPath:_filePath] settings:[self getAudioSetting] error:&errorRecord];
_recorder.delegate = self;
_recorder.meteringEnabled = YES; //如果要监控声波则必须设置为YES
// 准备录音
[_recorder prepareToRecord];
}
- 实例化录音对象, 要设置音频的编码参数
- (NSDictionary *)getAudioSetting
{
//录音设置
NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];
//音频质量,采样质量
[recordSettings setValue:[NSNumber numberWithInt:AVAudioQualityMax] forKey:AVEncoderAudioQualityKey];
//通道数 编码时每个通道的比特率
[recordSettings setValue:[NSNumber numberWithInt:2] forKey: AVNumberOfChannelsKey];
//录音格式 无法使用
// [recordSettings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey: AVFormatIDKey];
//LinearPCM 是iOS的一种无损编码格式,但是体积较为庞大
//采样率
[recordSettings setValue:[NSNumber numberWithFloat:44100.0] forKey: AVSampleRateKey];//44100.0
//线性采样位数
[recordSettings setValue:[NSNumber numberWithInt:32] forKey: AVLinearPCMBitDepthKey];
// 编码时的比特率,是每秒传送的比特(bit)数单位为bps(Bit Per Second),比特率越高传送数据速度越快值是一个整数
[recordSettings setValue:[NSNumber numberWithInt:128000] forKey:AVEncoderBitRateKey];
return recordSettings;
}
- 开始录制
- (void)recorderSoundStart:(NSString *)path
{
// 停止播放
[self stopPlayRecorderSound];
// 停止之前的录音
if ([_recorder isRecording]) {
[_recorder stop];
}
// 删除旧的录音文件
[APPUtil deleteFile:path];
// 不删除也可以, 同一会路径下会被覆盖
if (!_recorder) {
// 实例化录音对象
[self createAudioRecorder];
}
if (![_recorder isRecording]){
[_recorder record];
// 设定 录制 最长时间 60s
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self recorderSoundEnd];
});
}
}
- 由于设置了最长录制时间60s, 所以要加上下面录制完成代理代码
#pragma mark - AVAudioRecorderDelegate 录音机代理方法
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
NSLog(@"录音完成!");
[self recorderSoundEnd];
}
- 停止录制 , 在停止录制之前, 可能会有暂停录制,此处略过
- (void)recorderSoundEnd
{
// 停止录音
if ([_recorder isRecording]) {
[_recorder stop];
// [_recorder pause]; // 暂停录制
}
// 更新UI按钮
_recodeSound.selected = NO;
}
- 开始播放及停止播放
// 播放
- (void)recorderSoundPlay:(NSString *)path
{
// 先停止录音
if (_recorder) {
[_recorder stop];
}
if (!_player) {
// 创建播放器
[self createAudioPlayer];
}
[_session setCategory:AVAudioSessionCategoryPlayback error:nil];
// 播放
[_player play];
}
// 停止
- (void)stopPlayRecorderSound
{
if ([_player isPlaying]) {
[_player stop];
}
// 更新UI播放按钮
_playSound.selected = NO;
}
4. 语音识别
语音识别是iOS10增加的新特性,Xcode8之前的版本没有SpeechFramework库,所以此功能只能在Xcode8以上和iOS10以上运行。
- 请求语音识别权限
// 请求语音识别权限
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
NSLog(@"status %@", status == SFSpeechRecognizerAuthorizationStatusAuthorized ? @"语音识别权限授权成功" : @"语音识别权限授权失败"); }];
所谓语音识别, 就是用户说话然后马上把用户说的话转成文字显示!这才是理想中的语音识别, 当然也是支持识别一个本地音频文件
打开Speech kit
库,找到语音识别请求文件 SFSpeechRecognitionRequest.h
, 发现 识别请求的API有两种 SFSpeechAudioBufferRecognitionRequest
和 SFSpeechURLRecognitionRequest
都继承于SFSpeechRecognitionRequest
类
-
SFSpeechAudioBufferRecognitionRequest
实时识别音频流 也就是现说现译 -
SFSpeechURLRecognitionRequest
识别路径URL的音频文件
既然语音识别配置工作上面都已经做好了, 下面就看下这两种识别请求吧 ()
5. 语音识别--现说现译
- 激活AVAudioSession
_session = [AVAudioSession sharedInstance];
[_session setCategory:AVAudioSessionCategoryRecord mode:AVAudioSessionModeMeasurement options:AVAudioSessionCategoryOptionDuckOthers error:nil];
[_session setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
AVAudioSessionCategoryRecord
: 设置录音(现说现译, 要录制说的话)
AVAudioSessionModeMeasurement
:减少系统提供信号对应用程序输入和/或输出音频信号的影响
AVAudioSessionCategoryOptionDuckOthers
: 在实时通话的场景,降低别的声音。比如QQ音乐,当进行视频通话的时候,会发现QQ音乐自动声音降低了,此时就是通过设置这个选项来对其他音乐App进行了压制
AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
:判断当前是否有其他App在播放音频
- 多媒体引擎的建立
- (void)createAudioEngine
{
if (!_speechRecognizer) {
// 设置语言
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"zh-CN"];
_speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
}
// 初始化引擎
if (!_audioEngine) {
_audioEngine = [[AVAudioEngine alloc] init];
}
}
- 创建语音识别请求, 创建并开启语音识别任务
// 创建语音识别请求
- (void)createSpeechRequest
{
if (_speechRequest) {
[_speechRequest endAudio];
_speechRequest = nil;
}
_speechRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
_speechRequest.shouldReportPartialResults = YES; // 实时翻译
__weak typeof(self) weakSelf = self;
// 建立语音识别任务, 并启动. block内为语音识别结果回调
[_speechRecognizer recognitionTaskWithRequest:_speechRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
// 语音识别结果回调
__strong typeof(weakSelf) strongSelf = weakSelf;
if (error) {
NSLog(@"语音识别解析失败,%@",error);
}
else {
// 识别的内容
NSString *text = result.bestTranscription.formattedString;
// 实时打印说话的内容
NSLog(@"is final: %d result: %@", result.isFinal, result.bestTranscription.formattedString);
if (result.isFinal) { // 结束时 显示内容
// 显示说话的内容
strongSelf.content.text = text;
// 多次说话的内容拼接到一起显示
// strongSelf.content.text = [NSString stringWithFormat:@"%@%@", strongSelf.content.text, text];
}
}
}];
}
语音识别任务及回调结果有2中实现方法, 一种是代理, 一种block, 此处选择了block
// Recognize speech utterance with a request
// If request.shouldReportPartialResults is true, result handler will be called
// repeatedly with partial results, then finally with a final result or an error.
- (SFSpeechRecognitionTask *)recognitionTaskWithRequest:(SFSpeechRecognitionRequest *)request
resultHandler:(void (^)(SFSpeechRecognitionResult * __nullable result, NSError * __nullable error))resultHandler;
// Advanced API: Recognize a custom request with with a delegate
// The delegate will be weakly referenced by the returned task
- (SFSpeechRecognitionTask *)recognitionTaskWithRequest:(SFSpeechRecognitionRequest *)request
delegate:(id <SFSpeechRecognitionTaskDelegate>)delegate;
- 开始语音识别
- (IBAction)stardRecorder:(UIButton *)sender
{
// 开始录音前清空显示的内容, 如果需要拼接多次录音的内容,不要清空,
_content.text = @"";
// 创建新的语音识别请求
[self createSpeechRequest];
__weak typeof(self) weakSelf = self;
// 录音格式配置 -- 监听输出流 并拼接流文件
AVAudioFormat *recordingFormat = [[_audioEngine inputNode] outputFormatForBus:0];
// 创建一个Tap,(创建前要先删除旧的)
// 文档注释: Create a "tap" to record/monitor/observe the output of the node.
[[_audioEngine inputNode] installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
__strong typeof(weakSelf) strongSelf = weakSelf;
// 拼接流文件
[strongSelf.speechRequest appendAudioPCMBuffer:buffer];
}];
// 准备并启动引擎
[_audioEngine prepare];
NSError *error = nil;
if (![_audioEngine startAndReturnError:&error]) {
NSLog(@"%@",error.userInfo);
};
[sender setTitle:@"语音识别中..." forState:UIControlStateNormal];
}
- 重置多媒体引擎
- (void)releaseEngine
{
// 销毁tap
[[_audioEngine inputNode] removeTapOnBus:0];
[_audioEngine stop];
[_speechRequest endAudio];
_speechRequest = nil;
}
到这里 现说现译-语音识别就完成了。
6. 语音识别--本地音频文件
这个需要个音频文件, 上面做的录音功能, 就可以录制语音caf文件, 那就直接在录音功能基础上, 加个语音识别吧。这样就集录制、播放、语音识别于一体了。
直接看代码
- (IBAction)speechSound:(UIButton *)sender
{
// 识别的录音文件是否存在
NSFileManager* manager = [NSFileManager defaultManager];
if (![manager fileExistsAtPath:_filePath]){
NSLog(@"音频文件不存在");
return ;
}
_speechContent.text = @"";
//转化过后的MP3文件位置
// NSString *mp3Path = [NSString stringWithFormat:@"%@/%@", [APPUtil speechPath], @"lame.mp3"];
// [APPUtil lameCafToMp3:_filePath mp3:mp3Path];
// [self speechSoundRecord:mp3Path]; // 语音识别失败
// 不转成mp3也可以 识别成功
[self speechSoundRecord:_filePath]; // 能识别成功
}
- (void)speechSoundRecord:(NSString *)path
{
// 设置语言中文
NSLocale *local = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"];
SFSpeechRecognizer *localRecognizer =[[SFSpeechRecognizer alloc] initWithLocale:local];
NSURL *url = [NSURL fileURLWithPath:path];
if (!url) return;
SFSpeechURLRecognitionRequest *res =[[SFSpeechURLRecognitionRequest alloc] initWithURL:url];
__weak typeof(self) weakSelf = self;
[localRecognizer recognitionTaskWithRequest:res resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (error) {
NSLog(@"语音识别解析失败,%@",error);
}
else {
// 显示 识别的内容
NSString *text = result.bestTranscription.formattedString;
strongSelf.speechContent.text = text;
}
}];
}
历时一天半终于写完了实现录音和语音识别功能的代码 , 现在运行看下效果吧,
直接看图:
可以看到, 录音和语音识别功能, 除了识别内容会有些错别字, 效果还是挺完美的。
本文Demo地址: 音频录制和Speech语音识别
网友评论