iOS 音頻學習邊錄音邊轉(zhuǎn)碼Audio Queues

如果在錄音的過程中我想滿足需求:邊錄音邊轉(zhuǎn)碼夺颤, 邊錄音邊上傳到服務器, 而不是等錄音結束

在錄音的時候望拖, 使用AVAudioRecorder的話洛波,要拿到錄音的數(shù)據(jù)只能等錄音結束之后全肮,從錄音保存的路徑中獲取塞蹭。如果你想實時進行編碼的話是做不到的, 有沒有好的方法呢门坷, 如果要實現(xiàn)上述功能的話我覺得有兩個方法:

1宣鄙、用AudioToolbox 框架中的Audio Queues進行錄音, 在錄音元數(shù)據(jù)回調(diào)過程中對數(shù)據(jù)進行轉(zhuǎn)碼默蚌, 上傳
2冻晤、用AVFounation 框架中的AVCaptureSession進行錄音, 在錄音元數(shù)據(jù)回調(diào)過程中對數(shù)據(jù)進行轉(zhuǎn)碼绸吸, 上傳(直播都是用這種方法鼻弧, 一般音視頻一起錄制)

本篇簡單介紹一下第一種方法實現(xiàn)用AudioToolbox 框架中的Audio Queues進行錄音

1设江、什么是Audio Queue?

Audio Queue是在iOS或OS平臺中用來錄音或者播放音頻的一個對象攘轩, 可以參照AudioQueue.h文件叉存, 這是一個C語言框架, 屬于蘋果錄音中層框架度帮。

作用:
1鹉胖、連接磁盤內(nèi)存的錄音文件
2、管理內(nèi)存
3够傍、可以用來配合編碼器或解碼器編碼和解碼
4甫菠、錄音或播放錄音

Audio Queue Services可以play和record以下三類任何audio data:
  • Linear PCM.
  • Any compressed format supported natively on the Apple platform you are developing for.
  • Any other format for which a user has an installed codec.
    對于最后一種類型,我們可以在使用AudioQueue同時自己將自己需要的format轉(zhuǎn)化成LPCM冕屯。AudioQueue是對mic和speaker的高度抽象寂诱,同時可以非常簡單的時間音頻codecs。與此同時安聘,它也有一些高級功能痰洒,例如多個音頻的同步播放,回放等等浴韭。
2丘喻、工作原理

Audio Queues for Recording
一個用于record 的audio queue,需要使用AudioQueueNewInput
方法創(chuàng)建念颈,它的具體結構如圖:


Audio Queues for Playback
一個用于play的audio queue泉粉,需要使用AudioQueueNewOutput
函數(shù)創(chuàng)建,
A playback audio queue
A playback audio queue

Audio Queue Buffers

audio queue buffer的數(shù)據(jù)結構如下:

typedef struct AudioQueueBuffer {
    const UInt32   mAudioDataBytesCapacity;
    void *const    mAudioData;
    UInt32         mAudioDataByteSize;
    void           *mUserData;
} AudioQueueBuffer;
typedef AudioQueueBuffer *AudioQueueBufferRef;

其中mAudioData字段表示這個buffer中的有用數(shù)據(jù)的地址榴芳,其他的字段用來輔助audio queue來管理使用這個buffer嗡靡。一個audio queue可以使用任何數(shù)目的buffers。但是我們一般選擇3個窟感,比較好管理讨彼。

The Buffer Queue and Enqueuing

buffer queue是由audio buffers組成的,是audio queue中的buffers柿祈。我們前面介紹了audio queue是如何使用callback管理內(nèi)部的buffers哈误。不論當前是用于record或者是pleyback,將buffer放到audio queue都是需要我們在callback函數(shù)中去手動調(diào)用的躏嚎。
The Recording Process

In step 1 , recording begins. The audio queue fills a buffer with acquired data.
In step 2, the first buffer has been filled. The audio queue invokes the callback, handing it the full buffer (buffer 1). The callback (step 3) writes the contents of the buffer to an audio file. At the same time, the audio queue fills another buffer (buffer 2) with freshly acquired data.
In step 4, the callback enqueues the buffer (buffer 1) that it has just written to disk, putting it in line to be filled again. The audio queue again invokes the callback (step 5), handing it the next full buffer (buffer 2). The callback (step 6) writes the contents of this buffer to the audio file. This looping steady state continues until the user stops the recording.

The Playback Process


Controlling the Playback Process
Audio queue buffers在queue是順序播放的蜜自,我們可以通theAudioQueueEnqueueBufferWithParameters
方法來進行控制

The Audio Queue Callback Function

