共用方式為


藍牙低功耗(LE)音訊

本文提供 Windows 11 22H2 版 (KB5026446) 中引進的藍牙 LE 音訊概觀。

簡介

藍牙 LE 音訊可以透過等時傳輸,將單播或廣播音訊串流至藍牙 LE 裝置。 從藍牙核心規格 5.3 版開始,主機平台沒有標準定義的主機控制器介面 (HCI)來回傳送和接收藍牙控制器的不時分數據。 本檔會定義 Windows 藍牙廠商特定的音訊路徑 (VSAP),以允許平臺使用廠商特定的解決方案來啟用藍牙 LE 音訊串流。 VSAP 軟體介面會使用本文件中定義的 Windows 音訊類別延伸模組 (ACX) 和更多介面屬性。

術語和必要條件

除了此表格中定義的詞彙之外,本檔也會參考 Windows 音訊類別延伸模組所定義的詞彙。

術語 定義
LE 音訊 藍牙 LE 音訊的縮寫
傳統音訊 使用免持式設定檔 (HFP) 和進階音訊散發設定檔的藍牙音訊串流 (A2DP)
音訊裝置 單一遠端藍牙 LE 音訊裝置或一組藍牙 LE 音訊裝置,共同構成從 Windows 的角度來看的一個音訊端點。
BAP 基本音訊配置檔會定義裝置如何使用藍牙低能 (LE) 通訊來散發和取用音訊。
TMAP 電話語音和媒體音訊配置檔會指定較低層級音訊服務和配置檔的互通組態。
ASCS 音訊串流控制服務會定義藍牙 LE 音訊裝置設定及建立單播音訊串流的標準方式。
PACS 已發佈的音訊功能服務會定義藍牙 LE 音訊裝置報告其支援的音訊編解碼器功能的標準方式。
CIS Connected Isochronous Streams 傳輸可用來在藍牙 LE 裝置之間傳送和接收單向音訊數據。
BIS 廣播等時串流傳輸用於無連線音訊數據傳輸。
ACX 音訊類別延伸模組的縮寫,這是所有音訊驅動程式在 Windows 上支援藍牙 LE 音訊所需的驅動程式模型。
串流線路 廠商特定音訊驅動程式堆疊為其串流路徑所建立的一或多個 ACXCIRCUIT 物件。
輪廓線路 由 Windows 上的藍牙 LE 音訊設定檔實作所建立的 ACXCIRCUIT 物件。 此 ACXCIRCUIT 不是串流電路。

本文假設您熟悉先前定義的術語,以及 藍牙核心規格中定義的下列 HCI 命令:

  • 本機控制器命令
    • HCI_Read_Local_Supported_Codecs (v2)
    • HCI_Read_Local_Supported_Codec_Capabilities
    • HCI_LE_設定_ISO_資料_路徑
    • HCI_LE_Remove_ISO_Data_Path
    • HCI_Configure_Data_Path
  • 單播串流命令
    • HCI_LE_Set_CIG_Parameters
    • HCI_LE_Create_CIS
    • HCI_LE_Remove_CIG
  • 廣播串流命令
    • HCI_LE_Create_BIG
    • HCI_LE_Terminate_BIG
    • HCI_LE_BIG_Create_Sync
    • HCI_LE_BIG_Terminate_Sync
    • HCI_LE_Set_Periodic_Advertising_Parameters
    • HCI_LE_Set_Periodic_Advertising_Data
    • HCI_LE_Set_Periodic_Advertising_Enable
    • HCI_LE_Periodic_Advertising_Create_Sync
    • HCI_LE_Periodic_Advertising_Create_Sync_Cancel
    • HCI_LE_Periodic_Advertising_Terminate_Sync
    • HCI_LE_Set_Periodic_Advertising_Receive_Enable
    • HCI_LE_Periodic_Advertising_Report
    • HCI_LE_BIGInfo_Advertising_Report
    • HCI_LE_Read_Periodic_Advertiser_List_Size
    • HCI_LE_Add_Device_To_Periodic_Advertiser_List
    • HCI_LE_Remove_Device_From_Periodic_Advertiser_List
    • HCI_LE_Clear_Periodic_Advertiser_List
    • HCI_LE_Periodic_Advertising_Set_Info_Transfer
    • HCI_LE_Periodic_Advertising_Sync_Transfer
    • HCI_LE_Set_Default_Periodic_Advertising_Sync_Transfer_Parameters
    • HCI_LE_Set_Periodic_Advertising_Sync_Transfer_Parameters

藍牙 LE 音訊 VSAP 需要音訊驅動程式才能使用 ACX 架構。 採用 ACX for Bluetooth LE Audio 提供數個優點,例如:

  • 支援未來 Windows 的慣用音訊驅動程式模型。
  • ACX 原生支援多重堆疊的音訊解決方案,而無需驅動程式之間的專用 DDI。
  • 不需要IHV音訊驅動程式將來自音訊系統的要求轉送至藍牙堆棧。 相反地,ACX 可以透過配置文件電路將要求直接傳送至藍牙協議棧。

建築

定義

下列元件涉及不同的 VSAP 架構變體。

Windows ACX 架構

此元件可支援多堆疊音訊端點。 針對藍牙 LE 音訊,組成音訊端點的軟體元件是廠商特定的音訊驅動程式堆疊和 Windows 藍牙 LE 音訊配置檔。

廠商特定的音訊驅動程式架構

此廠商特定元件負責透過廠商定義的音訊介面,來回傳送和接收藍牙 LE 音訊數據。 它至少應包含 ACX 串流驅動程式,以管理傳入和傳出音訊數據。 如果更多 ACX 驅動程式是多線路 ACX 音訊端點的必要部分,則可能會包含更多 ACX 驅動程式。 此元件在本文中也稱為IHV ACX串流驅動程式。

Windows 藍牙 LE 音訊配置檔

此元件包含基本音訊配置檔 (BAP)、音量控制配置檔和麥克風控制配置檔的實作。 它負責為每個藍牙 LE 音訊裝置或與 Windows 配對的裝置集建立控制 ACXCIRCUIT 。 它也會報告來自遠端裝置和藍牙控制器的音訊格式,並管理同步通道和群組的狀態。

Windows 藍牙核心協定套疊

此元件提供介面,允許 Windows 藍牙 LE 音訊配置檔從本機藍牙控制器查詢支援的編解碼器功能,以及管理不時訊通道和群組的狀態。

LC3 編解碼器

此子元件會在壓縮的 LC3 音訊和 PCM 音訊之間轉換。 它必須同時支援編碼和解碼功能。 LC3 編解碼器可以在軟體中實作,作為廠商特定音訊驅動程式 (VSAP) 堆疊的一部分。 或者,它可以作為音頻 DSP 或藍牙控制器的一部分在硬件中實現。 此圖表會以名稱提及 LC3,因為它是藍牙 SIG 支援的標準編解碼器。 Windows 支援的未來編解碼器和廠商特定編解碼器也可能以類似的方式併入架構。

架構變體

藍牙 LE 音訊 VSAP 架構支援不同的串流變體。

  1. 無音訊卸除的側帶藍牙 LE 音訊串流
  2. 側頻藍牙 LE 音訊串流與音訊分擔
  3. 廠商特定的內嵌式 Bluetooth LE 音訊串流

在下圖中,著色元件是由 IHV 提供,而非陰影元件則由 OS 提供。

無音訊卸除的側帶藍牙 LE 音訊架構

側帶架構會使用廠商特定的音訊介面,允許音訊驅動程式堆疊將音訊數據傳送和接收至藍牙控制器。 此數據路徑與用於其他藍牙數據的 HCI 數據路徑不同,例如在單播用戶端與遠端單播伺服器之間發出訊息訊號。 下圖會建立側帶架構模型,其中 LC3 編解碼器裝載於藍牙控制器中。 將 LC3 編解碼器作為廠商特定音訊驅動程式堆疊的一部分來進行軟體編碼和解碼也是可行的。 在此情況下,傳送至藍牙控制器的音訊會格式化為 LC3 音訊畫面,而不是 PCM 音訊。

下圖顯示藍牙控制器中具有 LC3 編解碼器的側帶藍牙 LE 音訊架構。

側帶藍牙 LE 音訊架構圖表,其中 LC3 編解碼器位於藍牙控制器中。

下圖顯示具有音訊驅動程式堆疊中 LC3 編解碼器的側帶藍牙 LE 音訊架構。

側帶藍牙 LE 音訊架構的圖表,其中 LC3 編解碼器位於音訊驅動程式堆疊中。

側頻 Bluetooth 低功耗音訊架構與音訊卸載

具有音訊卸除的側帶架構包含音訊 DSP 硬體元件,以提供具有省電優勢的藍牙 LE 音訊串流解決方案。 下圖示範藍牙控制器中的 LC3 編解碼器和音訊 DSP 中編解碼器的可能架構。

下圖顯示具有藍牙控制器中 LC3 編解碼器之音訊卸除架構的側帶藍牙 LE 音訊。

側帶藍牙 LE 音訊與音訊卸載架構的圖表,其具有藍牙控制器中的 LC3 編解碼器。

