参看文章 写的很用心
音频播放和录制
1、音频会话
音频会话分类
Category | 播放类型 | 后台播放 | 静音或屏幕关闭 | 音频输入 | 音频输出 | 作用 |
---|---|---|---|---|---|---|
AVAudioSessionCategoryAmbient | 播放混合 | 有影响 | 支出 | 游戏背景音乐 | ||
AVAudioSessionCategorySoloAmbient(默认) | 独占播放 | 有影响 | 支持 | 微信中播放语音 | ||
AVAudioSessionCategoryPlayback | 可选 | 支持 | 支持 | 音频播放器 | ||
AVAudioSessionCategoryRecord | 独占录音 | 支持 | 支持 | 微信中录制语音 | ||
AVAudioSessionCategoryPlayAndRecord | 可选 | 支持 | 支持 | 支持 | 微信语音聊天 | |
AVAudioSessionCategoryAudioProcessing | – | – | – | 硬件解码音频 | ||
AVAudioSessionCategoryMultiRoute | 支持 | 支持 | 多设备输入输出 |
上述分类所提供的几种场景的行为可以满足大部分程序的需要,如果需要更复杂的功能,上述其中一种分类可以通过使用options 和 modes 方法进一步自定义开发.
激活音频会话
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内容请搜索靠谱客的其他文章。
发表评论 取消回复