Audio Unit和ExtendedAudioFile播放音頻

前言

相關(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é)束舶掖;

demo播放

遇到的問(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具體使用方式。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末衷模,一起剝皮案震驚了整個(gè)濱河市鹊汛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌阱冶,老刑警劉巖刁憋,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異木蹬,居然都是意外死亡至耻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)镊叁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)尘颓,“玉大人,你說(shuō)我怎么就攤上這事晦譬“唐唬” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵敛腌,是天一觀的道長(zhǎng)卧土。 經(jīng)常有香客問(wèn)我,道長(zhǎng)像樊,這世上最難降的妖魔是什么尤莺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮生棍,結(jié)果婚禮上缝裁,老公的妹妹穿的比我還像新娘。我一直安慰自己足绅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布韩脑。 她就那樣靜靜地躺著氢妈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪段多。 梳的紋絲不亂的頭發(fā)上首量,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼加缘。 笑死鸭叙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拣宏。 我是一名探鬼主播沈贝,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼勋乾!你這毒婦竟也來(lái)了宋下?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辑莫,失蹤者是張志新(化名)和其女友劉穎学歧,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體各吨,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枝笨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了揭蜒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片横浑。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖忌锯,靈堂內(nèi)的尸體忽然破棺而出伪嫁,到底是詐尸還是另有隱情,我是刑警寧澤偶垮,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布张咳,位于F島的核電站,受9級(jí)特大地震影響似舵,放射性物質(zhì)發(fā)生泄漏脚猾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一砚哗、第九天 我趴在偏房一處隱蔽的房頂上張望龙助。 院中可真熱鬧,春花似錦蛛芥、人聲如沸提鸟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)称勋。三九已至,卻和暖如春涯竟,著一層夾襖步出監(jiān)牢的瞬間赡鲜,已是汗流浹背空厌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留银酬,地道東北人嘲更。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像揩瞪,于是被迫代替她去往敵國(guó)和親赋朦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容