下圖顯示側帶藍牙 LE 音訊,其音訊 DSP 中配備了音訊卸除架構和 LC3 編解碼器。

側帶藍牙 LE 音訊與音訊卸除架構的圖表,其中包含音訊 DSP 中的 LC3 編解碼器。

廠商特定的內頻藍牙 LE 音訊架構

VSAP inband 架構可讓自定義管線將藍牙 LE 音訊數據從廠商特定的音訊驅動程式堆棧傳送和接收到藍牙控制器的 HCI。 此架構包含新的元件「IHV ISO 合併元件」。此元件負責管理 ISO 數據的流程控制。 如果需要傳送任何 HCI 命令,它也應該與 Windows 藍牙核心堆棧共用 HCI 命令流程控制。

下圖顯示廠商特定的帶藍牙 LE 音訊架構。

廠商專屬的帶式藍牙 LE 音訊架構圖表。

詳細設計

音訊格式需求

KSAUDIO_PACKETSIZE_CONSTRAINTS2

需要 IHV ACX 音訊驅動程式才能支援 KSAUDIO_PACKETSIZE_CONSTRAINTS2 屬性。 支援此屬性可減少將藍牙 LE 音訊裝置新增至 Windows 與音訊裝置可供應用程式串流之間的時間。

音訊畫面持續時間

藍牙 LE 音訊設定檔可讓實作支援影格持續時間為 7.5 毫秒或 10 毫秒的音訊串流。 Windows 需要 IHV 所提供的編解碼器,才能支援兩個畫面持續時間。 此要求可確保與藍牙 LE 音訊配件裝置的互通性,以及與連接到系統的其他藍牙 LE 裝置的品質共存。

訊號處理模式定義

藍牙 LE 音訊支援各種不同的串流格式,以支援不同的使用者案例。 BAP 和TMAP規格會定義認證的必要支援格式。 Windows 會套用 音訊訊號處理模式 ,將要使用的格式與系統正在執行的案例相互關聯。 支援藍牙 LE 音訊的音訊驅動程式應指出下表中訊號處理模式和格式的支援。 此外,藍牙 LE 音訊不支援原始訊號處理模式,因此音訊驅動程式不得公告此模式的任何支援格式。

單播轉譯串流音訊格式和訊號處理模式

藍牙 LE 音訊需要針對下列訊號處理模式宣告單播轉譯音訊格式:

  • 預設值 (AUDIO_SIGNALPROCESSINGMODE_DEFAULT)
    • 此模式用於單向轉譯案例,例如音樂播放、通知和視頻遊戲音訊。
  • 通訊(音訊信號處理模式:通訊)
    • 此模式用於雙向案例,例如語音通話。

下表是每個使用案例和訊號處理模式的對稱格式清單。 非對稱格式支援定義在 語音案例的超寬頻立體聲中。

音訊格式是從最慣用到最不慣用的排序。

連接到立體聲裝置或協調的一組設備時,系統音效、音樂播放和遊戲聲音

訊號處理模式: 預設值

取樣頻率 通道計數 位深度 框架持續時間 音訊數據速率 BAP 編解碼器組態識別碼 (BAP 規格表 3.11)
48 千赫 2 16 7.5 毫秒 96 kbps 48_3
48 千赫 2 16 7.5 毫秒 80 kbps 48_1
48 千赫 2 16 10 毫秒 96 kbps 48_4
48 千赫 2 16 10 毫秒 80 kbps 48_2
32 kHz(32千赫) 2 16 7.5 毫秒 64 kbps 32_1
32 kHz(32千赫) 2 16 10 毫秒 64 kbps 32_2
24 千赫 2 16 7.5 毫秒 48 kbps 24_1
24 千赫 2 16 10 毫秒 48 kbps 24_2
連接到協調配對裝置的單一成員時,系統音效、音樂播放及電子遊戲音效(單一耳機或助聽器)

訊號處理模式: 預設值

取樣頻率 通道計數 位深度 框架持續時間 音訊數據速率 BAP 編解碼器組態識別碼 (BAP 規格表 3.11)
48 千赫 1 16 7.5 毫秒 96 kbps 48_3
48 千赫 1 16 7.5 毫秒 80 kbps 48_1
48 千赫 1 16 10 毫秒 96 kbps 48_4
48 千赫 1 16 10 毫秒 80 kbps 48_2
32 kHz(32千赫) 1 16 7.5 毫秒 64 kbps 32_1
32 kHz(32千赫) 1 16 10毫秒 64 kbps 32_2
24 千赫 1 16 7.5 毫秒 48 kbps 24_1
24 千赫 1 16 10 毫秒 48 kbps 24_2
16 千赫 1 16 7.5 毫秒 32 kbps 16_1
16 千赫 1 16 10 毫秒 32 kbps 16_2
使用語音聊天轉譯錄音機、VOIP 通話或視頻遊戲音訊

訊號處理模式: 通訊

取樣頻率 通道計數 位深度 框架持續時間 音訊數據速率 BAP 編解碼器組態識別碼 (BAP 規格表 3.11)
32 kHz(32千赫) 1 16 7.5 毫秒 64 kbps 32_1
32 kHz(32千赫) 1 16 10 毫秒 64 kbps 32_2
24 千赫 1 16 7.5 毫秒 48 kbps 24_1
24 千赫 1 16 10 毫秒 48 kbps 24_2
16 千赫 1 16 7.5 毫秒 32 kbps 16_1
16 千赫 1 16 10 毫秒 32 kbps 16_2
單播擷取串流音訊格式和訊號處理模式

藍牙 LE 音訊需要針對預設 (AUDIO_SIGNALPROCESSINGMODE_DEFAULT) 訊號處理模式宣告單播擷取音訊格式。 下表列出支援的擷取格式。

音訊格式是從最慣用到最不慣用的排序。

使用語音聊天擷取錄音機、VOIP 通話或視頻遊戲音訊

訊號處理模式: 預設值

取樣頻率 通道計數 位深度 框架持續時間 音訊數據速率 BAP 編解碼器組態識別碼 (BAP 規格表 3.11)
32 kHz(32千赫) 1 16 7.5 毫秒 64 kbps 32_1
32 kHz(32千赫) 1 16 10 毫秒 64 kbps 32_2
24 千赫 1 16 7.5 毫秒 48 kbps 24_1
24 千赫 1 16 10 毫秒 48 kbps 24_2
16 千赫 1 16 7.5 毫秒 32 kbps 16_1
16 千赫 1 16 10 毫秒 32 kbps 16_2
廣播音訊訊號處理模式

Windows 藍牙 LE 音訊需要針對預設 (AUDIO_SIGNALPROCESSINGMODE_DEFAULT) 訊號處理模式宣告廣播來源 (轉譯) 音訊格式。

Windows 藍牙 LE 音訊需要針對預設 (AUDIO_SIGNALPROCESSINGMODE_DEFAULT) 訊號處理模式宣告廣播接收 (擷取) 音訊格式。

下列必要支援格式的完整清單對於這兩個角色來說是相同的。

用於系統聲音、音樂播放和視頻遊戲音頻的立體聲廣播流

訊號處理模式: 預設值

取樣頻率 通道計數 位深度 框架持續時間 音訊數據速率 BAP 編解碼器組態識別碼 (BAP 規格表 3.11)
48 千赫 2 16 7.5 毫秒 96 kbps 48_3
48 千赫 2 16 7.5 毫秒 80 kbps 48_1
48 千赫 2 16 10 毫秒 96 kbps 48_4
48 千赫 2 16 10毫秒 80 kbps 48_2
24 千赫 2 16 7.5 毫秒 48 kbps 24_1
24 千赫 2 16 10毫秒 48 kbps 24_2
用於系統聲音、音樂播放和視頻遊戲音頻的單聲道廣播流

訊號處理模式: 預設值

取樣頻率 通道計數 位深度 框架持續時間 音訊數據速率 BAP 編解碼器組態識別碼 (BAP 規格表 3.11)
48 千赫 1 16 7.5 毫秒 96 kbps 48_3
48 千赫 1 16 7.5 毫秒 80 kbps 48_1
48 千赫 1 16 10毫秒 96 kbps 48_4
48 千赫 1 16 10毫秒 80 kbps 48_2
24 千赫 1 16 7.5 毫秒 48 kbps 24_1
24 千赫 1 16 10毫秒 48 kbps 24_2
16 千赫 1 16 7.5 毫秒 32 kbps 16_1
16 千赫 1 16 10毫秒 32 kbps 16_2

定義的數據流組態和拓撲

單播僅限轉譯組態
基本音頻設定檔配置 1

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

圖表顯示基本音訊配置檔組態 1。

計算機會連線到支援單聲道串流的單一音訊裝置。 單一裝置可能是獨立式裝置,或協調集的單一連線成員。

使用案例範例 Windows 音訊設定 藍牙控制器設定
媒體播放 轉譯
訊號處理模式:預設值
通道計數:1
擷取:無
CIS 計數:1
CIG 計數:1
BAP QoS 設定:可靠性高
音訊裝置上沒有麥克風的語音通話 轉譯
訊號處理模式:通訊
通道計數:1
擷取:無
CIS 計數:1
CIG 計數:1
BAP QoS 設定:低延遲
視頻遊戲播放 轉譯
訊號處理模式:預設值
通道計數:1
擷取:無
CIS 計數:1
CIG 計數:1
BAP QoS 設定:低延遲
基本音訊設定檔設定 4

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

