OC AVAudioRecorder、AVAudioSession和AVAudioPlayer的使用
音频录制需要的权限,需要在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