LE Audio 协议栈
总体设计
LE Audio 协议栈的总体设计是尽可能贴近规范实现,既包括结构也包括命名。大多数 API 函数都以规范缩写作为前缀(例如,基本音频配置文件(BAP)的 bt_bap 和音量控制配置文件(VCP)的 bt_vcp)。在适用时,函数还会进一步加上各配置文件的具体角色前缀(例如 bt_bap_unicast_client_discover() 和 bt_vcp_vol_rend_set_vol())。通常,配置文件或服务规范定义的每个过程对应一个函数,另有不对应于过程的辅助函数或元函数。
文件结构通常也遵循这一方式:与 BAP 相关的文件以 bap 为前缀,与 VCP 相关的文件以 vcp 为前缀。如果文件特定于某个配置文件角色,文件名中也会包含该角色。
通用音频框架(GAF)
通用音频框架(GAF)被视为 Bluetooth LE Audio 架构的中间件。GAF 包含的配置文件和服务使上层应用和配置文件能够建立流、更改音量、控制媒体与电话等。GAF 构建在 GATT、GAP 和等时通道(ISO)之上。
GAF 使用 GAP 连接、广播并与其他设备同步。GAF 使用 GATT 配置流、将流与内容(例如媒体或电话)关联、控制音量等。GAF 使用 ISO 承载音频流本身,既可以是单播(已连接)音频流,也可以是广播(未连接)音频流。
GAF 强制使用 LC3 编解码器,但也支持其他编解码器。
顶层配置文件 TMAP 和 HAP 不属于 GAF,而是为如何使用 GAF 提供顶层要求。
GAF 和顶层配置文件已在 Zephyr 中按以下结构实现。
配置文件依赖关系
LE Audio 配置文件依赖其他配置文件和服务,如下表所示。在这些表中,“服务器”表示担任特定服务的 GATT 服务器角色,“客户端”表示担任该服务的 GATT 客户端角色。如果某个配置文件角色依赖另一个配置文件,而该配置文件又依赖某个服务,那么该依赖也会隐式适用于该配置文件。例如,如果 CAP 接受者使用 BAP 单播服务器角色,那么对 ASCS 服务器和 PACS 服务器的要求同样适用于 CAP 接受者。
流控制(BAP)的依赖关系如下表所示。
单播服务器 |
单播客户端 |
广播源端 |
广播接收端 |
扫描委托者 |
广播助手 |
|
|---|---|---|---|---|---|---|
BAP 扫描委托者 |
M |
|||||
ASCS 客户端 |
M |
|||||
ASCS 服务器 |
M |
|||||
PACS 客户端 |
M |
O |
||||
PACS 服务器 |
M |
M |
||||
BASS 客户端 |
M |
|||||
BASS 服务器 |
M |
注意:
如上表所示,广播源端角色不依赖其他 LE Audio 配置文件或服务。
内容控制(MCP 和 CCP)的依赖关系如下表所示。
媒体控制服务器 |
媒体控制客户端(MCC) |
|
|---|---|---|
GMCS 服务器 |
M |
|
GMCS 客户端 |
M |
|
MCS 服务器 |
O |
|
MCS 客户端 |
O |
|
OTS 服务器 |
O |
|
OTS 客户端 |
O |
呼叫控制服务器 |
呼叫控制客户端 |
|
|---|---|---|
GTBS 服务器 |
M |
|
GTBS 客户端 |
M |
|
TBS 服务器 |
M |
|
TBS 客户端 |
M |
渲染控制(MICP 和 VCP)的依赖关系如下表所示。
麦克风控制器 |
麦克风设备 |
|
|---|---|---|
MICS 服务器 |
M |
|
MICS 客户端 |
M |
|
AICS 服务器 |
O |
|
AICS 客户端 |
O |
音量渲染器 |
音量控制器 |
|
|---|---|---|
VCS 服务器 |
M |
|
VCS 客户端 |
M |
|
VOCS 服务器 |
O |
|
VOCS 客户端 |
O |
|
AICS 服务器 |
O |
|
AICS 客户端 |
O |
GAF 的最后一个元素是过渡与协调控制(CAP 和 CSIP),其依赖关系见下表。
备注:
C.1:至少支持 BAP 单播客户端或 BAP 广播源端之一
C.2:至少支持 BAP 单播服务器或 BAP 广播接收端之一
C.3:如果作为 BAP 广播接收端则为必需
C.4:如果作为 BAP 扫描委托者则为必需
C.5:如果作为 BAP 单播客户端则为必需
C.6:至少支持其中一种
C.7:如果是协调集合的一部分则为必需
C.8:如果指挥者发送 CAP 公告则为必需
集合成员 |
集合协调者 |
|
|---|---|---|
CSIS 服务器 |
M |
|
CSIS 客户端 |
M |
更高层配置文件(GMAP、HAP、PBP 和 TMAP)的依赖关系见下表。
备注:
C.1 如果 UGT 支持 UGT 接收端功能则为必需
C.2 如果 UGT 支持 UGT 源端功能则为可选
备注:
C.1 如果 HA 支持音量平衡功能,并且属于双耳助听器集合,则为必需
C.2 如果 HA 支持 BAP 音频源端角色则为必需
C.3 如果 HA 能够成为双耳助听器集合的一部分则为必需
C.4 如果配备电池
C.5 如果支持 CCP 呼叫控制服务器
公共广播源端 |
公共广播接收端 |
公共广播助手 |
|
|---|---|---|---|
CAP 发起者 |
M |
||
CAP 接受者 |
M |
||
CAP 指挥者 |
M |
||
BAP 广播助手 |
M |
备注:
C.1 如果 BAP 单播服务器作为音频接收端,则必须支持
Bluetooth 音频协议栈状态
下表显示了 Bluetooth 音频协议栈中各配置文件的当前状态和支持情况。
使用 Bluetooth 音频协议栈
若要使用 Bluetooth 音频协议栈中的任何配置文件(包括 GAF 之外的顶层配置文件),应启用 CONFIG_BT_AUDIO。该 Kconfig 选项允许启用 Bluetooth 音频协议栈中的各个配置文件。每个配置文件通常可单独启用,但启用更高层配置文件(例如 CAP、TMAP 和 HAP)通常需要同时启用某些低层配置文件。
不过,也可以创建仅使用例如流控制(仅使用 BAP)而不使用任何内容控制或渲染/采集控制配置文件的设备,反之亦然。不过,使用更高层配置文件通常能提供更好的用户体验以及与其他设备更好的互操作性。
通用音频配置文件(CAP)
通用音频配置文件对低层配置文件施加限制和要求。CAP 中的过程可作用于一个或多个设备的一个或多个流。因此,可以通过 CAP 使用一次函数调用在多个设备上建立多个流。
下图展示了 CAP 中过程的完整结构及其与其他配置文件过程的对应关系。带有 I、A 和 C 的圆圈分别表示该过程是否有 CAP 发起者、CAP 接受者和 CAP 指挥者角色的主动参与或要求。
CAP 的 API 参考见 通用音频配置文件。
流控制(BAP)
流控制由基本音频配置文件实现。该配置文件定义了多个角色:
Unicast Client
Unicast Server
Broadcast Source
Broadcast Sink
Scan Delegator
Broadcast Assistant
每个角色均可单独启用,并且可以支持多个角色。
关于流控制服务的说明
基本音频配置文件主要使用 3 个服务来进行流控制。
音频流控制服务(ASCS)
ASCS 是一种专用于建立单播流的服务,位于 BAP 单播服务器设备上。该服务公开一个或多个端点,这些端点从单播服务器的角度看可以是接收端或源端。这意味着接收端端点始终表示音频从单播客户端流向单播服务器,而源端端点始终表示音频从单播服务器流向单播客户端。
与大多数其他 GATT 服务不同,ASCS 要求服务中的每个特征都为每个客户端提供唯一数据。这意味着,如果单播服务器连接到多个单播客户端,则这些客户端无法看到或控制其他客户端配置的端点。例如,如果某人的智能手机正在向耳机传输音频,那么同一个人无法通过其智能手表看到或控制该流。
广播音频扫描服务(BASS)
BASS 是扫描委托者和广播助手专用的服务。该服务的主要目的是将扫描任务从低功耗外设卸载到例如手机和 PC。与要求每个客户端数据唯一的 ASCS 不同,BASS 中的数据(称为接收状态)通常在所有已连接客户端之间共享。这意味着用户可以通过手机让自己的耳机同步到某个广播源端,之后再通过智能手表让耳机停止同步。
广播助手可以是任何设备,并且可以只支持这一个角色而不具备任何音频能力。这使得不支持周期性广播或等时通道的旧设备仍然能够提供接口,并为外设卸载扫描。Bluetooth SIG 提供了一份指南,说明如何开发此类旧式广播助手,可在 https://www.bluetooth.com/bluetooth-resources/developing-auracast-receivers-with-an-assistant-application-for-legacy-smartphones/ 找到。关于该指南的一个重要说明是,许多操作系统(尤其是手机上的操作系统)不允许通用地使用 BASS UUID,这实际上使实现自己的广播助手变得不可能,因为无法访问 BASS。
已发布音频能力服务(PACS)
PACS 用于以已发布音频能力(PAC)记录公开设备的音频能力。几乎所有角色都会使用 PACS,其中单播客户端和广播助手充当 PACS 客户端,单播服务器和广播接收端充当 PACS 服务器。这些记录包含编解码器信息以及每个编解码器支持哪些值。LC3 编解码器的值由 Bluetooth 分配编号(https://www.bluetooth.com/specifications/assigned-numbers/)定义,而其他编解码器(例如 SBC)的值在 BAP 中未定义或由实现决定。
PACS 通常也在各已连接客户端之间共享相同数据,但通过使用 bt_pacs_conn_set_available_contexts_for_conn() 之类的函数,可以为特定客户端设置特定值。
流控制的 API 参考见 Bluetooth 音频。
渲染与采集控制
渲染与采集控制由音量控制配置文件(VCP)和麦克风控制配置文件(MICP)实现。
VCP 实现支持以下角色:
音量控制服务(VCS)服务器
音量控制服务(VCS)客户端
MICP 实现支持以下角色:
麦克风控制配置文件(MICP)麦克风设备(服务器)
麦克风控制配置文件(MICP)麦克风控制器(客户端)
音量控制的 API 参考见 Bluetooth 音量控制。
麦克风控制的 API 参考见 Bluetooth 麦克风控制。
内容控制
内容控制由呼叫控制配置文件(CCP)和媒体控制配置文件(MCP)实现。
Zephyr 目前尚未实现 CCP。
MCP 实现支持以下角色:
通过媒体代理模块实现的媒体控制服务(MCS)服务器
媒体控制客户端(MCC)
媒体控制的 API 参考见 Bluetooth 媒体控制。
通用 TBS 与通用 MCS
CCP 使用的电话承载服务(TBS)和 MCP 使用的媒体控制服务(MCS)都有通用实例的概念,分别称为通用 TBS(GTBS)和通用 MCS(GMCS)。
虽然这两者共享相同的前缀名称,但它们的行为可能大不相同。
通用 TBS
TBS 规范将 GTBS 定义为
GTBS 提供单一访问点,并将其内部电话承载的表示公开为单个电话承载。该服务以单一单元的形式提供设备的电话状态和控制,并使用单组特征。GTBS 的某个特征在任意时刻代表哪个电话承载由实现决定。规范没有规定如何将设备上各个 TBS 的特征映射到 GTBS 的同一特征。
例如,如果设备上有多个 TBS,并且每个 TBS 都有唯一的电话承载名称(例如 Name1 和 Name2),那么 GTBS 如何表示电话承载名称由实现决定。GTBS 适用于不需要访问或控制特定电话承载上所有可用信息的客户端。
这意味着一个 GTBS 实例代表一个或多个电话承载。电话承载可以是设备上任何能够处理(电话)呼叫的应用,例如智能手机上的默认电话应用,也可以是 Signal、Discord、Teams、Slack 等其他应用。
GTBS 可以是独立存在的(即设备只有 GTBS 实例而没有任何 TBS 实例),并且 GTBS 的行为在很大程度上由实现决定。在 Zephyr 中,GTBS 的实现包含一些通用信息,例如提供方名称被定义为“Generic TBS”,但 Zephyr 中 GTBS 实例的大部分信息被实现为其他承载数据的并集。例如,如果你有一个用于普通电话呼叫的承载和一个用于 Teams 的承载,并且两者都有活动呼叫,那么每个承载都会报告一个呼叫,但 GTBS 实例会报告 2 个呼叫,从而使简单的呼叫控制客户端能够通过单个承载控制所有呼叫。类似地,各承载支持的 URI 在 GTBS 中也会合并为并集,使用 GTBS 发起呼叫时,服务器会根据 URI 选择最合适的承载。例如,URI 为 tel 的呼叫会转到普通电话应用,而 URI 为 skype 的呼叫会转到 Teams 应用。
总之,Zephyr 中的 GTBS 实现是非通用电话承载的并集。
通用 MCS
MCS 规范将 GMCS 定义为
GMCS 以单一单元的形式提供设备媒体播放的状态和控制。MCS 实例描述并控制设备内特定媒体播放器的媒体播放。设备实现 MCS 实例,以便客户端访问各个内部媒体播放器实体。
并且 GMCS 的行为定义为
……MCS 和 GMCS 的行为完全相同,所有特征及其行为也相同。文档通篇使用术语“MCS”。除非本规范另有明确说明,否则同一含义也适用于 GMCS。
这意味着 GMCS 实例的工作方式与 MCS 实例相同,因此 GMCS
控制设备内特定媒体播放器的媒体播放
设备上的媒体播放器可以是任何播放媒体的应用,例如智能手机上的 Spotify 或 Youtube 应用。因此,如果设备有多个 MCS 实例,则每个实例控制该特定应用的媒体,而 GMCS 也控制特定媒体播放器的媒体播放。因此,GMCS 可以视为指向特定 MCS 实例的指针,可以控制例如 Spotify 或 Youtube,但不能同时控制两者。
不过,MCS 规范提供了一个 GMCS 示例,其中设备可以
实现一个 GMCS,以提供整个设备的媒体播放状态和控制。
这可能表明,实现可以使用 GMCS 来表示所有媒体播放器,而不是如上所述表示特定媒体播放器。在设备没有任何 MCS 实例而只有 GMCS 的情况下,GMCS 将指向一个通用实例。
Zephyr 的 MCS 和 GMCS 实现并不完整,目前仅支持实例化单个实例,该实例可以是 MCS 或 GMCS。这意味着该实现既不完整也不符合规范。
GTBS 与 GMCS 的区别
如上所述,GTBS 和 GMCS 的定义与实现明显不同。GTBS 作为其他 TBS 实例(如果有)之间的并集工作,而 GMCS 作为指向特定 MCS 实例(如果有)的指针工作。这实际上意味着简单的呼叫控制客户端只需使用 GTBS 就能控制所有呼叫,而媒体控制客户端仅使用 GMCS 时可能只能控制单个播放器。
协调集合
协调集合由协调集合标识配置文件(CSIP)实现。
CSIP 实现支持以下角色:
协调集合标识服务(CSIP)集合成员
协调集合标识服务(CSIP)集合协调者
媒体控制的 API 参考见 Bluetooth 协调集合。
规范正确性与数据位置
这些实现旨在尽可能确保符合规范。当规范提出带有 shall 之类的要求时,实现应尽力确保始终遵循该要求。根据具体语境,实现通过拒绝来自应用或远程设备的无效参数来保证这一点。
有些规范要求由于各种原因无法或不能由协议栈自身处理。协议栈无法处理某项要求的一个原因是,与该要求相关的数据完全由应用控制。广播数据就是一个例子:多个服务都要求广播什么内容以及何时广播,但广播状态和数据都完全由应用控制。
相反,规范中也有一些要求,其相关数据完全由协议栈控制。音量控制服务(VCS)状态就是一个例子:规范强制要求 VCP 音量渲染器(VCS 服务器)在例如设置绝对音量时只能修改这些值,别无选择。在这种情况下,应用只会通过回调收到变更通知,但不能拒绝请求(协议栈会拒绝任何无效请求)。
通常,当数据比较简单时(例如只占几个字节的 VCS 状态),数据由协议栈保存和控制,因为这样可以确保协议栈能够处理相关要求,从而更容易正确使用某个配置文件角色。当数据更复杂时(例如 PAC 记录),数据可能由应用保存,而协议栈只包含对它的引用。当数据非常特定于应用时(例如广播数据),数据由应用保存和控制。
作为经验法则,每个配置文件实现中回调的返回类型表明数据是由协议栈还是应用控制。例如,VCP 音量渲染器的所有回调返回类型都是 void,而 BAP 单播服务器回调的返回类型是 int,这表明应用不仅控制大量单播服务器数据,还可以拒绝请求。回调返回类型的选择通常取决于规范以及该角色在给定语境中的控制程度。
使用 LE Audio 时值得了解或考虑的事项
本节介绍在 Zephyr 中贡献或使用 LE Audio 时需要考虑的一些事项。本节描述的内容并非 Zephyr 特有,因为它们是由规范定义的。
安全要求
所有 LE Audio 服务都要求安全等级 2,但密钥必须为 128 位,并通过 OOB 方法或 LE Secure Connections 派生。核心规范没有定义在 GATT 中报告这一情况的方式,因为 ATT 没有针对缺少 OOB 方法或 LE Secure Connections 的特定错误码(不过有一种方式可以报告密钥长度错误)。
在 Zephyr 中,我们不会强制设备始终使用这些安全要求,因为使用 LE Audio 的设备也可能使用其他不要求此类安全的配置文件和服务。我们使用在 subsys/bluetooth/audio/audio.c 中实现的自定义安全检查来保护所有服务访问,其中所有 LE Audio 服务都必须使用内部 BT_AUDIO_CHRC 宏,以便进行正确的安全验证。
CSIS 中用于加密 SIRK 的 LTK 访问
协调集合标识服务(CSIS)可以加密 SIRK(集合标识解析密钥)。加密 SIRK 的过程需要将 LTK 作为加密密钥,而 LTK 通常不会暴露给 CSIS 等更高层实现。不过,这不会对安全性产生任何影响。
MTU 要求
基本音频配置文件(BAP)要求双方在非增强 ATT 承载上至少支持 64 的最小 ATT_MTU,或者至少支持一个增强 ATT 承载。该要求源于优先(有时是强制)使用 GATT Write Without Response,而在大多数情况下对 Write Long Characteristic Value 的支持是可选的。
如果 ASCS 设备支持大于最小 ATT_MTU 64 字节的值,则应通过将 CONFIG_BT_ATT_PREPARE_COUNT 设置为非零值来支持 Read long Characteristic Value。
LE Audio 资源
本节包含一些链接和资源参考,对 Zephyr 中 LE Audio 协议栈的贡献者、LE Audio 应用开发者或两者都有用。
Discord 上的 LE Audio 频道
Zephyr 有一个专门用于 LE Audio 开发的 Discord 频道,向所有人开放。可在此处找到:https://discordapp.com/channels/720317445772017664/1207326649591271434,或直接在 Discord 中搜索“bt-audio”。由于 #bt-audio 频道对所有人开放,我们无法在该频道讨论任何正在制定中的规范。需要 Bluetooth SIG 会员资格的讨论请前往位于 https://discordapp.com/channels/720317445772017664/869172014018097162 的 #bt-sig Discord 频道。
Zephyr 每周会议
任何既是 Bluetooth SIG 成员又是 Zephyr 成员的人都可以参加每周会议,我们在会上讨论并规划 Zephyr 中 LE Audio 的开发。您可以加入 https://lists.zephyrproject.org/g/Bluetooth-sig 上的 Bluetooth-sig 邮件列表来查找会议时间。
Github 项目
Zephyr 中的 LE Audio 有自己的 Github 项目,位于 https://github.com/orgs/zephyrproject-rtos/projects/26。该项目大部分是自动化的,LE Audio 贡献者几乎完全依赖自动化工作流来呈现开发状态。任何人都可以挑选任何未解决的 issue 并开展工作。如果您无法将 issue 分配给自己,请在 issue 中留言,或在 Discord 频道中求助。
LE Audio 的 Bluetooth SIG 勘误
LE Audio 有许多规范,其中一些仍在更新和制定中。要了解 LE Audio 规范勘误的概览,可以访问
通用音频(GA)勘误 https://bluetooth.atlassian.net/wiki/spaces/GA/pages/1634402349/GAWG+Errata+Lists
助听器(HA)勘误 https://bluetooth.atlassian.net/wiki/spaces/HA/pages/1634140216/HA+WG+Errata+List
音频、电话与汽车(ATA)勘误 https://bluetooth.atlassian.net/wiki/spaces/ATA/pages/1668481034/ATA+Errata+Lists
访问勘误需要 Bluetooth SIG 会员资格。
Bluetooth SIG 中负责 LE Audio 的工作组
Bluetooth SIG 中有 3 个与 LE Audio 相关的工作组:
通用音频(GA) https://www.bluetooth.org/groups/group.aspx?gId=665
音频、电话与汽车(ATA) https://www.bluetooth.org/groups/group.aspx?gId=659
加入这些工作组后,您还会收到各自邮件列表的电子邮件,其中会处理许多问题和讨论。这些工作组还定期召开每周会议,处理问题并制定规范。
访问 Bluetooth SIG 工作组需要 Bluetooth SIG 会员资格。
LE Audio 书籍
有一本关于 LE Audio 的免费电子书,位于 https://www.bluetooth.com/bluetooth-resources/le-audio-book/。该书于 2022 年 1 月发布,因此早于某些规范定稿,也早于规范的一些已发布更新。尽管如此,这本书仍然很好地解释了许多概念和思想,但技术信息请参阅各个规范。
Bluetooth SIG 信息文件、报告和指南
Bluetooth SIG 会不定期发布新的信息文件、报告和指南。这些资料可在 https://www.bluetooth.com/bluetooth-resources/?tags=le-audio&keyword 找到。在这里,您还可以找到前面提到的 LE Audio 书籍,以及许多其他优质资源。
示例
所有 LE Audio 示例都位于 samples/bluetooth/audio。