示意圖說明基本音訊配置檔案組態 4。

計算機會連線到支援立體聲串流的單一音訊裝置。 音訊裝置能夠處理單一 CIS 上的兩個音訊通道。

使用案例範例 Windows 音訊設定 藍牙控制器設定
媒體播放 轉譯:訊號處理模式:預設值
通道計數:2
擷取:無
CIS 計數:1
CIG 計數:1
BAP QoS 設定:高可靠性 音頻通道分配:左前和右前
視頻遊戲播放 訊號處理模式:預設值
通道計數:2
擷取:無
CIS 計數:1
CIG 計數:1
BAP QoS 設定:低延遲
音訊通道配置:前左和前右
基本音訊設定檔組態 6(i)

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

說明基本音訊配置檔組態 6 I 的圖表。

計算機會連線到支援立體聲串流的單一音訊裝置。 音訊裝置只能處理兩個 CIS 上的一個音訊通道

使用案例範例 Windows 音訊設定 藍牙控制器設定
媒體播放 訊號處理模式:預設值
通道計數:2
擷取:無
CIS 計數:2
CIG 計數:1
BAP QoS 設定:可靠性高
音訊裝置上沒有麥克風的語音通話 訊號處理模式:通訊
通道計數:1
擷取:無
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
音訊通道配置:左前或右方
視頻遊戲播放 訊號處理模式:預設值
通道計數:2
擷取:無
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
音訊通道配置:前左和前右
基本音訊輪廓配置 6(ii)

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

示意基本音訊設定檔組態 6 II 的圖表。

個人電腦連接到一組協調的音效設備。 此集合能夠處理兩個音訊通道,每個成員處理單一通道。

使用案例範例 Windows 音訊設定 藍牙控制器設定
媒體播放 訊號處理模式:預設值
通道計數:2
擷取:無
CIS 計數:2
CIG 計數:1
BAP QoS 設定:可靠性高
任一裝置上沒有麥克風的語音通話 訊號處理模式:通訊
通道計數:1
擷取:無
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
視頻遊戲播放 訊號處理模式:預設值
通道計數:2
擷取:無
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
單播雙向組態

當藍牙 LE 音訊配置檔偵測到應用程式想要同時建立擷取和轉譯數據流至遠端裝置或一組裝置時,會使用雙向組態。 應用程式會分別控制擷取和轉譯串流。 因此,IHV 音訊驅動程式和藍牙控制器應該允許音訊在布建之後流經雙向 CIS 的單一方向。 此佈建使用 HCI 命令 Configure Data Path 和 LE Setup ISO Data Path。

基本音訊配置檔組態 3

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

顯示基本音訊設定檔組態 3 的圖表。

電腦連接到單一的音訊設備,並在單一 CIS 上建立雙向的音訊串流。

用例 Windows 音訊設定 藍牙控制器設定
語音通話 呈現:
訊號處理模式:通訊
通道計數:1
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:1
CIG 計數:1
BAP QoS 設定:低延遲
使用語音聊天播放視頻遊戲 呈現:
訊號處理模式:通訊
通道計數:1
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
基本音訊設定檔組態 8(i)

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

圖表顯示基本音訊配置檔組態 8 I。

計算機會連線到支援立體聲轉譯串流和單聲道擷取串流的單一音訊裝置。 裝置能夠在單一 CIS 上處理一個方向的音訊通道。

用例 Windows 音訊設定 藍牙控制器設定
語音通話 呈現:
訊號處理模式:通訊
通道數:1 或 2
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
使用語音聊天播放視頻遊戲 呈現:
訊號處理模式:通訊
通道計數:2
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
基本音訊設定檔組態 8(ii)

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

示意圖說明基本音訊設定檔配置 8 II。

個人電腦連接到一組協調的音效設備。 每個集合成員都會收到一個渲染音訊通道。 單一集合成員具有已建立的擷取數據流。 具有擷取數據流的集合成員是第一個連線至同時支援擷取數據流的電腦的集合成員。

用例 Windows 音訊設定 藍牙控制器設定
語音通話 呈現:
訊號處理模式:通訊
通道數:1 或 2
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
使用語音聊天播放視頻遊戲 呈現:
訊號處理模式:通訊
通道計數:2
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
單播僅限擷取設定
基本音訊配置檔組態 2

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

說明基本音訊配置檔組態 2 的圖表。

PC 連接到支援單聲道捕獲流的單一音訊設備。

用例 Windows 音訊設定 藍牙控制器設定
裝置上沒有喇叭的語音通話 渲染:
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:1
CIG 計數:1
BAP QoS 設定:低延遲
基本音效配置 9(i)

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

說明音訊設定檔基本組態的示意圖 9 I。

計算機會連線到支援傳送立體聲音頻數據的單一音訊裝置。 裝置能夠在單一 CIS 上編碼一條音訊通道。

用例 Windows 音訊設定 藍牙控制器設定
多頻道麥克風擷取 渲染:
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲
基本音訊設定檔配置 9(ii)

PC 連接到支援單聲道捕獲流的單一音訊設備。

下列音訊組態定義於藍牙 BAP 規格的表格 4.1 中

圖示顯示基本音訊配置設定 9(ii),PC 連線至單一音訊裝置。

電腦連接到一組音訊裝置。 每個集合成員都會將一個音訊通道傳送至計算機。

用例 Windows 音訊設定 藍牙控制器設定
多頻道麥克風擷取 渲染:
捕獲:
訊號處理模式:預設值
通道計數:1
CIS 計數:2
CIG 計數:1
BAP QoS 設定:低延遲

如果遠端裝置或裝置集支援雙向音訊,則僅擷取串流的設定與雙向相同。 此設定允許從僅擷取案例轉換至雙向案例,而不需要重新建立串流。

廣播來源設定
基本音訊設定檔設定 12

藍牙 BAP 規格的表 4.2 中定義了以下音訊配置

顯示基本音頻配置文件配置 12 的圖表,其中 PC 連接到單聲道音頻設備。

PC 正在廣播一個單聲道音頻通道。

用例 Windows 音訊設定 藍牙控制器設定
系統聲音、音樂播放 呈現:
訊號處理模式:預設值
通道計數:1
BIS 計數:1
大計數:1
BAP QoS 設定:高可靠性
電玩音訊 呈現:
訊號處理模式:預設值
通道計數:1
BIS 計數:1
大計數:1
BAP QoS 設定:低延遲
基本音訊設定檔配置 13

藍牙 BAP 規格的表 4.2 中定義了以下音訊配置

顯示基本音頻配置文件配置 13 的圖表,其中 PC 連接到立體聲的單個音頻設備。

PC 正在廣播立體聲音頻,每個通道都在自己的 BIS 上傳輸。

用例 Windows 音訊設定 藍牙控制器設定
系統聲音、音樂播放 呈現:
訊號處理模式:預設值
通道計數:2
BIS 計數:1
大計數:1
BAP QoS 設定:高可靠性
電玩音訊 呈現:
訊號處理模式:預設值
通道計數:1
BIS 計數:1
大計數:1
BAP QoS 設定:低延遲

資料結構

Microsoft定義的藍牙 LE 音訊介面屬性

串流建立屬性

下列屬性會透過 ACXOBJECTBAGDDI 在廠商特定音訊驅動程式堆疊與藍牙 LE 音訊配置檔之間共用。 這些屬性會通知資料流程端點建立和設定的決策,如 資料流程建立 案例中所示。

藍牙低功耗音訊_編解碼能力

音訊驅動程式會設定此屬性,以指出音訊驅動程式或音訊 DSP 中支援的音訊串流功能支援。 屬性值是使用 DDI AcxObjectBagAddBlob 來設定,而值的格式與 PACS 規格中所定義的 PAC 記錄相同。

Windows 藍牙 LE 音訊配置檔會讀取 屬性,以判斷要使用的可能編解碼器組態和串流組合。

領域 八位元組
能力計數 0
編解碼器標識碼[i] 1-6
編解碼器特定功能長度[i] 7
編解碼器特定功能 8... n
中繼資料長度(公尺) n + 1
後設資料 n+2...m

域值定義於 PACS 規格的數據表 3.2 和 3.4 中。

藍牙_DatapathID

音訊驅動程式會設定此屬性,以指出用來做為命令HCI_LE_Setup_ISO_Data_Path和HCI_Configure_Data_Path參數的資料路徑識別碼。 屬性值是使用 AcxObjectBagAddUI8 DDI 來設定。

藍牙 LE 音訊設定檔會讀取並使用這個屬性,在 HCI_Configure_Data_Path 和 HCI_LE_Setup_ISO_Data_Path 命令中做為參數。 此標識符會套用至針對與物件包相關聯的 ACXSTREAM 所建立的所有異時態數據流。 若要為每個資料流程連線指派不同的資料路徑識別碼,請在音訊驅動程式中使用 KSPROPERTY_BtLeAudio_DATAPATH_ID

領域 八位元組
數據路徑識別碼 0

