(二)AVFoundation 音频播放和录制

参看文章 写的很用心

音频播放和录制

1、音频会话

音频会话分类

Category播放类型后台播放静音或屏幕关闭音频输入音频输出作用
AVAudioSessionCategoryAmbient播放混合有影响支出游戏背景音乐
AVAudioSessionCategorySoloAmbient(默认)独占播放有影响支持微信中播放语音
AVAudioSessionCategoryPlayback可选支持支持音频播放器
AVAudioSessionCategoryRecord独占录音支持支持微信中录制语音
AVAudioSessionCategoryPlayAndRecord可选支持支持支持微信语音聊天
AVAudioSessionCategoryAudioProcessing硬件解码音频
AVAudioSessionCategoryMultiRoute支持支持多设备输入输出

上述分类所提供的几种场景的行为可以满足大部分程序的需要,如果需要更复杂的功能,上述其中一种分类可以通过使用optionsmodes 方法进一步自定义开发.

激活音频会话

/**
 激活音频会话
 */
-(void)activeAudioSessionCagegory{
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *err = nil;
    
    // 注意:
    // 如果分类允许后台播放, 则应该打开Capabilities 中 background Modes, 继而勾选打开后台播放选项
    if(![audioSession setCategory:AVAudioSessionCategoryPlayback error:&err]){
        
        NSLog(@"category err: %@",err);
    }
    
    
    if(![audioSession setActive:YES error:&err]){
        NSLog(@"active err: %@ ",err);
    }
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [self activeAudioSessionCagegory];
    
    return YES;
}

如果分类允许后台播放,则应该打开 Capabilities 中的 Background Modes 继而勾选后台播放音频选项




2、音频播放

除非需要从网络流中播放音频、需要访问原始音频样本,或者非常低的时延,否则**AVAudioPlayer ** 都能胜任.

-(void)initSetupPlayer{
    
    NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"" withExtension:@""];
    NSError *err = nil;
    //   注意: player 必须使用强指针引用
    self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:&err];
    
    if (self.player != nil) {
        self.player.numberOfLoops = -1; // 循环播放
        // 说明: prepareToPlay 方法是可选的, 在调用 player 的 play 方法前 也会自动调用, 作用是取得需要的音频硬件并预加载
        // Audio Queue 的缓冲区, 降低调用 play 方法后的延时
        [self.player prepareToPlay]; // 缓冲
    }
    
}

-(void)play{
    [self.player play];
}


/**
 通过pause 和 stop 方法停止的音频会继续播放.
 最主要的区别在底层处理上, 调用 stop 方法会撤销调用 prepareToPlay时所作的设置, 而调用 pause 方法则不会.
 */
-(void)pause{
    [self.player pause];
}

-(void)stop{
    [self.player stop];
    self.player.currentTime = 0.0f;
}


/**
 音量 0~1
 */
-(void)voiceSlider:(UISlider *)slider{
    self.player.volume = slider.value;
}

/**
 声道 -1~1
 */
-(void)vocalTractSlider:(UISlider *)slider{
    self.player.pan = slider.value * 2.0 -1.0;
}

/**
 速率 0.5 ~ 2
 */
-(void)speedSlider:(UISlider *)slider{
    self.player.rate = slider.value * 1.5 + 0.5;
    // 注意:
    // 如果要改变速率, 在初始化AVAudioPlayer 时, 应该做出如下设置
    // self.player.enableRate = YES;
}



3、处理中断事件

