IOS音視頻(四十四)AVFoundation 之 Audio Queue Services

IOS音視頻(一)AVFoundation核心類html

IOS音視頻(二)AVFoundation視頻捕捉c++

IOS音視頻(三)AVFoundation 播放和錄音編程

IOS音視頻(四十三)AVFoundation 之 Audio Sessionswift

IOS音視頻(四十四)AVFoundation 之 Audio Queue Services數組

IOS音視頻(四十五)HTTPS 自簽名證書 實現邊下邊播緩存

IOS音視頻(四十六)離線在線語音識別方案數據結構

1. Audio Queue Services簡介

Audio Queue Services,這是Core Audio的Audio Toolbox框架中的一個C編程接口。架構

  • 那麼什麼是音頻隊列服務呢? Audio Queue Services提供了一種簡單、低開銷的方式來在iOS和Mac OS X中錄製和播放音頻。 音頻隊列服務讓您記錄和播放音頻的任何下列格式:
  1. 線性PCM。
  2. 您正在開發的Apple平臺上原生支持的任何壓縮格式。
  3. 用戶已安裝編解碼器的任何其餘格式。

音頻隊列服務是高級的。它容許您的應用程序在不瞭解硬件接口的狀況下使用硬件記錄和回放設備(如麥克風和揚聲器)。它還容許您在不瞭解編解碼器工做原理的狀況下使用複雜的編解碼器。 同時,音頻隊列服務支持一些高級功能。它提供了細粒度的定時控制,以支持預約的回放和同步。您可使用它來同步多個音頻隊列的回放,並同步音頻和視頻。app

注意:Audio Queue Services提供的特性與以前Mac OS x中的聲音管理器提供的特性相似。聲音管理器在Mac OS X v10.5中是不支持的,而且不能用於64位應用程序。蘋果推薦全部新開發的音頻隊列服務,並將其做爲現有Mac OS X應用程序中的聲音管理器的替代品。框架

Audio Queue Services是一個純C接口,能夠在Cocoa應用程序中使用,也能夠在Mac OS X命令行工具中使用。爲了保持對音頻隊列服務的關注,本文中的代碼示例有時經過使用Core Audio SDK中的c++類進行了簡化。可是,不管是SDK仍是c++語言都不須要使用音頻隊列服務。

1.1 音頻隊列

  • 什麼是音頻隊列呢?

音頻隊列是在iOS或Mac OS x中用於錄製或播放音頻的軟件對象。它由AudioQueueRef不透明數據類型表示,在AudioQueue.h頭文件中聲明。您可使用音頻隊列和其餘核心音頻接口,以及相對少許的自定義代碼,在應用程序中建立完整的數字音頻錄製或回放解決方案。 一個音頻隊列作的工做以下:

  1. 鏈接到音頻硬件
  2. 管理內存
  3. 根據須要對壓縮的音頻格式使用編解碼器
  4. 調用錄音和回放

1.1.1 音頻隊列架構

全部的音頻隊列具備相同的通常結構,由如下部分組成:

  • 一組音頻隊列緩衝區,每一個緩衝區都是一些音頻數據的臨時存儲庫
  • 一個緩衝區隊列,一個音頻隊列緩衝區的有序列表
  • 你寫的一個音頻隊列回調函數

根據音頻隊列是用於錄製仍是用於回放,架構會有所不一樣。區別在於音頻隊列如何鏈接其輸入和輸出,以及回調函數的角色。

1.1.2 用於錄音的音頻隊列

使用AudioQueueNewInput函數建立的錄製音頻隊列的結構如圖1-1所示。

錄音音頻隊列

建立一個新的錄製音頻隊列對象。方法以下:

func AudioQueueNewInput(_ inFormat: UnsafePointer<AudioStreamBasicDescription>, _ inCallbackProc: AudioQueueInputCallback, _ inUserData: UnsafeMutableRawPointer?, _ inCallbackRunLoop: CFRunLoop?, _ inCallbackRunLoopMode: CFString?, _ inFlags: UInt32, _ outAQ: UnsafeMutablePointer<AudioQueueRef?>) -> OSStatus
複製代碼