如果音訊驅動程式未設定此屬性,則 OS 會使用值 1 作為 HCI 命令的參數。

Bluetooth_數據通道配置 (Datapath Configuration)

音訊驅動程式會設定此屬性,以透過 HCI_Configure_Data_Path 命令將廠商特定的設定提供給藍牙控制器。 它不得大於 255 個位元組,這是藍牙控制器接受 HCI 命令的最大承載。 屬性值是使用 AcxObjectBagAddBlob DDI 來設定。 此設定適用於音訊驅動程式所設定的所有資料路徑識別碼。 若要為每個資料路徑識別碼指派不同的資料路徑設定,請在音訊驅動程式中使用 KSPROPERTY_BtLeAudio_DATAPATH_CONFIG

Bluetooth_RequiresHciTransportInD0ForStreaming

音訊驅動程式會設定此屬性,以指出藍牙控制器在音訊資料流程作用中時,不應轉換成低電源狀態。 屬性值是使用 AcxObjectBagAddUI8 DDI 來設定。

領域 八位元組
ActiveTransportRequired (應設定為 1) 0
BluetoothLEAudio_CodecConfiguration

使用 DDI AcxObjectBagAddBlob 設定編解碼器設定後,應該使用藍牙 LE 音訊配置檔來設定這個屬性。 值的結構為:

領域 八位元組
組態計數 0
串流連線句柄[i] 1-2
編碼格式[i] 3
公司標識碼[i] 4-5
廠商特定編解碼器標識碼[i] 6-7
編解碼器特定組態長度[i] 8
編解碼器特定組態[i] 9... n

欄位值衍生自 藍牙音訊串流控制服務規格的表 4.3。

如果 LC3 編解碼器位於 ACX 串流驅動程式或音訊 DSP 中,廠商特定的音訊驅動程式堆疊應該會讀取此屬性。

BluetoothLEAudio_StreamConnectionHandles

此屬性應該由藍牙 LE 音訊配置檔設定,以通知音訊驅動程式針對 BIG 或 CIG 建立的 BIS 或 CIS 控制碼清單。 控制碼的順序符合藍牙控制器傳回給 HCI 命令LE_Set_CIG_Parameters或 HCI 事件LE_Create_BIG_Complete的順序。 值的結構為:

領域 大小 八位元組
連線句柄計數 1 0
連接句柄[i] 2 1-n
藍牙 LE 音訊 KS 屬性

KS 屬性可讓 IHV ACX 音訊驅動程式在建立資料流程之後設定或更新音訊資料流程設定。 此案例適用於音訊驅動程式,以根據建立資料流程程式中藍牙設定檔電路所設定的屬性來設定組態設定。

定義

#define STATIC_KSPROPSETID_BtLeAudio\
    0x1159b79, 0xea6, 0x4923, 0x80, 0xf5, 0x32, 0x58, 0xd1, 0xfd, 0x91, 0x56
DEFINE_GUIDSTRUCT("01159B79-0EA6-4923-80F5-3258D1FD9156", KSPROPSETID_BtLeAudio);
#define KSPROPSETID_BtLeAudio DEFINE_GUIDNAMED(KSPROPSETID_BtLeAudio)

typedef enum {
    KSPROPERTY_BtLeAudio_DATAPATH_ID,
    KSPROPERTY_BtLeAudio_DATAPATH_CONFIG,
} ksproperty_btleaudio;
KSPROPERTY_BtLeAudio_DATAPATH_ID

此 KSProperty 可讓 IHV ACX 音訊驅動程式在叫用建立資料流程回呼之後設定或更新 Bluetooth_DatapathID 所設定的值。 此屬性也可讓 IHV 音訊驅動程式為 BluetoothLEAudio_CodecConfiguration 中的每個編解碼器設定專案指派不同的資料路徑識別碼。 此屬性的值應設定為單一位元組值,以代表用於所有編解碼器設定的資料路徑識別碼,或 n 個位元組,其中 n 等於 BluetoothLEAudio_CodecConfiguration 屬性中設定的組態計數值。 如果值包含多個資料路徑標識碼,則標識碼的順序應該用於編解碼器配置,如屬性BluetoothLEAudio_CodecConfiguration中的順序。

KSPROPERTY_BtLeAudio_DATAPATH_CONFIG

此 KSProperty 可讓 IHV ACX 音訊驅動程式設定或更新Bluetooth_DatapathConfiguration中定義的數據路徑設定。 在叫用啟動音訊資料流程回呼之前,音訊驅動程式應該將 KSProperty 傳送至藍牙配置檔。 此屬性可用來為單一方向的所有資料路徑設定單一組態,或為BluetoothLEAudio_CodecConfiguration中設定的每個編解碼器組態項目設定特定的資料路徑組態。 如果值包含多個資料路徑配置,則配置的順序應用於編解碼器配置項目,如屬性BluetoothLEAudio_CodecConfiguration中的順序。 編解碼器配置的數量應等於KSPROPERTY_BtLeAudio_DATAPATH_ID或Bluetooth_DatapathID設定的資料路徑 ID 數量。

領域 大小 價值觀
組態計數 1 位元組 1 或編解碼器配置計數設定在BluetoothLEAudio_CodecConfiguration中
配置大小[i] 1 位元組 不得超過255
組態[i] 配置大小[i]  

介面

音訊端點範本系結標識碼

音訊驅動程式的 ACX 線路處理站用來知道何時建立配對藍牙裝置的 ACX 線路。

下列元件標識碼可用來建立藍牙 LE 音訊線路:

// {5C52FDB5-722A-4AB7-A342-70163B7E9B5C}
DEFINE_GUID(GUID_BLUETOOTH_LEAUDIO_RENDER_COMPONENT_ID,
0x5c52fdb5, 0x722a, 0x4ab7, 0xa3, 0x42, 0x70, 0x16, 0x3b, 0x7e, 0x9b, 0x5c);

// {1DFF2EE3-AE89-441C-BDE3-24F885C55DF8}
DEFINE_GUID(GUID_BLUETOOTH_LEAUDIO_CAPTURE_COMPONENT_ID,
0x1dff2ee3, 0xae89, 0x441c, 0xbd, 0xe3, 0x24, 0xf8, 0x85, 0xc5, 0x5d, 0xf8);

藍牙 LE 音訊支援介面

音訊驅動程式堆疊用來表示其可支援串流藍牙 LE 音訊。 在此介面上,Windows 藍牙音訊服務會監控並等待該介面發佈後,才啟用藍牙 LE 音訊支援。

下列介面標識碼可用來發佈藍牙 LE 音訊支援介面:

// {BA02FA1B-0FD0-4A0F-A748-4FAE2E2D2F67}
DEFINE_GUID(GUID_BLUETOOTH_LEAUDIO_SUPPORT_INTERFACE,
0xba02fa1b, 0x0fd0, 0x4a0f, 0xa7, 0x48, 0x4f, 0xae, 0x2e, 0x2d, 0x2f, 0x67);

常見序列

下列序列會針對單播和廣播 LE 音訊案例執行。

音訊驅動程式初始化

當 IHV ACX 串流驅動程式載入並判斷它支援藍牙 LE 音訊串流時,它應該藉由建立 ACXFACTORYCIRCUIT 物件,並使用 音頻端點範本系結標識符中定義的標識元向 ACX 註冊藍牙範本系結,以顯示技術支援。

說明藍牙 LE 音訊驅動程式初始化順序的流程圖。

單播音訊序列

端點建立
  1. 當 LE 音訊裝置與系統配對時,藍牙 LE 音訊設定檔:

    1. 讀取遠端裝置的已發佈音訊功能。
    2. 藉由傳送命令HCI_Read_Local_Support_Codecs [v2] 和 HCI_Read_Local_Supported_Codec_Capabilities,探索控制器支援的功能。
    3. 根據藍牙控制器和遠端音訊裝置支援的編解碼器功能,使用所設定的支援格式建立 ACXCIRCUIT 。 如果控制器不支援任何編解碼器,因為編解碼器支援位於音訊 DSP 或音訊驅動程式中,則支援的格式會設定為遠端音訊裝置所支援的格式。
  2. 建立 ACXCIRCUIT 之後,ACX會要求IHV ACX串流驅動程式的ACX線路處理站建立 ACXCIRCUIT 以進行串流處理。

  3. 收到建立線路的要求時,IHV ACX 串流驅動程式會:

    1. 建立 ACXCIRCUIT、ACXPINACXOBJECTBAGACXSTREAMBRIDGE 物件。
    2. 如果 LC3 或廠商特定的編解碼器裝載在音訊驅動程式或 DS 中,IHV ACX 串流驅動程式會在 ACXOBJECTBAG 上設定BluetoothLEAudio_CodecCapabilities屬性。
    3. 如果目前已知,IHV ACX 串流驅動程式可能會在 ACXOBJECTBAG 上設定Bluetooth_DatapathIDBluetooth_DatapathConfiguration
  4. 建立這兩個線路之後,ACX 會在 IHV ACX 驅動程式的網橋接釘上叫用 EvtAcxPinConnected 回呼。

  5. 叫用 EvtAcxPinConnected 回呼時,IHV ACX 串流驅動程式:

    1. 使用 AcxTarget API 擷取配置檔線路的橋接針腳以擷取配置檔線路所支援的格式。
    2. 逐一查看配置檔線路所設定的 ACXDATAFORMAT清單。 如果藍牙音訊編解碼器裝載於音訊驅動程式或音訊 DS 中,則 IHV 音訊驅動程式會使用編解碼器和配置檔線路所支援的格式來更新其 ACXDATAFORMAT。 否則,所有格式都會複製到 IHV ACX 串流驅動程式的主機埠針腳。
    3. 如果建立音訊引擎以卸載串流,則會在網橋接上設定更新的格式清單。
  6. 更新格式之後,ACX 會啟用介面,並建立音訊端點。

    描述藍牙 LE 音訊端點建立程式的流程圖。

