LE Audio Profile (BAP)
概述
LE Audio整体框图如下,对于BlueZ协议栈来说主要是实现了Generic Audio Framework层的profile,本章节主要针对BAP介绍CIS和BIS的相关service。 BlueZ协议栈的介绍可以参考Linux蓝牙框架(三) - BlueZ协议栈 链接。

从上图可知除了BAP,还有其他Profile,例如MCP(Media Control Profile), CCP(Call Control Profile), CSIP (Coordinated Set Identification Profile), MICP(Microphone Control Profile), VCP(Volume Control Profile),本章节的主要介绍BAP以及BAP下的基础service(PACS/ASCS/BASS);
BAP SPEC中定义了如下角色,下面的章节将针对Unicast和Broadcast分别介绍.
| Role | Sub Role | Description |
|---|---|---|
| Unicast | Unicast Server | 发送广播 声明支持的audio capabilities 声明ASEs(Audio Stream Endpoint) 通知当前音频流的可用性状态 接受/拒绝CIS建立请求,结束CIS连接音频服务 |
| Unicast Client | 扫描广播,发起LE连接 发现和配置Unicast Server 声明的服务以及音频流能力/状态 发起和结束CIG/CIS连接 |
|
| Broadcast | Broadcast Source | 配置BIG/BIS,并声明公共音频配置信息(PAC) 发送音频流数据 |
| Broadcast Sink | 发现Broadcast Source的音频配置信息 接收Audio stream数据 声明音频能力 (用于Assistant配置) |
|
| Broadcast Assistant | 发现Broadcast Sink的音频能力 发现Broadcast Source设备和Audio stream 配置 将Broadcast Source设备相关信息配置到Broadcast Sink设备上 接收Broadcast Sink设备的音频流状态变化 |
|
| Scan Delegator | 协助扫描Broadcast Source设备 获取加密Broadcast Code |
BlueZ软件框图

