本文概述了 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 | 连接的时序流传输用于在蓝牙 LE 设备之间发送和接收单播音频数据。 |
| BIS | 广播时序流传输用于无连接音频数据传输。 |
| ACX | 音频类扩展的缩写,这是所有音频驱动程序支持 Windows 上的蓝牙 LE 音频所需的驱动程序模型。 |
| 流式传输线路 | 由供应商特定音频驱动程序堆栈为其流路径创建的一个或多个 ACXCIRCUIT 对象。 |
| 轮廓电路 | 由 Windows 上的蓝牙 LE 音频配置文件实现创建的 ACXCIRCUIT 对象。 此 ACXCIRCUIT 不是流式传输线路。 |
本文假定熟悉之前定义的术语和 蓝牙核心规范中定义的以下 HCI 命令:
- 本地控制器命令
- HCI_Read_Local_Supported_Codecs (v2)
- HCI_读取本地支持的编解码器能力
- HCI_LE_Setup_ISO_Data_Path
- HCI_LE_Remove_ISO_Data_Path
- HCI_配置_数据路径
- 单播流式处理命令
- HCI_LE_设置_CIG_参数
- 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 驱动程序。 在本文档中,此组件也称为 IHV ACX 流驱动程序。
Windows 蓝牙 LE 音频配置文件
此组件包含基本音频配置文件(BAP)、音量控制配置文件和麦克风控制配置文件的实现。 它负责为每个蓝牙 LE 音频设备或与 Windows 配对的设备集创建控制 ACXCIRCUIT 。 它还报告来自远程设备和蓝牙控制器的音频格式,并管理不时序通道和组的状态。
Windows 蓝牙核心堆栈
此组件提供一个接口,允许 Windows 蓝牙 LE 音频配置文件从本地蓝牙控制器查询支持的编解码器功能,并管理不时序通道和组的状态。
LC3 编解码器
此子组件在压缩的 LC3 音频和 PCM 音频之间进行转换。 它必须同时支持编码和解码功能。 LC3 编解码器可以在软件中实现,作为供应商特定的音频驱动程序 (VSAP) 堆栈的一部分。 或者,它可以在硬件中实现,作为音频 DSP 或蓝牙控制器的一部分。 该图以名称提及 LC3,因为它是蓝牙 SIG 支持的标准编解码器。 Windows 支持的未来编解码器和供应商特定的编解码器也可能以类似的方式合并到体系结构中。
体系结构变体
蓝牙 LE 音频 VSAP 体系结构支持用于流式传输的不同变体。
- 无音频卸载的侧带蓝牙 LE 音频流式传输
- 带旁带蓝牙 LE 音频流式处理与音频卸载
- 特定于带蓝牙 LE 音频流式传输的供应商
在下图中,着色组件由 IHV 提供,非阴影组件由 OS 提供。
无音频卸载的侧带蓝牙 LE 音频体系结构
侧带体系结构使用供应商特定的音频接口,允许音频驱动程序堆栈向蓝牙控制器发送和接收音频数据。 此数据路径与用于其他蓝牙数据的 HCI 数据路径是分开的,例如单播客户端和远程单播服务器之间的信号消息。 下图建模了一个侧带体系结构,其中 LC3 编解码器托管在蓝牙控制器中。 对于软件编码和解码,在供应商特定的音频驱动程序堆栈中托管 LC3 编解码器也是有效的。 在这种情况下,发送到蓝牙控制器的音频将格式化为 LC3 音频帧,而不是 PCM 音频。
下图显示了蓝牙控制器中具有 LC3 编解码器的侧带蓝牙 LE 音频体系结构。
下图显示了在音频驱动程序堆栈中使用 LC3 编解码器的侧带蓝牙 LE 音频体系结构。
侧带 Bluetooth LE 音频架构与音频卸载
具有音频卸载的边带体系结构包括音频 DSP 硬件组件,用于提供具有省电优势的蓝牙 LE 音频流式处理解决方案。 下图演示了蓝牙控制器中的 LC3 编解码器和音频 DSP 中的编解码器的可能体系结构。
下图展示了一种旁带蓝牙 LE 音频架构,其中包含蓝牙控制器内的 LC3 编解码器用于音频卸载。
下图显示了带有音频卸载体系结构的侧带蓝牙 LE 音频,该体系结构在音频 DSP 中使用 LC3 编解码器。
供应商特定的带内蓝牙 LE 音频的体系结构
VSAP 内带体系结构使自定义管道能够将蓝牙 LE 音频数据从供应商特定的音频驱动程序堆栈发送和接收到蓝牙控制器的 HCI。 此体系结构包括一个新组件“IHV ISO 合并组件”。此组件负责管理 ISO 数据的流控制。 如果需要发送任何 HCI 命令,它还应与 Windows 蓝牙核心堆栈共享 HCI 命令流控制。
下图展示了一种供应商特定的带内蓝牙 LE 音频架构。
详细设计
音频格式要求
KSAUDIO_PACKETSIZE_CONSTRAINTS2
IHV ACX 音频驱动程序需要支持KSAUDIO_PACKETSIZE_CONSTRAINTS2属性。 支持此属性可以减少将蓝牙 LE 音频设备添加到窗口和音频设备可供应用程序流式传输的时间。
音频帧持续时间
蓝牙 LE 音频配置文件允许实现支持帧持续时间为 7.5 毫秒或 10 毫秒的音频流式处理。 Windows 要求 IHV 提供的编解码器支持这两个帧持续时间。 此要求可确保与蓝牙 LE 音频配件设备的互作性,并与连接到系统的其他蓝牙 LE 设备进行质量共存。
信号处理模式定义
蓝牙 LE 音频支持各种流式处理格式,以支持不同的用户方案。 BAP 和 TMAP 规范定义了必需的认证支持格式。 Windows 应用 音频信号处理模式 ,以将格式与系统正在执行的方案相关联。 支持蓝牙 LE 音频的音频驱动程序应指示对下表中的信号处理模式和格式的支持。 此外,蓝牙 LE 音频不支持原始信号处理模式,因此音频驱动程序不应为此模式播发任何受支持的格式。
单播呈现流音频格式和信号处理模式
蓝牙 LE 音频要求为以下信号处理模式声明单播呈现音频格式:
- 默认值(AUDIO_SIGNALPROCESSINGMODE_DEFAULT)
- 此模式用于单向呈现方案,例如音乐播放、通知和视频游戏音频。
- 通信(AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS)
- 此模式用于双向方案,例如语音呼叫。
下表列出了每种用例和信号处理模式的对称格式。 非对称格式支持在 超宽带立体声中为语音方案定义。
音频格式从最首选到最不首选的顺序排序。
当连接到立体声设备或协调的设备集合时,系统声音、音乐播放和视频游戏音频
信号处理模式: 默认值
| 采样频率 | 通道计数 | 位深度 | 帧持续时间 | 音频数据速率 | BAP 编解码器配置 ID (BAP 规范表 3.11) |
|---|---|---|---|---|---|
| 48 kHz | 2 | 16 | 7.5 毫秒 | 96 kbps | 48_3 |
| 48 kHz | 2 | 16 | 7.5 毫秒 | 80 kbps | 48_1 |
| 48 kHz | 2 | 16 | 10 毫秒 | 96 kbps | 48_4 |
| 48 kHz | 2 | 16 | 10 毫秒 | 80 kbps | 48_2 |
| 32 千赫 | 2 | 16 | 7.5 毫秒 | 64 kbps | 32_1 |
| 32 千赫 | 2 | 16 | 10 毫秒 | 64 kbps | 32_2 |
| 24 kHz | 2 | 16 | 7.5 毫秒 | 48 kbps | 24_1 |
| 24 kHz | 2 | 16 | 10 毫秒 | 48 kbps | 24_2 |
当连接到协调集合中的单个设备(如单个耳塞或助听器)时,系统声音、音乐播放和视频游戏音频
信号处理模式: 默认值
| 采样频率 | 通道计数 | 位深度 | 帧持续时间 | 音频数据速率 | BAP 编解码器配置 ID (BAP 规范表 3.11) |
|---|---|---|---|---|---|
| 48 kHz | 1 | 16 | 7.5 毫秒 | 96 kbps | 48_3 |
| 48 kHz | 1 | 16 | 7.5 毫秒 | 80 kbps | 48_1 |
| 48 kHz | 1 | 16 | 10 毫秒 | 96 kbps | 48_4 |
| 48 kHz | 1 | 16 | 10 毫秒 | 80 kbps | 48_2 |
| 32 千赫 | 1 | 16 | 7.5 毫秒 | 64 kbps | 32_1 |
| 32 千赫 | 1 | 16 | 10 毫秒 | 64 kbps | 32_2 |
| 24 kHz | 1 | 16 | 7.5 毫秒 | 48 kbps | 24_1 |
| 24 kHz | 1 | 16 | 10 毫秒 | 48 kbps | 24_2 |
| 16 kHz | 1 | 16 | 7.5 毫秒 | 32 kbps | 16_1 |
| 16 kHz | 1 | 16 | 10 毫秒 | 32 kbps | 16_2 |
使用语音聊天呈现录音机、VOIP 呼叫或视频游戏音频
信号处理模式: 通信
| 采样频率 | 通道计数 | 位深度 | 帧持续时间 | 音频数据速率 | BAP 编解码器配置 ID (BAP 规范表 3.11) |
|---|---|---|---|---|---|
| 32 千赫 | 1 | 16 | 7.5 毫秒 | 64 kbps | 32_1 |
| 32 千赫 | 1 | 16 | 10 毫秒 | 64 kbps | 32_2 |
| 24 kHz | 1 | 16 | 7.5 毫秒 | 48 kbps | 24_1 |
| 24 kHz | 1 | 16 | 10 毫秒 | 48 kbps | 24_2 |
| 16 kHz | 1 | 16 | 7.5 毫秒 | 32 kbps | 16_1 |
| 16 kHz | 1 | 16 | 10 毫秒 | 32 kbps | 16_2 |
单播捕获流音频格式和信号处理模式
蓝牙 LE 音频要求为默认(AUDIO_SIGNALPROCESSINGMODE_DEFAULT)信号处理模式声明单播捕获音频格式。 支持的捕获格式列表如下表所示。
音频格式从最首选到最不首选的顺序排序。
使用语音聊天捕获录音机、VOIP 呼叫或视频游戏音频
信号处理模式: 默认值
| 采样频率 | 通道计数 | 位深度 | 帧持续时间 | 音频数据速率 | BAP 编解码器配置 ID (BAP 规范表 3.11) |
|---|---|---|---|---|---|
| 32 千赫 | 1 | 16 | 7.5 毫秒 | 64 kbps | 32_1 |
| 32 千赫 | 1 | 16 | 10 毫秒 | 64 kbps | 32_2 |
| 24 kHz | 1 | 16 | 7.5 毫秒 | 48 kbps | 24_1 |
| 24 kHz | 1 | 16 | 10 毫秒 | 48 kbps | 24_2 |
| 16 kHz | 1 | 16 | 7.5 毫秒 | 32 kbps | 16_1 |
| 16 kHz | 1 | 16 | 10 毫秒 | 32 kbps | 16_2 |
广播音频信号处理模式
Windows 蓝牙 LE 音频要求将广播源(呈现)音频格式声明为默认(AUDIO_SIGNALPROCESSINGMODE_DEFAULT)信号处理模式。
Windows 蓝牙 LE 音频要求为默认(AUDIO_SIGNALPROCESSINGMODE_DEFAULT)信号处理模式声明广播接收器(捕获)音频格式。
对于这两个角色,以下所需支持格式的完整列表相同。
系统声音、音乐播放和视频游戏音频的立体声广播流
信号处理模式: 默认值
| 采样频率 | 通道计数 | 位深度 | 帧持续时间 | 音频数据速率 | BAP 编解码器配置 ID (BAP 规范表 3.11) |
|---|---|---|---|---|---|
| 48 kHz | 2 | 16 | 7.5 毫秒 | 96 kbps | 48_3 |
| 48 kHz | 2 | 16 | 7.5ms | 80 kbps | 48_1 |
| 48 kHz | 2 | 16 | 10 毫秒 | 96 kbps | 48_4 |
| 48 kHz | 2 | 16 | 10 毫秒 | 80 kbps | 48_2 |
| 24 kHz | 2 | 16 | 7.5ms | 48 kbps | 24_1 |
| 24 kHz | 2 | 16 | 10 毫秒 | 48 kbps | 24_2 |
系统声音、音乐播放和视频游戏音频的单声道广播流
信号处理模式: 默认值
| 采样频率 | 通道计数 | 位深度 | 帧持续时间 | 音频数据速率 | BAP 编解码器配置 ID (BAP 规范表 3.11) |
|---|---|---|---|---|---|
| 48 kHz | 1 | 16 | 7.5ms | 96 kbps | 48_3 |
| 48 kHz | 1 | 16 | 7.5ms | 80 kbps | 48_1 |
| 48 kHz | 1 | 16 | 10 毫秒 | 96 kbps | 48_4 |
| 48 kHz | 1 | 16 | 10 毫秒 | 80 kbps | 48_2 |
| 24 kHz | 1 | 16 | 7.5ms | 48 kbps | 24_1 |
| 24 kHz | 1 | 16 | 10 毫秒 | 48 kbps | 24_2 |
| 16 kHz | 1 | 16 | 7.5ms | 32 kbps | 16_1 |
| 16 kHz | 1 | 16 | 10 毫秒 | 32 kbps | 16_2 |
定义的流配置和拓扑
单播仅呈现配置
基本音频配置文件配置 1
以下音频配置在蓝牙 BAP 规范的表 4.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 中定义
电脑连接到支持立体声流的单个音频设备。 音频设备能够在单个 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 中定义
电脑连接到一组协调的音频设备。 该集能够处理两个音频通道,每个成员处理单个通道。
| 用例示例 | 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 命令配置数据路径和 LE 安装程序 ISO 数据路径。
基本音频配置文件设置 3
以下音频配置在蓝牙 BAP 规范的表 4.1 中定义
电脑连接到在单个 CIS 上建立的双向单声道流的单个音频设备。
| 用例 | Windows 音频设置 | 蓝牙控制器设置 |
|---|---|---|
| 语音呼叫 |
呈现: 信号处理模式:通信 通道计数:1 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:1 CIG 计数:1 BAP QoS 设置:低延迟 |
| 使用语音聊天播放视频游戏 |
呈现: 信号处理模式:通信 通道计数:1 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:2 CIG 计数:1 BAP QoS 设置:低延迟 |
基本音频配置文件 8(i)
以下音频配置在蓝牙 BAP 规范的表 4.1 中定义
电脑连接到支持立体声渲染流和单声道捕获流的单个音频设备。 设备能够在单个 CIS 上针对特定方向处理一个音频信道。
| 用例 | Windows 音频设置 | 蓝牙控制器设置 |
|---|---|---|
| 语音呼叫 |
呈现: 信号处理模式:通信 通道计数:1 或 2 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:2 CIG 计数:1 BAP QoS 设置:低延迟 |
| 使用语音聊天播放视频游戏 |
呈现: 信号处理模式:通信 通道计数:2 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:2 CIG 计数:1 BAP QoS 设置:低延迟 |
基本音频简介配置 8(ii)
以下音频配置在蓝牙 BAP 规范的表 4.1 中定义
电脑连接到一组协调的音频设备。 每个组成员都接收一个渲染音频通道。 单个集成员具有已建立的捕获流。 具有捕获流的集成员是连接到支持捕获流的电脑的第一组成员。
| 用例 | Windows 音频设置 | 蓝牙控制器设置 |
|---|---|---|
| 语音呼叫 |
呈现: 信号处理模式:通信 通道计数:1 或 2 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:2 CIG 计数:1 BAP QoS 设置:低延迟 |
| 使用语音聊天播放视频游戏 |
呈现: 信号处理模式:通信 通道计数:2 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:2 CIG 计数:1 BAP QoS 设置:低延迟 |
仅单播捕获配置
基本音频配置文件配置 2
以下音频配置在蓝牙 BAP 规范的表 4.1 中定义
电脑连接到支持单声道捕获流的单个音频设备。
| 用例 | Windows 音频设置 | 蓝牙控制器设置 |
|---|---|---|
| 设备上没有扬声器的语音呼叫 |
呈现: 没有 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:1 CIG 计数:1 BAP QoS 设置:低延迟 |
基本音频配置文件 9(i)
以下音频配置在蓝牙 BAP 规范的表 4.1 中定义
电脑连接到支持发送立体声音频数据的单个音频设备。 该设备能够在单个 CIS 上编码一个音频通道。
| 用例 | Windows 音频设置 | 蓝牙控制器设置 |
|---|---|---|
| 多声道麦克风录制 |
呈现: 没有 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:2 CIG 计数:1 BAP QoS 设置:低延迟 |
基本音频轮廓配置 9(ii)
电脑连接到支持单声道捕获流的单个音频设备。
以下音频配置在蓝牙 BAP 规范的表 4.1 中定义
电脑连接到一组音频设备。 每个集合成员将一个音频通道发送到电脑。
| 用例 | Windows 音频设置 | 蓝牙控制器设置 |
|---|---|---|
| 多声道麦克风录制 |
呈现: 没有 捕获: 信号处理模式:默认值 通道计数:1 |
CIS 计数:2 CIG 计数:1 BAP QoS 设置:低延迟 |
如果远程设备或设备集支持双向音频,则仅捕获流的配置与双向音频相同。 此配置允许从仅捕获方案转换到双向方案,而无需重新创建流。
广播源配置
基本音频配置文件配置 12
蓝牙 BAP 规范表 4.2 中定义了以下音频配置
电脑正在广播单声道音频的一个通道。
| 用例 | Windows 音频设置 | 蓝牙控制器设置 |
|---|---|---|
| 系统声音,音乐播放 |
呈现: 信号处理模式:默认值 通道计数:1 |
BIS 计数:1 BIG Count: 1 BAP QoS 设置:可靠性高 |
| 视频游戏音频 |
呈现: 信号处理模式:默认值 通道计数:1 |
BIS 计数:1 BIG Count: 1 BAP QoS 设置:低延迟 |
基本音频配置文件配置 13
蓝牙 BAP 规范表 4.2 中定义了以下音频配置
电脑正在广播立体声音频,每个通道在其自己的 BIS 上传输。
| 用例 | Windows 音频设置 | 蓝牙控制器设置 |
|---|---|---|
| 系统声音,音乐播放 |
呈现: 信号处理模式:默认值 通道计数:2 |
BIS 计数:1 BIG Count: 1 BAP QoS 设置:可靠性高 |
| 视频游戏音频 |
呈现: 信号处理模式:默认值 通道计数:1 |
BIS 计数:1 BIG Count: 1 BAP QoS 设置:低延迟 |
数据结构
Microsoft定义的蓝牙 LE 音频接口属性
流创建属性
以下属性通过 ACXOBJECTBAGDDI 在供应商特定的音频驱动程序堆栈和蓝牙 LE 音频配置文件之间共享。 这些属性告知流终结点的创建和配置决策,如 流创建 方案所示。
蓝牙低功耗音频_编解码器能力
音频驱动程序设置此属性以指示对音频驱动程序或音频 DSP 中支持的音频流式处理功能的支持。 属性值是使用 DDI AcxObjectBagAddBlob 设置的,该值的格式与 PACS 规范中定义的 PAC 记录相同。
Windows 蓝牙 LE 音频配置文件读取属性以确定要使用的可能的编解码器配置和流组合。
| 领域 | 八位字节 |
|---|---|
| 功能计数 | 0 |
| 编解码器 ID[i] | 1-6 |
| 编解码器特定功能长度[i] | 7 |
| 编解码器特定功能 | 8... n |
| 元数据长度 (m) | n + 1 |
| 元数据 | n+2...m |
字段值在 PACS 规范的表 3.2 和 3.4 中定义。
Bluetooth_DatapathID
音频驱动程序将此属性设置为指示用作命令HCI_LE_Setup_ISO_Data_Path和HCI_Configure_Data_Path参数的数据路径 ID。 使用 AcxObjectBagAddUI8 DDI 设置属性值。
蓝牙 LE 音频配置文件读取此属性,并将其作为参数用于 HCI_Configure_Data_Path 和 HCI_LE_Setup_ISO_Data_Path 命令。 此 ID 适用于为与对象包关联的 ACXSTREAM 创建的所有时序流。 若要为每个流连接分配不同的数据路径 ID,请在音频驱动程序中使用 KSPROPERTY_BtLeAudio_DATAPATH_ID 。
| 领域 | 八位字节 |
|---|---|
| 数据路径标识符 | 0 |
如果音频驱动程序未设置此属性,则 OS 将使用值 1 作为 HCI 命令的参数。
Bluetooth_数据路径配置
音频驱动程序将此属性设置为通过 HCI_Configure_Data_Path 命令向蓝牙控制器提供供应商特定的配置。 它不能大于 255 字节,这是蓝牙控制器接受 HCI 命令的最大有效负载。 使用 AcxObjectBagAddBlob DDI 设置属性值。 此配置适用于音频驱动程序设置的所有数据路径 ID。 若要为每个数据路径 ID 分配不同的数据路径配置,请在音频驱动程序中使用 KSPROPERTY_BtLeAudio_DATAPATH_CONFIG 。
Bluetooth_RequiresHciTransportInD0ForStreaming
音频驱动程序将此属性设置为指示蓝牙控制器在音频流处于活动状态时不应转换为低功率状态。 使用 AcxObjectBagAddUI8 DDI 设置属性值。
| 领域 | 八位字节 |
|---|---|
| ActiveTransportRequired (应设置为 1) | 0 |
BluetoothLEAudio_CodecConfiguration
此属性应由蓝牙 LE 音频配置文件使用 DDI AcxObjectBagAddBlob 在编解码器配置音频设备后设置。 值的结构为:
| 领域 | 八位字节 |
|---|---|
| 配置计数 | 0 |
| 流连接句柄[i] | 1-2 |
| 编码格式[i] | 3 |
| 公司 ID[i] | 4-5 |
| 供应商特定的编解码器 ID[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中的每个编解码器配置条目分配不同的数据路径 ID。 此属性的值应设置为单个字节值,表示用于所有编解码器配置的数据路径 ID,或 n 个字节,其中 n 等于 BluetoothLEAudio_CodecConfiguration 属性中设置的配置计数值。 如果值包含多个数据路径 ID,则 ID 的顺序将用于属性BluetoothLEAudio_CodecConfiguration中排序的编解码器配置。
KSPROPERTY_BtLeAudio_DATAPATH_CONFIG
此 KSProperty 允许 IHV ACX 音频驱动程序设置或更新Bluetooth_DatapathConfiguration中定义的数据路径配置。 在调用开始音频流回调之前,音频驱动程序应将 KSProperty 发送到蓝牙配置文件。 此属性可用于为单个方向中的所有数据路径设置单个配置,或为BluetoothLEAudio_CodecConfiguration中设置的每个编解码器配置条目设置特定的数据路径配置。 如果值包含多个数据路径配置,则应将配置的顺序用于属性BluetoothLEAudio_CodecConfiguration中排序的编解码器配置条目。 编解码器配置数应等于KSPROPERTY_BtLeAudio_DATAPATH_ID或Bluetooth_DatapathID设置的数据路径 ID 数。
| 领域 | 尺寸 | 价值 |
|---|---|---|
| 配置计数 | 1 个字节 | BluetoothLEAudio_CodecConfiguration中设置的 1 或编解码器配置计数 |
| 配置大小[i] | 1 个字节 | 不得超过 255 |
| Configuration[i] | 配置大小[i] |
接口
音频端点模板绑定 ID
音频驱动程序的 ACX 电路工厂用于识别何时创建配对蓝牙设备的 ACX 电路。
以下组件 ID 用于创建蓝牙 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 音频支持。
以下接口 ID 用于发布蓝牙 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 注册蓝牙模板绑定(使用 音频终结点模板绑定 ID 中定义的 ID)来显示对技术的支持。
单播音频序列
终结点创建
当 LE 音频设备与系统配对时,蓝牙 LE 音频配置文件:
- 读取远程设备的已发布音频功能。
- 通过发送命令HCI_Read_Local_Support_Codecs [v2] 和HCI_Read_Local_Supported_Codec_Capabilities来发现控制器支持的功能。
- 使用基于蓝牙控制器和远程音频设备支持的编解码器功能设置的受支持格式创建 ACXCIRCUIT 。 如果控制器不支持任何编解码器,因为编解码器支持位于音频 DSP 或音频驱动程序中,则支持的格式将设置为远程音频设备支持的格式。
创建 ACXCIRCUIT 后,ACX 请求 IHV ACX 流式驱动程序的电路厂创建 ACXCIRCUIT 进行流处理。
收到创建线路的请求时,IHV ACX 流式处理驱动程序:
- 创建 ACXCIRCUIT、 ACXPIN、 ACXOBJECTBAG 和 ACXSTREAMBRIDGE 对象。
- 如果 LC3 或供应商特定的编解码器托管在音频驱动程序或 DSP 中,则 IHV ACX 流式处理驱动程序会在 ACXOBJECTBAG 上设置BluetoothLEAudio_CodecCapabilities属性。
- 如果目前已知,IHV ACX 流式处理驱动程序可能会在 ACXOBJECTBAG 上设置 Bluetooth_DatapathID 或 Bluetooth_DatapathConfiguration。
创建这两条线路后,ACX 将在 IHV ACX 驱动程序的网桥引脚上调用 EvtAcxPinConnected 回调。
调用 EvtAcxPinConnected 回调时,IHV ACX 流式处理驱动程序:
- 使用 AcxTarget API 检索轮廓电路的桥接引脚,以检索轮廓电路支持的格式。
- 遍历配置文件电路中设置的 ACXDATAFORMAT 列表。 如果蓝牙音频编解码器托管在音频驱动程序或音频 DSP 中,则 IHV 音频驱动程序使用编解码器和配置文件线路支持的格式更新其 ACXDATAFORMAT。 否则,所有格式将复制到 IHV ACX 流式处理驱动程序的主机引脚。
- 如果为离线传输创建了音频引擎,则在桥接针上设置更新的格式列表。
更新格式后,ACX 会同时启用接口,并创建音频终结点。
创建流
当应用程序请求创建音频流时,ACX 会为每个线路调用已注册的 EvtCircuitCreateStream 回调,从 IHV ACX 流式处理驱动程序开始。
调用 EvtCircuitCreateStream 回调时,IHV ACX 流式处理驱动程序:
- 设置或更新附加在 ACXSTREAMBRIDGE 上的 ACXOBJECTBAG 的 Bluetooth_DatapathId 和 Bluetooth_DataPathConfiguration 属性。
- 创建一个 ACXSTREAM,设定回调以实现流状态转换和实时流处理。
- 如果音频管道支持卸载流,请在流中创建音频引擎组件。
- 将 ACXSTREAM 添加到其流桥。 这会调用蓝牙 LE 音频配置文件的 EvtCircuitCreateStream 回调。
调用 EvtAcxCircuitCreateStream 回调时,蓝牙 LE 音频配置文件:
- 从 IHV ACX 流式处理驱动程序设置的 ACXOBJECTBAG 中本地保存属性,以便将来进行流转换回调。
- 执行 BAP 规范中定义的配置编解码器操作。 操作的参数源自 EvtAcxCircuitCreateStream 回调中指定的 ACXDATAFORMAT,以及从 ACXOBJECTBAG 中其他流参数或蓝牙控制器支持的编解码器功能。
- 通过发送 HCI LE Set CIG 参数命令来分配流资源。
- 使用蓝牙控制器返回的 CIS 连接句柄列表设置 BluetoothLEAudio_StreamConnectionHandles 属性。
- 通过用于配置远程音频设备的值设置ACXOBJECTBAG上的BluetoothLEAudio_CodecConfiguration属性。
如果 IHV ACX 流式处理驱动程序需要根据配置文件设置的对象包值更新其数据路径 ID 或数据路径配置,则可以调用 KSPROPERTY 集作来更新配置文件线路存储的值。
- 创建一个 ACXSTREAM ,其中包含为流状态转换设置的回调。
流状态转换
ACX 根据音频流决定流状态转换的线路顺序,以及状态是转换为更活跃还是不太活跃的状态。
- 对于从不太活跃状态变为更活跃状态的呈现流,描述电路首先接收事件,然后是流电路。
- 对于从较活跃状态转变为不太活跃状态的渲染流,流媒体电路首先接收事件,然后是配置电路。
- 对于从低活跃状态转变为高活跃状态的捕获流,流式处理电路首先接收事件,其次是配置电路。
- 对于从较活跃状态转变为不太活跃状态的捕获流,轮廓电路将首先接收到事件,随后是流媒体电路。
准备流
调用 其 EvtAcxStreamPrepareHardware 回调时,蓝牙 LE 音频配置文件会根据需要发送 ASCS 配置 QoS作以将设置与远程设备同步。 当为双向流的另一个方向调用回调时,ASCS 配置 QoS作可能已经完成。
在调用其 EvtAcxStreamPrepareHardware 回调时,IHV ACX 流式处理驱动程序会分配必要的流式处理资源,并将音频管道初始化为已获状态。
启动直播
在调用 EvtAcxStreamRun 回调时,蓝牙 LE 音频规范:
- 使用 HCI_Configure_Data_Path 命令应用 ACX 流式处理驱动程序中的任何配置参数(如下所述)。 Windows 蓝牙核心堆栈为每个Data_Path_Direction和Data_Path_ID对缓存Vendor_Specific_Config缓冲区。 仅当Data_Path_Direction和Data_Path_ID对的Vendor_Specific_Config更改时,才会发送HCI_Configure_Data_Path命令。
- Data_Path_Direction是发出 EvtAcxStreamRun 回调的流线路回调的 AudioDirection。
- Data_Path_ID使用以下任一源中最近分配的值进行填充:
- 在 EvtCircuitCreateStream 回调期间,附加到 ACXSTREAMBRIDGE 的 ACXOBJECTBAG 上Bluetooth_DatapathID传递给 Windows 蓝牙 LE 音频配置文件。
- 来自KSPROPERTY_BtLeAudio_DATAPATH_ID的数据。
- Vendor_Specific_Config数据填充了以下任一源中最近分配的值:
- 在 EvtCircuitCreateStream 回调期间传递给 Windows 蓝牙 LE 音频配置文件线路的 ACXOBJECTBAG 上的 ACXOBJECTBAG 上的Bluetooth_DatapathConfiguration。
- 来自KSPROPERTY_BtLeAudio_DATAPATH_CONFIG的数据。
- 将 ASCS 启用作发送到远程设备。
- 如果尚未使用 HCI_LE_Create_CIS 命令创建 CIS,则创建 CIS。
- 如果尚未配置数据路径,蓝牙 LE 音频配置文件:
- 使用 HCI_LE_Setup_ISO_Data_Path 命令建立 ISO 数据路径
- 如果 IHV ACX 流驱动程序设置属性BluetoothLEAudio_CodecCapabilities,则HCI_LE_Setup_ISO_Data_Path中Codec_ID字段的值应设置为在蓝牙分配号码中定义的透明(0x3)。 否则,该值应与流创建过程中配置编解码器作中使用的编解码器 ID 相同。
- 使用 HCI_LE_Setup_ISO_Data_Path 命令建立 ISO 数据路径
- 如果音频流是捕获流,蓝牙 LE 音频配置文件将执行 BAP 接收器启动就绪作。
调用 其 EvtAcxStreamRun 回调时,IHV ACX 流式处理驱动程序将开始处理来自 Windows 音频系统(呈现)或蓝牙控制器(捕获)的传入音频数据。
暂停播放
调用 EvtAcxStreamPause 回调函数时,蓝牙 LE 音频配置文件:
- 执行 BAP 单播流禁用过程。
- 使用 HCI_LE_Remove_ISO_Data_Path 命令删除 ISO 数据路径。
- 如果音频流是单播捕获流,则执行 ASCS 接收器停止就绪程序。
- 如果没有用于该 CIS 的其他流,请断开连接 CIS。
调用 其 EvtAcxStreamPause 回调时,IHV ACX 流式处理驱动程序将暂停其音频处理管道。
发布流程
调用 其 EvtAcxStreamReleaseHardware 回调时,蓝牙 LE 音频配置文件:
- 将 ASCS 发布作发送到远程蓝牙 LE 音频设备
- 如果所有 CIS 断开连接,则删除 CIG。
调用其 EvtAcxStreamReleaseHardware回调时,IHV ACX 流式处理驱动程序会释放其音频管道资源。
终端断开连接
如果远程单播设备没有与电脑 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 中删除远程单播设备的配对或禁用蓝牙无线电时,可以删除配置文件线路。
- 当 Windows 蓝牙 LE 音频配置文件删除其线路时,ACX 会禁用其终结点接口,以向 Windows 音频服务发出信号,指出应删除该终结点。
- 当接口被禁用时,Windows 音频服务会将任何活动流失效到蓝牙 LE 音频终结点,此作会导致流暂停和释放回调,以在流式传输线路上调用。
- 若要完成端点移除,ACX 会使 IHV ACX 流媒体处理驱动程序的线路无效,这会导致 WDF 调用线路的清理回调。
- 调用其清理回调时,IHV ACX 流式处理驱动程序会释放其电路。
蓝牙 LE 和经典音频共存
Windows 应确保只有经典音频或 LE 音频对支持这两种技术的配对蓝牙音频设备处于活动状态。 如果 LE 音频处于活动状态,则禁用远程设备的 A2DP 和 HFP 的侧带 DDI,并且为 LE 音频终结点创建配置文件电路。 如果经典音频处于活动状态,则为远程设备的 A2DP 和 HFP 启用旁带 DDI,并且不会为 LE 音频端点创建配置文件电路。
电源管理
蓝牙 LE Audio 没有任何电源管理的要求或流程超出 WDF 已经定义的内容。
适用于语音方案的超宽带立体声
今天的蓝牙音频体验很方便,但有限制,尤其是与有线音频体验相比。 一个关键限制,具有面向用户的后果,是每当麦克风处于活动状态时下降到单声道音频。 这会阻止 Teams 和其他 VoIP 应用中的空间音频等体验工作,并且会严重降低涉及语音聊天的游戏体验。
蓝牙 LE 音频通过在麦克风正在使用时添加对立体声播放的支持来缩小音频保真度和降低延迟的差距。
呈现/捕获格式对
IHV 解决方案通过提供呈现/捕获格式对的列表来播发对立体声呈现的支持,每个呈现/捕获格式对都由立体声呈现格式和单声道捕获格式组成,可用于双向流式处理。 立体声呈现(或单声道捕获)格式定义为一对Sampling_Frequency(例如,16/24/32/48 kHz)和与特定音频编解码器关联的Audio_Channel_Count(例如 1/2 ch),这不限于 LC3。
例如,假设 IHV 解决方案支持具有 16kHz 单声道捕获的 16kHz 立体声渲染,以及具有 24kHz 或 32kHz 单声道捕获的 48kHz 立体声呈现。 相应的呈现/捕获格式对如下所示:
| 项 | 呈现格式 | 捕获格式 |
|---|---|---|
| 1 | Render(16 kHz,2 ch) | 捕获(16 kHz,1 ch) |
| 2 | Render(48 kHz,2 ch) | 捕获(24 kHz,1 ch) |
| 3 | Render(48 kHz,2 ch) | 捕获(32 kHz,1 ch) |
表 3:示例呈现/捕获格式对
由于协调集成员可以随时联接或取消加入,因此 IHV 解决方案必须支持采用格式对中每个条目的相同采样频率使用 mono 捕获的单声道呈现。 这意味着,鉴于表 3 中的示例,下面的所有格式对也必须隐式支持,即使它们未显式声明:
| 项 | 呈现格式 | 捕获格式 |
|---|---|---|
| 1 | Render(16 kHz、1 ch) | 捕获(16 kHz,1 ch) |
| 2 | Render(48 kHz,1 ch) | 捕获(24 kHz,1 ch) |
| 3 | Render(48 kHz,1 ch) | 捕获(32 kHz,1 ch) |
表 4:表 3 的隐式呈现/捕获格式对
表 3 和表 4 之间的主要区别是,后者中每个呈现格式的Audio_Channel_Count设置为 1(对于“mono render”):其他一切都保持不变。
强制呈现/捕获格式对
表 5 定义所有 IHV 解决方案应支持的音频格式列表:
| 项 | (Render_format、Capture_format) |
|---|---|
| 1 | { Render(48 kHz, 2 ch), Capture(32 kHz,1 ch) } |
| 2 | { Render(32 kHz, 2 ch), Capture(32 kHz,1 ch) } |
| 3 | { Render(24 kHz, 2 ch), Capture(24 kHz,1 ch) } |
| 4 | { Render(16 kHz, 2 ch), Capture(16 kHz,1 ch) } |
表 5 强制呈现/捕获格式对
功能播发
根据蓝牙控制器是否支持涉及的音频编解码器(默认为 LC3),IHV 解决方案以不同的方式播发它支持的呈现/捕获格式对列表。 具体而言:
如果编解码器位于蓝牙控制器中,则控制器和 IHV ACX 流式处理驱动程序应单独播发格式对列表。 如果两个列表相互分歧,Windows 应相交并保留共同部分。
如果编解码器不在蓝牙控制器中(例如,它位于音频 DSP 中),则只需要 IHV ACX 流式处理驱动程序来播发格式对列表。 蓝牙控制器
由于HCI_Read_Local_Supported_Codec_Capabilities的响应中的 Codec_Capability[i] 不支持元数据,因此需要蓝牙控制器来支持一系列特定于Microsoft编解码器 ID(请参阅表 7),以便 Windows 可以查询更多编解码器功能,例如,呈现/捕获格式对列表,这无法通过现有 HCI 接口轻松传达。
| 参数 | 大小 (八进制数) | Description |
|---|---|---|
| Codec_ID | 5 |
Octet 0: 0xFF(特定于供应商) 十进制 1 到 2: 0x0006 (Microsoft) Octet 3 到 4: 供应商定义的编解码器 ID 如果八进制 4 的最有效位设置为零(0),则八进制 3 包含 SIG 批准的编码格式(从 2024 年 5 月 31 日0x00到 0x07),但0xFF除外。 如果八进制 4 的最重要位设置为一(1),则八进制 3 包含尚未定义的编码格式,并由 Windows 保留以供将来使用。 |
表 7 Microsoft特定的编解码器 ID
这些特定于Microsoft编解码器 ID 的范围仅限于:
- HCI_Read_Local_Supported_Codecs [v2]
- HCI_读取本地支持的编解码器能力
根据协定,Windows 不得对其他类型的 HCI 命令使用这些Microsoft特定编解码器 ID 中的任何一个。
HCI_Read_Local_Supported_Codecs [v2]
控制器应通过Vendor_Specific_Codec_ID和Vendor_Specific_Codec_Transport播发对Microsoft特定编解码器 ID 的支持:
| 领域 | Description |
|---|---|
| Vendor_Specific_Codec_ID[k] |
八进制数 0 到 1: 公司 ID (0x0006) 有关详细信息,请参阅表 7 中的 Octet 1 到 2 。 八进制数 2 到 3: 供应商定义的编解码器 ID(例如,LC3 的0x0006) 有关详细信息,请参阅表 7 中的 Octet 3 到 4 。 |
| Vendor_Specific_Codec_Transport[k] | 必须支持LE_CIS(0x02)。 |
表 8 HCI_Read_Local_Supported_Codec [v2] 响应值
HCI_读取本地支持的编解码器能力
若要查询所有特定于 Windows 的编解码器功能(包括呈现/捕获格式对列表),Windows 调用HCI_Read_Local_Supported_Codec_Capabilities并具有以下参数:
| 参数 | 大小 (八进制数) | Description |
|---|---|---|
| Codec_ID(特定于Microsoft编解码器 ID) | 5 |
Octet 0: 0xFF(特定于供应商) Octet 1 到 2: 公司 ID (0x0006) 有关详细信息,请参阅表 8 中的 Octet 1 到 2 。 Octet 3 到 4: 供应商定义的编解码器 ID(例如,LC3 的0x0006) 有关详细信息,请参阅表 8 中的 Octet 3 到 4 。 |
| Logical_Transport_Type | 1 | 0x2(LE CIS) |
| 方向 | 1 | 0x00(输入,例如主机到控制器) |
表 9 HCI_Read_Local_Supported_Codec_Capabilities命令参数
收到此类命令后,控制器应返回供应商定义的编解码器 ID 指定的编解码器的所有特定于 Windows 的功能。 例如,如果供应商定义的编解码器 ID 设置为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 通道呈现,其中 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 | i + 1 |
位 0: 16 kHz 位 1: 24 kHz 位 2: 32 kHz 位 3: 48 kHz 位 4: RFU 位 5: RFU 位 6: RFU 位 7: RFU |
此列表中的所有采样频率都与由位 5-7 Channel_Count指定的通道计数相同。 每个Capture_Sampling_Frequencies_List实例的大小为一个八进制,最多可以有八个这样的实例(如果Render_Sampling_Frequencies中的所有位都设置为一个)。 所有 RFU 位都是保留的,必须设置为零。 |
表 11 Bidirectional_Multichannel_Streaming 格式(最大长度:11 字节)
Channel_Counts
呈现/捕获的位计数的选择是任意的 - 为呈现分配五位(用于覆盖所有 SIG 定义的音频位置),以及三位用于捕获(以最小化 HCI 有效负载大小)。
例如,表 3 的 Channel_Counts 为 0b0000'0001,因为呈现/捕获通道的数量(例如 m 和 n)分别为 2 和 1:
| 捕获 | Render | |
|---|---|---|
| 位 | 7 6 5 | 4 3 2 1 0 |
| 价值 | 0 0 0 | 0 0 0 0 1 |
表 12 表 3 的Channel_Counts
根据设计,具有同一对Microsoft特定编解码器 ID 和 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 Render_Sampling_Frequencies表 3
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_-Hzies[i] | Description |
|---|---|---|---|
| 0b0000'1001 ⇤ order ↤ |
0 | 0b0000'0001 |
Render_Sampling_Frequencies中的第一个最小有效“一”位(位 0)对应于 16 kHz。 启用 位 0 Capture_Sampling_Frequencies_List[0] 以指示 16 kHz 捕获可与该呈现频率配对。 |
| 0b0000'1 001 ⇤ order ↤ |
1 | 0b0000'0110 |
Render_Sampling_Frequencies中的第二个最小有效“一”位(位 3)对应于 48 kHz。 启用位 1 和 2 Capture_Sampling_Frequencies_List [1] 以指示 24 kHz 和 32 kHz 捕获可与该呈现频率配对。 |
表 14 用于为Render_Sampling_Frequencies生成 Capture_Sampling_Frequencies_List[i] 的示例
IHV ACX 流式处理驱动程序
为了支持单声道捕获的立体声呈现,IHV ACX 流驱动程序将设备属性 BluetoothLEAudioBidirectionalMultichannelStreamingCapabilities(表示 3.11.2 中所述的呈现/捕获格式对)设置为设备接口类的实例,GUID_BLUETOOTH_LEAUDIO_SUPPORT_INTERFACE。
创建设备接口类实例后,应立即提供该属性,并且该属性的值在设备接口类实例的整个生存期内保持不变。
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 的第一个最小有效位与 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;
}