当有电话呼入、闹铃响起时,播放中的音频会慢慢消失和暂停,但是终止通话后,播放、停止按钮的控件和音频的播放没有恢复, 为了优化用户体验,需要监听这些事件,并作出处理.

  • 添加中断监听通知
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 添加中断通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(udioSessionInterruptionNotice:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    
}
-(void)udioSessionInterruptionNotice:(NSNotification *)notice{
    
    
    NSDictionary *infoDic = notice.userInfo;
    
    AVAudioSessionInterruptionType interruptType = [infoDic[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
    
    // 判断中断的类型
    if(interruptType == AVAudioSessionInterruptionTypeBegan){
        // 中断开始, 设置停止音乐
        [self.player pause];
    }
    else{
        
        // 中断结束, 判断是否允许继续播放
        AVAudioSessionInterruptionOptions interruptOption = [infoDic[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
        if (interruptOption == AVAudioSessionInterruptionOptionShouldResume) {
            // 允许继续播放, 则继续播放
            [self.player play];
        }
    
    }
    
}



4、对线路改变的响应

播放音频期间插入耳机, 音频输出线路变成耳机插孔并继续播放. 断开耳机连接,音频线路再次回到设备的内置扬声器播放. 虽然线路变化和预期一样,不过按照苹果官方文档,认为该音频应该处于静音状态.

   // 音频线路改变通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionRouteChangeNotice:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];


/**
 音频线路变化通知
 
 播放音频期间插入耳机, 音频输出线路变成耳机插孔并继续播放.
 断开耳机连接,音频线路再次回到设备的内置扬声器播放.
 虽然线路变化和预期一样,不过按照苹果官方文档,认为该音频应该处于静音状态.
 */
-(void)audioSessionRouteChangeNotice:(NSNotification *)notice{
    
    NSDictionary *infoDic = notice.userInfo;
    AVAudioSessionRouteChangeReason routerChangeReason = [infoDic[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];
    
    if (routerChangeReason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
        
        AVAudioSessionRouteDescription *previousRoute = infoDic[AVAudioSessionRouteChangePreviousRouteKey];
        
        AVAudioSessionPortDescription *previousOutput = [previousRoute.outputs firstObject];
        
        if ([previousOutput.portType isEqualToString:AVAudioSessionPortHeadphones]) {
            
            // 停止播放音乐
            [self.player stop];
        }
    }
}



5、 音频录制

一般情况存在录音功能,必然会存在播放功能,所以不能使用默认的录制的音频会话,应该使用既可以录制又能播放的AVAudioSessionCategoryPalyAndRecord


- (void)viewDidLoad {
    [super viewDidLoad];
   
   
    NSURL *fileUrl =  [NSURL fileURLWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"record.caf"]];
    
    /**
     在录制过程中,Core Audio Format (caf) 通常是最好的容器格式,因为他和内容无关可以保存Core Audio 支持的任何音频格式.
     在设置字典中是定的键值信息也是值得讨论一番的
     */
    NSDictionary *settting = @{
                               AVFormatIDKey : @(kAudioFormatAppleIMA4),
                               AVSampleRateKey : @(22050.0f),
                               AVNumberOfChannelsKey : @(1)
                               };
    
    NSError *err = nil;
    self.recorder = [[AVAudioRecorder alloc] initWithURL:fileUrl settings:settting error:&err];
    
    if (self.recorder) {
        
        self.recorder.delegate = self;
        
        [self.recorder prepareToRecord];
    }
}



-(void)startRecord{
    
    [self.recorder record];
}


-(void)recordFinish{
    [self.recorder stop];
}



#pragma mark- AVAudioRecorderDelegate
/**
 音频录制完成调用
 */
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
    
    if(flag){
        
        // 一般把录制好的音频复制或者剪切到目录的文件夹下
        NSURL *sourceUrl = self.recorder.url;
        
        NSURL *targetUrl = [NSURL fileURLWithPath:@"目标文件夹/音频文件名.caf"];
        
        NSError *err = nil;
        [[NSFileManager defaultManager] copyItemAtURL:sourceUrl toURL:targetUrl error:&err];
        
    }
}
音频格式

AVFormatIDKey 定义了写入内容的音频格式,下面是常用格式

  • kAudioFormatLinearPCM : 将未压缩的音频流写入到文件中. 保真度最高,文件也最大.
  • kAudioFormatMPEG4AAC (AAC) 或 kAudioFormat-AppleIMA4 (Apple IMA4) 文件显著缩小还能保证高质量音频.
采样率

**AVSampleRateKey **定义了录音器的采样率, 采样率定义了对输入的模拟信号每一秒的采样数. 采样率越高,越能得到高质量的内容,不过文件也越大,标准的采样率是: 8000, 16000,22050,44100

通道数

AVNumberOfChannelsKey 定义了记录音频内容的通道数.默认值1 是单声道录制, 2 是立体声录制. 除非使用外部硬件录制,否则应该创建单声道录制.




6、 音频测量

AVAudioPlayer 和 AVAudioRecorder 中最使用的功能就是对音频进行测量. AVAudio Metering 可以读取音频的平均平均分贝和峰值分贝数据, 并使用这些数据以可视化方式将声音大小呈现给用户.

首先在初始化 AVAudioPlayer 或 AVAudioRecorder 时应做出如下设置

self.recorder.meteringEnabled = YES;
self.player.meteringEnabled = YES;

点击音频播放或者音频录制, 开始测量


-(void)startMeterTimer{
    [self.link invalidate];
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateMeter)];
    link.frameInterval = 4;   // 间隔时间为刷帧率的 1/4
    [link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    self.link = link;
}

-(void)stopMeterTimer{
    [self.link invalidate];
    self.link = nil;
}

/**
 返回用于表示声音分贝(dB)等级的浮点值,这个值的范围是 -160dB ~ 0dB
 */
-(void)updateMeter{
    
    [self.recorder updateMeters];
    CGFloat num1 = [self.recorder averagePowerForChannel:0];
    CGFloat num2 = [self.recorder peakPowerForChannel:0];
    NSLog(@"录音平均分贝: %f, 峰值分贝: %f",num1, num2);
    
    
    
//    [self.player updateMeters];  // 刷新
//
//    CGFloat num1 = [self.player averagePowerForChannel:0];
//    CGFloat num2 = [self.player peakPowerForChannel:0];
//
//    NSLog(@"播放平均分贝:%f, 峰值分贝:%f", num1, num2);
    
}

上面方法都会返回用于表示声音分贝(dB)等级的浮点值,这个值的范围是 -160dB ~ 0dB


网上录音后播放声音小解决方案

1)录音的时候

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error: nil];
 [[AVAudioSession sharedInstance] setActive: YES error: nil]; 
 UInt32 doChangeDefault = 1; 
 AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(doChangeDefault), &doChangeDefault);