上面AudioQueueNewInput的參數詳解以下:

  1. inFormat: 要記錄到的壓縮或未壓縮音頻數據格式。當記錄到線性PCM時,只支持交錯格式。
  2. inCallbackProc : 一個回調函數,用於記錄音頻隊列。當音頻隊列完成填充緩衝區時,音頻隊列調用此函數。看到AudioQueueInputCallback
  3. inUserData : 與回調函數一塊兒使用的自定義數據結構。
  4. inCallbackRunLoop : 要調用inCallbackProc參數所指向的回調函數的事件循環。若是指定NULL,則在音頻隊列的內部線程上調用回調。
  5. inCallbackRunLoopMode : 調用在inCallbackProc參數中指定的回調函數的運行循環模式。一般,您傳遞kCFRunLoopCommonModes或使用NULL,這是等價的。您能夠選擇用本身的run循環建立本身的線程。有關運行循環的更多信息,請參見運行循環和CFRunLoop
  6. inFlags : 保留供未來使用。必須是0。
  7. outAQ : 在輸出端,新建立的錄製音頻隊列。

還有一個音頻隊列輸入回調方法:AudioQueueInputCallback,這個回調是當錄製音頻隊列完成填充音頻隊列緩衝區時,系統調用。

在調用AudioQueueNewInput(::::::_: ::)函數時,指定一個錄製音頻隊列回調。每次其記錄音頻隊列用新音頻數據填充音頻隊列緩衝區時,都會調用回調。一般,回調將數據寫入文件或其餘緩衝區,而後從新對音頻隊列緩衝區進行排隊以接收更多數據。

typealias AudioQueueInputCallback = (UnsafeMutableRawPointer?, AudioQueueRef, AudioQueueBufferRef, UnsafePointer<AudioTimeStamp>, UInt32, UnsafePointer<AudioStreamPacketDescription>?) -> Void

複製代碼

參數詳解以下:

  1. inUserData :您在AudioQueueNewInput(::::::_: ::)函數的inUserData參數中指定的定製數據。一般,這包括音頻隊列的格式和狀態信息。
  2. inAQ :調用回調的錄製音頻隊列。
  3. inBuffer : 一個音頻隊列緩衝區,由記錄音頻隊列新填充,包含回調須要寫入的新音頻數據。
  4. inStartTime : 音頻隊列緩衝區啓動的示例時間。此參數不用於基本記錄。
  5. inNumberPacketDescriptions : 在inBuffer參數中發送回調的音頻數據包的數量。當以恆定比特率(CBR)格式錄製時,音頻隊列將此參數設置爲NULL。
  6. inPacketDescs : 對於須要包描述的壓縮格式,編碼器爲inBuffer參數中的音頻數據生成的包描述集。當以CBR格式錄製時,音頻隊列將此參數設置爲NULL。
  • 錄音音頻隊列的輸入端一般鏈接到外部音頻硬件,如麥克風。例如,在iOS中,音頻來自用戶內置麥克風或耳機麥克風鏈接的設備。在Mac OS X的默認狀況下,音頻來自系統的默認音頻輸入設備,由用戶在系統首選項中設置。
  • 錄製音頻隊列的輸出端使用您編寫的回調函數。當錄製到磁盤時,回調將從其音頻隊列接收到的新音頻數據的緩衝區寫入音頻文件。然而,錄製音頻隊列能夠以其餘方式使用。例如,回調能夠直接嚮應用程序提供音頻數據,而不是將其寫入磁盤。
  • 如想了解關於此回調的更多信息請參考:錄製音頻隊列回調函數
  • 每一個音頻隊列—不管是錄製仍是播放—都有一個或多個音頻隊列緩衝區。這些緩衝區按照稱爲緩衝區隊列的特定順序排列。在圖中,音頻隊列緩衝區根據它們被填入的順序進行編號——這與它們被傳遞給回調的順序相同。

1.1.3 用於回放的音頻隊列

回放音頻隊列(使用AudioQueueNewOutput函數建立)的結構如圖1-2所示。

用於回放的音頻隊列

在回放音頻隊列中,回調位於輸入端。回調負責從磁盤(或其餘源)獲取音頻數據並將其傳遞給音頻隊列。回放回調也告訴它們的音頻隊列在沒有更多數據播放時中止。

回放音頻隊列的輸出一般鏈接到外部音頻硬件,如揚聲器。在iOS系統中,音頻會傳送到用戶選擇的設備上,例如,接收器或耳機。在Mac OS X的默認狀況下,音頻將按照用戶在系統首選項中設置的方式進入系統的默認音頻輸出設備。

接下來認識一下AudioQueueNewOutput函數,該函數用來建立一個新的播放音頻隊列對象。函數定義以下:

