前言
相關文章:
使用VideoToolbox硬編碼H.264
使用VideoToolbox硬解碼H.264
使用AudioToolbox編碼AAC
使用AudioToolbox播放AAC
HLS點播實現(H.264和AAC碼流)
HLS推流的實現(iOS和OS X系統)
iOS在線音頻流播放
Audio Unit播放PCM文件
Audio Unit錄音(播放伴奏+耳返)
前面兩篇介紹了Audio Unit播放PCM文件和邊錄邊播,這次引入AudioConvert實現aac/m4a/mp3格式的播放。
正文
1、格式轉換
音頻數據的格式轉換包括采樣率改變,單聲道到多聲道的轉變、音調的升高降低等,audio unit有一個專門格式轉換unit(kAudioUnitType_FormatConverter,type of 'aufc'
)。
AudioUnit不支持vbr的數據,也不支持從一個有損壓縮格式轉換為pcm或者pcm轉換為有損格式,對于有損格式的音頻數據轉換,需要用CoreAudio的Audio Converter API。
2、AudioFile API 和 Converter
AudioFile API提供了API對音頻文件的創建、打開、修改和保存;
Audio Converters 用于音頻文件的編解碼,還可以用于sample rate的改變、int到float的轉變,最常見是將音頻文件轉成pcm播放;
下面Converter的兩個格式:
Source Format
Sample Rate: 44100
Format ID: .mp3
Format Flags: 0
Bytes per Packet: 0
Frames per Packet: 1152
Bytes per Frame: 0
Channels per Frame: 2
Bits per Channel: 0
Target Format
Sample Rate: 44100
Format ID: lpcm
Format Flags: 4
Bytes per Packet: 2
Frames per Packet: 1
Bytes per Frame: 2
Channels per Frame: 1
Bits per Channel: 16
3、具體細節
1、初始化AudioFile,通過AudioFileOpenURL
打開音頻文件,并讀取對應的音頻格式(AudioStreamBasicDescription
);這里和Audio Unit播放PCM文件不同的是,還需要讀取kAudioFilePropertyMaximumPacketSize
和kAudioFilePropertyAudioDataPacketCount
兩個屬性,分別是單個package的最大size和packet的數量,并通過緩存的大小和package的size創建AudioStreamPacketDescription
的數組;
2、初始化AudioUnit,設置AVAudioSession的Category為AVAudioSessionCategoryPlayback
;初始化AudioBufferList,設置AudioUnit的playback回調;
3、在AudioUnit的playback回調中,調用AudioConvert的AudioConverterFillComplexBuffer
函數并設置好回調方法lyInInputDataProc
;在回調的lyInInputDataProc
中,通過AudioFileReadPacketData
讀取音頻數據并把讀取的AudioStreamPacketDescription回傳;
4、AudioConvert轉換后的音頻數據會填入參數buffList,將對應的數據復制給AudioUnit的playback參數;
遇到的問題
1、API替換
一開始用的是AudioFileReadPackets
方法讀取音頻數據,后面在遇到問題后發現AudioFileReadPackets
被替換成AudioFileReadPacketData
,參數類似;
2、AudioConverter的轉換函數的返回值
調用AudioConverterFillComplexBuffer
后,在回調方法lyInInputDataProc
中,如果設置 *ioNumberDataPackets = 0
,并且返回 noErr
, AudioConverter 會進入 Finished
的狀態;
返回非零的值,表示數據未完成,比如在demo中返回了
NO_MORE_DATA
,NO_MORE_DATA
是自定義的非零返回值;
3、AudioConverterNewSpecific返回-50
通過OSStatus
,可以看到-50是AVAudioSessionErrorCodeBadParam 參數不一致;
檢查代碼,發現是在使用AudioConverterNewSpecific() 創建轉換器的時候輸入流格式與輸出流格式的聲道數設置不同;(解決方案就是聲道數改成一致)
4、AudioConverterFillComplexBuffer返回561015652
通過OSStatus
,查到561015652是kAudioConverterErr_RequiresPacketDescriptionsError = '!pkd'
,意思是沒有回調AudioStreamPacketDescriptions
參數;
對于音頻格式mBytesPerPacket=0
的數據,需要AudioStreamPacketDescriptions
參數來輔助轉換音頻數據;
解決方案就是新建AudioStreamPacketDescriptions
數組,并且在讀取后賦值給outDataPacketDescription
(見demo);
總結
AudioUnit和AudioConvert的API雖然簡單,卻是功能強大。
文章中的介紹更多是自己在學習過程中的一些收獲,對于知識點的介紹很多是不夠全面和仔細的,對此建議看看參考目錄。
Extended Audio File Services
是Audio File Services
和 Audio Converter Services
的結合,提供統一的接口進行處理,下篇可能會是Extended Audio File
相關。
參考
Playing a sound file using the Default Output Audio Unit
Supported Audio File and Data Formats in OS X