目標
學習AVAudioPlayer和AVAudioRecorder類來實現(xiàn)音頻播放及錄制功能
理解音頻會話
iOS默認音頻會話的預配置
- 激活了音頻播放讯蒲,但是音頻錄制未激活
- 當用戶切換響鈴/靜音開關到“靜音”模式時昂利,應用程序播放的所有音頻都會消失
- 當設備顯示解鎖屏幕時澈蝙,應用程序的音頻處于靜音狀態(tài)
- 當應用程序播放音頻時奕谭,所有后臺播放的音頻都會處于靜音狀態(tài)
音頻會話分類
-
上述分類提供滿足大部分需求的常見行為甘苍,如果需要更加復雜的功能,其中一些分類通過使用options和modes方法進一步自定義開發(fā)
- options讓開發(fā)者使用一些附加行為(如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的緩沖區(qū)蓖谢,降低調用play方法和聽到聲音輸出之間的延時
- 通過pause和stop方法停止的音頻都會繼續(xù)播放捂蕴,主要區(qū)別在底層處理上(stop方法會撤銷調用prepareToPlay時所作的設置,而pause方法則不會)
- 指定位置播放:currentTime
- 修改播放器的音量:volume
- 修改播放器的pan值: -1.0(極左)闪幽, 1.0(極右)啥辨,默認0.0居中
- 調整播放率rate:iOS5加入,范圍(0.5 - 2.0)半速-2倍速盯腌。前提條件需要設置enableRate屬性
- 無縫循環(huán)numberOfLoops:大于0可實現(xiàn)n次循環(huán)溉知,-1無限循環(huán)(音頻循環(huán)可以是未壓縮的線性PCM音頻,也可以是AAC之類的壓縮格式音頻。但是MP3格式音頻要實現(xiàn)循環(huán)的目的通常需要使用特殊工具處理级乍,建議使用AAC或AppleLossless格式循環(huán))
-(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) {
//無限循環(huán)
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設備上添加或移除音頻輸入捅厂、輸出線路時贯卦,會發(fā)生線路改變。
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 確認系統(tǒng)中斷類型
//來電、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];
}
}
}
通知處理
//線路切換監(jiān)聽
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注簿,這個方法執(zhí)行底層Audio Queue初始化的必要過程契吉。該方法還在URL參數指定的位置創(chuàng)建一個文件,將錄制啟動時的延遲降到最低
音頻格式(指定的音頻格式一定要和URL參數定義的文件類型兼容)
- kAudioFormatLinearPCM
- kAudioFormatMPEG4AAC
- kAudioFormatAppleLossless
- kAudioFormatAppleIMA4
- kAudioFormatilBC
- kAudioFormatULaw
采樣率 - AVSampleRateKey定義錄音器的采樣率诡渴。采樣率定義了對輸入的模擬音頻信號每一秒的采樣數捐晶。對音頻的質量以及最終文件大小起到重要作用。盡量使用標準的采樣率(8000妄辩、16000惑灵、22050、44100)
通道數 - AVNumberOfChannelsKey用于定義記錄音頻內容的通道數眼耀。1意味著使用單聲道英支,2意味著立體聲錄制。
指定格式的鍵 - 處理Linear PCM或壓縮音頻格式時哮伟,可以定義一些其他指定格式的鍵
配置音頻會話 - AVAudioSessionCategoryPlayAndRecord這個分類既可以錄音有需要對外播放
currentTime屬性干花,因為該屬性不可見,所以無法使用KVO來監(jiān)聽
初始化
-(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屬性才支持對音頻進行測量