func AudioQueueNewOutput(_ inFormat: UnsafePointer<AudioStreamBasicDescription>, _ inCallbackProc: AudioQueueOutputCallback, _ inUserData: UnsafeMutableRawPointer?, _ inCallbackRunLoop: CFRunLoop?, _ inCallbackRunLoopMode: CFString?, _ inFlags: UInt32, _ outAQ: UnsafeMutablePointer<AudioQueueRef?>) -> OSStatus

複製代碼

它的參數詳解以下:

  1. inFormat: 要記錄到的壓縮或未壓縮音頻數據格式。當記錄到線性PCM時,只支持交錯格式。
  2. 一個回調函數,用於回放音頻隊列。音頻隊列在音頻隊列完成獲取緩衝區後調用回調。參考:AudioQueueOutputCallback
  3. inUserData : 與回調函數一塊兒使用的自定義數據結構。
  4. inCallbackRunLoop : 要調用inCallbackProc參數所指向的回調函數的事件循環。若是指定NULL,則在音頻隊列的內部線程上調用回調。
  5. inCallbackRunLoopMode : 調用在inCallbackProc參數中指定的回調函數的運行循環模式。一般,您傳遞kCFRunLoopCommonModes或使用NULL,這是等價的。您能夠選擇用本身的run循環建立本身的線程。有關運行循環的更多信息,請參見運行循環和CFRunLoop
  6. inFlags : 保留供未來使用。必須是0。
  7. outAQ : 在輸出時,新建立的回放音頻隊列對象。
  • 用於回放音頻隊列。音頻隊列在音頻隊列完成獲取緩衝區後調用回調。這個回調函數當音頻隊列緩衝區可重用時,由系統調用。AudioQueueOutputCallback的定義以下:
typealias AudioQueueOutputCallback = (UnsafeMutableRawPointer?, AudioQueueRef, AudioQueueBufferRef) -> Void

複製代碼

參數詳解以下:

  1. inUserData :您在AudioQueueNewOutput(::::::: :::)函數的inUserData參數中指定的定製數據。一般,這包括音頻隊列的數據格式和狀態信息。
  2. inAQ :調用回調的回放音頻隊列。
  3. inBuffer : 一個音頻隊列緩衝區,最近可用來填充,由於回放音頻隊列已經獲取了它的內容。
  • 若是你將你的回調函數命名爲MyAudioQueueOutputCallback,你會這樣聲明它: 此回調函數在其關聯的回放音頻隊列從音頻隊列緩衝區獲取數據時調用,此時該緩衝區可用於重用。新可用的緩衝區在inBuffer參數中被髮送到這個回調。一般,你寫這個回調到:
  1. 用文件或其餘緩衝區中的下一組音頻數據填充新可用的緩衝區。
  2. 從新排隊播放緩衝區。要對緩衝區從新排隊,可使用AudioQueueEnqueueBuffer(::::)或AudioQueueEnqueueBufferWithParameters(:::::::::: _:)函數。

要將此回調與回放音頻隊列關聯,請在建立音頻隊列時提供對回調的引用。查看AudioQueueNewOutput(::::::_: _:)函數的inCallbackProc參數。 當系統調用此回調時,您不能假定已播放了來自新可用緩衝區的音頻數據。有關如何檢查聲音是否已完成播放的說明,請參閱AudioQueuePropertyListenerProc回調函數的討論。

1.1.4 音頻隊列緩衝區

音頻隊列緩衝區是一種數據結構,類型爲AudioQueueBuffer,在AudioQueue.h頭文件中聲明:

typedef struct AudioQueueBuffer {
    const UInt32   mAudioDataBytesCapacity;
    void *const    mAudioData;
    UInt32         mAudioDataByteSize;
    void           *mUserData;
} AudioQueueBuffer;
typedef AudioQueueBuffer *AudioQueueBufferRef;
複製代碼

上面代碼中突出顯示的mAudioData字段指向緩衝區自己:一塊內存,用做正在播放或錄製的音頻數據的暫態塊的容器。其餘字段中的信息有助於音頻隊列管理緩衝區。

一個音頻隊列可使用任意數量的緩衝區。您的應用程序指定了數量。一個典型的數字是3。這使得一我的能夠忙於寫磁盤,而另外一我的則忙於填充新的音頻數據。若是須要補償磁盤I/O延遲等問題,可使用第三個緩衝區。圖1-3說明了這一點。

音頻隊列爲其緩衝區執行內存管理:

AudioQueueAllocateBuffer函數一旦分配,指向音頻隊列緩衝區的指針和緩衝區的容量就不能更改。緩衝區的size字段mAudioDataByteSize最初設置爲0,表示有效數據的數量。其中AudioQueueAllocateBuffer函數定義以下:

func AudioQueueAllocateBuffer(_ inAQ: AudioQueueRef, _ inBufferByteSize: UInt32, _ outBuffer: UnsafeMutablePointer<AudioQueueBufferRef?>) -> OSStatus

複製代碼

函數參數解析:

  1. inAQ :要分配緩衝區的音頻隊列。
  2. inBufferByteSize : 新緩衝區所需的容量,以字節爲單位。適當的容量取決於對數據和音頻數據格式的處理。
  3. outBuffer : 在輸出時,指向新分配的音頻隊列緩衝區。

AudioQueueDispose函數處理音頻隊列也會處理它的資源,包括它的緩衝區。調用此函數後,您將不能再與音頻隊列進行交互。此外,音頻隊列再也不調用任何回調。 AudioQueueDispose函數定義以下:

func AudioQueueDispose(_ inAQ: AudioQueueRef, _ inImmediate: Bool) -> OSStatus
複製代碼

函數參數解析:

  1. inAQ :要處理的音頻隊列。
  2. inImmediate : 若是傳遞true,則當即(即同步地)處理音頻隊列。若是傳遞false,則在處理全部進入隊列的緩衝區(即異步處理)以前不會執行處理。

使用音頻隊列緩衝提升了添加到應用程序的錄製和回放功能的健壯性。它還有助於優化資源使用。

有關AudioQueueBuffer數據結構的完整描述,請參見AudioQueue Services參考資料。

1.1.5 音頻隊列服務

  • 音頻隊列服務容許您在線性PCM、壓縮格式(如Apple無損和AAC)和其餘用戶已安裝編解碼器的格式中錄製和播放音頻。音頻隊列服務還支持多個音頻隊列的預約回放和同步以及音頻與視頻的同步。
  • 音頻隊列是用於錄製或播放音頻的軟件對象。一個音頻隊列作的工做:
  1. 鏈接到音頻硬件
  2. 管理內存
  3. 根據須要對壓縮的音頻格式使用編解碼器
  4. 調用錄音和回放

注意: 音頻隊列服務提供了與以前由聲音管理器和macOS提供的相似的功能。它增長了額外的功能,好比同步。聲音管理器在OS X v10.5中是不支持的,而且不能用於64位應用程序。建議全部新開發的應用程序都使用音頻隊列服務,以替代現有Mac應用程序中的聲音管理器。

  • 提供了控制音頻隊列的接口以下:
//開始播放或錄製音頻。
func AudioQueueStart(AudioQueueRef, UnsafePointer<AudioTimeStamp>?) -> OSStatus

//解碼進入隊列的緩衝區,爲回放作準備。
func AudioQueuePrime(AudioQueueRef, UInt32, UnsafeMutablePointer<UInt32>?) -> OSStatus

//重置音頻隊列的解碼器狀態。
func AudioQueueFlush(AudioQueueRef) -> OSStatus

//中止播放或錄製音頻。
func AudioQueueStop(AudioQueueRef, Bool) -> OSStatus

//暫停音頻播放或錄音。
func AudioQueuePause(AudioQueueRef) -> OSStatus

//重置音頻隊列。
func AudioQueueReset(AudioQueueRef) -> OSStatus

複製代碼
  • 提供了建立和處理音頻隊列的接口以下:
//建立一個新的播放音頻隊列對象。
func AudioQueueNewOutput(UnsafePointer<AudioStreamBasicDescription>, AudioQueueOutputCallback, UnsafeMutableRawPointer?, CFRunLoop?, CFString?, UInt32, UnsafeMutablePointer<AudioQueueRef?>) -> OSStatus

//建立一個新的錄製音頻隊列對象。
func AudioQueueNewInput(UnsafePointer<AudioStreamBasicDescription>, AudioQueueInputCallback, UnsafeMutableRawPointer?, CFRunLoop?, CFString?, UInt32, UnsafeMutablePointer<AudioQueueRef?>) -> OSStatus

////析構一個音頻隊列。
func AudioQueueDispose(AudioQueueRef, Bool) -> OSStatus

複製代碼
  • 提供了處理音頻隊列緩衝區的接口以下:
//請求音頻隊列對象分配音頻隊列緩衝區。
func AudioQueueAllocateBuffer(AudioQueueRef, UInt32, UnsafeMutablePointer<AudioQueueBufferRef?>) -> OSStatus

