IOS音視訊(四十三)AVFoundation 之 Audio Session

孔雨露發表於2020-04-05

@[TOC](IOS音視訊(四十三)AVFoundation 之 Audio Session)

1.音訊會話概述

音訊是iOS、tvOS和watchOS中的託管服務。系統通過使用音訊會話來管理應用程式、應用程式間和裝置級別上的音訊行為。

音訊會話

你使用一個音訊會話來與系統溝通,告訴系統你打算如何在你的應用程式中使用音訊。這個音訊會話充當了你的應用程式和作業系統之間的媒介,反過來,也就是底層音訊硬體之間的媒介。你可以使用它來與作業系統交流應用程式音訊的性質,而無需詳細說明具體的行為或與音訊硬體的必要互動。將這些細節的管理委託給音訊會話可以確保對使用者音訊體驗的最佳管理。

你與你的應用程式的音訊會話使用AVAudioSession的一個例項:

  1. 配置音訊會話類別和模式,以向系統傳達您打算如何在應用程式中使用音訊
  2. 啟用你的應用程式的音訊會話,把你的類別和模式配置到行動
  3. 訂閱和響應重要的音訊會話通知,如音訊中斷和路由更改
  4. 執行高階音訊裝置配置,如設定取樣速率、I/O緩衝區持續時間和通道數量
  • 音訊會話管理音訊行為 音訊會話是應用程式和作業系統之間的中介,用於配置應用程式的音訊行為。在啟動時,你的應用程式會自動提供一個單例音訊會話。您可以配置它來提供所需的行為,並啟用它來將該行為轉化為操作。

  • 類別表示音訊角色

表達音訊行為的主要機制是音訊會話類別。通過設定類別,您可以指示應用程式是否使用輸入或輸出路徑,是否希望音樂與音訊一起繼續播放,等等。你指定的行為應該滿足使用者的期望,正如在iOS人機介面指南音訊中描述的那樣。

AVFoundation定義了許多音訊會話類別,以及一組覆蓋和修改開關,允許您根據應用程式的個性或角色自定義音訊行為。各種類別支援回放、錄製和帶有錄製的回放。當系統知道您的應用程式的音訊角色時,它將為您提供對硬體資源的適當訪問。該系統還確保裝置上的其他音訊以適合您的應用程式的方式工作,並符合使用者的期望。

某些類別還可以通過指定用於專門化給定類別的行為的模式來進一步定製。例如,當應用程式使用視訊錄製模式時,系統可能會選擇不同於使用預設模式時的內建麥克風。該系統還可能採用為視訊錄製用例進行調優的麥克風訊號處理。

  • 通知支援中斷處理 音訊中斷是應用程式的音訊會話的停用,它會立即停止音訊。當來自應用程式的競爭音訊會話被啟用,並且該會話未被系統分類以與您的會話混合時,就會出現中斷。您的應用程式應該通過儲存狀態、更新使用者介面等方式來響應中斷。要在音訊中斷開始和結束時得到通知,請註冊以觀察AVAudioSessionInterruptionNotification型別的通知。

  • 通知支援音訊路由更改處理 當使用者通過連線或斷開裝置、插入或斷開耳機來啟動音訊路由更改時,他們有特定的期望。iOS人機介面指南描述了這些期望,並提供瞭如何滿足這些期望的指南。通過註冊來觀察AVAudioSessionRouteChangeNotification型別的通知來處理路由更改。

  • 音訊會話控制裝置配置 應用程式不能直接控制裝置硬體,但音訊會話為您提供了請求首選硬體裝置設定的介面。這個介面使您能夠執行高階音訊裝置配置,如設定取樣速率、I/O緩衝區持續時間和音訊通道的數量。

  • 音訊會話保護使用者隱私 單獨或與視訊一起錄製音訊的應用程式,在允許錄製之前,需要明確的使用者許可。在使用者授予你的應用錄製許可權之前,應用只能錄製靜音。AVAudioSession提供了請求此許可權並確定使用者隱私設定的介面。

2. 配置音訊會話

音訊會話類別是一個鍵,用於識別應用程式的一組音訊行為。通過設定一個類別,您可以向系統表明您的音訊意圖——例如,當鈴聲/靜音開關翻轉時,音訊是否應該繼續。幾個音訊會話類別,以及一組覆蓋和修改開關,讓您自定義您的應用程式的音訊行為。

如表B-1所示,每個音訊會話類別都指定了一組特定的響應,以響應下列每個行為:

  1. 中斷非混合應用程式音訊:如果是,當你的應用程式啟用其音訊會話時,非混合應用程式被中斷。
  2. 靜音開關靜音:如果是,當使用者啟用靜音開關時,您的音訊將被靜音。(在iPhone上,這個開關叫做鈴聲/靜音開關。)
  3. 支援音訊輸入:如果支援,則允許app音訊輸入(錄製)。
  4. 支援音訊輸出:如果是,應用程式音訊輸出(播放)是允許的。

大多數應用程式只需要在啟動時設定類別一次,但你可以根據需要隨時更改類別。你可以改變它,而音訊會話是積極的;然而,在更改類別或其他會話屬性之前,通常更可取的做法是禁用音訊會話。在會話被停用時進行這些更改可以防止音訊系統進行不必要的重新配置。

2.1 音訊會話預設行為

所有的iOS、tvOS和watchOS應用程式都有一個預設的預設音訊會話,如下所示:

  • 支援音訊播放,但不允許錄製音訊。
  • 在iOS系統中,將鈴聲/靜音開關設定為靜音模式,應用程式播放的任何音訊都會被靜音。
  • 在iOS系統中,當裝置被鎖定時,應用程式的音訊會被靜音。
  • 當您的應用程式播放音訊時,任何其他背景音訊(如音樂應用程式播放的音訊)都將被靜音。

預設的音訊會話具有有用的行為,但在大多數情況下,您應該自定義它以更好地滿足您的應用程式的需要。要更改行為,需要配置應用程式的音訊會話。

2.2 配置音訊會話

配置音訊會話的主要方法是設定其類別。音訊會話類別定義了一組音訊行為。與每個類別相關的精確行為並不在應用程式的控制之下,而是由作業系統設定的。蘋果可能會在未來的作業系統版本中完善類別行為,所以你最好的策略是選擇最準確地描述你想要的音訊行為意圖的類別。音訊會話類別和模式總結了每個類別的行為細節。

