前言
相關(guān)文章:
使用VideoToolbox硬編碼H.264
使用VideoToolbox硬解碼H.264
使用AudioToolbox編碼AAC
使用AudioToolbox播放AAC
HLS點(diǎn)播實(shí)現(xiàn)(H.264和AAC碼流)
HLS推流的實(shí)現(xiàn)(iOS和OS X系統(tǒng))
iOS在線音頻流播放
Audio Unit播放PCM文件
Audio Unit錄音(播放伴奏+耳返)
Audio Unit播放aac/m4a/mp3等文件
前文介紹了AudioUnit的錄音/播放功能被因,也介紹了通過(guò)AudioConvert進(jìn)行音頻的轉(zhuǎn)換,但是AudioConvert的API使用起來(lái)較為麻煩,除了需要調(diào)用AudioFileGetProperty
獲取許多信息之外,還要調(diào)用AudioConverterFillComplexBuffer
進(jìn)行ConvertBuffer的填充伐割,并在其數(shù)據(jù)輸入回調(diào)中調(diào)用AudioFileReadPacketData
目木,且要考慮AudioStreamPacketDescription的賦值。
本文嘗試使用更為簡(jiǎn)單的方法 Extended Audio File Services滑废。
Extended Audio File Services是high-level的API困乒,提供音頻文件的讀/寫(xiě)寂屏,是Audio File Services 和 Audio Converter Services 的結(jié)合,在AudioFile和AudioConvert的基礎(chǔ)上提供統(tǒng)一的接口進(jìn)行讀寫(xiě)操作娜搂。
正文
概念儲(chǔ)備
-
ExtAudioFileOpenURL
是新建一個(gè)ExtAudioFileRef迁霎,用于讀取音頻文件; -
ExtAudioFileWrapAudioFileID
是通過(guò)一個(gè)已有的AudioFileID百宇,創(chuàng)建一個(gè)ExtAudioFileRef考廉;
開(kāi)發(fā)者必須保證在ExtAudioFileRef被銷(xiāo)毀前,AudioFileID是處于打開(kāi)的狀態(tài)恳谎,并且在ExtAudioFileRef被銷(xiāo)毀后芝此,手動(dòng)關(guān)閉AudioFileID; -
ExtAudioFileGetProperty
獲取對(duì)應(yīng)PropertyID的屬性因痛; -
ExtAudioFileGetProperty
獲取設(shè)置PropertyID的屬性;
ExtAudioFile對(duì)應(yīng)的PropertyID如下
CF_ENUM(ExtAudioFilePropertyID) {
kExtAudioFileProperty_FileDataFormat = 'ffmt', // AudioStreamBasicDescription
kExtAudioFileProperty_FileChannelLayout = 'fclo', // AudioChannelLayout
kExtAudioFileProperty_ClientDataFormat = 'cfmt', // AudioStreamBasicDescription
kExtAudioFileProperty_ClientChannelLayout = 'cclo', // AudioChannelLayout
kExtAudioFileProperty_CodecManufacturer = 'cman', // UInt32
// read-only:
kExtAudioFileProperty_AudioConverter = 'acnv', // AudioConverterRef
kExtAudioFileProperty_AudioFile = 'afil', // AudioFileID
kExtAudioFileProperty_FileMaxPacketSize = 'fmps', // UInt32
kExtAudioFileProperty_ClientMaxPacketSize = 'cmps', // UInt32
kExtAudioFileProperty_FileLengthFrames = '#frm', // SInt64
// writable:
kExtAudioFileProperty_ConverterConfig = 'accf', // CFPropertyListRef
kExtAudioFileProperty_IOBufferSizeBytes = 'iobs', // UInt32
kExtAudioFileProperty_IOBuffer = 'iobf', // void *
kExtAudioFileProperty_PacketTable = 'xpti' // AudioFilePacketTableInfo
};
介紹其中常用的屬性:
kExtAudioFileProperty_FileDataFormat
:讀取文件格式岸更,只讀鸵膏,返回文件的ASBD;kAudioFormatProperty_FormatInfo
:根據(jù)給定的格式怎炊,盡可能填充格式的其他信息谭企。kExtAudioFileProperty_ClientDataFormat
:設(shè)置這個(gè)屬性,才能進(jìn)行對(duì)非pcm格式的文件進(jìn)行編解碼评肆,這個(gè)格式也是ExtAudioFileRead 和 ExtAudioFileWrite 時(shí)的格式债查。kExtAudioFileProperty_FileLengthFrames
:文件的長(zhǎng)度,單位是sample frames瓜挽,獲取前需要先設(shè)置好輸入和輸出的格式盹廷;kExtAudioFileProperty_AudioConverter
,是獲取系統(tǒng)的AudioConverterRef久橙,如果在獲取之后俄占,手動(dòng)修改converter的屬性管怠,比如說(shuō)碼率,必須通過(guò)kExtAudioFileProperty_ConverterConfig
設(shè)置ExtAudioFileRef缸榄;kExtAudioFileError_CodecUnavailableInputConsumed
:當(dāng)ExtAudioFileWrite被打斷的時(shí)候會(huì)返回這個(gè)錯(cuò)誤渤弛,需要先停止調(diào)用ExtAudioFileWrite,等待audioSession恢復(fù)甚带,并調(diào)用AudioSessionSetActive
她肯,再進(jìn)行resuming;與kExtAudioFileError_CodecUnavailableInputNotConsumed的區(qū)別是鹰贵,前者的buffer已經(jīng)被使用晴氨,下次調(diào)用需要賦值新的buffer,后者需要再次提供相同的buffer砾莱;
具體細(xì)節(jié)
1瑞筐、初始化AVAudioSession和AudioBufferList;
2腊瑟、通過(guò)url打開(kāi)ExtAudioFileRef聚假,并通過(guò)
ExtAudioFileGetProperty
獲取文件格式;初始化讀取的格式闰非,并通過(guò)ExtAudioFileSetProperty
設(shè)置給ExtAudioFileRef膘格;輸入和輸出格式設(shè)置,類(lèi)似初始化AudioConvert的過(guò)程财松。3瘪贱、初始化AudioUnit,并設(shè)置輸入的格式與ExtAudioFileRef的輸出格式一致辆毡;
4菜秦、在AudioUnit的播放回調(diào)中調(diào)用
ExtAudioFileRead
讀取ExtAudioFileRef的數(shù)據(jù),如果讀取返回的數(shù)組長(zhǎng)度是0表示播放結(jié)束舶掖;
遇到的問(wèn)題
1球昨、獲取的音頻frame幀數(shù)不正常
如果在未設(shè)置好輸入輸出格式前,就通過(guò)kExtAudioFileProperty_FileLengthFrames
獲取的總frame數(shù)眨攘,此時(shí)獲取的frame是不準(zhǔn)確的主慰,并且會(huì)導(dǎo)致后續(xù)的操作錯(cuò)誤。
正確的做法是先設(shè)置好 kExtAudioFileProperty_ClientDataFormat
屬性的值鲫售,再獲取總的frame數(shù)共螺。
2、播放進(jìn)度不準(zhǔn)確
播放的進(jìn)度=當(dāng)前播放的幀數(shù)/音頻文件的總幀數(shù)情竹;
進(jìn)度不準(zhǔn)確問(wèn)題是因?yàn)楂@取的是frame數(shù)藐不,之前在計(jì)算已播放的幀數(shù)時(shí)沒(méi)有正確的把讀取的字節(jié)長(zhǎng)度除以輸出格式的mBytesPerFrame。
當(dāng)前已播放的幀數(shù) += 讀取的字節(jié)長(zhǎng)度 / ASBD.mBytesPerFrame。
總結(jié)
ExtendedAudioFile相對(duì)Audio File Services 和 Audio Converter Services 佳吞,API調(diào)用非常簡(jiǎn)單和明確拱雏,并且不需要去處理AudioStreamPacketDescription,在實(shí)際開(kāi)發(fā)中邏輯更為清晰底扳。
demo 的代碼在這里铸抑,可以看到ExtendedAudioFile具體使用方式。