OC AVAudioRecorder、AVAudioSession和AVAudioPlayer的使用

音頻錄製須要的權限,須要在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
相關文章
相關標籤/搜索