雖然類別設定了應用程式的基本音訊行為,但您可以通過設定類別的模式進一步專門化這些行為。例如,IP語音(VoIP)應用程式將使用AVAudioSessionCategoryPlayAndRecord。您可以通過將音訊會話模式設定為AVAudioSessionModeVoiceChat來專門化VoIP應用程式的此類行為。這種模式確保通過系統提供的訊號處理來優化語音訊號。

AVAudioSessionCategoryPlayAndRecord模式如下:

static let playAndRecord: AVAudioSession.Category
複製程式碼
  1. 您的音訊繼續與靜音開關設定為靜音和與螢幕鎖定。(這個開關在iPhone上被稱為鈴聲/靜音開關。)為了在你的應用程式轉換到背景時(例如,當螢幕鎖定時)繼續播放音訊,在你的資訊屬性列表檔案的UIBackgroundModes鍵中新增音訊值。
  2. 這個類別適用於同時錄製和回放,也適用於錄製和回放但不是同時播放的應用程式。
  3. 預設情況下,使用這個類別意味著你的應用程式的音訊是不可混合的——啟用你的會話將中斷任何其他不可混合的音訊會話。要允許混合此類別,請使用mixWithOthers選項。
  4. 使用者必須為音訊錄製授予許可權(參見錄製需要使用者許可權)。 這個類別支援Airplay的映象版本。然而,如果AVAudioSessionModeVoiceChat模式用於此類別,則AirPlay映象將被禁用。
  5. 某些類別支援通過在會話上設定一個或多個類別選項來覆蓋其預設行為(參見AVAudioSessionCategoryOptions)。例如,當會話被啟用時,與AVAudioSessionCategoryPlayback類別相關聯的預設行為會中斷其他系統音訊。在大多數情況下,回放應用程式需要這種行為。但是,如果您希望您的音訊與其他系統音訊混合,您可以通過在會話中設定AVAudioSessionCategoryOptionMixWithOthers選項來覆蓋此行為。
  • 音訊會話模式有:
    音訊會話模式有

注意:當鈴聲/靜音開關設定為靜音並鎖定螢幕時,為了讓你的應用程式繼續播放音訊,請確保UIBackgroundModes音訊鍵已新增到你的應用程式的資訊中。plist檔案。這個要求是除了你使用正確的類別。

  • 模式及相關類別:
    模式及相關類別
    要設定音訊會話類別(以及可選的模式和選項),請呼叫setCategory:mode:options:error: method,使用AVFoundation框架設定音訊會話類別程式碼如下:
// Access the shared, singleton audio session instance
let session = AVAudioSession.sharedInstance()
do {
    // Configure the audio session for movie playback
    try session.setCategory(AVAudioSessionCategoryPlayback,
                            mode: AVAudioSessionModeMoviePlayback,
                            options: [])
} catch let error as NSError {
    print("Failed to set the audio session category and mode: \(error.localizedDescription)")
}

複製程式碼

2.3 使用多路由類別擴充套件選項

多路由類別的工作方式與其他類別略有不同。所有其他類別的裝置都遵循“最後入網”規則,即最後插入輸入或輸出路由的裝置是占主導地位的裝置。但是,多路由類允許應用程式使用所有連線的輸出埠,而不是僅使用最後一個埠。例如,如果您正在通過HDMI輸出路徑聽音訊,並插入一組耳機,您的應用程式將繼續通過HDMI輸出路徑播放音訊,同時也通過耳機播放音訊。

使用multiroute類別,您的應用程式還可以將不同的音訊流傳送到不同的輸出路徑。例如,您的應用程式可以將一個音訊流傳送到左側耳機,另一個傳送到右側耳機,第三個傳送到HDMI路由。圖1-1顯示了將多個音訊流傳送到不同音訊路由的示例。

傳送不同的音訊流到不同的音訊路由

根據裝置和任何連線的附件,以下是有效的輸出路徑組合:

  • USB和耳機
  • HDMI和耳機
  • 列隊爭球和耳機

多路由類別支援使用單個輸入埠。

重要提示:只有在沒有其他合適的輸出埠(USB、HDMI、LineOut)連線時才能使用內建揚聲器。

2.4 為AirPlay選擇類別和模式

只有特定的類別和模式支援AirPlay。以下類別同時支援映象和非映象版本的AirPlay:

AVAudioSessionCategorySoloAmbient AVAudioSessionCategoryAmbient AVAudioSessionCategoryPlayback

AVAudioSessionCategoryPlayAndRecord類別和以下模式只支援映象版本的AirPlay:

AVAudioSessionModeDefault AVAudioSessionModeVideoChat AVAudioSessionModeGameChat

注意:從ios10開始,當你使用AVAudioSessionCategoryPlayAndRecord目錄時,你可以通過AVAudioSessionCategoryOptionAllowAirPlay選項啟用你的會話來啟用非映象AirPlay輸出。

AVAudioSessionCategoryOptionAllowAirPlay = 0x40

  1. 只有在音訊會話類別為AVAudioSessionCategoryPlayAndRecord時,才能顯式設定此選項。對於大多數其他音訊會話類別,系統將隱式地設定此選項。使用AVAudioSessionCategoryMultiRoute或AVAudioSessionCategoryRecord類別的音訊會話隱式地清除此選項。
  2. 如果您清除此選項,AirPlay裝置將不會顯示為可用的音訊輸出路由。如果設定此選項,這些裝置將顯示為可用的輸出路由。

2.5 開啟後臺音訊

iOS和tvOS應用程式要求您為某些後臺操作啟用某些功能。回放應用程式需要的一個常見功能是播放背景音訊。啟用這個功能後,當使用者切換到其他應用程式或鎖定iOS裝置時,應用程式的音訊可以繼續。在iOS中支援高階回放功能,如AirPlay流媒體播放和圖片中的圖片回放,也需要此功能。

配置這些功能的最簡單方法是使用Xcode。在Xcode中選擇應用程式的目標並選擇capability選項卡。在capability選項卡下,將背景模式設定為ON,並從可用模式列表中選擇“Audio, AirPlay, and Picture in Picture”選項。

開啟後臺音訊模式

啟用此後臺模式,並將音訊會話配置為適當的類別,您的應用程式就可以開始播放後臺音訊了