//請求一個音頻隊列對象分配一個帶有數據包描述空間的音頻隊列緩衝區。
func AudioQueueAllocateBufferWithPacketDescriptions(AudioQueueRef, UInt32, UInt32, UnsafeMutablePointer<AudioQueueBufferRef?>) -> OSStatus

//請求音頻隊列處理音頻隊列緩衝區。
func AudioQueueFreeBuffer(AudioQueueRef, AudioQueueBufferRef) -> OSStatus

//將緩衝區添加到錄製或回放音頻隊列的緩衝區隊列中。
func AudioQueueEnqueueBuffer(AudioQueueRef, AudioQueueBufferRef, UInt32, UnsafePointer<AudioStreamPacketDescription>?) -> OSStatus

//將緩衝區添加到回放音頻隊列對象的緩衝區隊列中,指定開始時間和其餘設置。
func AudioQueueEnqueueBufferWithParameters(AudioQueueRef, AudioQueueBufferRef, UInt32, UnsafePointer<AudioStreamPacketDescription>?, UInt32, UInt32, UInt32, UnsafePointer<AudioQueueParameterEvent>?, UnsafePointer<AudioTimeStamp>?, UnsafeMutablePointer<AudioTimeStamp>?) -> OSStatus

複製代碼
  • 提供了操做音頻隊列參數的接口以下:
//獲取音頻隊列參數值.
func AudioQueueGetParameter(AudioQueueRef, AudioQueueParameterID, UnsafeMutablePointer<AudioQueueParameterValue>) -> OSStatus

//設置播放音頻隊列參數值。
func AudioQueueSetParameter(AudioQueueRef, AudioQueueParameterID, AudioQueueParameterValue) -> OSStatus

複製代碼
  • 提供了操做音頻隊列屬性的接口以下:
//獲取音頻隊列屬性值。
func AudioQueueGetProperty(AudioQueueRef, AudioQueuePropertyID, UnsafeMutableRawPointer, UnsafeMutablePointer<UInt32>) -> OSStatus

//設置一個音頻隊列屬性值。
func AudioQueueSetProperty(AudioQueueRef, AudioQueuePropertyID, UnsafeRawPointer, UInt32) -> OSStatus

//獲取音頻隊列屬性值的大小。
func AudioQueueGetPropertySize(AudioQueueRef, AudioQueuePropertyID, UnsafeMutablePointer<UInt32>) -> OSStatus

//將屬性偵聽器回調添加到音頻隊列。
func AudioQueueAddPropertyListener(AudioQueueRef, AudioQueuePropertyID, AudioQueuePropertyListenerProc, UnsafeMutableRawPointer?) -> OSStatus

//從音頻隊列中移除一個屬性偵聽器回調。
func AudioQueueRemovePropertyListener(AudioQueueRef, AudioQueuePropertyID, AudioQueuePropertyListenerProc, UnsafeMutableRawPointer?) -> OSStatus

複製代碼
  • 提供了處理時間的接口以下:
//爲音頻隊列建立一個時間軸對象。
func AudioQueueCreateTimeline(AudioQueueRef, UnsafeMutablePointer<AudioQueueTimelineRef?>) -> OSStatus

//析構釋放音頻隊列的時間軸對象。
func AudioQueueDisposeTimeline(AudioQueueRef, AudioQueueTimelineRef) -> OSStatus

//獲取與音頻隊列關聯的音頻硬件設備的當前時間。
func AudioQueueDeviceGetCurrentTime(AudioQueueRef, UnsafeMutablePointer<AudioTimeStamp>) -> OSStatus

//獲取音頻硬件設備最接近請求的啓動時間的啓動時間。
func AudioQueueDeviceGetNearestStartTime(AudioQueueRef, UnsafeMutablePointer<AudioTimeStamp>, UInt32) -> OSStatus

//將音頻隊列的相關音頻硬件設備的時間從一種時基表示形式轉換爲另外一種時基表示形式。
func AudioQueueDeviceTranslateTime(AudioQueueRef, UnsafePointer<AudioTimeStamp>, UnsafeMutablePointer<AudioTimeStamp>) -> OSStatus

//獲取當前音頻隊列時間。
func AudioQueueGetCurrentTime(AudioQueueRef, AudioQueueTimelineRef?, UnsafeMutablePointer<AudioTimeStamp>?, UnsafeMutablePointer<DarwinBoolean>?) -> OSStatus