BAP in BlueZ
BAP在BlueZ中分为两个部分src/shared/bap.c和profiles/audio/bap.c,这两部分在BlueZ框架中有明确的功能划分
BAP核心逻辑和底层行为 (src/shared/bap.c),主要功能如下:
- 定义 BAP 的核心数据结构
- 定义 BAP Stream、Endpoint、Codec、QoS 等结构体。例如:struct bt_bap_stream; struct bt_bap_qos; struct bt_bap_endpoint;
- 这些对象与 ASCS/GATT 紧密绑定
- 处理 GATT 层交互
- 实现 BAP 在 GATT 层的发现、配置、通知逻辑。包括:
- 发现 ASE(Audio Stream Endpoint)
- 设置 Codec Configuration
- 配置 QoS
- 启用 / 禁用 Stream
- 实现 BAP 在 GATT 层的发现、配置、通知逻辑。包括:
- 抽象 BAP Stream 生命周期管理
- BAP 是 ASCS 的上层逻辑封装,负责把多个 ASE 组织为一个 stream。
提供接口bt_bap_stream_config()bt_bap_stream_qos()bt_bap_stream_enable()bt_bap_stream_start()bt_bap_stream_disable()bt_bap_stream_stop()bt_bap_stream_metadata()bt_bap_stream_release()
- BAP 是 ASCS 的上层逻辑封装,负责把多个 ASE 组织为一个 stream。
- 维护本地与远端 ASE 的状态同步
- 当手机端发起操作(如 enable),shared 层更新 stream 状态并通过回调通知上层。
- 不暴露 D-Bus 接口,它是纯逻辑层,不直接面向应用层。
BAP Profile 逻辑与 D-Bus 集成层 (profiles/audio/bap.c),该文件是真正注册为 BlueZ “BAP Profile” 的实现部分,它负责把 shared/bap.c 的底层协议封装成可被外部系统控制的 DBus 接口。
主要功能:
- 注册 BAP Profile
- 调用 BlueZ Profile 注册框架(audio_register_profile())。
- 初始化并管理多个 BAP 实例(unicast client/server)。
- 例如:static struct bap_data *bap_register(struct btd_adapter *adapter, bool unicast);
- 创建和管理 D-Bus 对象
- 把每个 transport、endpoint 映射成 D-Bus 对象(例如object path /MediaEndpointLE/BAPSink/lc3)。
- 例如暴露Endpoint的方法SetConfiguration,这些方法由 PipeWire 或 Android Audio Service 调用。
- 调用 shared 层 API
- 当上层通过 D-Bus 发起命令时(例如配置一个新的 stream),profiles/audio/bap.c 会调用 shared 层接口来执行,例如:bap_config() -> bt_bap_stream_config()
- 转发底层事件到 D-Bus,当 shared 层(src/shared/bap.c)报告状态变化(如 stream started),它会通过回调反向通知 D-Bus。
- 管理多角色
- Profile 层同时支持:
- BAP Client (Unicast Client):例如手机;
- BAP Server (Unicast Server):例如耳机。
- Profile 层同时支持:
BAP Role
Unicast Audio
Unicast Audio是基于LE ACL Link,并且Client和Server之间在建立CIS连接前还需要进行Audio Capability交互和配置,例如Codec的参数匹配,ASE(Audio Stream Endpoint)发现和配置等,这部分主要涉及:
PACS = “我能干什么”
ASCS = “我现在要干什么”
PACS Service (UUID: 0x1850)
PACS service SPEC定义了如下特征值:
| Characteristic 名称 | UUID | 功能说明 |
|---|---|---|
| Sink PAC | 0x2BC9 | 设备作为接收端(Sink)时支持的编解码能力 |
| Source PAC | 0x2BCA | 设备作为发送端(Source)时支持的编解码能力 |
| Sink Audio Locations | 0x2BCE | 音频输出位置(左耳、右耳、前置等) |
| Source Audio Locations | 0x2BCF | 音频输入位置(麦克风位置等) |
| Available Audio Contexts | 0x2BD0 | 当前设备支持哪些音频场景(媒体、通话、紧急等) |
| Supported Audio Contexts | 0x2BD1 | 所有可支持的音频场景(上限) |
主要功能是让一个设备向远端公开它的 音频能力信息(Audio Capabilities),包括:
- 支持哪些音频方向(输入/输出);
- 支持哪些编解码器(Codec);
- 每个编解码器支持的采样率、声道、比特率;
- 支持的音频位置(左耳、右耳、前置、后置等);
HCI 实例
从系统框图中可以看到,pipewire主要作用是Audio的处理和路由,所以也承担了对Audio的相关参数配置,以上参数的配置流程如下:
1 | sequenceDiagram |
Pipewire在loading bluez插件后,会先读取bluez的配置文件(/etc/wireplumber/wireplumber.conf.d/bluetooth.conf), 并根据role加载对应的Endpoint, 如下表所示
| BlueZ Role | Endpoint Path |
|---|---|
| a2dp_sink | /MediaEndpoint/A2DPSink/sbc |
| bap_sink | /MediaEndpointLE/BAPSink/lc3 |
| bap_source | /MediaEndpointLE/BAPSource/lc3 |
| bap_bcast_sink | /MediaEndpointLE/BAPBroadcastSink/lc3 |
| bap_bcast_source | /MediaEndpointLE/BAPBroadcastSource/lc3 |
并且上面ATT交互中关于PACS中的sink pac特征值的参数如下表所配置,需要注意的是当前Pipewire还不支持PAC定义的全部内容,例如Metadata的解析,Locations和Audio Context的配置解析等。
1 | ... |
ASCS Service (UUID: 0x184E)
ASCS SPEC 定义了如下特征值:
| Characteristic 名称 | UUID | 功能说明 |
|---|---|---|
| ASE Control Point | 0x2BC6 | 客户端用于发送控制命令(例如配置、启用、禁用、释放等) |
| Sink ASE | 0x2BC4 | 表示服务端支持的一个音频接收端点(Audio Sink) |
| Source ASE | 0x2BC5 | 表示服务端支持的一个音频发送端点(Audio Source) |
主要功能:
- 如何建立、配置、启用和停用 Audio Stream(即 ASE, Audio Stream Endpoint)
- 如何在 Unicast Audio Server(通常是耳机)与 Unicast Audio Client(通常是手机或主机)之间协调音频流传输。
HCI 示例

下面是CIS source(Android phone) 与CIS sink (BA401 Board)建立和断开CIS link时ASCS service的交互图
1 | sequenceDiagram |
Broadcast Audio
Broadcast Source
Broadcast Source主要维护下面三层广播数据,并且Sink端通过对这些广播的解析和同步就可以收听到source端广播的音频数据。