2)播放的时候


  AVAudioSession *audioSession = [AVAudioSession sharedInstance];  
  NSError *err = nil; 
  [audioSession setCategory :AVAudioSessionCategoryPlayback error:&err];

这样就行了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Objective-C中实现音频文件的存储和播放,可以按照以下步骤进行操作: 1. 导入AVFoundation框架和AudioToolbox框架。 ```objective-c @import AVFoundation; @import AudioToolbox; ``` 2. 创建一个AVAudioRecorder实例来录制音频文件。例如: ```objective-c NSError *error = nil; NSURL *audioURL = [NSURL fileURLWithPath:@"path/to/audio/file"]; NSDictionary *settings = @{ AVFormatIDKey : @(kAudioFormatMPEG4AAC), AVSampleRateKey : @44100.0, AVNumberOfChannelsKey : @2 }; AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:audioURL settings:settings error:&error]; if (error) { NSLog(@"Error creating audio recorder: %@", error); return; } [recorder prepareToRecord]; [recorder record]; ``` 3. 创建一个AVAudioPlayer实例来播放音频文件。例如: ```objective-c NSError *error = nil; NSURL *audioURL = [NSURL fileURLWithPath:@"path/to/audio/file"]; AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error]; if (error) { NSLog(@"Error creating audio player: %@", error); return; } [player play]; ``` 4. 如果要在后台播放音频,需要将音频会话设置为AVAudioSessionCategoryPlayback,例如: ```objective-c AVAudioSession *audioSession = [AVAudioSession sharedInstance]; NSError *error = nil; [audioSession setCategory:AVAudioSessionCategoryPlayback error:&error]; if (error) { NSLog(@"Error setting audio session category: %@", error); return; } [audioSession setActive:YES error:&error]; if (error) { NSLog(@"Error activating audio session: %@", error); return; } ``` 5. 最后,如果要删除音频文件,可以使用NSFileManager来删除。例如: ```objective-c NSString *filePath = @"path/to/audio/file"; NSError *error = nil; BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; if (!success) { NSLog(@"Error deleting audio file: %@", error); } ``` 以上就是Objective-C中实现音频文件的存储和播放的步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值