注意:要允許視訊演示的音訊部分在後臺播放,請參閱媒體播放程式設計指南中的播放背景音訊

3. 啟用音訊會話

您已經通過設定音訊會話的類別、選項和模式來配置它。要使配置生效,現在需要啟用音訊會話。

3.1 系統如何解決競爭的音訊需求

當你的應用程式啟動時,內建的應用程式(訊息、音樂、Safari、手機)可能在後臺執行。每一個都可以產生音訊:一條簡訊來了,你10分鐘前開始的播客還在繼續播放,等等。

如果你把一個裝置想象成一個機場,應用程式就像滑行的飛機,這個系統就像一個控制塔。你的應用程式可以發出音訊請求並宣告它想要的優先順序,但是“在停機坪上”發生的事情的最終權威來自系統。使用音訊會話與“控制塔”通訊。圖2-1展示了一個典型的場景—您的應用程式要求在音樂應用程式已經在播放時使用音訊。在這個場景中,您的應用程式中斷了音樂應用程式。

系統如何解決競爭的音訊需求

在圖的第1步中,應用程式請求啟用它的音訊會話。例如,在應用程式啟動時,或者在使用者輕擊音訊錄製和回放應用程式中的Play按鈕時,您可能會發出這樣的請求。在步驟2中,系統將考慮啟用請求。具體來說,它會考慮您分配給音訊會話的類別。在圖2-1中,您的應用程式使用了一個類別,該類別需要對其他音訊進行消音。

在步驟3和步驟4中,系統關閉音樂應用程式的音訊會話,停止其音訊播放。最後,在第五步,系統啟用你的應用程式的音訊會話和播放可以開始。

3.2 啟用和關閉您的音訊會話

雖然AVFoundation回放和錄製類會自動啟用音訊會話,但手動啟用它會讓您有機會測試啟用是否成功。但是,如果你的應用程式有一個play/pause UI元素,那麼編寫你的程式碼,這樣使用者必須在啟用會話之前按play。同樣,在更改音訊會話的活動/非活動狀態時,請檢查以確保呼叫成功。編寫程式碼來優雅地處理系統拒絕啟用您的會話。

該系統將關閉您的音訊會話,用於時鐘或日曆鬧鐘或來電。當使用者解除警報或選擇忽略電話呼叫時,系統允許您的會話再次啟用。是否在中斷結束時重新啟用會話取決於應用程式型別,如Audio Guidelines By app type所述。

  • 啟用音訊會話的程式碼如下:
let session = AVAudioSession.sharedInstance()
do {
    // 1) Configure your audio session category, options, and mode
    // 2) Activate your audio session to enable your custom configuration
    try session.setActive(true)
} catch let error as NSError {
    print("Unable to activate audio session:  \(error.localizedDescription)")
}
複製程式碼

若要停用音訊會話,請將false傳遞給setActive方法。

當使用AVFoundation物件(AVPlayer、AVAudioRecorder等)播放或錄製音訊時,系統負責在中斷結束時重新啟用音訊會話。但是,如果您註冊了通知訊息並顯式地重新啟用音訊會話,則可以驗證重新啟用成功,並可以更新應用程式的狀態和使用者介面。有關更多資訊,請參見圖3-1。

許多應用程式從來不需要顯式地停用它們的音訊會話。重要的例外包括VoIP應用程式、逐嚮導航應用程式,在某些情況下還包括回放和錄音應用程式。

  • 確保VoIP應用程式的音訊會話(通常在後臺執行)僅在應用程式處理呼叫時是活動的。在後臺,準備接收電話時,VoIP應用程式的音訊會話不應處於啟用狀態。
  • 確保使用錄製類別的應用程式的音訊會話僅在錄製時處於活動狀態。在開始錄製和停止錄製之前,請確保您的會話處於非活動狀態,以允許播放其他聲音,例如傳入訊息警報。
  • 如果應用程式支援後臺音訊播放或錄製,如果應用程式不積極使用音訊(或準備使用音訊),則在進入後臺時禁用其音訊會話。這樣做允許系統釋放音訊資源,以便其他程式可以使用它們。它還可以防止應用程式的音訊會話在應用程式程式被作業系統掛起時失效(參見AVAudioSessionInterruptionWasSuspendedKey)。

這個userInfo鍵只出現在AVAudioSession.InterruptionType中。開始中斷事件,其中中斷是作業系統掛起應用程式的直接結果。它的關聯值是一個布林NSNumber,其中一個真值表示中斷是由於系統掛起應用程式造成的,而不是由另一個音訊會話中斷的。

3.2.1 Audio Guidelines By app type

3.3 檢查其他音訊是否正在播放

當你的應用程式啟用時,聲音可能已經在裝置上播放了。例如,當使用者啟動應用程式時,音樂應用程式可能正在播放歌曲,或者Safari可能正在播放音訊流。如果你的應用是一款遊戲,瞭解是否有其他音訊在播放尤其重要。許多遊戲都有音樂音軌和音效。在iOS人機介面指南中,建議你假設使用者在玩遊戲時希望其他音訊和遊戲音效能夠繼續。

在你的應用委派的applicationDidBecomeActive:方法中,檢查音訊會話的secondaryAudioShouldBeSilencedHint屬性,以確定音訊是否已經在播放。當另一個具有非混合音訊會話的應用程式正在播放音訊時,該值為true。應用程式應該使用這個屬性作為使次要於應用程式功能的音訊靜音的提示。例如,一個使用AVAudioSessionCategoryAmbient的遊戲可以使用這個屬性來決定是否應該在保持聲音效果不靜音的情況下靜音音軌。

您還可以訂閱型別為AVAudioSessionSilenceSecondaryAudioHintNotification的通知,以確保在可選的輔助音訊靜音應該開始或結束時通知您的應用程式。此通知僅傳送給當前處於前臺且具有活動音訊會話的已註冊偵聽器。

func setupNotifications() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(handleSecondaryAudio),
                                           name: .AVAudioSessionSilenceSecondaryAudioHint,
                                           object: AVAudioSession.sharedInstance())
}
 
func handleSecondaryAudio(notification: Notification) {
    // Determine hint type
    guard let userInfo = notification.userInfo,
        let typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey] as? UInt,
        let type = AVAudioSessionSilenceSecondaryAudioHintType(rawValue: typeValue) else {
            return
    }
 
    if type == .begin {
        // Other app audio started playing - mute secondary audio
    } else {
        // Other app audio stopped playing - restart secondary audio
    }
}
複製程式碼