| 层级 | 类型 | 数据类型 | 主要内容 | 描述 |
|---|---|---|---|---|
| 第一层 | EA (Extended Advertising) | ADV_EXT_IND AUX_ADV_IND AUX_CHAIN_IND |
Broadcast ID、Announcement 数据 | 让设备被发现 |
| 第二层 | PA (Periodic Advertising) | AUX_SYNC_IND | BASE、BIG Info | PA 是 Auracast 广播的“控制层”,负责告诉接收方如何同步 BIS、如何解码音频。 |
| 第三层 | BIS (Broadcast Isochronous Stream) | BIS | LC3 音频帧 | 真正的音频数据流传输 |
注释:
- AdvA: 广播设备地址(Advertiser Address)
- ADI: Advertising Data Info(包括 SID)
- SyncInfo:如果设备开启了周期性广播(PA),这里会嵌入 PA 的同步信息;
- ACAD:Advertising Common Additional Data,其中可以嵌入 BIGInfo(BIG 参数信息);
- BASE:Broadcast Audio Stream Endpoint 信息,描述音频的格式、采样率、声道配置等;
- AuxPtr:如果数据太多,会通过链式结构扩展(AUX_CHAIN_IND)。
Broadcast Audio Announcements
Broadcast source在Extend ADV中申明UUID:0x1852,另外Broadcast_ID 在BIG的声明周期中存在并具有唯一性,其左右是让Sink设备识别和确定指向感兴趣 BIG 的广播集。
下面是HCI示例:
Basic Audio Announcements
下图是BAP SPEC中定义的BIS source Codec配置和Metadata配置。
当前Pipewire (V1.4.5)不支持subgroup的配置,所以只能设置1个BIG下多个BIS的情况,下面是示例按照AC14 (1路bises包含2通道数据)的格式设置的BIS source pac,其参数对应的PA ADV中的BASE。
1 | ... |
HCI 示例
Broadcast Source Stream States
1 | stateDiagram-v2 |
Broadcast Sink With Assistant (BASS UUID: 0x184F)
BASS SPEC定了如下特征值。
| Characteristic 名称 | UUID | 功能说明 |
|---|---|---|
| Broadcast Receive State | 0x2BC9 | 表示当前设备已知的广播源及其状态(最多多个实例) |
| Broadcast Audio Scan Control Point (BASS CP) | 0x2BC7 | 控制操作入口,用于添加/删除/修改广播源或触发扫描 |
主要功能:
- BASS Client = Assistant(通常是手机/控制器)
- 手机作为 Assistant,负责扫描广播源(BIS Source)信息、决定哪个广播要接收、并通过 BASS Control Point 下发“加入某个广播源”的配置给 sink 设备(音箱/耳机的 sink 端)。
- BASS Server = Broadcast Sink 设备(例如音箱 / earbud sink)
-Sink 设备在本地实现 BASS 服务,接收 Assistant 的命令后去执行 PA sync / BIG sync,并把同步状态回报给 Assistant(通过 Broadcast Receive State 通知)。 - BASS CP(Control Point)支持的opcode,Client->Server
- Add Source:把一个 source 条目写入 sink(包含 adv SID、broadcast_id、bis list、scan params)
- Remove Source:删除 source 条目
- Modify Source:修改已添加的 source(例如更换 BIS 列表)
- Remote Scan Start/Stop:指示 sink 开/关扫描(辅助寻找 source)
- Set Broadcast Code:提供解密 key(若广播加密)
- 状态反馈, Server->Client
-Sink 用 Broadcast Receive State characteristic(read/notify)来上报每个 source 的状态(PA sync、BIG sync、NUM_BIS、BIS索引、是否加密、同步失败原因等)。Assistant 根据这些通知判断是否成功加入或需要重试/提示用户。
Assistant和BIS sink设备的交互流程
1 | sequenceDiagram |
BlueZ 中BASS 代码
BASS相关的代码主要实现在下面文件中:
src/shared/bass.c 该文件属于共享库层(shared library layer),主要定义了 BASS 协议的通用解析、编码和GATT操作逻辑(handlers),既可供 client 也可供 server 使用。
profiles/audio/bass.c 该文件属于 Profile层(蓝牙应用服务层),它构建在 src/shared/bass.c 之上,实现 BASS 作为一个完整的 BlueZ Profile,并通过 D-Bus 提供给上层系统(如PipeWire、PulseAudio或Android HAL)使用。
下面是BASS定义的操作码的处理函数
1 | struct bass_op_handler { |
Broadcast Sink With Scan Delegator
该组合是设备自己扫描附近的BIS source设备,然后根据一些策略来选择BIS source设备进行Sync,所以流程相对比较简单,比较重要的两个流程就是short PA和BIG sync,下面是流程图。
1 | sequenceDiagram |
Short PA的BlueZ代码
当扫描到包含UUID=0x1852的设备时会自动probe bap_bcast_profile 即调用bap_bcast_probe接口,然后在pa sync成功的回调函数big_info_report_cb中关闭对应的socket,在kernel中就会发起terminal PA的流程。
1 | // profiles/audio/bap.c |
Formal PA Sync and BIG Sync,当bt_mgr 选择了目标BIS source设备,即调用transport.Select以及transport.Acquire方法,接下来transport状态会被设置会Enabling,调用**bap_state_bcast_sink() ->setup_create_bcast_io() **
1 | // profiles/audio/transport.c |
下面是bluetoothd.log中PA sync和BIG sync部分的内容,可以很直观的看到大概的调用流程
1 | bluetoothd[2490]: [:1.3:method_call] > org.bluez.MediaTransport1.Acquire [#35] |




