zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    (转)DMA(Direct Memory Access)
    linux根文件系统的挂载过程详解
    Linux根文件系统的挂载过程详解
    1byte、1KB、4KB,1MB、1GB用16进制表示的范围。任意地址范围求字节数
    Hi3531a海思logo加载的实现流程
    u-boot中添加mtdparts支持以及Linux的分区设置
    在uboot里面添加环境变量使用run来执行
    (转) 嵌入式 Linux 利用 udev 实现自动检测挂载U盘
    Shell之变量
    Shell之哈希表
  • 原文地址:https://www.cnblogs.com/hualuoshuijia/p/11512990.html
Copyright © 2011-2022 走看看