《AV Foundation 开发秘籍》读书笔记(二)
来源:互联网 发布:网络上jr是什么意思 编辑:程序博客网 时间:2024/05/21 22:25
第二章 音频播放和录制
1. 音频会话
音频会话分类
上述分类所提供的几种常见行为可以满足大部分应用程序的需要,如果需要更复杂的功能,上述其中一种分类可以通过使用 options 和 modes 方法进一步自定义开发。
激活音频会话
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { AVAudioSession *session = [AVAudioSession sharedInstance]; NSError *error; if (![session setCategory:AVAudioSessionCategoryPlayback error:&error]) { NSLog(@"Category Error : %@", error.localizedDescription); } if (![session setActive:YES error:&error]) { NSLog(@"Activation Error : %@", error.localizedDescription); } return YES;}
如果分类允许后台播放,则应该打开 Capabilities 中的 Background Modes 继而勾选后台播放音频选项
2. 音频播放
除非需要从网络流中播放音频、需要访问原始音频样本,或者需要非常低的时延,否则 AVAudioPlayer 都能胜任
- (void)viewDidLoad { [super viewDidLoad]; NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"白洁01" withExtension:@"mp3"]; // Must Maintain a strong reference to player self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil]; if (self.player) { self.player.numberOfLoops = -1; // 循环播放 [self.player prepareToPlay]; }}- (IBAction)play { [self.player play];}
prepareToPlay 方法是可选的,在调用 play 方法前也会自动调用,作用是取得需要的音频硬件并预加载 Audio Queue 的缓冲区,降低调用 play 方法后的延时。
- (IBAction)pause { [self.player pause];}- (IBAction)stop { [self.player stop]; self.player.currentTime = 0.0f;}
通过 pause 和 stop 方法停止的音频都会继续播放。最主要的区别在底层处理上,调用 stop 方法会撤销调用 prepareToPlay 时所做的设置,而调用 pause 方法则不会。
// 音量 0 ~ 1- (IBAction)voice:(UISlider *)sender { self.player.volume = sender.value;}// 声道 -1 ~ 1- (IBAction)pan:(UISlider *)sender { self.player.pan = sender.value;}// 速率 0.5 ~ 2- (IBAction)speed:(UISlider *)sender { self.player.rate = sender.value;}
如果要改变速率,在初始化 AVAudioPlayer 时应做出如下设置
self.player.enableRate = YES;
3. 处理中断事件
当有电话呼入、闹钟响起的时候,播放中的音频会慢慢消失和暂停,但是终止通话后,播放、停止按钮的控件和音频的播放没有恢复。为了优化用户体验,需要监听这些事件,并作出处理:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
- (void)handleInterruption:(NSNotification *)notification{ NSDictionary *info = notification.userInfo; AVAudioSessionInterruptionType type = [info[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue]; if (type == AVAudioSessionInterruptionTypeBegan) { // 中断开始,设置停止音乐 [self.player pause]; } else { // 中断结束,判断是否允许继续播放 AVAudioSessionInterruptionOptions options = [info[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue]; if (options == AVAudioSessionInterruptionOptionShouldResume) { // 允许继续播放,则继续播放 [self.player play]; } }}
4. 对线路改变的响应
播放音频期间插入耳机,音频输出线路变成耳机插孔并继续播放。断开耳机连接,音频线路再次回到设备的内置扬声器播放。虽然线路变化和预期一样,不过按照苹果官方文档,认为该音频应该处于静音状态。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRouteChange:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
- (void)handleRouteChange:(NSNotification *)notification{ NSDictionary *info = notification.userInfo; AVAudioSessionRouteChangeReason reason = [info[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue]; if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) { AVAudioSessionRouteDescription *previousRoute = info[AVAudioSessionRouteChangePreviousRouteKey]; AVAudioSessionPortDescription *previousOutput = previousRoute.outputs[0]; if ([previousOutput.portType isEqualToString:AVAudioSessionPortHeadphones]) { // 停止播放音乐 [self.player stop]; } }}
5. 音频录制
一般情况存在录音功能,必然会有播放功能,所以不能使用默认的录制音频会话,应该使用既可以录制又能播放的 AVAudioSessionCategoryPlayAndRecord
- (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [NSURL fileURLWithPath:[@"Users/mayan/Desktop" stringByAppendingPathComponent:@"voice.caf"]]; NSDictionary *settings = @{ AVFormatIDKey : @(kAudioFormatAppleIMA4), AVSampleRateKey : @22050.0f, AVNumberOfChannelsKey : @1, }; self.recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:nil]; if (self.recorder) { self.recorder.delegate = self; [self.recorder prepareToRecord]; }}- (IBAction)record { [self.recorder record];}- (IBAction)recordFinish { [self.recorder stop];}// 音频录制完成调用- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{ if (flag) { // 一般把录制好的音频复制或者剪切到目的文件夹下 NSURL *srcURL = self.recorder.url; NSURL *destURL = [NSURL URLWithString:@"目的文件路径/音频文件名称.caf"]; [[NSFileManager defaultManager] copyItemAtURL:srcURL toURL:destURL error:nil]; }}
在录制音频过程中,Core Audio Format(CAF)通常是最好的容器格式,因为它和内容无关可以保存 Core Audio 支持的任何音频格式。在设置字典中指定的键值信息也值得讨论一番:
音频格式
AVFormatIDKey 定义了写入内容的音频格式,下面是常用格式:
- kAudioFormatLinearPCM:将未压缩的音频流写入到文件中。保真度最高,文件也最大;
- kAudioFormatMPEG4AAC(AAC) 或 kAudioFormat-AppleIMA4(Apple IMA4):文件显著缩小,还能保证高质量音频
采样率
AVSampleRateKey 定义了录音器的采样率,采样率定义了对输入的模拟音频信号每一秒的采样数。采样率越高,越能得到高质量的内容,不过文件相对越大。标准的采样率:8000、16000、22050、44100
通道数
AVNumberOfChannelsKey 定义记录音频内容的通道数。默认值 1 是单声道录制,2 是立体声录制。除非使用外部硬件录制,否则应该创建单声道录音。
6. 音频测量
AVAudioPlayer 和 AVAudioRecorder 中最实用的功能就是对音频进行测量。Audio Metering 可以读取音频的平均分贝和峰值分贝数据,并使用这些数据以可视化方式将声音大小呈现给用户。
首先在初始化 AVAudioPlayer 或 AVAudioRecorder 时应做出如下设置
self.player.meteringEnabled = YES;
self.recorder.meteringEnabled = YES;
点击音频播放或者音频录制,开始测量
- (void)startMeterTimer{ [self.link invalidate]; self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateMeter)]; self.link.frameInterval = 4; // 时间间隔为刷新率的 1/4 [self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];}- (void)stopMeterTimer{ [self.link invalidate]; self.link = nil;}
下面分别是音频播放情况下测量、音频录制情况下测量
- (void)updateMeter{ [self.player updateMeters]; // 刷新 CGFloat num1 = [self.player averagePowerForChannel:0]; CGFloat num2 = [self.player peakPowerForChannel:0]; NSLog(@"平均分贝:%f, 峰值分贝:%f", num1, num2);}
- (void)updateMeter{ [self.recorder updateMeters]; // 刷新 CGFloat num1 = [self.recorder averagePowerForChannel:0]; CGFloat num2 = [self.recorder peakPowerForChannel:0]; NSLog(@"平均分贝:%f, 峰值分贝:%f", num1, num2);}
上面方法都会返回用于表示声音分贝(dB)等级的浮点值,这个值的范围是 -160dB ~ 0dB
- 《AV Foundation 开发秘籍》读书笔记(二)
- 《AV Foundation 开发秘籍》读书笔记(待续)
- 《AV Foundation 开发秘籍》读书笔记(三)
- AV Foundation学习之(二)
- AV Foundation学习之补充(二)
- AV Foundation 开发秘籍--实践掌握iOS & OS X应用的视听处理技术——互动出版网
- FOUNDATION 秘籍
- IOS 基于AV Foundation框架开发简单音乐播放器
- IOS 基于AV Foundation框架开发简单音乐播放器
- Android开发秘籍学习笔记(二)
- iphone开发秘籍-读书笔记
- iphone ios AV Foundation
- AV Foundation - 播放音乐
- AV Foundation - 录制音频
- AV Foundation 框架图
- AV Foundation系列(四)AVAssetReader和AVAssetWrite
- 《微软开发快速秘籍》读书笔记2-锦囊妙计
- 《微软开发快速秘籍》读书笔记7-团队
- php报错 syntax error: unexpected end of file
- [paper]Efficient Deep Learning for Stereo Matching(未完成)
- vue的解构
- 关于UITableViewCell的重用
- mui写web项目,获取当前地理位置
- 《AV Foundation 开发秘籍》读书笔记(二)
- javascript计算对象的长度
- 机器学习技法-01-5-Reasons behind Large-Margin Hyperplane
- 双精度,单精度和半精度
- 前后端分离实践(一)
- 例 5.9 输入一个大于3的整数n,判定它是否为素数(prime,又称质数)。
- 数据集划分函数 train_test_split()
- Dubbo的两种启动模式,基于注解的和基于XML配置的
- JavaEsSpark.esJsonRDD函数读取ES数据报错