串流創建
  1. 當應用程式要求建立音訊串流時,ACX 會針對每個線路叫用已註冊的 EvtCircuitCreateStream 回呼,從 IHV ACX 串流驅動程序開始。

  2. 叫用其 EvtCircuitCreateStream 回呼時,IHV ACX 串流驅動程式:

    1. 設定或更新附加至 ACXSTREAMBRIDGEACXOBJECTBAG 上的Bluetooth_DatapathId和Bluetooth_DataPathConfiguration屬性。
    2. 建立 ACXSTREAM ,並針對串流狀態轉換和 RT 數據流處理設定回呼
    3. 如果音訊管線支援卸載串流,則在音訊串流上建立音訊引擎元素。
    4. ACXSTREAM 新增至其串流橋接器。 這會叫用藍牙 LE 音訊配置檔的 EvtCircuitCreateStream 回呼。
  3. 叫用其 EvtAcxCircuitCreateStream 回呼時,藍牙 LE 音訊配置檔:

    1. 對由 IHV ACX 串流驅動程式設定的 ACXOBJECTBAG 本機屬性進行儲存,以便在未來的串流轉移回呼中使用。
    2. 執行 BAP 規格中所定義的設定編解碼器作業。 作業的參數衍生自 EvtAcxCircuitCreateStream 回呼中指定的 ACXDATAFORMAT,以及 ACXOBJECTBAG 中的其他數據流參數或藍牙控制器支援的編解碼器功能。
    3. 透過傳送 HCI LE 設定 CIG 參數命令來配置串流資源。
    4. 使用藍牙控制器所傳回的 CIS 連線控制碼清單來設定 BluetoothLEAudio_StreamConnectionHandles 屬性。
    5. 設定 ACXOBJECTBAG 上的 BluetoothLEAudio_CodecConfiguration 屬性,並使用該值來設定遠端音訊裝置。
  4. 如果 IHV ACX 串流驅動程式需要根據配置檔所設定的物件包值更新其資料路徑識別碼或資料路徑設定,則可以叫用 KSPROPERTY 設定作業來更新設定檔線路所儲存的值。

    1. 建立 ACXSTREAM ,並針對數據流狀態轉換設定回呼。

    顯示藍牙 LE 音訊串流建立程式的流程圖。

數據流狀態轉換

ACX 會根據音訊流程決定數據流狀態轉換的線路順序,以及狀態是否轉換為較作用中或較不作用中狀態。

  • 對於渲染流從較不活躍到較活躍的狀態,配置線路會先接收事件,然後是流媒體線路接收事件。
  • 對於轉譯數據流從較使用中狀態到較不作用中的狀態,串流線路會先接收事件,後面接著配置檔線路。 
  • 針對擷取從較不使用中狀態到較主動狀態的擷取數據流,串流線路會先接收事件,後面接著配置檔線路。 
  • 針對擷取數據流從較活躍狀態轉變到較不活躍狀態,首先由配置電路接收事件,然後是串流電路接收。

準備數據流

叫用其 EvtAcxStreamPrepareHardware 回呼時,藍牙 LE 音訊配置檔會傳送 ASCS 設定 QoS 作業,以視需要將設定與遠端裝置同步處理。 當針對雙向資料流程的另一個方向呼叫回呼時,ASCS 設定 QoS 作業可能已經完成。

說明配置檔線路藍牙 LE 音訊串流準備的流程圖。

叫用 其 EvtAcxStreamPrepareHardware 回呼時,IHV ACX 串流驅動程式會配置必要的串流資源,並將音頻管線初始化為已取得的狀態。

描述串流線路之藍牙 LE 音訊串流準備的流程圖。

啟動串流

叫用 其 EvtAcxStreamRun 回呼時,藍牙 LE 音訊配置檔:

  1. 套用 ACX 串流驅動程式中的任何組態引數,如下所述,如果它們已變更,請使用 HCI_Configure_Data_Path 命令。 Windows 藍牙核心堆疊會快取每個Data_Path_Direction和Data_Path_ID配對的Vendor_Specific_Config緩衝區。 只有在Data_Path_Direction和Data_Path_ID配對的Vendor_Specific_Config變更時,才會傳送HCI_Configure_Data_Path命令。
    1. Data_Path_Direction 是發出 EvtAcxStreamRun 回呼的串流線路回呼的 AudioDirection。
    2. Data_Path_ID會填入來自下列其中一個來源的最新指派值:
      1. 在 EvtCircuitCreateStream 回呼期間,連結至 ACXSTREAMBRIDGE 的 ACXOBJECTBAG 上的 Bluetooth_DatapathID ACXOBJECTBAG 上傳遞至 Windows 藍牙 LE 音訊配置檔。
      2. 數據來自KSPROPERTY_BtLeAudio_DATAPATH_ID。
    3. Vendor_Specific_Config資料會填入來自下列任一來源的最新指派值:
      1. 在 EvtCircuitCreateStream 回呼期間,連結至 ACXSTREAMBRIDGE 傳遞至 Windows 藍牙 LE 音訊設定檔線路的 ACXOBJECTBAG 上的Bluetooth_DatapathConfiguration。
      2. 數據來自KSPROPERTY_BtLeAudio_DATAPATH_CONFIG。
  2. 將 ASCS 啟用作業傳送至遠端裝置。
  3. 建立 CIS(如果尚未使用 HCI_LE_Create_CIS 命令建立)。
  4. 如果尚未設定資料路徑,藍牙 LE 音訊設定檔會:
    1. 使用 HCI_LE_Setup_ISO_Data_Path 命令建立 ISO 資料路徑
      1. 如果 IHV ACX 串流驅動程式設定屬性BluetoothLEAudio_CodecCapabilities,則HCI_LE_Setup_ISO_Data_Path中 Codec_ID 欄位的值應該設定為藍牙指派號碼中所定義的透明 (0x3) 。 否則,此值應該與數據流建立程式中組態編解碼器作業中使用的編解碼器標識元相同。
  5. 如果音訊資料流程是擷取資料流程,藍牙 LE 音訊設定檔會執行 BAP 接收器啟動就緒作業。

流程圖顯示配置檔線路中藍牙 LE 音訊串流的啟動過程。

叫用 其 EvtAcxStreamRun 回呼時,IHV ACX 串流驅動程式會開始處理來自 Windows 音訊系統(轉譯)或藍牙控制器的傳入音訊數據(擷取)。

圖解藍牙 LE 音訊串流電路啟動過程的流程圖。

暫停數據流

叫用 其 EvtAcxStreamPause 回呼時,藍牙 LE 音訊配置檔:

  1. 執行 BAP 單播數據流停用程序。
  2. 使用 HCI_LE_Remove_ISO_Data_Path 命令移除 ISO 資料路徑。
  3. 如果音訊數據流是單播擷取數據流,則執行 ASCS 接收者停止就緒程式。
  4. 如果該 CIS 沒有其他串流正在使用,請中斷 CIS 的連線。

顯示配置檔電路藍牙 LE 音訊串流暫停過程的流程圖。

叫用 其 EvtAcxStreamPause 回呼時,IHV ACX 串流驅動程式會暫停其音訊處理管線。

顯示串流線路藍牙 LE 音訊串流暫停程式的流程圖。

發佈流程

叫用其 EvtAcxStreamReleaseHardware 回呼時,藍牙 LE 音訊配置檔:

  1. 將 ASCS 釋放操作傳送到遠端藍牙 LE 音訊裝置
  2. 如果所有 CIS 都中斷連線,則移除 CIG。

描述配置檔回路的藍牙 LE 音訊串流釋放過程的流程圖。

叫用 其 EvtAcxStreamReleaseHardware 回呼時,IHV ACX 串流驅動程式會釋放其音訊管線資源。

描述串流迴路中藍牙 LE 音訊串流釋放過程的流程圖。

端點中斷連線

如果遠端單播裝置沒有與計算機的 LE-ACL 連線,或透過其 PACS 可用的音訊內容報告它無法進行串流,那麼 Windows 藍牙 LE 音訊配置檔會更新端點的連線狀態。 當端點中斷連線後,Windows 音訊服務會使任何連接到該端點的活動數據流失效。 這會導致數據流暫停和釋放順序發生。

音量和靜音

如果串流驅動程式需要音訊引擎,IHV ACX 串流線路應該只包含音量和靜音元素。 使用音訊引擎時,必須設定組態旗標,如下所示:

ACX_AUDIOENGINE_CONFIG audioEngineCfg;
ACX_AUDIOENGINE_CONFIG_INIT(&audioEngineCfg);
…

audioEngineCfg.Flags |= AcxAudioEngineConfigVolumeSecondary; // Use this control only if endpoint doesn't have one.

audioEngineCfg.MuteElement = muteElement;

audioEngineCfg.Flags |= AcxAudioEngineConfigMuteSecondary; // Use this control only if endpoint doesn't have one.

audioEngineCfg.PeakMeterElement = peakmeterElement;

audioEngineCfg.Flags |= AcxAudioEngineConfigPeakMeterSecondary; // Use this control only if endpoint doesn't have one.

這是必要的,以使藍牙 LE 音訊端點能使用藍牙 SIG 定義的音量和麥克風控制配置檔,以進行單播音訊端點的音量調整和麥克風靜音變更。

如果遠端藍牙 LE 音訊裝置不支援音量或麥克風控制服務,或針對廣播音訊建立端點,則音訊引擎中的音量和靜音元素應作為後援來處理音訊系統的變更要求。 Windows 音訊系統會處理音量和靜音的變更。 如果沒有音音引擎,且遠端裝置不支援音量或麥克風服務,或者音訊端點是用於廣播音訊。

端點移除

當設定檔線路或串流線路遭到毀損時,會從系統中移除藍牙 LE 音訊端點。 從 Windows 移除遠端單播裝置的配對或停用藍牙無線電時,可以移除設定檔電路。

  1. 當 Windows 藍牙 LE 音訊配置檔移除其線路時,ACX 會停用其端點介面,以向 Windows 音訊服務發出訊號,指出應該移除端點。
  2. 停用介面時,Windows 音訊服務會使藍牙 LE 音訊端點的任何作用中資料流程失效,此作業會導致串流暫停,並釋放要在串流線路上叫用回呼。
  3. 若要完成端點移除,ACX 會使 IHV ACX 串流驅動程式的線路失效,這會導致 WDF 叫用線路的清除回呼。
  4. 叫用其清除回呼時,IHV ACX 串流驅動程式會釋放其線路。

藍牙 LE 音訊端點移除流程的流程圖。

藍牙 LE 和傳統音訊共存

Windows 應確保只有傳統音訊或 LE 音訊適用於支援這兩種技術的配對藍牙音訊裝置。 如果 LE 音訊為使用中,則會停用遠端裝置 A2DP 和 HFP 的側帶 DDI,並針對 LE 音訊端點建立剖面電路。 如果經典音訊為使用中,則會啟用遠端裝置的 A2DP 和 HFP 的側頻 DDI,而且不會為 LE 音訊端點建立配置檔迴路。

電源管理

藍牙 LE 音頻沒有任何電源管理需求或流程超出 WDF 已定義的流程以外。

超寬頻立體聲,適用於語音場景

當今的藍牙音訊體驗很方便,但也有局限性,尤其是與有線音訊體驗相比。 一個關鍵限制,以及面向用戶的後果,是每當麥克風處於活動狀態時,就會變成單聲道音頻。 這會阻止 Teams 和其他 VoIP 應用程序中的空間音頻等體驗正常工作,並嚴重降低涉及語音聊天的遊戲體驗。

低功耗藍牙音訊透過增加對麥克風使用時立體聲播放的支援,提高了音訊保真度並減少了延遲,從而縮小了差距。

彩現/擷取格式配對

IHV 解決方案會藉由提供轉譯/擷取格式組的清單來宣告其對單聲道擷取立體聲轉譯的支援,每個格式組都包含立體聲轉譯格式和單聲道擷取格式,可同時用於雙向串流。 立體聲轉譯 (或單聲道擷取) 格式定義為一對Sampling_Frequency (例如 16/24/32/48 kHz) 和一對 Audio_Channel_Count (例如 1/2 通道) 與特定音訊編解碼器相關聯,不限於 LC3。

例如,假設 IHV 解決方案同時支援 16kHz 立體聲轉譯與 16kHz 單聲道擷取,以及 48kHz 立體聲轉譯與 24kHz 或 32kHz 單聲道擷取。 對應的轉譯/擷取格式配對如下所示:

Entry 轉譯格式 擷取格式
1 渲染(16 kHz,2 聲道) 擷取(16 kHz,1 聲道)
2 渲染(48 kHz,2 聲道) 擷取(24 kHz,1 聲道)
3 渲染(48 kHz,2 聲道) 擷取(32 kHz,1 聲道)

表 3:範例轉譯/擷取格式配對

由於協調集成員可能隨時聯結或中斷聯結,因此 IHV 解決方案必須支援單一轉譯,並以格式配對中每個專案的相同個別取樣頻率擷取。 這表示,假設 表 3 中的範例,即使未明確宣告,下列所有格式組也必須隱含支援:

Entry 轉譯格式 擷取格式
1 渲染(16 kHz,1 聲道) 擷取(16 kHz,1 聲道)
2 渲染(48 kHz,1 聲道) 擷取(24 kHz,1 聲道)
3 渲染(48 kHz,1 聲道) 擷取(32 kHz,1 聲道)

表 4:表 3 的隱含轉譯/擷取格式對

表 3 和表 4 之間的主要區別在於,後者中每種渲染格式的Audio_Channel_Count都設置為 1(“單色渲染”);其他一切都保持不變。

強制彩現/擷取格式配對

表 5 定義所有 IHV 解決方案都應支援的音訊格式清單:

Entry (Render_format,Capture_format)
1 { 渲染(48 kHz,2 通道),捕獲(32 kHz,1 通道) }
2 { 渲染(32 kHz,2 通道),捕獲(32 kHz,1 通道) }
3 { 渲染(24 kHz,2 通道),捕獲(24 kHz,1 通道) }
4 { 渲染(16 kHz,2 通道),捕獲(16 kHz,1 通道)}

表 5 強制渲染/捕獲格式對

功能廣告

根據藍牙控制器是否支援涉及的音訊編解碼器 (預設為 LC3) ,IHV 解決方案會以不同的方式公告其支援的轉譯/擷取格式配對清單。 具體而言:

  • 如果編解碼器位於藍牙控制器中,控制器和 IHV ACX 串流驅動程式都應該獨立公告格式組清單。 如果兩個清單彼此不一致,Windows 應相交並保留共同部分。

  • 例如,如果編解碼器不在藍牙控制器中 (,則位於音訊 DSP 中) ,則只需要 IHV ACX 串流驅動程式來公告格式配對清單。 藍牙控制器

由於HCI_Read_Local_Supported_Codec_Capabilities回應中的 Codec_Capability[i] 不支援中繼資料,因此藍牙控制器必須支援一系列 Microsoft 特定的編解碼器識別碼 (請參閱 表 7) ,讓 Windows 可以查詢更多編解碼器功能,例如轉譯/擷取格式配對的清單,這些功能無法透過現有的 HCI 介面輕鬆傳達。

參數 大小(八位元組) Description
Codec_ID 5 八位元組 0: 0xFF (廠商特定)

八位組 1 至 2: 0x0006 (Microsoft)

八位元組 3 至 4: 廠商定義的編解碼器識別碼

如果八位元組 4 的最高有效位元設定為零 (0),則八位元組 3 包含 SIG 核准的編碼格式 (截至 2024 年 5 月 31 日,範圍從 0x00 到 0x07),但 0xFF 除外。

如果八位元組 4 的最有效位設定為一 (1) ,則八位元組 3 包含尚未定義的編碼格式,並由 Windows 保留以供未來使用。

表 7 Microsoft 特定的編解碼器識別碼

這些 Microsoft 特定編解碼器識別碼的範圍僅限於:

  • HCI_Read_Local_Supported_Codecs [v2]
  • HCI_Read_Local_Supported_Codec_Capabilities

根據合約,Windows 不得將任何這些 Microsoft 特定的編解碼器識別碼用於其他類型的 HCI 命令。

HCI_Read_Local_Supported_Codecs [v2]

控制器應透過Vendor_Specific_Codec_ID和Vendor_Specific_Codec_Transport宣傳其對Microsoft特定編解碼器 ID 的支援:

領域 Description
Vendor_Specific_Codec_ID[k] 八位元組 0 到 1: 公司編號 (0x0006)
有關更多信息,請參閱表 1 中的 八位元組 2 到 7

八位元組 2 至 3: 廠商定義的編解碼器識別碼 (例如,LC3 的0x0006)
有關更多信息,請參閱表 7 中的 八位元組 3 到 4
Vendor_Specific_Codec_Transport[k] 必須支援LE_CIS (0x02)。

表8 HCI_Read_Local_Supported_Codec[v2]回應值

HCI_Read_Local_Supported_Codec_Capabilities

若要查詢所有 Windows 特定的編解碼器功能,包括轉譯/擷取格式組的清單,Windows 會使用下列引數呼叫 HCI_Read_Local_Supported_Codec_Capabilities:

參數 大小(八位元組) Description
Codec_ID (Microsoft特定編解碼器 ID) 5 八位元組 0: 0xFF (廠商特定)

八位元組 1 至 2: 公司編號 (0x0006)
有關更多信息,請參閱表 8 中的 八位元組 1 至 2

