我是靠谱客的博主 迷路小松鼠,这篇文章主要介绍(二)AVFoundation 音频播放和录制,现在分享给大家,希望可以做个参考。

参看文章 写的很用心

音频播放和录制

1、音频会话

音频会话分类

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

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

激活音频会话

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/** 激活音频会话 */ -(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 ** 都能胜任.

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
-(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、处理中断事件

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

  • 添加中断监听通知
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- (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、对线路改变的响应

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 音频线路改变通知 [[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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
- (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 时应做出如下设置

复制代码
1
2
self.recorder.meteringEnabled = YES;
复制代码
1
2
self.player.meteringEnabled = YES;

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
-(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)录音的时候

复制代码
1
2
3
4
5
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error: nil]; [[AVAudioSession sharedInstance] setActive: YES error: nil]; UInt32 doChangeDefault = 1; AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(doChangeDefault), &doChangeDefault);

2)播放的时候

复制代码
1
2
3
4
5
AVAudioSession *audioSession = [AVAudioSession sharedInstance]; NSError *err = nil; [audioSession setCategory :AVAudioSessionCategoryPlayback error:&err];

这样就行了。

最后

以上就是迷路小松鼠最近收集整理的关于(二)AVFoundation 音频播放和录制的全部内容,更多相关(二)AVFoundation内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部