此通知的userInfo字典包含AVAudioSessionSilenceSecondaryAudioHintType值的AVAudioSessionSilenceSecondaryAudioHintTypeKey。使用音訊提示型別來確定輔助音訊靜音應該開始還是結束

4. 響應中斷

新增音訊會話程式碼來處理中斷,確保您的應用程式的音訊在電話到來、時鐘或日曆鬧鈴響或其他應用程式啟用其音訊會話時繼續正常工作。

音訊中斷是應用程式的音訊會話的停用,它會立即停止音訊。當來自應用程式的競爭音訊會話被啟用,並且該會話沒有被系統分類以與您的會話混合時,就會發生中斷。在您的會話變為非活動狀態後,系統將傳送一條“您被中斷了”訊息,您可以通過儲存狀態、更新使用者介面等方式對其進行響應。

您的應用程式可能會在中斷後暫停。當使用者接電話時就會發生這種情況。如果使用者忽略了一個呼叫,或者取消了一個警報,系統就會發出一個“中斷結束”的訊息,你的應用程式就會繼續執行。要恢復您的音訊,您必須重新啟用您的音訊會話。

4.1 中斷生命週期

圖3-1說明了播放應用程式的音訊會話中斷之前、期間和之後的事件序列。

中斷生命週期

中斷事件—在本例中,FaceTime請求的到來—按如下方式進行。編號的步驟與圖中的數字相對應。

  1. 你的應用程式是活動的,播放音訊。
  2. FaceTime請求到達。系統啟用FaceTime應用程式的音訊會話。
  3. 系統將關閉您的音訊會話。此時,應用程式中的回放已經停止。
  4. 系統會發出一個通知,指示您的會話已被停用。
  5. 您的通知處理程式將採取適當的操作。例如,它可以更新使用者介面並儲存在停止回放時恢復回放所需的資訊。
  6. 如果使用者拒絕中斷(忽略傳入的FaceTime請求),系統就會發出通知,表明中斷已經結束。
  7. 通知處理程式在中斷結束時採取適當的操作。例如,它可以更新使用者介面、重新啟用音訊會話和恢復播放。
  8. (圖中未顯示)如果使用者接了一個電話,而不是在第6步取消中斷,你的應用程式將被掛起。

4.2 音訊中斷處理技術

通過註冊觀察AVAudioSession釋出的中斷通知來處理中斷。您在中斷程式碼中所做的事情取決於您正在使用的音訊技術,以及您在回放、錄製、音訊格式轉換、讀取流音訊包等方面所使用的技術。一般來說,從使用者的角度來看,您需要確保儘可能少的中斷和儘可能好的恢復。

表3-1總結了中斷期間適當的音訊會話行為。如果您使用AVFoundation回放或錄製物件,系統會自動處理其中的一些步驟。

表3-1音訊會話中斷期間應該發生什麼:

時間 處理
中斷開始後 1.儲存狀態和上下文,2.更新的使用者介面
中斷結束後 1.恢復狀態和上下文,2.更新的使用者介面,3.重新啟用音訊會話,如果適當的應用程式

表3-2總結了如何根據技術處理音訊中斷:

音訊技術 中斷處理
1. AVFoundation framework 系統自動暫停播放或錄製中斷和重新啟用您的音訊會話時,您恢復播放或錄製。2.如果你想儲存和恢復播放位置之間的應用程式啟動,儲存播放位置在中斷以及在應用程式退出。
Audio Queue Services, I/O audio unit 這些技術讓你的應用程式控制處理中斷。你負責儲存回放或錄製位置,並在中斷結束後重新啟用音訊會話。
System Sound Services 當中斷開始時,使用系統聲音服務播放的聲音將變為靜音。如果中斷結束,聲音可以再次播放。應用程式不能影響使用這種回放技術的聲音的中斷行為。

4.3 處理Siri中斷

  • 當Siri打斷你的應用程式回放時,你必須在音訊會話處於中斷狀態時跟蹤Siri發出的任何遠端控制命令。在中斷期間,跟蹤Siri發出的所有命令,並在中斷結束時做出相應的響應。例如,在中斷期間,使用者要求Siri暫停應用程式的音訊播放。當你的應用程式被通知中斷已經結束,它不應該自動恢復播放。相反,應用程式的UI應該指示應用程式處於暫停狀態。

4.4 觀察音訊中斷

  • 要處理音訊中斷,首先註冊AVAudioSessionInterruptionNotification型別的通知。
func registerForNotifications() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(handleInterruption),
                                           name: .AVAudioSessionInterruption,
                                           object: AVAudioSession.sharedInstance())
}
 
func handleInterruption(_ notification: Notification) {
    // Handle interruption
}

複製程式碼
  • 釋出的NSNotification例項包含一個已填充的userInfo字典,提供中斷的詳細資訊。通過從userInfo字典中檢索AVAudioSessionInterruptionType值來確定中斷的型別。中斷型別指示中斷是已經開始還是已經結束。
func handleInterruption(_ notification: Notification) {
    guard let info = notification.userInfo,
        let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
        let type = AVAudioSessionInterruptionType(rawValue: typeValue) else {
            return
    }
    if type == .began {
        // Interruption began, take appropriate actions (save state, update user interface)
    }
    else if type == .ended {
        guard let optionsValue =
            userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else {
                return
        }
        let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
        if options.contains(.shouldResume) {
            // Interruption Ended - playback should resume
        }
    }
}
複製程式碼
  • 如果中斷型別是AVAudioSessionInterruptionTypeEnded,則userInfo字典可能包含AVAudioSessionInterruptionOptions值。AVAudioSessionInterruptionOptionShouldResume的一個選項值是一個提示,指示如果應用程式在被中斷時正在播放,它是否應該自動恢復播放。媒體播放應用程式在中斷後開始播放之前應始終尋找此標誌。如果它不存在,播放不應該再次開始,直到由使用者發起。沒有播放介面的應用程式,比如遊戲,可以忽略這個標誌,在中斷結束時重新啟用並恢復播放。

注意:不能保證開始中斷會有相應的結束中斷。你的應用程式需要知道一個切換到前臺執行狀態或使用者按下播放按鈕。在這兩種情況下,確定你的應用程式是否應該重新啟用它的音訊會話。