八位元組 3 至 4: 廠商定義的編解碼器識別碼 (例如,LC3 的0x0006)
有關更多信息,請參閱表8中的 八位元組3至4
Logical_Transport_Type 1 0x2 (LE CIS)
方向 1 0x00(輸入,例如主機到控制器)

表 9 HCI_Read_Local_Supported_Codec_Capabilities 命令引數

收到這類命令時,控制器應該傳回廠商定義的編解碼器識別碼所指定編解碼器的所有 Windows 特定功能。 例如,如果廠商定義的編解碼器識別碼設定為 0x0006,控制器應該傳回 Windows 所需的所有 LC3 相關功能。

命令的回應會維護與藍牙核心規格所定義的相同最上層結構:

參數 大小(八位元組) Description
地位 1 0x00(成功);0x01到0xFF(錯誤代碼)
Num_Codec_Capabilities 1 傳回的功能總數。
Codec_Capability_Length[i] 1 Codec_Capability[i] 欄位的長度。
Codec_Capability [i] 不定 Codec_Capability_Length[i] 編解碼器特定功能資料的八位元組。

表10 HCI_Read_Local_Supported_Codec_Capabilities響應結構

但是, Codec_Capability[i] 的有效負載與 SIG 定義的有效負載不同,並且是針對 Windows 量身定制的。

目前,Windows 定義的唯一編解碼器功能是 Bidirectional_Multichannel_Streaming,如下所述。

Bidirectional_Multichannel_Streaming

