简介
最近公司研发了一个语音识别的框架,但这个框架是后端识别,所以需要手机端录音,录音后将音频文件通转成NSData类型,然后通过bsae64转码传给后台进行语音识别,识别的文字再传回给前端,虽然我认为这样做体验并不好,毕竟请求是耗时的,并且iOS10以后,自带语音识别框架,但毕竟是公司研发的框架,所以就配合做了一下测试。
iOS录音和音频播放用到时AVFoundation.h框架中的,AVAudioRecorder类和AVAudioPlayer,其中AVAudioPlayer播放器只能播放本地音频文件,如果要在线播放需要用AVPlayer,其配合AVPlayerLayer类还可实现视频播放。另外支持播放进度监听。
AVAudioRecorder录音
AVAudioRecorder录音的主要步骤:
创建录音文件保存路径,并设置相关属性(是一个字典),然后实例化AVAudioRecorder录音对象,该对象必须是全局变量。
使用AVAudioSession的单例对象(音频会话对象)来设置当前音频会话状态和会话类别。
录音对象设置开始录音,录音结束后会调用录音完成的代理方法。
//导入头文件
#import
#import "GTMBase64.h"
@interface ViewController ()
{ NSURL * recordUrl;
AVAudioRecorder * audioRecorder;//必须为全局变量
AVAudioPlayer * player;//必须为全局变量
}
//开始录音
- (void)startRecord
{
//删除上次生成的文件,保留最新文件
NSFileManager *fileManager = [NSFileManager defaultManager];
//默认就是wav格式,是无损的
if ([fileManager fileExistsAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordAudio.wav"]]) {
[fileManager removeItemAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordAudio.wav"] error:nil];
}
//录音设置
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
//设置录音格式 AVFormatIDKey==kAudioFormatLinearPCM
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
//设置录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量), 采样率必须要设为11025才能使转化成mp3格式后不会失真
[recordSetting setValue:[NSNumber numberWithFloat:16000] forKey:AVSampleRateKey];
//录音通道数 1 或 2 ,要转换成mp3格式必须为双通道
[recordSetting setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
//线性采样位数 8、16、24、32
[recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
//录音的质量
[recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey];
// 设置录制音频采用高位优先的记录格式
[recordSetting setValue:[NSNumber numberWithBool:YES] forKey:AVLinearPCMIsBigEndianKey];
// 设置采样信号采用浮点数
[recordSetting setValue:[NSNumber numberWithBool:YES] forKey:AVLinearPCMIsFloatKey];
//存储录音文件
NSURL * recordUrl = [NSURL URLWithString:[NSTemporaryDirectory()stringByAppendingPathComponent:@"recordAudio.wav"]];
//初始化录音对象
NSError * error;
audioRecorder = [[AVAudioRecorder alloc] initWithURL:recordUrl settings:recordSetting error:&error];
if (error) {
NSLog(@"%@",error.description);
return;
}
audioRecorder.delegate = self;
//开启音量检测
audioRecorder.meteringEnabled = YES;
AVAudioSession * audioSession = [AVAudioSession sharedInstance];//得到音频会话单例对象
//如果不是正在录音
if (![audioRecorder isRecording]) {
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];//设置类别,表示该应用同时支持播放和录音
[audioSession setActive:YES error:nil];//激活当前应用的音频会话,此时会阻断后台音乐的播放.
[audioRecorder prepareToRecord];//准备录音
[audioRecorder record];//开始录音
//暂停录音
// [audioRecorder pause];
}
}
//结束录音
- (void)endRecord
{
[audioRecorder stop]; //录音停止
}
//录音结束后代理
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
[[AVAudioSession sharedInstance] setActive:NO error:nil];//一定要在录音停止以后再关闭音频会话管理(否则会报错),此时会延续后台音乐播放
if (!flag) return;
//请求接口传给后台
[self postwavdata];
}
注意:
录音时音频文件类型后缀必须为.caf、.aif、.wav中的一种,不能是.mp3,但播放是可以播放.mp3文件,可以导入githu上的一个C语言框架lame转成mp3音频文件。
将音频文件转成NSData然后用bsae64加密传给服务器,用系统自带的base64EncodedStringWithOptions编码方法后台可能解析有问题,主要是有空格和换行,可以多encode一次转义去掉这些特殊符号,也可以用第三方框架GTMBase64,请求数据时候request的Content-Type要设置为application/json,否则后台可能结束不到音频转码后端参数。
//设置request的Content-Type为application/json
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
//转成base64编码格式上传服务器
-(NSString *)wavToBASE64{
NSData * wavData = [NSData dataWithContentsOfFile:[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordAudio.wav"]];
NSString * encodedImageStr = [GTMBase64 encodeBase64Data:wavData];
}
AVAudioPlayer播放音频文件。
AVAudioPlayer播放音频文件主要步骤:
获取音频文件URL或者音频文件数据;
初始化AVAudioPlayer音频播放器全局对象;
设置相关属性,并播放文件。
相关代码
————————————————
//导入头文件
#import
#import "GTMBase64.h"
@interface ViewController ()
{ NSURL * recordUrl;
AVAudioRecorder * audioRecorder;//必须为全局变量
AVAudioPlayer * player;//必须为全局变量
}
//开始录音
- (void)startRecord
{
//删除上次生成的文件,保留最新文件
NSFileManager *fileManager = [NSFileManager defaultManager];
//默认就是wav格式,是无损的
if ([fileManager fileExistsAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordAudio.wav"]]) {
[fileManager removeItemAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordAudio.wav"] error:nil];
}
//录音设置
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
//设置录音格式 AVFormatIDKey==kAudioFormatLinearPCM
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
//设置录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量), 采样率必须要设为11025才能使转化成mp3格式后不会失真
[recordSetting setValue:[NSNumber numberWithFloat:16000] forKey:AVSampleRateKey];
//录音通道数 1 或 2 ,要转换成mp3格式必须为双通道
[recordSetting setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
//线性采样位数 8、16、24、32
[recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
//录音的质量
[recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey];
// 设置录制音频采用高位优先的记录格式
[recordSetting setValue:[NSNumber numberWithBool:YES] forKey:AVLinearPCMIsBigEndianKey];
// 设置采样信号采用浮点数
[recordSetting setValue:[NSNumber numberWithBool:YES] forKey:AVLinearPCMIsFloatKey];
//存储录音文件
NSURL * recordUrl = [NSURL URLWithString:[NSTemporaryDirectory()stringByAppendingPathComponent:@"recordAudio.wav"]];
//初始化录音对象
NSError * error;
audioRecorder = [[AVAudioRecorder alloc] initWithURL:recordUrl settings:recordSetting error:&error];
if (error) {
NSLog(@"%@",error.description);
return;
}
audioRecorder.delegate = self;
//开启音量检测
audioRecorder.meteringEnabled = YES;
AVAudioSession * audioSession = [AVAudioSession sharedInstance];//得到音频会话单例对象
//如果不是正在录音
if (![audioRecorder isRecording]) {
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];//设置类别,表示该应用同时支持播放和录音
[audioSession setActive:YES error:nil];//激活当前应用的音频会话,此时会阻断后台音乐的播放.
[audioRecorder prepareToRecord];//准备录音
[audioRecorder record];//开始录音
//暂停录音
// [audioRecorder pause];
}
}
//结束录音
- (void)endRecord
{
[audioRecorder stop]; //录音停止
}
//录音结束后代理
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
[[AVAudioSession sharedInstance] setActive:NO error:nil];//一定要在录音停止以后再关闭音频会话管理(否则会报错),此时会延续后台音乐播放
if (!flag) return;
//请求接口传给后台
[self postwavdata];
}
注意:
录音时音频文件类型后缀必须为.caf、.aif、.wav中的一种,不能是.mp3,但播放是可以播放.mp3文件,可以导入githu上的一个C语言框架lame转成mp3音频文件。
将音频文件转成NSData然后用bsae64加密传给服务器,用系统自带的base64EncodedStringWithOptions编码方法后台可能解析有问题,主要是有空格和换行,可以多encode一次转义去掉这些特殊符号,也可以用第三方框架GTMBase64,请求数据时候request的Content-Type要设置为application/json,否则后台可能结束不到音频转码后端参数。
————————————————
//设置request的Content-Type为application/json
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
//转成base64编码格式上传服务器
-(NSString *)wavToBASE64{
NSData * wavData = [NSData dataWithContentsOfFile:[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordAudio.wav"]];
NSString * encodedImageStr = [GTMBase64 encodeBase64Data:wavData];
}
AVAudioPlayer播放音频文件。
AVAudioPlayer播放音频文件主要步骤:
获取音频文件URL或者音频文件数据;
初始化AVAudioPlayer音频播放器全局对象;
设置相关属性,并播放文件。
相关代码
//开始播放音频文件
- (void)playWav{
//获取音频文件url
// NSURL * url = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordAudio.wav"]];
//获取录音数据
NSData * wavData = [NSData dataWithContentsOfFile:[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordAudio.wav"]];
NSError * error;
// AVAudioPlayer * player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
player = [[AVAudioPlayer alloc]initWithData:wavData error:&error];
player.delegate = self;
if (error) {
NSLog(@"语音播放失败,%@",error);
return;
}
//播放器的声音会自动切到receiver,所以听起来特别小,如果需要从speaker出声,需要自己设置。
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
// 单独设置音乐的音量(默认1.0,可设置范围为0.0至1.0,两个极端为静音、系统音量):
player.volume = 1.0;
// 修改左右声道的平衡(默认0.0,可设置范围为-1.0至1.0,两个极端分别为只有左声道、只有右声道):
player.pan = -1;
// 设置播放速度(默认1.0,可设置范围为0.5至2.0,两个极端分别为一半速度、两倍速度):
player.rate = 2.0;
// 设置循环播放(默认1,若设置值大于0,则为相应的循环次数,设置为-1可以实现无限循环):
player.numberOfLoops = 0;
// player.currentTime = 0;
//调用prepareToPlay方法,这样可以提前获取需要的硬件支持,并加载音频到缓冲区。在调用play方法时,减少开始播放的延迟。
[player prepareToPlay];
// 开始播放音乐:
[player play];
}
//播放完成代理
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
if (flag) {
NSLog(@"停止播放");
//调用pause或stop来暂停播放,这里的stop方法的效果也只是暂停播放,不同之处是stop会撤销prepareToPlay方法所做的准备。
[player stop];
player = nil;
}
}
最后
给大家推荐一个优秀的iOS交流平台,平台里的伙伴们都是非常优秀的iOS开发人员,我们专注于技术的分享与技巧的交流,大家可以在平台上讨论技术,交流学习。欢迎大家的加入(想要进入的可加小编微信1367798518)