4.5 響應媒體伺服器重置

媒體伺服器通過共享伺服器程式提供音訊和其他多媒體功能。雖然很少見,但是媒體伺服器可以在您的應用程式處於活動狀態時進行重置。註冊AVAudioSessionMediaServicesWereResetNotification通知以監視媒體伺服器重置。收到通知後,您的app需要做以下工作:

  • 處理孤立的音訊物件(如播放器、錄音機、轉換器或音訊佇列)並建立新物件
  • 重置任何被跟蹤的內部音訊狀態,包括AVAudioSession的所有屬性
  • 在適當的時候,使用setActive:error:方法重新啟用AVAudioSession例項

5. 響應路由更改

當您的應用程式執行時,使用者可能會插入或拔出耳機,或使用帶有音訊連線的塢站。iOS人機介面指南描述了應用程式應該如何應對此類事件。要實現這些建議,請編寫音訊會話程式碼來處理音訊硬體路由更改。某些型別的應用程式,比如遊戲,並不總是需要對路線變化做出響應。然而,其他型別的應用程式,如媒體播放器,必須響應所有的路由變化。

5.1 各種音訊硬體路由變化

音訊硬體路由是音訊訊號的有線電子路徑。當裝置的使用者插入或拔出耳機時,系統會自動改變音訊硬體路線。如果你註冊了AVAudioSessionRouteChangeNotification型別的通知,你的應用程式可以被通知這些變化。

圖4-1描述了在錄製和回放期間各種路由更改的事件序列。圖的底部顯示了四個可能的結果,它們來自您編寫的屬性偵聽器回撥函式所採取的操作。

處理硬體線路變換

如圖所示,在您的app啟動後,系統最初會確定音訊路由。它將在應用程式執行時繼續監視活動路由。首先考慮使用者點選應用程式中的記錄按鈕的情況,該按鈕由圖左側的“開始記錄”框表示。

在錄製過程中,使用者可以將耳機插入或拔出,如圖左下方所示為鑽石形狀的決策元件。作為響應,系統傳送一個路由更改通知,其中包含更改的原因和前一個路由。你的應用程式應該停止錄製。

回放的情況類似,但結果不同,如圖右側所示。如果使用者在播放過程中拔下耳機,應用程式應該暫停音訊。如果使用者在回放過程中插入耳機,應用程式應該允許回放繼續。

5.2 觀察音訊路由的變化

  • 發生音訊路由更改的原因有很多,包括使用者插入一對耳機、連線藍芽LE耳機或拔掉USB音訊介面。知道什麼時候發生這些變化可能對你的應用程式很重要,這樣你就可以更新它的使用者介面或改變它的內部狀態。通過註冊AVAudioSessionRouteChangeNotification型別的通知,可以在音訊路由更改時通知您。
func setupNotifications() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(handleRouteChange),
                                           name: .AVAudioSessionRouteChange,
                                           object: AVAudioSession.sharedInstance())
}
 
func handleRouteChange(_ notification: Notification) {
 
}
複製程式碼
  • 釋出的通知包含一個已填充的userInfo字典,提供路由更改的詳細資訊。您可以通過從userInfo字典中檢索AVAudioSessionRouteChangeReason值來確定這種變化的原因。當連線一個新裝置時,原因是AVAudioSessionRouteChangeReasonNewDeviceAvailable,當一個裝置被刪除時,原因是avaudiosessionroutechangereasonolddeviceavailable。
func handleRouteChange(_ notification: Notification) {
    guard let userInfo = notification.userInfo,
        let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
        let reason = AVAudioSessionRouteChangeReason(rawValue:reasonValue) else {
            return
    }
    switch reason {
    case .newDeviceAvailable:
        // Handle new device available.
    case .oldDeviceUnavailable:
        // Handle old device removed.
    default: ()
    }
}
複製程式碼
  • 當新裝置可用時,您可以查詢音訊會話的currentRoute屬性,以確定音訊輸出當前路由到何處。這將返回一個AVAudioSessionRouteDescription物件,該物件列出了音訊會話的所有輸入和輸出。當裝置被移除時,您可以從userInfo字典中檢索上一條路由的AVAudioSessionRouteDescription物件。在這兩種情況下,您可以查詢路由描述的輸出屬性,該屬性返回一個AVAudioSessionPortDescription物件陣列,提供音訊輸出路由的詳細資訊。
func handleRouteChange(notification: NSNotification) {
    guard let userInfo = notification.userInfo,
        let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
        let reason = AVAudioSessionRouteChangeReason(rawValue:reasonValue) else {
            return
    }
    switch reason {
    case .newDeviceAvailable:
        let session = AVAudioSession.sharedInstance()
        for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortHeadphones {
            headphonesConnected = true
        }
    case .oldDeviceUnavailable:
        if let previousRoute =
            userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
            for output in previousRoute.outputs where output.portType == AVAudioSessionPortHeadphones {
                headphonesConnected = false
            }
        }
    default: ()
    }
}
複製程式碼

重要提示:媒體播放應用程式應該暫停播放,如果路線改變的原因是AVAudioSessionRouteChangeReasonOldDeviceUnavailable,但不應該,如果原因是AVAudioSessionRouteChangeReasonOverride。

注意:音訊路由的更改也可能導致音訊會話的取樣率、I/O緩衝區持續時間、通道計數或其他硬體相關值的更改。如果這些值對您的應用程式很重要,請在路由更改後查詢它們,以檢視它們的值是否已更改。

6. 配置裝置硬體

使用音訊會話屬性,您可以在執行時為裝置硬體優化應用程式的音訊行為。這樣做可以使您的程式碼適應它所執行的裝置的特性,以及使用者在應用程式執行時所做的更改(如插入耳機或將裝置停靠在其上)。

使用AVAudioSession:

  • 為示例速率和I/O緩衝區持續時間指定首選硬體設定
  • 查詢許多硬體特性,如輸入和輸出延遲、輸入和輸出通道計數、硬體取樣率、硬體卷設定和音訊輸入的可用性

6.1 選擇首選音訊硬體值

使用音訊會話指定您的首選裝置設定,如取樣率和硬體I/O緩衝區持續時間。表5-1描述了這些偏好的好處和代價。

