需求
本人要做一個錄音同時播放音樂的App, 對錄音要求較高, 因為要分析噪音情況, 同時去掉播放音樂的回聲
錄音方案
- AVAudioRecorder, 此種方法已經(jīng)封裝的比較簡單, 雖然AVAudioRecorder很方便好用,但是其需要將數(shù)據(jù)存到文件中,對于實時流的方式則不適用,此時還需要使用其他方式
- Audio Queue Services, 通過Queue對象來管理存放音頻的數(shù)據(jù)的各個Buffer,其通過AudioQueueNewInput創(chuàng)建一個會采集數(shù)據(jù)到Buffer中的AudioQueue。在驅(qū)動回調(diào)里面,從Buffer中取得采集到的數(shù)據(jù),再把這個空Buffer Enqueue到BufferQueue給AudioQueue采集存數(shù)據(jù)使用, 拿到的數(shù)據(jù)需要算法來消除音樂回環(huán)
- AudioUnit在iOS音頻開發(fā)最底層, 作者使用的方法, 自帶VoIP硬件消除回環(huán)
AudioUnit 來錄音并消除回環(huán)
我參考了huisedediao的Demo, 在這里簡單介紹下幾個重點需要注意的
- 配置AudioSession, 這是播放音樂或者錄音都必須要做的事情, 錄音我們選擇playAndRecord
- 配置AudioComponentDescription, 這里選擇VoiceProcessingIO, Description里的對應(yīng)關(guān)系可以看Identifier Keys for Audio Units
//其中“componentType”和“componentSubType”表示了這個Unit是上面描述的那種類型
AudioComponentDescription inputcd = {0};
inputcd.componentType = kAudioUnitType_Output;
inputcd.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
inputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
- 原本需要通過AUGraph來運行AudioUnit, 我參考的Demo也是, 現(xiàn)在 Apple已經(jīng)把所有的Audio Unit Progressing Graph Services給Deprecated了, 所以想實現(xiàn)的朋友可以直接用AudioComponentDescription初始化AUAudioUnit, AudioUnitSetProperty來設(shè)置屬性, 回調(diào)方法, AudioStreamBasicDescription設(shè)置采樣速率, 通道等來實現(xiàn)
遇到的問題
- 播放音樂為什么聲音很輕, 有時候用聽筒播放?
錄音時設(shè)置AVAudioSession時候把option設(shè)置Speaker, 如果播放音樂也設(shè)置了option, 那么需要后啟動錄音 - 錄音斷斷續(xù)續(xù)
錄音的AVAudioSession在options設(shè)置成Speaker情況下, 如果播放音樂又設(shè)置了一遍Speaker會沖突, 雖然是個單例, 但是因為底層是個黑盒, 所以不知道為啥會造成沖突, 最好音樂options設(shè)置成mixWithOthers - AVAudioSession在PortOverride為Speaker的情況下, 音樂回環(huán)處理無效
播放音樂的AVAudioSession也選擇playAndRecord, 或者把這段代碼刪除 - 系統(tǒng)的回聲處理會將低頻聲音給過濾
原本我需要實現(xiàn)分析環(huán)境噪音, 在使用過后, 環(huán)境噪音從原來的60dB變成了40dB, 在研究了消除回聲算法后, 發(fā)現(xiàn)消除噪音提取有效信息是必須做的