美文网首页
AVFoundation-播放和录制音频

AVFoundation-播放和录制音频

作者: 亡灵诅咒 | 来源:发表于2019-11-12 22:14 被阅读0次

    目标

    学习AVAudioPlayer和AVAudioRecorder类来实现音频播放及录制功能

    理解音频会话

    iOS默认音频会话的预配置

    • 激活了音频播放,但是音频录制未激活
    • 当用户切换响铃/静音开关到“静音”模式时,应用程序播放的所有音频都会消失
    • 当设备显示解锁屏幕时,应用程序的音频处于静音状态
    • 当应用程序播放音频时,所有后台播放的音频都会处于静音状态

    音频会话分类

    屏幕快照 2019-11-12 下午10.05.39.png
    • 上述分类提供满足大部分需求的常见行为,如果需要更加复杂的功能,其中一些分类通过使用options和modes方法进一步自定义开发

      • options让开发者使用一些附加行为(如Playback分类允许输出音频和背景声音混合)
      • modes可以通过引入被定制的行为进一步对分类进行修改以满足特殊需求

    配置音频会话

    • 音频会话在应用程序的生命周期中是可以修改的,但通常只配置一次,就是在应用程序启动时
    • 通过设置合适的分类,可为音频的播放指定需要的音频会话,其中定制一些行为
        //配置音频会话
        AVAudioSession *session = [AVAudioSession sharedInstance];
        NSError *error = nil;
        if ([session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]) {
            NSLog(@"AVAudioSession setCategory error = %@",error.userInfo);
        }
        
        if ([session setActive:YES error:&error]) {
            NSLog(@"AVAudioSession setActive error = %@",error.userInfo);
        }
        
    

    AVAudioPlayer播放音频

    • 初始化AVAudioPlayer(使用包含播放音频的内存版本的NSData,或本地音频文件的NSURL)
    • 建议调用其prepareToPlay方法,这样会取得需要的音频硬件并预加载Audio Queue的缓冲区,降低调用play方法和听到声音输出之间的延时
    • 通过pause和stop方法停止的音频都会继续播放,主要区别在底层处理上(stop方法会撤销调用prepareToPlay时所作的设置,而pause方法则不会)
    • 指定位置播放:currentTime
    • 修改播放器的音量:volume
    • 修改播放器的pan值: -1.0(极左), 1.0(极右),默认0.0居中
    • 调整播放率rate:iOS5加入,范围(0.5 - 2.0)半速-2倍速。前提条件需要设置enableRate属性
    • 无缝循环numberOfLoops:大于0可实现n次循环,-1无限循环(音频循环可以是未压缩的线性PCM音频,也可以是AAC之类的压缩格式音频。但是MP3格式音频要实现循环的目的通常需要使用特殊工具处理,建议使用AAC或AppleLossless格式循环)
    -(void)adjustPan:(float)pan{
        self.player.pan = pan;
    }
    
    -(void)adjustVolume:(float)volume{
        self.player.volume = volume;
    }
    
    - (void)adjustRate:(float)rate{
        self.player.rate = rate;
    }
    
    -(AVAudioPlayer *)playerWithFile:(NSString *)file{
        NSURL *fileUrl = [NSURL fileURLWithPath:file];
        NSError *error = nil;
        
        AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:fileUrl error:&error];
        if (player) {
            //无限循环
            player.numberOfLoops = -1;
            player.delegate = self;
            //循序修改倍速
            player.enableRate = YES;
            [player prepareToPlay];
        }else{
            if ([self.delegate respondsToSelector:@selector(DKAudioPlayerManagerDidFailedWithError:target:)]) {
                [self.delegate DKAudioPlayerManagerDidFailedWithError:error target:self];
            }
        }
        return player;
    }
    

    音频会话通知

    • 中断通知AVAudioSessionInterruptionNotification,在通知响应函数中可以通过userInfo字典获取重要信息,就可以通过AVAudioSessionInterruptionTypeKey的值来确定中断类型,来标识中断开始或结束,做出响应处理

    • 线路改变通知AVAudioSessionRouteChangeNotification,在iOS设备上添加或移除音频输入、输出线路时,会发生线路改变。

      • userInfo字典中通过AVAudioSessionRouteChangeReasonKey来获取中断原因。

      • userInfo字典中通过AVAudioSessionRouteChangePreviousRouteKey字典来获取线路描述对象。

        • 线路描述对象整合了一个inputs和outputs的输入输出数组,数组中都是AVAudioSessionPortDescription实例对象,用于描述不同的I/O接口属性
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeRate:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeRate:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
    
    通知处理
        NSDictionary *userInfo = noti.userInfo;
        //AVAudioSessionInterruptionTypeKey 确认系统中断类型
        //来电、QQ微信语音、其他音乐软件暂停
        AVAudioSessionInterruptionType reason = [userInfo[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
        
        //中断开始
        if (reason == AVAudioSessionInterruptionTypeBegan) {
            if (self.isPlaying) {
                [self stop];
                if ([self.delegate respondsToSelector:@selector(DKAudioPlayerManagerPlayBackStoppedWithTarget:)]) {
                    [self.delegate DKAudioPlayerManagerPlayBackStoppedWithTarget:self];
                }
            }
        }else if (reason == AVAudioSessionInterruptionTypeEnded){
            //中断结束
            if (!self.isPlaying) {
                [self play];
                if ([self.delegate respondsToSelector:@selector(DKAudioPlayerManagerPlayBackBeginWithTarget:)]) {
                    [self.delegate DKAudioPlayerManagerPlayBackBeginWithTarget:self];
                }
            }
        }
    
    通知处理
        
        //线路切换监听
        AVAudioSessionRouteChangeReason reason1 = [userInfo[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];
        //旧音频设备中断原因
        if (reason1 == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
            //线路描述信息
            AVAudioSessionRouteDescription *previousRoute = userInfo[AVAudioSessionRouteChangePreviousRouteKey];
            //第一个输出接口并判断是否是耳机接口
            AVAudioSessionPortDescription *previousOutput = previousRoute.outputs[0];
            NSString *portType = previousOutput.portType;
            if ([portType isEqualToString:AVAudioSessionPortHeadphones]) {
                [self stop];
                //输出到有线耳机
                if ([self.delegate respondsToSelector:@selector(DKAudioPlayerManagerPlayBackStoppedWithTarget:)]) {
                    [self.delegate DKAudioPlayerManagerPlayBackStoppedWithTarget:self];
                }
            }
        }
    

    AVAudioRecorder录制音频

    初始化AVAudioRecorder实例(1.用于表示音频流写入文件的本地URL,2.包含用于配置录音会话健值信息的字典,3.用于捕获初始化阶段各种错误饿NSError指针)
    prepareToPlay,这个方法执行底层Audio Queue初始化的必要过程。该方法还在URL参数指定的位置创建一个文件,将录制启动时的延迟降到最低
    音频格式(指定的音频格式一定要和URL参数定义的文件类型兼容)

    • kAudioFormatLinearPCM
    • kAudioFormatMPEG4AAC
    • kAudioFormatAppleLossless
    • kAudioFormatAppleIMA4
    • kAudioFormatilBC
    • kAudioFormatULaw
      采样率
    • AVSampleRateKey定义录音器的采样率。采样率定义了对输入的模拟音频信号每一秒的采样数。对音频的质量以及最终文件大小起到重要作用。尽量使用标准的采样率(8000、16000、22050、44100)
      通道数
    • AVNumberOfChannelsKey用于定义记录音频内容的通道数。1意味着使用单声道,2意味着立体声录制。
      指定格式的键
    • 处理Linear PCM或压缩音频格式时,可以定义一些其他指定格式的键
      配置音频会话
    • AVAudioSessionCategoryPlayAndRecord这个分类既可以录音有需要对外播放
      currentTime属性,因为该属性不可见,所以无法使用KVO来监听
    初始化
    
    -(instancetype)init{
        if (self = [super init]) {
    
            NSURL *url = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"memo.caf"]];
            NSDictionary *settings = @{
                                       AVFormatIDKey: @(kAudioFormatAppleIMA4),
                                       AVSampleRateKey:@441000.0f,
                                       AVNumberOfChannelsKey:@1,
                                       AVEncoderBitDepthHintKey:@16,
                                       AVEncoderAudioQualityKey:@(AVAudioQualityMedium)
                                       };
            NSError *error = nil;
            self.recorder = [[AVAudioRecorder alloc]initWithURL:url settings:settings error:&error];
            if (self.recorder) {
                self.recorder.delegate = self;
                self.recorder.meteringEnabled = YES;
                [self.recorder prepareToRecord];
            }else{
                if (self.delegate && [self.delegate respondsToSelector:@selector(DKAudioRecorderManagerDidFailedWithError:)]) {
                    [self.delegate DKAudioRecorderManagerDidFailedWithError:error];
                }
            }
        }
        return self;
    }
    

    Audio Metering

    可以读取音频的平均分贝(averagePowerForChannel:)和峰值分贝(peakPowerForChannel:),[-160dB, 0db] 最小/禁音分贝-- 最大分贝
    在读取之前需要设置录音器的meteringEnabled属性才支持对音频进行测量

    相关文章

      网友评论

          本文标题:AVFoundation-播放和录制音频

          本文链接:https://www.haomeiwen.com/subject/cxlcictx.html