透過通告Bidirectional_Multichannel_Streaming,控制器確認它支援並發 m 通道渲染和 n 通道捕獲,其中 m ≥ 1、 n ≥ 1 和 m + n> 2。 (具有單聲道捕捉的立體聲渲染實際上是 m = 2 和 n = 1 的Bidirectional_Multichannel_Streaming。

下表說明Bidirectional_Multichannel_Streaming的格式:

參數 大小(八位元組) Description
類型 1 0x00 (Bidirectional_Multichannel_Streaming)
Channel_Counts 1 位元 0 到 4: (m – 1),其中 m 是渲染通道的數目 (對於具有單聲道捕獲的立體聲渲染,此值應為 2 – 1 = 1。
Channel_Counts 1 位 5 到 7: (n – 1),其中 n 是捕獲通道的數量 (對於具有單聲道捕獲的立體聲渲染,此值應為 1 – 1 = 0。
Render_Sampling_Frequencies 1 位元 0: 16 kHz
位元 1: 24 kHz
位 2: 32 kHz
位元 3: 48 kHz
位元 4: RFU
位元 5: RFU
位元 6: RFU
位元7: RFU
此清單中的所有取樣頻率都具有與Channel_Count位元 0-4 指定的通道數相同的通道數。

所有 RFU 位都是保留的,必須設為零。
Capture_Sampling_Frequencies_-List[i],其中 0 ≤ i ≤ 7 我 + 1 位元 0: 16 kHz
位元 1: 24 kHz
位 2: 32 kHz
位元 3: 48 kHz
位元 4: RFU
位元 5: RFU
位元 6: RFU
位元7: RFU
此清單中的所有取樣頻率都具有與Channel_Count位元 5-7 指定的通道數相同的通道數。

每個Capture_Sampling_Frequencies_List實例的大小為一個八位元組,最多可以有八個這樣的實例(如果Render_Sampling_Frequencies中的所有位都設置為一個)。

所有 RFU 位都是保留的,必須設為零。

表11 Bidirectional_Multichannel_Streaming格式(最大長度:11位元組)

Channel_Counts

渲染/捕獲的位計數選擇是任意的——分配五個位用於渲染(以涵蓋所有 SIG 定義的音頻位置),三個位用於捕獲(以最小化 HCI 有效負載大小)。

例如,表 3 的 Channel_Counts 為 0b0000'0001,因為轉譯/擷取通道的數目 (例如 mn) 分別為 2 和 1:

  擷取 Render
7 6 5 4 3 2 1 0
價值 0 0 0 0 0 0 0 1

表12 表3的Channel_Counts

根據設計,具有相同一對Microsoft特定編解碼器識別碼和 Channel_Counts 的所有功能都必須分組在一起,並由單一Bidirectional_Multichannel_Streaming記錄表示。

Render_Sampling_Frequencies

Render_Sampling_Frequencies欄位會指定可在相關聯Bidirectional_Multichannel_Streaming結構前後關聯中使用的所有彩現頻率。

例如,表 3 的 Render_Sampling_Frequencies 為 0b0000'1001,這意味著 16kHz 和 48kHz 都可以用作雙通道渲染的採樣頻率:

千赫 RFU RFU RFU RFU 48 32 24 16
7 6 5 4 3 2 1 0
價值 0 0 0 0 1 0 0 1

表13 表3的Render_Sampling_Frequencies

Capture_Sampling_Frequencies_List[i]

對於 Render_Sampling_Frequencies中的每個“一個”位,從最不有效到最高有效位,控制器應提供唯一的位遮罩 (Capture_Sampling_Frequencies_List[i]),指定與該渲染位所表示的頻率兼容的所有捕獲頻率。 控制器不得為Render_Sampling_Frequencies中的任何“零”位提供Capture_Sampling_Frequencies位遮罩。

例如,表3的捕獲位掩碼如下所示:

// The order matters!
{
    // Capture_Sampling_Frequencies_List[0] for 16kHz dual-channel rendering.
    0b0000'0001, // 16 kHz single-channel capture

    // Do not create a dummy Capture_Sampling_Frequencies_List entry, for example, 0b0000'0000,
    // for 24kHz dual-channel rendering, which is not supported at all.

    // Do not create a dummy Capture_Sampling_Frequencies_List entry, for example, 0b0000'0000,
    // for 32kHz dual-channel rendering, which is not supported at all.

    // Capture_Sampling_Frequencies_List[1] for 48kHz dual-channel rendering.
    0b0000'0110 // Either 24 or 32 kHz single-channel capture
}

具體而言:

Render_-Sampling_-Frequencies Capture_-Sampling_頻率[i] Description
0b0000'1001
   ⇤ 訂單 ↤
0 0b0000'0001 Render_Sampling_Frequencies 中的第一個最低有效“一”位(位 0)對應於 16 kHz。

啟用 Capture_Sampling_Frequencies_List[0] 的位 0 以指出 16 kHz 擷取可以與該轉譯頻率配對。
0b0000'1 001
   ⇤ 訂單 ↤
1 0b0000'0110 Render_Sampling_Frequencies中第二個最低有效“一”位(位 3)對應於 48 kHz。

啟用 Capture_Sampling_Frequencies_List[1] 的位 1 和 2,以指示 24 kHz 和 32 kHz 擷取可以與該彩現頻率配對。

表14 為Render_Sampling_Frequencies建立Capture_Sampling_Frequencies_List[i]的範例

IHV ACX 串流驅動程式

若要支援具有單聲道擷取的立體聲轉譯,IHV ACX 串流驅動程式會將裝置屬性 BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities 設定為裝置介面類別GUID_BLUETOOTH_LEAUDIO_SUPPORT_INTERFACE的實例,這代表 3.11.2 中所述的轉譯/擷取格式組。

屬性應該在建立裝置介面類別實例之後立即提供,而且屬性的值會在裝置介面類別實例的整個存留期內保持不變。

BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities 的屬性索引鍵定義為:

DEFINE_DEVPROPKEY(DEVPKEY_BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities,
    0xd27ba3a4, 0x1bfe, 0x4374, 0x88, 0x7d, 0xe8, 0xb3, 0xa6, 0xac, 0xe, 0xe9, 2); // DEVPROP_TYPE_BINARY (BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_CAPABILITY[])

與索引鍵相關聯的屬性值類型 DEVPKEY_BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities 定義為:

typedef struct _BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_CAPABILITY
{
    BTH_LE_AUDIO_CODEC_ID CodecId;
    BOOL IsCodecPresent;
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_CHANNEL_COUNT RenderChannelCount;
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_CHANNEL_COUNT CaptureChannelCount;
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY RenderSamplingFrequencies;
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY CaptureSamplingFrequenciesList[
        BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_BIT_LENGTH
    ];
} BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_CAPABILITY;

Where:

typedef struct _BTH_LE_AUDIO_CODEC_ID
{
    UINT8 CodingFormat;
    UINT16 CompanyId;
    UINT16 VendorCodecId;
} BTH_LE_AUDIO_CODEC_ID;

typedef UINT8 BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_CHANNEL_COUNT;

typedef enum _BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY :
    UINT8 // Bit flags
{
    // 16 kHz
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_16000HZ = 0x1,

    // 24 kHz
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_24000HZ = 0x2,

    // 32 kHz
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_32000HZ = 0x4,

    // 48 kHz
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_48000HZ = 0x8,

    // A dummy value for indicating a sampling frequency is "not applicable" in the
    // respective context.
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_NONE = 0,

    // All valid sampling frequencies combined.
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_ALL =
        BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_16000HZ |
        BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_24000HZ |
        BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_32000HZ |
        BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_48000HZ,
} BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY;

DEFINE_ENUM_FLAG_OPERATORS(BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY);

#define BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_BIT_LENGTH \
    (sizeof(BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY) * 8)

BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_CAPABILITY結構遵循與Bidirectional_Multichannel_Streaming中所述的類似規則,但以下不同之處在於:

  • 需要 ACX 串流驅動程式來設定額外的旗標 IsCodecPresent,以指出感興趣的編解碼器在概念上是否是 ACX 串流驅動程式的一部分。 例如,如果編解碼器位於音訊 DSP 中,則 IsCodecPresent 應該設定為 TRUE。 如果編解碼器位於藍牙控制器中,則旗標應該設定為 FALSE。

  • 針對具有 n 通道擷取的 m 通道轉譯,RenderChannelCount 和 CaptureChannelCount 的值分別為 m 和 n。 換句話說,RenderChannelCount 和 CaptureChannelCount 會指出轉譯和擷取通道的實際數目。

  • 假設索引 i,RenderSamplingFrequencies 的第 i 個最低有效位與 CaptureSamplingFrequenciesList 的第 i 個專案之間有一對一對一對應。 如果 RenderSamplingFrequencies 的第 i 位為零,請將 CaptureSamplingFrequenciesList[i] 設定為零。

下列範例程式碼示範如何建立GUID_BLUETOOTH_LEAUDIO_SUPPORT_INTERFACE裝置介面,並設定 BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities 裝置介面屬性:

PAGED_CODE_SEG
NTSTATUS
AdvertiseBluetoothLEAudioSupport(
    WDFDEVICE Device
    )
{
    // Create a device interface with the class,
    // GUID_BLUETOOTH_LEAUDIO_SUPPORT_INTERFACE, for the specified WDF device.
    DECLARE_CONST_UNICODE_STRING(
        bluetoothLEAudioSupportInterface, L"BluetoothLEAudioSupport");
    RETURN_NTSTATUS_IF_FAILED(WdfDeviceCreateDeviceInterface(
        Device,
        &GUID_BLUETOOTH_LEAUDIO_SUPPORT_INTERFACE,
        (PUNICODE_STRING)&bluetoothLEAudioSupportInterface));

#pragma region associate BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities with GUID_BLUETOOTH_LEAUDIO_SUPPORT_INTERFACE.
    // Advertise bidirectional multichannel streaming support by setting the device
    // interface property, 
    // BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities,
    // to the newly created device interface.

    // See Table 7 "Microsoft-specific codec ID" in Microsoft Bluetooth LE Audio
    // IHV Specification for reference.
    constexpr BTH_LE_AUDIO_CODEC_ID microsoftLC3CodecId
    {
        0xff, // Vendor-specific
        0x6,  // Microsoft
        0x6,  // LC3
    };

    constexpr BTH_LE_AUDIO_CODEC_ID microsoftCVSDCodecId
    {
        0xff, // Vendor-specific
        0x6,  // Microsoft
        0x2,  // CVSD
    };

    // For readability purpose only
    constexpr auto SamplingFrequency_None = BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_NONE;
    constexpr auto SamplingFrequency_16000Hz = BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_16000HZ;
    constexpr auto SamplingFrequency_24000Hz = BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_24000HZ;
    constexpr auto SamplingFrequency_32000Hz = BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_32000HZ;
    constexpr auto SamplingFrequency_48000Hz = BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_48000HZ;
    constexpr auto SamplingFrequency_All = BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_SAMPLING_FREQUENCY_ALL;

    // Bidirectional multichannel streaming capabilities
    BTH_LE_AUDIO_BIDIRECTIONAL_MULTICHANNEL_STREAMING_CAPABILITY capabilities[]
    {
        // List of formats supported for 2-channel render with 1-channel capture using
        // the LC3 codec:
        //
        //      Render           Capture
        //   (Freq, #Chan)    (Freq, #Chan)
        //   =============    =============
        //    (16kHz, 2) <---> (16kHz, 1)
        //    ----------       ----------
        //    (24kHz, 2) <---> (16kHz, 1)
        //    (24kHz, 2) <---> (24kHz, 1)
        //    ----------       ----------
        //    (32kHz, 2) <---> (16kHz, 1)
        //    (32kHz, 2) <---> (24kHz, 1)
        //    (32kHz, 2) <---> (32kHz, 1)
        //    ----------       ----------
        //    (48kHz, 2) <---> (16kHz, 1)
        //    (48kHz, 2) <---> (24kHz, 1)
        //    (48kHz, 2) <---> (32kHz, 1)
        //    (48kHz, 2) <---> (48kHz, 1)
        //
        {
            // CodecId
            microsoftLC3CodecId,
            // IsCodecPresent,
            FALSE, // The LC3 codec is in the Bluetooth Controller.
            // RenderChannelCount
            2,
            // CaptureChannelCount
            1,
            // RenderSamplingFrequencies
            SamplingFrequency_All,
            // CaptureSamplingFrequencies: List of 1-channel capture sampling
            // frequencies compatible with 16kHz, 2-channel render
            SamplingFrequency_16000Hz,
            // CaptureSamplingFrequencies: List of 1-channel capture sampling
            // frequencies compatible with 24kHz, 2-channel render
            SamplingFrequency_16000Hz | SamplingFrequency_24000Hz,
            // CaptureSamplingFrequencies: List of 1-channel capture sampling
            // frequencies compatible with 32kHz, 2-channel render
            SamplingFrequency_16000Hz |
                SamplingFrequency_24000Hz |
                SamplingFrequency_32000Hz,
            // CaptureSamplingFrequencies: List of 1-channel capture sampling
            // frequencies compatible with 48kHz, 2-channel render
            SamplingFrequency_All,
            // CaptureSamplingFrequencies: RFU
            SamplingFrequency_None,
            // CaptureSamplingFrequencies: RFU
            SamplingFrequency_None,
            // CaptureSamplingFrequencies: RFU
            SamplingFrequency_None,
            // CaptureSamplingFrequencies: RFU
            SamplingFrequency_None,
        },
        // List of formats supported for 4-channel render with 2-channel capture using
        // the CVSD codec:
        //
        //      Render           Capture
        //   (Freq, #Chan)    (Freq, #Chan)
        //   =============    =============
        //    (16kHz, 4) <---> (16kHz, 2)
        //    ----------       ----------
        //    (32kHz, 4) <---> (16kHz, 2)
        //    (32kHz, 4) <---> (32kHz, 2)
        //
        {
            // CodecId
            microsoftCVSDCodecId,
            // IsCodecPresent,
            TRUE, // The CVSD codec is in the audio DSP.
            // RenderChannelCount
            4,
            // CaptureChannelCount
            2,
            // RenderSamplingFrequencies
            SamplingFrequency_16000Hz | SamplingFrequency_32000Hz,
            // CaptureSamplingFrequencies: List of 2-channel capture sampling
            // frequencies compatible with 16kHz, 4-channel render
            SamplingFrequency_16000Hz,
            // CaptureSamplingFrequencies: List of 2-channel capture sampling
            // frequencies compatible with 24kHz, 4-channel render
            SamplingFrequency_None, // N/A
            // CaptureSamplingFrequencies: List of 2-channel capture sampling
            // frequencies compatible with 32kHz, 4-channel render
            SamplingFrequency_16000Hz | SamplingFrequency_32000Hz,
            // CaptureSamplingFrequencies: List of 2-channel capture sampling
            // frequencies compatible with 48kHz, 4-channel render
            SamplingFrequency_None, // N/A
            // CaptureSamplingFrequencies: RFU
            SamplingFrequency_None,
            // CaptureSamplingFrequencies: RFU
            SamplingFrequency_None,
            // CaptureSamplingFrequencies: RFU
            SamplingFrequency_None,
            // CaptureSamplingFrequencies: RFU
            SamplingFrequency_None,
        }
    };

    // Call IoSetDeviceInterfacePropertyData to associate the capabilities associated
    // with the DEVPKEY.
    WDFSTRING wdfSymbolicLinkName;
    RETURN_NTSTATUS_IF_FAILED(WdfStringCreate(
        nullptr, WDF_NO_OBJECT_ATTRIBUTES, &wdfSymbolicLinkName));
    auto deleteWdfStringOnExt = scope_exit([wdfSymbolicLinkName]() -> void
    {
        WdfObjectDelete(wdfSymbolicLinkName);
    });

    RETURN_NTSTATUS_IF_FAILED(WdfDeviceRetrieveDeviceInterfaceString(
        Device,
        &GUID_BLUETOOTH_LEAUDIO_SUPPORT_INTERFACE,
        &bluetoothLEAudioSupportInterface,
        wdfSymbolicLinkName));
    
    UNICODE_STRING symbolicLinkName;
    WdfStringGetUnicodeString(wdfSymbolicLinkName, &symbolicLinkName);

    RETURN_NTSTATUS_IF_FAILED(IoSetDeviceInterfacePropertyData(
        &symbolicLinkName,
        &DEVPKEY_BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities,
        LOCALE_NEUTRAL,
        PLUGPLAY_PROPERTY_PERSISTENT,
        DEVPROP_TYPE_BINARY,
        sizeof(capabilities), capabilities));
#pragma endregion

    return STATUS_SUCCESS;
}