音頻錄製須要的權限,須要在plist文件中設置:Privacy - Microphone Usage Descriptionios
AVAudioRecorder視頻錄製,AVAudioPlayer視頻播放,AVAudioSession咱們也是須要了解的,經過它能夠實現對App當前上下文音頻資源的控制,好比插拔耳機、接電話、是否和其餘音頻數據混音等,常常咱們遇到的一些問題登陸,若是有問題,或者又補充,能夠聯繫我,應該經常使用的轉態我都覆蓋了的macos
#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當前上下文音頻資源的控制,好比插拔耳機、接電話、是否和其餘音頻數據混音等,常常咱們遇到的一些問題,好比下面的這些: 一、是進行錄音仍是播放? 二、當系統靜音鍵按下時該如何表現? 三、是從揚聲器仍是從聽筒裏面播放聲音? 四、插拔耳機後如何表現? 五、來電話/鬧鐘響了後如何表現? 六、其餘音頻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]; //每一個採樣點位數,分爲八、1六、2四、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