AVFoundation-播放和錄制音頻

目標

學習AVAudioPlayer和AVAudioRecorder類來實現(xiàn)音頻播放及錄制功能

理解音頻會話

iOS默認音頻會話的預配置

  • 激活了音頻播放讯蒲,但是音頻錄制未激活
  • 當用戶切換響鈴/靜音開關到“靜音”模式時昂利,應用程序播放的所有音頻都會消失
  • 當設備顯示解鎖屏幕時澈蝙,應用程序的音頻處于靜音狀態(tài)
  • 當應用程序播放音頻時奕谭,所有后臺播放的音頻都會處于靜音狀態(tài)

音頻會話分類

屏幕快照 2019-11-12 下午10.05.39.png
  • 上述分類提供滿足大部分需求的常見行為甘苍,如果需要更加復雜的功能,其中一些分類通過使用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屬性才支持對音頻進行測量

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末楞黄,一起剝皮案震驚了整個濱河市池凄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鬼廓,老刑警劉巖修赞,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡柏副,警方通過查閱死者的電腦和手機勾邦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來割择,“玉大人眷篇,你說我怎么就攤上這事±笥荆” “怎么了蕉饼?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長玛歌。 經常有香客問我昧港,道長,這世上最難降的妖魔是什么支子? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任创肥,我火速辦了婚禮,結果婚禮上值朋,老公的妹妹穿的比我還像新娘叹侄。我一直安慰自己,他們只是感情好昨登,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布趾代。 她就那樣靜靜地躺著,像睡著了一般丰辣。 火紅的嫁衣襯著肌膚如雪撒强。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天笙什,我揣著相機與錄音尿褪,去河邊找鬼。 笑死得湘,一個胖子當著我的面吹牛杖玲,可吹牛的內容都是我干的。 我是一名探鬼主播淘正,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼摆马,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鸿吆?” 一聲冷哼從身側響起囤采,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惩淳,沒想到半個月后蕉毯,有當地人在樹林里發(fā)現(xiàn)了一具尸體乓搬,經...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年代虾,在試婚紗的時候發(fā)現(xiàn)自己被綠了进肯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡棉磨,死狀恐怖江掩,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情乘瓤,我是刑警寧澤环形,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站衙傀,受9級特大地震影響抬吟,放射性物質發(fā)生泄漏。R本人自食惡果不足惜统抬,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一火本、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蓄喇,春花似錦发侵、人聲如沸交掏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盅弛。三九已至钱骂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挪鹏,已是汗流浹背见秽。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留讨盒,地道東北人解取。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像返顺,于是被迫代替她去往敵國和親禀苦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內容