複製代碼
  • 提供了執行離線渲染的接口以下:
//設置播放音頻隊列的呈現模式和音頻格式。
func AudioQueueSetOfflineRenderFormat(AudioQueueRef, UnsafePointer<AudioStreamBasicDescription>?, UnsafePointer<AudioChannelLayout>?) -> OSStatus

//使用回放音頻隊列將音頻導出到緩衝區,而不是設備。
func AudioQueueOfflineRender(AudioQueueRef, UnsafePointer<AudioTimeStamp>, AudioQueueBufferRef, UInt32) -> OSStatus

複製代碼
  • 提供了回調函數以下:
//當一個錄製音頻隊列完成填充音頻隊列緩衝區時,系統調用。
typealias AudioQueueInputCallback

//當一個音頻隊列緩衝區能夠重用時,系統調用。
typealias AudioQueueOutputCallback

//當指定的音頻隊列屬性改變值時,系統調用。
typealias AudioQueuePropertyListenerProc

複製代碼

1.1.6 緩存入隊和排隊

緩衝區隊列提供音頻隊列(其實是音頻隊列服務)及其名稱。您在音頻隊列體系結構中遇到了緩衝隊列(一個按順序排列的緩衝區列表)。在這裏,您將瞭解音頻隊列對象以及回調函數如何在錄製或回放期間管理緩衝區隊列。特別是,您將瞭解排隊,即將音頻隊列緩衝區添加到緩衝區隊列。不管您是實現錄製仍是回放,排隊都是回調執行的任務

1.1.6.1 錄音過程

在錄製時,一個音頻隊列緩衝區將填充從輸入設備(如麥克風)獲取的音頻數據。緩衝區隊列中的其他緩衝區排在當前緩衝區後面,等待依次填充音頻數據。

音頻隊列按獲取音頻數據的順序將填滿的緩衝區傳遞給回調。圖1-3說明了在使用音頻隊列時如何進行錄製。

使用音頻隊列時如何進行錄製

  • 在圖1-3的步驟1中,開始記錄。音頻隊列用獲取的數據填充緩衝區。

  • 在步驟2中,第一個緩衝區已被填充。音頻隊列調用回調,將完整的緩衝區(緩衝區1)交給它。回調(步驟3)將緩衝區的內容寫入音頻文件。同時,音頻隊列用新得到的數據填充另外一個緩衝區(緩衝區2)。

  • 在第4步中,回調將它剛剛寫到磁盤的緩衝區(緩衝區1)放入隊列中,使其再次被填滿。音頻隊列再次調用回調(步驟5),並將下一個完整的緩衝區(緩衝區2)交給它。這種循環穩定狀態一直持續到用戶中止錄製爲止。

1.1.6.2 回放過程

播放時,一個音頻隊列緩衝區被髮送到輸出設備,如揚聲器。緩衝區隊列中剩餘的緩衝區排在當前緩衝區後面,等待依次播放。

音頻隊列將音頻數據的播放緩衝區按播放的順序傳遞給回調。回調將新的音頻數據讀入緩衝區,而後對其進行排隊。圖1-4演示了在使用音頻隊列時回放是如何工做的。

圖1-4演示了在使用音頻隊列時回放是如何工做的

在圖1-4的步驟1中,應用程序啓動回放音頻隊列。應用程序爲每一個音頻隊列緩衝區調用一次回調,填充它們並將它們添加到緩衝區隊列中。啓動確保回放能夠在應用程序調用AudioQueueStart函數時當即啓動(步驟2)。

在步驟3中,音頻隊列將第一個緩衝區(緩衝區1)發送到輸出。

一旦播放了第一個緩衝區,播放音頻隊列就進入循環穩定狀態。音頻隊列開始播放下一個緩衝區(緩衝區2,步驟4)並調用回調(步驟5),將剛剛播放的緩衝區(緩衝區1)交給它。

1.1.6.3 控制回放過程

音頻隊列緩衝區老是按照它們進入隊列的順序播放。然而,音頻隊列服務經過AudioQueueEnqueueBufferWithParameters函數爲您提供了對回放過程的一些控制。這個功能讓你:

  • 爲緩衝區設置精確的回放時間。這使您可以支持同步。
  • 在音頻隊列緩衝區的開始或結束處修剪幀。這可讓您移除引導或尾隨的靜默。
  • 在緩衝區的粒度上設置回放增益