Audio queue在運行過程中會不斷的調(diào)用callback函數(shù),通常間隔時間和audio queue buffer的大小相關紧索,一般是幾秒一次袁辈。
audio queue callback主要任務是將audio queue buffer歸還給audio queue菜谣。callback中通過AudioQueueEnqueueBuffer
方法將buffer加載到audio queue的最后珠漂。在playback中晚缩,可以使用AudioQueueEnqueueBufferWithParameters
在enqueue的過程中進行更多的控制。
The Recording Audio Queue Callback Function
如果你僅僅使用audio queue去將record的audio data寫入file system媳危,callback的方法實現(xiàn)的原型如下:

AudioQueueInputCallback (
void *inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumberPacketDescriptions,
const AudioStreamPacketDescription *inPacketDescs
);

一個recording audio queue會觸發(fā)我們注冊的callback荞彼,會在callback的參數(shù)中傳入所有需要的關于audio data的相關信息:
inUserData 是一個自定義的結構體,用來存儲audio queueu以及audio queue buffer的狀態(tài)信息待笑,也包括AudioFileID鸣皂,audio data format等。
inAQ 表示哪個audio queue觸發(fā)這個callback暮蹂。
inBuffer 是一個audio queue buffer寞缝,它的內(nèi)容是由audio queue填充的,內(nèi)部包括最新的audio data仰泻。并且這些audio data已經(jīng)根據(jù)初始化時候傳遞的格式參數(shù)格式化好的數(shù)據(jù)荆陆。
inStartTime 表示這個buffer中的第一個采樣的采樣時間點,一般app中不太需要這個參數(shù)集侯。
inNumberPacketDescriptions 表示inPacketDescs參數(shù)中的packet descriptions的個數(shù)被啼。如果你是錄入VBR format,audio queue就會在callback中提供這個參數(shù)棠枉,如果是CBR浓体,audio queue就不會使用packet descriptions參數(shù),這個參數(shù)會是NULL辈讶。
inPacketDescs 表示buffer中samples相關的一系列的packet descriptions命浴。是否設置同上一個參數(shù)。

The Playback Audio Queue Callback Function
這個片段會介紹如果使用playing audio queue贱除,那么callback應該的信息:


AudioQueueOutputCallback (
void *inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer
);

一個playback audio queue會觸發(fā)這個callback咳促,提供一些關于audio data的有用信息:
inUserData 見上
inAQ 表示哪個audio queue觸發(fā)這個callback。
inBuffer 表示被audio queue設置為空的audio queue buffer勘伺,你需要在callback中將其內(nèi)部信息填滿跪腹,填充內(nèi)容是你從AudioFile中讀取的audio data。

Using Codecs and Audio Data Formats

我們?nèi)粘J褂肁udio Queue Services時飞醉,都會使用codecs(audio data coding/decoding componets)用來在不同audio format之間進行轉(zhuǎn)化冲茸。
每個audio queue都有一個audio data format,可以在AudioStreamBasicDescription
結構體中得到缅帘。當我們在ASBD中指定了mFormatID
以后轴术,audio queue在向buffer中填充數(shù)據(jù)時候就會使用相應的codec。同樣如果指定sample rate和channel count钦无,audio queue也會同樣逗栽。具體的過程見下圖:


第一步中,app會告知audio queue開始record失暂,同時告訴它使用的的data format彼宠。
第二步中鳄虱,audio queue將獲取到的new data使用codec轉(zhuǎn)化成目標format。然后audio queue會調(diào)用callback函數(shù)凭峡,傳入格式化以后的audio data拙已。
第三步中,callback函數(shù)會將格式化以后的audio data寫入file中摧冀。

整個過程中倍踪,callback函數(shù)壓根就不需要知道data fromat是什么。


在播放過程中索昂,正好和錄音過程相反建车,只需要在創(chuàng)建audio queue時候?qū)ata format告知即可。

Audio Queue Control and State

audio queue在創(chuàng)建和銷毀的過程有一個聲明周期椒惨。app需要管理它的聲明周期癞志,控制它的狀態(tài),具體控制狀態(tài)的方法如下:
Start (AudioQueueStart).
初始化audio queue用來record或者playback框产。
Prime (AudioQueuePrime).
對于playback凄杯,在調(diào)用AudioQueueStart
摯愛去哪調(diào)用確保數(shù)據(jù)可用,這個方法和record沒有關系秉宿。
Stop (AudioQueueStop).
調(diào)用以后會重置audio queue戒突,然后會停止record或者playback。在playback應用中描睦,一般在沒有audio data可以播放時候調(diào)用膊存。
Pause (AudioQueuePause).
在record或者playback中調(diào)用這個方法不會影響到buffers。如果需要恢復忱叭,調(diào)用AudioQueueStart
隔崎。
Flush (AudioQueueFlush).
在enqueue最后一個audio queue buffer以后調(diào)用這個方法,確保所有的數(shù)據(jù)被record或者play(主要是在midst processing的數(shù)據(jù))韵丑。
Reset (AudioQueueReset).
調(diào)用以后立即停止audio queue爵卒,然后將所有的buffers移除,重置所有的DSP狀態(tài)等到撵彻。