選擇硬體
例如,如果音訊質量在您的應用程式中非常重要,並且大檔案或緩衝區大小不是一個重要問題,那麼您可以指定一個高取樣率的首選項。

注意:預設的音訊I/O緩衝時間(44.1 kHz音訊大約0.02秒)為大多數應用程式提供了足夠的響應能力。您可以為延遲關鍵型應用程式(如live musical instrument monitoring)設定一個較低的I/O持續時間,但是對於大多數應用程式,您永遠不需要修改這個設定。

6.2 設定首選音訊硬體值

在啟用音訊會話之前設定首選硬體值。如果你已經在執行一個音訊會話,那麼就停用它。對首選值的更改將在音訊會話啟用後生效,您可以在此時驗證更改。清單5-1展示瞭如何設定首選硬體值以及如何驗證它們。

  • 清單5-1設定和驗證音訊硬體值
let session = AVAudioSession.sharedInstance()
 
// Configure category and mode
do {
    try session.setCategory(AVAudioSessionCategoryRecord, mode: AVAudioSessionModeDefault)
} catch let error as NSError {
    print("Unable to set category:  \(error.localizedDescription)")
}
 
// Set preferred sample rate
do {
    try session.setPreferredSampleRate(44_100)
} catch let error as NSError {
    print("Unable to set preferred sample rate:  \(error.localizedDescription)")
}
 
// Set preferred I/O buffer duration
do {
    try session.setPreferredIOBufferDuration(0.005)
} catch let error as NSError {
    print("Unable to set preferred I/O buffer duration:  \(error.localizedDescription)")
}
 
// Activate the audio session
do {
    try session.setActive(true)
} catch let error as NSError {
    print("Unable to activate session. \(error.localizedDescription)")
}
 
// Query the audio session's ioBufferDuration and sampleRate properties
// to determine if the preferred values were set
print("Audio Session ioBufferDuration: \(session.ioBufferDuration), sampleRate: \(session.sampleRate)")
複製程式碼

注意:當競爭音訊會話設定首選硬體值時,系統優先考慮非混合會話。使用AVAudioSessionCategoryAmbient類別或AVAudioSessionCategoryOptionMixWithOthers選項的音訊會話不太可能提供其首選的硬體設定。

6.3 選擇和配置麥克風

在擁有兩個或更多內建麥克風的裝置上,iOS會通過音訊會話模式自動選擇麥克風。模式指定用於輸入的數字訊號處理(DSP)和可能的路由。為每種模式的用例優化輸入和路由。設定模式還可能影響正在使用的路由的其他方面。

開發人員還可以手動選擇麥克風,如果硬體支援,甚至可以選擇首選的麥克風極性模式。

重要提示:在使用任何輸入選擇功能之前,為您的應用程式設定音訊會話類別和模式,然後啟用音訊會話。

  • 設定首選輸入

要發現內建的或連線的輸入埠,請使用音訊會話的availableInputs屬性。此屬性返回AVAudioSessionPortDescription物件陣列,這些物件描述裝置的可用輸入埠。埠可以通過它們的portType屬性來標識。要設定首選輸入埠(內建麥克風、有線麥克風、USB輸入,等等),請使用音訊會話的setPreferredInput:error:方法。

  • 設定首選資料來源
  1. 一些埠,如內建麥克風和一些USB配件,支援資料來源。應用程式可以通過查詢埠描述的dataSources屬性來發現可用的資料來源。對於內建麥克風,返回的資料來源描述物件表示每個麥克風。不同的裝置為內建麥克風返回不同的值。例如,iPhone 4和iPhone 4S有兩個麥克風:底部和頂部。iPhone 5有三個麥克風:底部、前面和後面。
  2. 單個內建麥克風可以通過資料來源描述的位置屬性(上、下)和方向屬性(前、後等)的組合進行標識。應用程式可以使用AVAudioSessionPortDescription物件的setPreferredDataSource:error:方法設定首選資料來源。
  • 設定一個首選的極座標模式

一些iOS裝置支援為一些內建麥克風配置麥克風極性模式。麥克風的極模式決定了它對聲音的敏感度與聲源的方向有關。當前的iphone支援為前後內建麥克風設定首選的極座標模式。可用模式使用資料來源描述物件的supportedPolarPatterns屬性返回。此屬性為資料來源返回一個受支援的極性模式陣列(如cardioid或omnidirectional),如果沒有可用的可選模式,則返回nil。如果資料來源有許多受支援的極性模式,您可以通過使用資料來源描述的setPreferredPolarPattern:error:方法來設定首選的極性模式。

  • 下面的程式碼提供了一個簡單的示例,演示如何選擇特定的麥克風並設定其極性模式。
// Preferred Mic = Front, Preferred Polar Pattern = Cardioid
let preferredMicOrientation = AVAudioSessionOrientationFront
let preferredPolarPattern = AVAudioSessionPolarPatternCardioid
 
// Retrieve your configured and activated audio session
let session = AVAudioSession.sharedInstance()
 
// Get available inputs
guard let inputs = session.availableInputs else { return }
 
// Find built-in mic
guard let builtInMic = inputs.first(where: {
    $0.portType == AVAudioSessionPortBuiltInMic
}) else { return }
 
// Find the data source at the specified orientation
guard let dataSource = builtInMic.dataSources?.first (where: {
    $0.orientation == preferredMicOrientation
}) else { return }
 
// Set data source's polar pattern
do {
    try dataSource.setPreferredPolarPattern(preferredPolarPattern)
} catch let error as NSError {
    print("Unable to preferred polar pattern: \(error.localizedDescription)")
}
 
// Set the data source as the input's preferred data source
do {
    try builtInMic.setPreferredDataSource(dataSource)
} catch let error as NSError {
    print("Unable to preferred dataSource: \(error.localizedDescription)")
}
 
// Set the built-in mic as the preferred input
// This call will be a no-op if already selected
do {
    try session.setPreferredInput(builtInMic)
} catch let error as NSError {
    print("Unable to preferred input: \(error.localizedDescription)")
}
 
// Print Active Configuration
session.currentRoute.inputs.forEach { portDesc in
    print("Port: \(portDesc.portType)")
    if let ds = portDesc.selectedDataSource {
        print("Name: \(ds.dataSourceName)")
        print("Polar Pattern: \(ds.selectedPolarPattern ?? "[none]")")
    }
}
複製程式碼

