本篇是AudioQueue的官方文檔的筆記。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轉化成LPCM。AudioQueue是對mic和speaker的高度抽象,同時可以非常簡單的時間音頻codecs。與此同時,它也有一些高級功能,例如多個音頻的同步播放,回放等等。
這章會了解到audio queue的功能,結構體,以及內部運行的機理。具體的內容包括audio queues,audio queue buffers,audio queue會使用到的callback等。還有就是audio queue的狀態以及參數。
An audio queue 是iOS中play和record audio的對象.底層是AudioQueueRef
。Audio queue可以完成以下工作:
Audio queue的具體結構有以下幾個部分構成:
A set of audio queue buffers, each of which is a temporary repository for some audio dataA buffer queue, an ordered list for the audio queue buffersAn audio queue callback function, that you write根據我們使用audio queue的用途(record or play),具體的結構略有不同,僅僅只是callback函數函數的內容不同。
一個用于record 的audio queue,需要使用AudioQueueNewInput
方法創建,它的具體結構如圖:
一個用于play的audio queue,需要使用AudioQueueNewOutput
函數創建,
audio queue buffer的數據結構如下:
1234567 | typedef struct AudioQueueBuffer { const UInt32 mAudioDataBytesCapacity; void *const mAudioData; UInt32 mAudioDataByteSize; void *mUserData;} AudioQueueBuffer;typedef AudioQueueBuffer *AudioQueueBufferRef; |
其中mAudioData字段表示這個buffer中的有用數據的地址,其他的字段用來輔助audio queue來管理使用這個buffer。一個audio queue可以使用任何數目的buffers。但是我們一般選擇3個,比較好管理。
Audio queue通過下面的方式管理它們內部的buffers:
An audio queue allocates a buffer when you call the AudioQueueAllocateBuffer function.When you release an audio queue by calling the AudioQueueDispose function, the queue releases its buffers.buffer queue是由audio buffers組成的,是audio queue中的buffers。我們前面介紹了audio queue是如何使用callback管理內部的buffers。不論當前是用于record或者是pleyback,將buffer放到audio queue都是需要我們在callback函數中去手動調用的。
Audio queue buffers在queue是順序播放的,我們可以通theAudioQueueEnqueueBufferWithParameters
方法來進行控制
Audio queue在運行過程中會不斷的調用callback函數,通常間隔時間和audio queue buffer的大小相關,一般是幾秒一次。
audio queue callback主要任務是將audio queue buffer歸還給audio queue。callback中通過AudioQueueEnqueueBuffer
方法將buffer加載到audio queue的最后。在playback中,可以使用AudioQueueEnqueueBufferWithParameters
在enqueue的過程中進行更多的控制。
如果你僅僅使用audio queue去將record的audio data寫入file system,callback的方法實現的原型如下:
12345678 | AudioQueueInputCallback ( void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions, const AudioStreamPacketDescription *inPacketDescs); |
一個recording audio queue會觸發我們注冊的callback,會在callback的參數中傳入所有需要的關于audio data的相關信息:
inUserData 是一個自定義的結構體,用來存儲audio queueu以及audio queue buffer的狀態信息,也包括AudioFileID,audio data format等。inAQ 表示哪個audio queue觸發這個callback。inBuffer 是一個audio queue buffer,它的內容是由audio queue填充的,內部包括最新的audio data。并且這些audio data已經根據初始化時候傳遞的格式參數格式化好的數據。inStartTime 表示這個buffer中的第一個采樣的采樣時間點,一般app中不太需要這個參數。inNumberPacketDescriptions 表示inPacketDescs參數中的packet descriptions的個數。如果你是錄入VBR format,audio queue就會在callback中提供這個參數,如果是CBR,audio queue就不會使用packet descriptions參數,這個參數會是NULL。inPacketDescs 表示buffer中samples相關的一系列的packet descriptions。是否設置同上一個參數。這個片段會介紹如果使用playing audio queue,那么callback應該的信息:
12345 | AudioQueueOutputCallback ( void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer); |
一個playback audio queue會觸發這個callback,提供一些關于audio data的有用信息:
inUserData 見上inAQ 表示哪個audio queue觸發這個callback。inBuffer 表示被audio queue設置為空的audio queue buffer,你需要在callback中將其內部信息填滿,填充內容是你從AudioFile中讀取的audio data。我們日常使用Audio Queue Services時,都會使用codecs(audio data coding/decoding componets)用來在不同audio format之間進行轉化。
每個audio queue都有一個audio data format,可以在AudioStreamBasicDescription
結構體中得到。當我們在ASBD中指定了mFormatID
以后,audio queue在向buffer中填充數據時候就會使用相應的codec。同樣如果指定sample rate和channel count,audio queue也會同樣。具體的過程見下圖:
整個過程中,callback函數壓根就不需要知道data fromat是什么。
在播放過程中,正好和錄音過程相反,只需要在創建audio queue時候將data format告知即可。
audio queue在創建和銷毀的過程有一個聲明周期。app需要管理它的聲明周期,控制它的狀態,具體控制狀態的方法如下:
Start (AudioQueueStart
).初始化audio queue用來record或者playback。Prime (AudioQueuePrime
).對于playback,在調用AudioQueueStart
摯愛去哪調用確保數據可用,這個方法和record沒有關系。Stop (AudioQueueStop
). 調用以后會重置audio queue,然后會停止record或者playback。在playback應用中,一般在沒有audio data可以播放時候調用。Pause (AudioQueuePause
). 在record或者playback中調用這個方法不會影響到buffers。如果需要恢復,調用AudioQueueStart
。Flush (AudioQueueFlush
). 在enqueue最后一個audio queue buffer以后調用這個方法,確保所有的數據被record或者play(主要是在midst processing的數據)。Reset (AudioQueueReset
). 調用以后立即停止audio queue,然后將所有的buffers移除,重置所有的DSP狀態等到。在調用AudioQueueStop
方法時候有兩種模式:同步和異步。
當我們的record使用Audio Queue Services,存儲的路徑可以是磁盤上的任何地方,或者網絡,或者內存中。這部分內容記錄大多數的使用場景,存儲在磁盤中。
具體的步驟如下:
定義一個結構體去存儲狀態,format,文件路徑等信息。完成audio queue callback函數,其中將record以后的數據進行存儲。為audio queue buffers計算出合適的大小,并且在file中寫入magic cookies。初始化自定義的結構體創建recording audio queue,然后給它創建3個audio queue buffers,然后創建一個file用來存儲record以后的audio data。啟動audio queue當audio queue停止以后,dispose它以及buffers具體的實現內容可以參考Apple官方文檔:Recording Audio。
當我們使用Audio Queue Service去play audio時,音頻源文件可以是任何在disk file或者memory中,這部分內容是如何用Audio Queue Service播放存儲在disk上的audio file。
具體的步驟如下:
定義一個結構體管理Audio queue的狀態,format,file path等完成audio queue callback函數去進行實際的播放創建一個函數用來計算最適合的audio queue buffer的大小打開audio file,確定它的audio data format創建audio queue,對它進行配置為audio queue創建buffers,然后啟動audio queue,當播放結束,callback讓audio queue停止播放銷毀audio queue具體的實現內容可以參考Apple官方文檔:Playing Audio。
請參考我的github: https://github.com/brownfeng/AudioQueueServiceDemo
新聞熱點
疑難解答