在調(diào)用AudioQueueStop
方法時候有兩種模式:同步和異步钓株。
Synchronous stopping happens immediately, without regard for previously buffered audio data.
Asynchronous stopping happens after all queued buffers have been played or recorded.

Recording Audio

當我們的record使用Audio Queue Services,存儲的路徑可以是磁盤上的任何地方陌僵,或者網(wǎng)絡轴合,或者內(nèi)存中。這部分內(nèi)容記錄大多數(shù)的使用場景碗短,存儲在磁盤中受葛。
具體的步驟如下:
定義一個結構體去存儲狀態(tài),format,文件路徑等信息总滩。
完成audio queue callback函數(shù)纲堵,其中將record以后的數(shù)據(jù)進行存儲。
為audio queue buffers計算出合適的大小咳秉,并且在file中寫入magic cookies婉支。
初始化自定義的結構體
創(chuàng)建recording audio queue鸯隅,然后給它創(chuàng)建3個audio queue buffers澜建,然后創(chuàng)建一個file用來存儲record以后的audio data。
啟動audio queue
當audio queue停止以后蝌以,dispose它以及buffers

具體的實現(xiàn)內(nèi)容可以參考Apple官方文檔:Recording Audio炕舵。
Playing Audio
當我們使用Audio Queue Service去play audio時,音頻源文件可以是任何在disk file或者memory中跟畅,這部分內(nèi)容是如何用Audio Queue Service播放存儲在disk上的audio file咽筋。
具體的步驟如下:

定義一個結構體管理Audio queue的狀態(tài),format徊件,file path等
完成audio queue callback函數(shù)去進行實際的播放
創(chuàng)建一個函數(shù)用來計算最適合的audio queue buffer的大小
打開audio file奸攻,確定它的audio data format
創(chuàng)建audio queue,對它進行配置
為audio queue創(chuàng)建buffers虱痕,然后啟動audio queue睹耐,當播放結束,callback讓audio queue停止播放
銷毀audio queue

具體的實現(xiàn)內(nèi)容可以參考Apple官方文檔:Playing Audio部翘。

關于AudioToolBoolx的蘋果Demo
最后給大家推薦一個好用的硝训,封裝的比較好的第三方框架MLAudioRecorder

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市新思,隨后出現(xiàn)的幾起案子窖梁,更是在濱河造成了極大的恐慌,老刑警劉巖夹囚,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纵刘,死亡現(xiàn)場離奇詭異,居然都是意外死亡荸哟,警方通過查閱死者的電腦和手機彰导,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來敲茄,“玉大人位谋,你說我怎么就攤上這事⊙吡牵” “怎么了掏父?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秆剪。 經(jīng)常有香客問我赊淑,道長爵政,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任陶缺,我火速辦了婚禮钾挟,結果婚禮上,老公的妹妹穿的比我還像新娘饱岸。我一直安慰自己掺出,他們只是感情好,可當我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布苫费。 她就那樣靜靜地躺著汤锨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪百框。 梳的紋絲不亂的頭發(fā)上闲礼,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機與錄音铐维,去河邊找鬼柬泽。 笑死,一個胖子當著我的面吹牛嫁蛇,可吹牛的內(nèi)容都是我干的锨并。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼棠众,長吁一口氣:“原來是場噩夢啊……” “哼琳疏!你這毒婦竟也來了?” 一聲冷哼從身側響起闸拿,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤空盼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后新荤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揽趾,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年苛骨,在試婚紗的時候發(fā)現(xiàn)自己被綠了篱瞎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡痒芝,死狀恐怖俐筋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情严衬,我是刑警寧澤澄者,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響粱挡,放射性物質(zhì)發(fā)生泄漏赠幕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一询筏、第九天 我趴在偏房一處隱蔽的房頂上張望榕堰。 院中可真熱鬧,春花似錦嫌套、人聲如沸逆屡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽康二。三九已至碳胳,卻和暖如春勇蝙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挨约。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工味混, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诫惭。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓翁锡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親夕土。 傳聞我的和親對象是個殘疾皇子馆衔,可洞房花燭夜當晚...
    茶點故事閱讀 44,647評論 2 354

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