您可使用此函數對緩衝區隊列施加一些控制。您能夠分配音頻隊列設置,這些設置其實是由音頻隊列緩衝區攜帶的。所以,設置在音頻隊列緩衝區開始播放時生效。 這個函數只適用於回放。錄製音頻隊列不接受參數,也不支持可變比特率(VBR)格式(這可能須要調整)。 AudioQueueEnqueueBufferWithParameters函數的完整定義以下:

func AudioQueueEnqueueBufferWithParameters(_ inAQ: AudioQueueRef, _ inBuffer: AudioQueueBufferRef, _ inNumPacketDescs: UInt32, _ inPacketDescs: UnsafePointer<AudioStreamPacketDescription>?, _ inTrimFramesAtStart: UInt32, _ inTrimFramesAtEnd: UInt32, _ inNumParamValues: UInt32, _ inParamValues: UnsafePointer<AudioQueueParameterEvent>?, _ inStartTime: UnsafePointer<AudioTimeStamp>?, _ outActualStartTime: UnsafeMutablePointer<AudioTimeStamp>?) -> OSStatus

複製代碼

函數參數詳解以下:

  1. inAQ : 擁有音頻隊列緩衝區的音頻隊列對象。
  2. inBuffer : 要添加到緩衝區隊列中的音頻隊列緩衝區。在調用此函數以前,緩衝區必須包含要播放的音頻數據。
  3. inNumPacketDescs : inBuffer參數中音頻數據的包數。對下列任何一種狀況使用0值:(1)當播放恆定比特率(CBR)格式時。(2)當使用audioqueueallocatebufferwithpacketdescription(:::: _:)函數分配正在從新排隊的緩衝區時。在這種狀況下,回調應該描述緩衝區的mpacketdescription和mPacketDescriptionCount字段中的緩衝區包。
  4. inPacketDescs : 包描述的數組。在下列任何一種狀況下使用NULL值:(1)當播放恆定比特率(CBR)格式時。(2)當使用audioqueueallocatebufferwithpacketdescription(:::: _:)函數分配正在從新排隊的緩衝區時。在這種狀況下,回調應該描述緩衝區的mpacketdescription和mPacketDescriptionCount字段中的緩衝區包。
  5. inTrimFramesAtStart : 在緩衝區開始時要跳過的啓動幀數。
  6. inTrimFramesAtEnd : 緩衝區結束時要跳過的幀數。
  7. inNumParamValues : inParamValues參數指向的音頻隊列參數值的數量。若是不設置參數,則使用0。
  8. inParamValues : 要應用於音頻隊列緩衝區的參數數組。(在OS X v10.5中,只有一個音頻隊列參數kAudioQueueParam_Volume。)若是沒有設置緩衝區的參數,則使用NULL。 在播放以前分配參數值——在緩衝區播放時不能更改參數值。音頻隊列緩衝區參數的更改將在緩衝區開始播放時生效。
  9. inStartTime : 播放緩衝區所需的開始時間。要指定與音頻隊列啓動時間相關的時間,請使用AudioTimeStamp結構的mSampleTime字段。使用NULL來指示緩衝區應該儘快播放—這多是在前面排隊的緩衝區完成播放以後。 緩衝區按它們進入隊列的順序運行(先入先出)。若是有多個緩衝區在排隊,則開始時間必須是升序或NULL;不然,將發生錯誤。此參數指定音頻數據什麼時候開始播放,忽略在mframesatstart參數中指定的任何修剪幀。
  10. outActualStartTime : 在輸出時,緩衝區實際開始播放的時間。

1.1.7 使用編解碼器和音頻數據格式

音頻隊列服務根據須要使用編解碼器(音頻數據編碼/解碼組件)在音頻格式之間進行轉換。您的錄音或播放應用程序可使用任何音頻格式,其中安裝了一個編解碼器。您不須要編寫自定義代碼來處理各類音頻格式。具體來講,回調不須要知道數據格式。

事情是這樣的。每一個音頻隊列都有一個音頻數據格式,用AudioStreamBasicDescription結構表示。當您在結構的mFormatID字段中指定格式時,音頻隊列將使用適當的編解碼器。而後指定採樣率和通道計數,這就是所有內容。您將在錄製音頻播放音頻中看到設置音頻數據格式的示例。

錄音音頻隊列使用已安裝的編解碼器,如圖1-5所示。

錄音期間的音頻格式轉換