在iPhone 6s上執行這段程式碼會產生以下控制檯輸出:

Port: MicrophoneBuiltIn
Name: Front
Polar Pattern: Cardioid

複製程式碼

6.4 在模擬器中執行應用程式

當你新增音訊會話支援到你的應用程式時,你可以在模擬器或裝置上執行你的應用程式。但是,模擬器不能模擬不同程式或音訊路由更改中的音訊會話之間的大多數互動。當執行你的應用程式在模擬器,你不能:

  • 呼叫一箇中斷
  • 模擬插入或拔出耳機
  • 改變靜音開關的設定
  • 模擬螢幕鎖
  • 測試音訊混合行為——即將音訊與來自另一個應用程式(如音樂應用程式)的音訊一起播放。

由於模擬器的特性,您可能希望對程式碼進行條件設定,以允許在模擬器中進行部分測試。下面程式碼展示瞭如何做到這一點。

#if arch(i386) || arch(x86_64)
    // Execute subset of code that works in the Simulator
#else
    // Execute device-only code as well as the other code
#endif
複製程式碼

7. 保護使用者隱私

為了保護使用者隱私,你的應用程式在錄製音訊之前必須獲得使用者的許可。如果使用者不授予許可權,則只記錄靜默。當你使用一個支援記錄的類別,而應用程式試圖使用輸入路徑時,系統會自動提示使用者允許。

您可以使用requestRecordPermission:方法來手動請求許可權,而不是等待系統提示使用者記錄許可權。使用這種方法允許您的應用程式在不中斷應用程式的自然流的情況下獲得許可,從而獲得更好的使用者體驗。

AVAudioSession.sharedInstance().requestRecordPermission { granted in
    if granted {
        // User granted access. Present recording interface.
    } else {
        // Present message to user indicating that recording
        // can't be performed until they change their preference
        // under Settings -> Privacy -> Microphone
    }
}
複製程式碼

重要提示:從iOS 10開始,所有訪問裝置麥克風的應用程式必須靜態地宣告它們的意圖。要做到這一點,應用程式現在必須在它們的資訊中包含NSMicrophoneUsageDescription鍵。併為此鍵提供一個目的字串。當系統提示使用者允許訪問時,此字串將作為警報的一部分顯示。 如果一個應用程式試圖訪問裝置的麥克風沒有這個鍵和值存在,應用程式將終止。

8. AVAudioSession

AVAudioSession是一個物件,它向系統傳達你打算如何在你的應用程式中使用音訊。它的類宣告如下:

class AVAudioSession : NSObject
複製程式碼

音訊會話充當應用程式和作業系統之間的中介,進而充當底層音訊硬體之間的中介。您使用一個音訊會話來與作業系統通訊應用程式音訊的一般性質,而不詳細說明特定的行為或與音訊硬體所需的互動。您將這些細節的管理委託給音訊會話,以確保作業系統能夠最好地管理使用者的音訊體驗。

所有的iOS、tvOS和watchOS應用程式都有一個預設的音訊會話,並預先配置了以下行為:

  • 它支援音訊回放,但不允許音訊錄製(tvOS不支援音訊錄製)。
  • 在iOS系統中,將鈴聲/靜音開關設定為靜音模式,應用程式播放的任何音訊都會被靜音。
  • 在iOS系統中,鎖定裝置會使應用程式的音訊靜音。
  • 當應用程式播放音訊時,它會靜音任何其他背景音訊。

雖然預設的音訊會話提供了有用的行為,但它通常不提供媒體應用程式需要的音訊行為。要更改預設行為,需要配置應用程式的音訊會話類別。

你可以使用七種可能的類別(參見音訊會話類別和模式),但是回放是回放應用程式最常用的一種。這個類別表明音訊播放是你的應用程式的核心功能。當你指定這個類別時,你的應用程式的音訊將繼續與鈴聲/靜音開關設定為靜音模式(只有iOS)。使用這個類別,你也可以播放背景音訊,如果你在圖片背景模式中使用音訊,AirPlay和圖片。有關更多資訊,請參見啟用背景音訊。

使用AVAudioSession物件來配置應用程式的音訊會話。該類是一個單例物件,用於設定音訊會話的類別、模式和其他配置。您可以在應用程式的整個生命週期中與音訊會話進行互動,但是在應用程式啟動時執行此配置通常很有用,如下面的示例所示。

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    // Get the singleton instance.
    let audioSession = AVAudioSession.sharedInstance()
    do {
        // Set the audio session category, mode, and options.
        try audioSession.setCategory(.playback, mode: .moviePlayback, options: [])
    } catch {
        print("Failed to set audio session category.")
    }
    
    // Other post-launch configuration.
    return true
}
複製程式碼

當您使用setActive(:)或setActive(:options:)方法啟用會話時,音訊會話將使用此配置。

請注意 你可以在設定類別後的任何時候啟用音訊會話,但通常最好將此呼叫推遲到應用程式開始音訊播放之後。延遲呼叫可以確保您不會過早地中斷正在進行的任何其他背景音訊。

8.1 獲取音訊會話

class func sharedInstance() -> AVAudioSession
//Returns the shared audio session instance.
複製程式碼

8.2 配置音訊會話


var category: AVAudioSession.Category
//The current audio session category.
func setCategory(AVAudioSession.Category)
//Sets the audio session’s category.
var availableCategories: [AVAudioSession.Category]
//The audio session categories available on the current device.
struct AVAudioSession.Category
//Audio session category identifiers.
var categoryOptions: AVAudioSession.CategoryOptions
//The set of options associated with the current audio session category.
func setCategory(AVAudioSession.Category, options: AVAudioSession.CategoryOptions)
//Sets the audio sessions category with the specified options.
struct AVAudioSession.CategoryOptions
//Constants that specify optional audio behaviors.
var mode: AVAudioSession.Mode
//The current audio sessions mode.
func setMode(AVAudioSession.Mode)
//Sets the audio sessions mode.
func setCategory(AVAudioSession.Category, mode: AVAudioSession.Mode, options: AVAudioSession.CategoryOptions)
//Sets the audio sessions category, mode, and options.
var availableModes: [AVAudioSession.Mode]
//The audio session modes available on the device.
struct AVAudioSession.Mode
//Audio session mode identifiers.
var routeSharingPolicy: AVAudioSession.RouteSharingPolicy
//The current route-sharing policy.
func setCategory(AVAudioSession.Category, mode: AVAudioSession.Mode, policy: AVAudioSession.RouteSharingPolicy, options: AVAudioSession.CategoryOptions)
//Sets the session category, mode, route-sharing policy, and options.
enum AVAudioSession.RouteSharingPolicy
//Cases that indicate the possible route-sharing policies for an audio session.
複製程式碼

