音频录制需要的权限,需要在plist文件中设置:Privacy - Microphone Usage Description
AVAudioRecorder视频录制,AVAudioPlayer视频播放,AVAudioSession我们也是需要了解的,通过它可以实现对App当前上下文音频资源的控制,比如插拔耳机、接电话、是否和其他音频数据混音等,经常我们遇到的一些问题登录,如果有问题,或者又补充,可以联系我,应该常用的转态我都覆盖了的
#import <AVFoundation/AVFoundation.h>
#import <Masonry.h>
@interface AVAudioVC ()<AVAudioRecorderDelegate>
@property(nonatomic,strong)AVAudioRecorder *audioRecorder;//音频录制
@property(nonatomic,strong)UIButton *audioRecorderBeginBtn;//音频录制开始
@property(nonatomic,strong)UIButton *audioRecorderPauseBtn;//暂停录音
@property(nonatomic,strong)UIButton *audioRecorderStopBtn;//音频停止录制
/**AVAudioSession 我们也是需要了解的,通过它可以实现对App当前上下文音频资源的控制,比如插拔耳机、接电话、是否和其他音频数据混音等,经常我们遇到的一些问题,比如下面的这些:
1、是进行录音还是播放?
2、当系统静音键按下时该如何表现?
3、是从扬声器还是从听筒里面播放声音?
4、插拔耳机后如何表现?
5、来电话/闹钟响了后如何表现?
6、其他音频App启动后如何表现?*/
@property (nonatomic, strong) AVAudioSession *session;
@property (nonatomic, strong) AVAudioPlayer *player; //播放器
@end
@implementation AVAudioVC
-(AVAudioSession *)session{
if(!_session){
//AVAudioSession是一个单例 实例化
_session =[AVAudioSession sharedInstance];
NSError *sessionError;
if (_session == nil) {
NSLog(@"Error creating session: %@",[sessionError description]);
}else{
//激活session
[_session setActive:YES error:nil];
}
}
return _session;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setView];
//设备改变
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRouteChange:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
//当前的流程被中断了
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
}
//拔出耳机等
- (void)handleRouteChange:(NSNotification *)noti {
NSDictionary *info = noti.userInfo;
AVAudioSessionRouteChangeReason reason = [info[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];
/**
AVAudioSessionRouteChangeReasonUnknown :未知原因
AVAudioSessionRouteChangeReasonNewDeviceAvailable :有新设备可用
AVAudioSessionRouteChangeReasonOldDeviceUnavailable :老设备不可用
AVAudioSessionRouteChangeReasonCategoryChange :类别变了
AVAudioSessionRouteChangeReasonOverride :app重置了输出设置
AVAudioSessionRouteChangeReasonWakeFromSleep :从睡眠转态呼醒
AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory :当前的category下没有合适的设备
AVAudioSessionRouteChangeReasonRouteConfigurationChange :router的配置改变了
*/
//旧音频设备断开
if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
//获取上一线路描述信息并获取上一线路的输出设备类型
AVAudioSessionRouteDescription *previousRoute = info[AVAudioSessionRouteChangePreviousRouteKey];
AVAudioSessionPortDescription *previousOutput = previousRoute.outputs[0];
NSString *portType = previousOutput.portType;
if ([portType isEqualToString:AVAudioSessionPortHeadphones]) {
//在这里暂停播放
}
}
}
/*监听系统中断音频播放
来电暂停
QQ 微信语音暂停
其他音乐软件占用
*/
- (void)audioInterruption:(NSNotification *)noti {
NSDictionary *info = noti.userInfo;
AVAudioSessionInterruptionType type = [info[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
if (type == AVAudioSessionInterruptionTypeBegan) {
//表示中断开始,我们应该暂停播放和采集,取值为AVAudioSessionInterruptionTypeEnded表示中断结束,我们可以继续播放和采集。
} else {
//当前只有一种值AVAudioSessionInterruptionOptionShouldResume表示此时也应该恢复继续播放和采集。
AVAudioSessionInterruptionOptions options = [info[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
if (options == AVAudioSessionInterruptionOptionShouldResume) {
}
}
}
/**
所有的控件初始化
*/
-(void)setView{
//音频录制
UIView *audioRecorderView = [UIView new];
audioRecorderView.layer.cornerRadius = 5.0f;
audioRecorderView.layer.borderColor = [UIColor blackColor].CGColor;
audioRecorderView.layer.borderWidth = 1.0f;
[self.view addSubview:audioRecorderView];
audioRecorderView.backgroundColor = [UIColor redColor];
[audioRecorderView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.offset(90);
make.left.offset(12);
make.right.offset(-12);
make.height.offset(74);
}];
UILabel *audioRecorderTitleLab = [UILabel new];
audioRecorderTitleLab.text = @"音频录制";
[audioRecorderView addSubview:audioRecorderTitleLab];
[audioRecorderTitleLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.offset(12);
make.height.offset(30);
}];
self.audioRecorderBeginBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.audioRecorderBeginBtn setTitle:@"开始" forState:UIControlStateNormal];
[self.audioRecorderBeginBtn addTarget:self action:@selector(audioRecorderBeginBtnClick) forControlEvents:UIControlEventTouchUpInside];
[audioRecorderView addSubview:self.audioRecorderBeginBtn];
[self.audioRecorderBeginBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(audioRecorderTitleLab.mas_bottom);
make.left.offset(12);
make.bottom.offset(0);
make.width.offset(80);
}];
self.audioRecorderPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.audioRecorderPauseBtn setTitle:@"暂停" forState:UIControlStateNormal];
[self.audioRecorderPauseBtn setTitle:@"开始" forState:UIControlStateSelected];
[self.audioRecorderPauseBtn addTarget:self action:@selector(audioRecorderPauseBtnClick) forControlEvents:UIControlEventTouchUpInside];
[audioRecorderView addSubview:self.audioRecorderPauseBtn];
[self.audioRecorderPauseBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.audioRecorderBeginBtn.mas_right).offset(12);
make.size.equalTo(self.audioRecorderBeginBtn);
make.bottom.equalTo(self.audioRecorderBeginBtn.mas_bottom);
}];
self.audioRecorderStopBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.audioRecorderStopBtn setTitle:@"停止" forState:UIControlStateNormal];
[self.audioRecorderStopBtn addTarget:self action:@selector(audioRecorderStopBtnClick) forControlEvents:UIControlEventTouchUpInside];
[audioRecorderView addSubview:self.audioRecorderStopBtn];
[self.audioRecorderStopBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.audioRecorderPauseBtn.mas_right).offset(12);
make.size.equalTo(self.audioRecorderBeginBtn);
make.bottom.equalTo(self.audioRecorderBeginBtn.mas_bottom);
}];
//音频播放
}
/**
录音开始
*/
-(void)audioRecorderBeginBtnClick{
/**
一下是两个初始化的方法,两个方法差不多,NSDictionary是配置信息
- (nullable instancetype)initWithURL:(NSURL *)url settings:(NSDictionary<NSString *, id> *)settings error:(NSError **)outError;
- (nullable instancetype)initWithURL:(NSURL *)url format:(AVAudioFormat *)format error:(NSError **)outError API_AVAILABLE(macos(10.12), ios(10.0), watchos(4.0)) API_UNAVAILABLE(tvos);
准备开始录音
- (BOOL)prepareToPlay;
暂停录音
- (void)pause;
停止录音
- (void)stop;
*/
if(self.audioRecorderBeginBtn.selected){
//已经开始了
NSLog(@"-------------------------------录音已经开始了,不需要重复录制");
}else{
/**
设置session属性
AVAudioSessionCategoryAmbient: 当用户锁屏或者静音的时候静音,支持混音,只支持播放
AVAudioSessionCategorySoloAmbient: 当用户锁屏或者静音的时候静音,不支持混音,只支持播放
AVAudioSessionCategoryPlayback: 当用户锁屏或者静音的时候不静音,不支持混音,只支持播放
AVAudioSessionCategoryRecord :当用户锁屏或者静音的时候不静音,不支持混音,只支持录音
AVAudioSessionCategoryPlayAndRecord:当用户锁屏或者静音的时候不静音,支持混音,可以录音和播放
AVAudioSessionCategoryAudioProcessing:都不支持
AVAudioSessionCategoryMultiRoute:当用户锁屏或者静音的时候不静音,不支持混音,可以录音和播放
*/
[self.session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
//开始
self.audioRecorder = [[AVAudioRecorder alloc]initWithURL:[self getSavePath] settings:[self getAudioSetting] error:nil];
self.audioRecorder.delegate = self;
// self.audioRecorder.meteringEnabled = YES;//开启音频测量
[self.audioRecorder prepareToRecord];//
[self.audioRecorder record];
//
[self.audioRecorder updateMeters];
[self.audioRecorder averagePowerForChannel:0];//指定频道分贝值
[self.audioRecorder peakPowerForChannel:0];//平均分贝值
NSLog(@"-------------------------------录音已经开始了 %@",self.audioRecorder);
}
self.audioRecorderBeginBtn.selected = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"isRecording:1----------------------------------------:%d",self.audioRecorder.isRecording);
});
}
/*
音频的存储url
*/
-(NSURL *)getSavePath{
NSString *urlStr=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
urlStr = [urlStr stringByAppendingPathComponent:@"myRecord.caf"];
NSLog(@"file path:%@",urlStr);
NSURL *url=[NSURL fileURLWithPath:urlStr];
return url;
}
/*
@return 录音设置
*/
-(NSDictionary *)getAudioSetting{
NSMutableDictionary *dicM=[NSMutableDictionary dictionary];
//设置录音格式
[dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
//设置录音采样率,8000是电话采样率,对于一般录音已经够了
[dicM setObject:@(8000) forKey:AVSampleRateKey];
//设置通道,这里采用单声道
[dicM setObject:@(1) forKey:AVNumberOfChannelsKey];
//每个采样点位数,分为8、16、24、32
[dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];
//是否使用浮点数采样
[dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
//录音质量
[dicM setObject:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey];
//....其他设置等
return dicM;
}
/**
录音暂停
*/
-(void)audioRecorderPauseBtnClick{
if(!self.audioRecorder ){
return;
}
if(self.audioRecorderPauseBtn.selected){
//录音音频开始
[self.audioRecorder record];
}else{
//录音音频暂停
[self.audioRecorder pause];
}
self.audioRecorderPauseBtn.selected = !self.audioRecorderPauseBtn.selected;
}
/**
音频停止录制
*/
-(void)audioRecorderStopBtnClick{
//是否还在录
[self.audioRecorder stop];
self.audioRecorderBeginBtn.selected = NO;
}
#pragma mark AVAudioRecorderDelegate
/* audioRecorderDidFinishRecording:successfully: is called when a recording has been finished or stopped. This method is NOT called if the recorder is stopped due to an interruption. */
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
//录音完成
NSLog(@"--------------:录音完成");
// AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[self getSavePath] error:nil];
// if ([audioPlayer prepareToPlay] == YES &&
// [audioPlayer play] == YES) {
// NSLog(@"--------------------------------:开始播放");
// }else{
// NSLog(@"--------------------------------:失败");
// }
}
/* if an error occurs while encoding it will be reported to the delegate. */
- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError * __nullable)error{
NSLog(@"--------------:录音编码发生错误");
}
/**
音频播放
*/
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.audioRecorder stop];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[self getSavePath] error:nil];
// NSLog(@"%li",self.player.data.length/1024);
[self.session setCategory:AVAudioSessionCategoryPlayback error:nil];
if([self.player prepareToPlay] == YES && [self.player play] == YES){
NSLog(@"-------------------:播放");
}else{
NSLog(@"-------------------:停止");
}
}
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end