在圖1-5的步驟1中,應用程序告訴音頻隊列開始錄製,並告訴它要使用的數據格式。在步驟2中,音頻隊列獲取新的音頻數據並根據指定的格式使用編解碼器進行轉換。而後,音頻隊列調用回調,將一個包含適當格式的音頻數據的緩衝區交給它。在步驟3中,回調將格式化的音頻數據寫入磁盤。一樣,您的回調不須要知道數據格式。

回放音頻隊列使用已安裝的編解碼器,如圖1-6所示。

播放期間的音頻格式轉換

在圖1-6的步驟1中,應用程序告訴音頻隊列開始播放,並告訴它要播放的音頻文件中包含的數據格式。在步驟2中,音頻隊列調用您的回調,它從音頻文件中讀取數據。回調函數將原始格式的數據傳遞給音頻隊列。在步驟3中,音頻隊列使用適當的編解碼器,而後將音頻發送到目的地。

音頻隊列可使用任何已安裝的編解碼器,不管是Mac OS X本地的仍是由第三方提供的。要指定要使用的編解碼器,須要向音頻隊列的AudioStreamBasicDescription結構提供其四字符代碼ID。你會在錄製音頻中看到一個這樣的例子。

Mac OS X包含普遍的音頻編解碼器,如CoreAudioTypes.h頭文件中的格式IDs枚舉所列,並如Core audio Data Types Reference所述。您可使用Audio Toolbox框架中AudioFormat.h頭文件中的接口來肯定系統上可用的編解碼器。您可使用Fiendishthngs應用程序在系統上顯示編解碼器,能夠經過http://developer.apple.com/samplecode/Fiendishthngs/得到樣例代碼。

1.1.8 音頻隊列控制和狀態

音頻隊列在建立和處理之間有一個生命週期。你的應用程序管理這個生命週期,並控制音頻隊列的狀態——使用AudioQueue.h頭文件中聲明的六個函數:

  • 開始(AudioQueueStart)。呼叫以啓動錄製或回放。
  • (AudioQueuePrime)。對於回放,在調用AudioQueueStart以前調用,以確保音頻隊列能夠當即播放數據。此功能與記錄無關。
  • 中止(AudioQueueStop)。調用重置音頻隊列(請參閱下面的AudioQueueReset描述),而後中止錄製或回放。播放音頻隊列回調在沒有更多數據播放時調用此函數。
  • 暫停(AudioQueuePause)。調用暫停錄製或回放而不影響緩衝區或重置音頻隊列。要繼續,請調用AudioQueueStart函數。
  • 沖洗(AudioQueueFlush)。進入最後一個音頻隊列緩衝區後調用,以確保全部緩衝的數據以及處理中的全部音頻數據都被錄製或播放。
  • 重置(AudioQueueReset)。調用當即靜音一個音頻隊列,從先前預約的使用中刪除全部緩衝區,並重置全部解碼器和DSP狀態。

您能夠在同步或異步模式下使用AudioQueueStop函數:

  1. 同步中止當即發生,而不考慮先前緩衝的音頻數據。
  2. 異步中止發生在播放或記錄全部排隊的緩衝區以後。

有關這些函數的完整描述,請參閱Audio Queue Services參考資料,其中包括關於同步和異步中止音頻隊列的更多信息。

1.1.9 音頻隊列參數

音頻隊列有可調的設置,稱爲參數。每一個參數都有一個枚舉常量做爲其鍵,一個浮點數做爲其值。參數一般用於回放,而不是錄製。

在Mac OS X v10.5中,惟一可用的音頻隊列參數是for gain。該參數的值是使用kAudioQueueParam_Volume常量設置或檢索的,可用範圍爲0.0(靜默)到1.0(統一增益)。

你的應用程序能夠設置音頻隊列參數的兩種方式:

  • 每一個音頻隊列,使用AudioQueueSetParameter函數。這容許您直接更改音頻隊列的設置。這些變化當即生效。
  • 每一個音頻隊列緩衝區,使用AudioQueueEnqueueBufferWithParameters函數。這使您能夠分配音頻隊列設置,這些設置其實是由音頻隊列緩衝區攜帶的。這些更改將在音頻隊列緩衝區開始播放時生效。

在這兩種狀況下,音頻隊列的參數設置將一直有效,直到您更改它們。

可使用AudioQueueGetParameter函數在任什麼時候候訪問音頻隊列的當前參數值。有關獲取和設置參數值的函數的完整描述,請參閱音頻隊列服務參考資料。

參考蘋果官方文檔:developer.apple.com/documentati…

相關文章
相關標籤/搜索