8.3 啟用音訊會話

//使用指定的選項啟用或關閉應用程式的音訊會話。
func setActive(Bool, options: AVAudioSession.SetActiveOptions)

//在watchOS上非同步啟用音訊會話。
func activate(options: AVAudioSessionActivationOptions, completionHandler: (Bool, Error?) -> Void)

複製程式碼

8.4 請求錄音許可權

//當前的錄音許可狀態。
var recordPermission: AVAudioSession.RecordPermission

//請求使用者錄製音訊的許可權。
func requestRecordPermission(PermissionBlock)

複製程式碼

8.5 與其他音訊混合


var isOtherAudioPlaying: Bool
//A Boolean value that indicates whether another app is playing audio.
var secondaryAudioShouldBeSilencedHint: Bool
//A Boolean value that indicates whether another app, with a nonmixable audio session, is playing audio.
var allowHapticsAndSystemSoundsDuringRecording: Bool
//A Boolean value that indicates whether system sounds and haptics play while recording from audio input.
func setAllowHapticsAndSystemSoundsDuringRecording(Bool)
//Sets a Boolean value that indicates whether system sounds and haptics play while recording from audio input.
var promptStyle: AVAudioSession.PromptStyle
//A hint to audio sessions that use voice prompt mode to alter the type of prompts they issue in response to other system audio, such as Siri and phone calls.
enum AVAudioSession.PromptStyle
//Constants that indicate the prompt style to use.
複製程式碼

8.6 響應音訊會話通知

class let interruptionNotification: NSNotification.Name
//A notification thats posted when an audio interruption occurs.
class let routeChangeNotification: NSNotification.Name
//A notification thats posted when the systems audio route changes.
class let silenceSecondaryAudioHintNotification: NSNotification.Name
//A notification thats posted when the primary audio from other applications starts and stops.
class let mediaServicesWereLostNotification: NSNotification.Name
//A notification thats posted when the system terminates the media server.
class let mediaServicesWereResetNotification: NSNotification.Name
//A notification thats posted when the media server restarts.
複製程式碼

8.7 使用音訊路由

//當前音訊路由的輸入和輸出埠的描述。
var currentRoute: AVAudioSessionRouteDescription

//一個物件,它描述與會話的音訊路由相關聯的輸入和輸出埠。
class AVAudioSessionRouteDescription

//一個布林值,指示音訊輸入路徑是否可用。
var isInputAvailable: Bool

//一個可用於音訊路由的輸入埠陣列。
var availableInputs: [AVAudioSessionPortDescription]?

//音訊路由的首選輸入埠。
var preferredInput: AVAudioSessionPortDescription?

//設定音訊路由的首選輸入埠。
func setPreferredInput(AVAudioSessionPortDescription?)

//關於埠功能及其支援的硬體通道的資訊。
class AVAudioSessionPortDescription

//當前選擇的輸入資料來源。
var inputDataSource: AVAudioSessionDataSourceDescription?

//音訊會話當前輸入埠的可用資料來源陣列。
var inputDataSources: [AVAudioSessionDataSourceDescription]?

//選擇音訊會話當前輸入埠的資料來源。
func setInputDataSource(AVAudioSessionDataSourceDescription?)

//當前音訊路由的可用輸出資料來源的陣列。
var outputDataSources: [AVAudioSessionDataSourceDescription]?

//當前選擇的輸出資料來源。
var outputDataSource: AVAudioSessionDataSourceDescription?

//設定音訊會話的輸出資料來源。
func setOutputDataSource(AVAudioSessionDataSourceDescription?)

//為音訊輸入或輸出定義資料來源的物件,提供資料來源的名稱、位置和方向等資訊。
class AVAudioSessionDataSourceDescription

//臨時改變當前的音訊路由。
func overrideOutputAudioPort(AVAudioSession.PortOverride)

複製程式碼

8.8 使用音訊通道

//當前路由的音訊輸入通道的數量。
var inputNumberOfChannels: Int

//當前音訊路由可用的最大輸入通道數。
var maximumInputNumberOfChannels: Int

//當前路由的優先輸入通道數。
var preferredInputNumberOfChannels: Int

//設定當前路由的優先輸入通道數。
func setPreferredInputNumberOfChannels(Int)

//音訊輸出通道的數目。
var outputNumberOfChannels: Int

//當前音訊路由可用的最大輸出通道數。
var maximumOutputNumberOfChannels: Int

//當前路由的輸出通道的優先數量。
var preferredOutputNumberOfChannels: Int

//設定當前路由的輸出通道的首選數目。
func setPreferredOutputNumberOfChannels(Int)

複製程式碼

8.9 處理音訊裝置設定



//應用於與會話相關的輸入的增益。
var inputGain: Float

//一個布林值,指示是否可以設定輸入增益。
var isInputGainSettable: Bool

//將輸入增益更改為指定值。
func setInputGain(Float)

//由使用者設定的系統範圍的輸出卷。
var outputVolume: Float

//當前音訊取樣率,單位為赫茲。
var sampleRate: Double

//首選取樣率,單位為赫茲。
var preferredSampleRate: Double

//設定音訊輸入和輸出的首選取樣率。
func setPreferredSampleRate(Double)

//音訊輸入的延遲,以秒為單位。
var inputLatency: TimeInterval

//音訊輸出的延遲,以秒為單位。
var outputLatency: TimeInterval

//當前I/O緩衝區持續時間(以秒為單位)。
var ioBufferDuration: TimeInterval

//首選的I/O緩衝區持續時間(以秒為單位)。
var preferredIOBufferDuration: TimeInterval

//設定首選音訊I/O緩衝區持續時間。
func setPreferredIOBufferDuration(TimeInterval)
複製程式碼

8.10 設定聚合的I/O首選項

//設定音訊會話的聚合I/O配置首選項。
func setAggregatedIOPreference(AVAudioSession.IOType)

複製程式碼

參考蘋果官方文件:音訊會話章節

相關文章