LE Audio BASS深度解析:Broadcast Receive State状态特征全流程拆解
广播接收状态(Broadcast Receive State)是BASS(广播音频扫描服务)的核心状态载体,它像一块智能仪表盘,实时展示设备与广播源的同步、解密、元数据等全流程信息。本文将基于BASS规范,从基础规则、字段解析、行为逻辑到开发避坑,层层拆解这一关键状态特征,帮助嵌入式开发者(尤其使用C++或Java实现蓝牙协议栈的工程师)快速掌握其设计精髓。
一、广播接收状态的基础规则:仪表盘的底层设计
Broadcast Receive State作为BASS服务器的核心状态特征,其设计遵循三项基础规则,确保设备间互联互通:
- 多实例要求:与仅能存在一个实例的控制点不同,状态特征在服务器上必须存在一个或多个实例,且推荐数量不小于设备能同时同步的BIG数量。例如,支持同步3个BIG的TWS耳机,应至少创建3个状态实例,每个实例唯一对应一个广播源,避免多源状态混乱。
- 属性与安全:属性强制为读+通知双模式,且必须加密传输。无任何可选属性,所有BASS服务器必须严格遵循。
- 三大行为规范:
空值规则:若未写入Source_ID,特征值必须为空(零长度);
实时通知规则:GATT连接中,任意字段变化必须立即推送;
重连通知规则:绑定客户端重连后,若状态非空,需立即推送当前值。
在LE Audio的广播音频接收体系中,BASS的两大核心特征构成了指令-状态的完整交互闭环:上一篇解析的Broadcast Audio Scan Control Point是客户端向服务器下发指令的中央指挥台,而本次要详解的Broadcast Receive State则是服务器向客户端实时暴露广播接收状态的智能仪表盘。如果说控制点是让服务器做什么的指令入口,状态特征就是让客户端看得到服务器执行结果的状态窗口,所有与广播源同步、加密解密相关的状态变化,都会实时体现在这个仪表盘上,是客户端感知广播接收过程、做出后续指令决策的核心依据。
二、全字段深度解析:仪表盘的每一个指示灯
状态特征由12个字段组成,按功能分为五大类。下面逐类解析,结合Python或TypeScript开发中常见的位操作和状态机设计,让抽象字段更直观。

2.1 广播源标识字段:设备铭牌
包含Source_ID、Source_Address_Type、Source_Address、Source_Adv_SID、Broadcast_ID五个固定长度字段,是广播源的唯一身份标识。其中Source_ID为1字节内部唯一标识(0x00-0xFF),是客户端后续操作的核心索引。其余四个字段来自广播包或客户端指令,服务器仅做透传存储。
字段名 | 长度(字节) | 核心作用 | 通俗比喻 |
Source_ID | 1 | 服务器为广播源分配的唯一内部标识 | 广播源的“服务器内部工号” |
Source_Address_Type | 1 | 广播源的设备地址类型 | 广播源地址的“类型标签” |
Source_Address | 6 | 广播源的蓝牙设备地址 | 广播源的“物理地址” |
Source_Adv_SID | 1 | 广播源的广播SID标识 | 广播源的“广播通道编号” |
Broadcast_ID | 3 | 广播源的全局唯一标识 | 广播源的“全球身份证号” |
必选属性:Read(读)+ Notify(通知),实现主动查询和实时推送的双重状态获取方式。客户端可通过Read操作主动查询当前广播接收状态,也可通过订阅Notify操作,让服务器在状态变化时主动推送最新状态,既保证了状态获取的灵活性,又能让客户端实时感知状态变化,无需频繁轮询,降低设备间的交互功耗。
安全权限:加密连接为硬性要求,所有的Read和Notify操作都必须在加密的GATT连接下进行。这是因为状态特征中包含广播源的唯一标识、加密状态等敏感信息,加密连接能避免这些信息被窃取或篡改,尤其是当广播源为加密状态时,状态特征的加密保护能防止第三方获取解密相关的状态信息,保证音频隐私。
唯一性:服务器上所有非空的状态特征实例,其Source_ID字段值必须唯一,不能重复,这是服务器区分不同广播源的核心依据;
写入触发:当服务器通过客户端的Add Source指令添加广播源,或自主同步到某个广播源时,必须为该广播源分配并写入唯一的Source_ID,无Source_ID则状态特征为空值。
Source_Address_Type:仅支持0x00(公有地址)和0x01(随机地址),其他取值为RFU(未来保留),写入时必须设为0;
Source_Address:6字节的蓝牙设备标准地址,与Source_Address_Type一一对应,若广播源的地址发生变化,服务器必须及时更新该字段值;
Source_Adv_SID:广播源的广播SID子字段,取值范围0x00-0x0F,其他取值为RFU,用于匹配广播源的广播包;
Broadcast_ID:3字节的全局唯一标识,由BAP规范定义,是跨设备识别广播源的核心依据,服务器可通过该字段匹配广播源的AUX_ADV_IND广播包。
2.2 PA同步状态字段:同步指示灯
PA_Sync_State(1字节)描述服务器与广播源PA的同步状态,包含5个有效取值:0x00(未同步)、0x01(SyncInfo请求)、0x02(已同步)、0x03(同步失败)、0x04(同步传输失败)。状态转换严格遵循:服务器仅能从0x01转为0x02或0x03;所有非0x02状态最终可转为0x00。
取值 | 状态含义 | 核心触发条件 |
0x00 | 未同步PA | 服务器未尝试同步/同步停止/同步丢失 |
0x01 | SyncInfo请求 | 服务器支持PAST,需要客户端传递PA同步信息 |
0x02 | 已同步PA | 服务器成功通过Periodic Advertising Synchronization Establishment流程同步PA |
0x03 | 同步PA失败 | 服务器尝试同步PA,但流程执行失败 |
0x04 | No PAST | 服务器请求SyncInfo后,未在规定时间内收到客户端的同步信息 |
未获取BIGInfo时的默认取值:若服务器未从PA中获取到BIGInfo,无法判断BIS是否加密,此时BIG_Encryption必须设为0x00/未加密,而非其他取值;
Bad_Code的固定值:当取值为0x03时,Bad_Code字段必须写入16字节的0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,不能为其他任何值,这是客户端识别密钥错误的统一标识。
2.3 加密状态字段:解密信号灯
包含BIG_Encryption和Bad_Code两个字段。BIG_Encryption有4个取值:0x00(未加密)、0x01(需要Broadcast_Code)、0x02(正在解密)、0x03(Bad_Code)。核心联动规则:服务器仅在PA同步成功(0x02)后才能检测加密状态;解密失败时,Bad_Code置1且BIG_Encryption设为0x03。
取值 | 状态含义 | 核心触发条件 | Bad_Code字段状态 |
0x00 | 未加密 | BIS为明文传输,或服务器未获取BIGInfo无法判断加密状态 | 空值(零长度) |
0x01 | 需要Broadcast_Code | 服务器检测到BIS加密,且无有效解密密钥 | 空值(零长度) |
0x02 | 正在解密 | 服务器获取到正确的Broadcast_Code,正在解密BIS | 空值(零长度) |
0x03 | Bad_Code | 服务器使用客户端传递的Broadcast_Code解密,结果失败 | 固定值0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
位图与BIS_index的对应:4字节共32位,Bit0-Bit30分别对应BIS_index1-BIS_index31,Bit31为保留位,设为0;位值为0b0表示未同步该BIS,0b1表示已同步该BIS;
特殊取值:若服务器尝试同步整个BIG但失败,该字段需设为0xFFFFFFFF,表示BIG同步失败,而非单个BIS同步失败;
同步触发规则:服务器仅能在成功同步PA(PA_Sync_State=0x02)后,根据客户端指令的BIS_Sync参数尝试同步BIS,且同一个BIS_index不能在多个子组中同时设为0b1;
状态更新规则:服务器同步BIS成功后,将对应位设为0b1;同步失败/丢失同步后,将对应位设为0b0;客户端下发Modify Source指令停止同步某BIS时,服务器立即将对应位设为0b0。
2.4 BIS同步状态字段:多流指示灯组
包含Num_Subgroups和BIS_Sync_State[i](4字节位图)。位图中每个bit对应一个BIS_index,0表示未同步,1表示已同步。若子组同步失败,整个字段设为0xFFFFFFFF。这种设计在Go或Java中可用位运算高效管理最多31个BIS通道。
长度匹配:Metadata[i]的实际长度必须与Metadata_Length[i]的取值一致,若Metadata_Length[i]=0x00,则Metadata[i]不存在;
格式要求:Metadata[i]必须遵循LTV格式,这是蓝牙协议中通用的元数据格式,保证了不同厂商设备之间的元数据解析兼容性;
写入灵活性:服务器可选择是否写入该字段,既可以从客户端的Add Source/Modify Source指令中解析元数据并写入,也可以在自主同步PA后,将自身获取的元数据写入,甚至可以添加BASE结构中没有的元数据信息。
2.5 元数据字段:附加信息屏
Metadata_Length[i]和Metadata[i]采用LTV格式,长度可为0。元数据通常包含音频采样率、声道数、设备名称等,虽非核心字段,但能提升客户端用户体验。
Add Source:服务器接受指令后,写入所有广播源标识字段,根据PA_Sync参数初始化PA_Sync_State,写入Num_Subgroups和BIS_Sync_State[i]的初始值,元数据字段按需写入;
Modify Source:服务器根据指令的Source_ID匹配对应的状态特征,更新PA_Sync_State、BIS_Sync_State[i]、元数据字段,其余标识字段保持不变;
Set Broadcast_Code:服务器根据指令的Source_ID匹配对应的状态特征,根据解密结果更新BIG_Encryption和Bad_Code字段;
Remove Source:服务器根据指令的Source_ID匹配对应的状态特征,清空所有字段,将状态特征恢复为空值。
三、核心行为逻辑:仪表盘的刷新与联动
字段写入有两种触发方式:客户端指令触发(如Add Source、Set Broadcast_Code)和服务器自主同步触发(如自主扫描到广播源后自动写入)。无论哪种方式,写入后必须立即触发通知。
核心字段间存在三条强联动规则:
- ⚠️ PA同步是BIS同步和加密检测的前提(PA未同步时,BIS同步和加密检测均禁止)。
- ⚠️ 加密密钥是解密BIS的前提(未获取正确Broadcast_Code时无法解码)。
- ⚠️ Source_ID是所有字段操作的核心索引(无Source_ID则状态为空)。
问题:Broadcast Receive State的实例数量要求是什么?为什么要做这样的设计?同时其必选属性和安全权限要求是什么?
问题:简述PA_Sync_State的所有有效取值及核心触发条件,其与BIS_Sync_State[i]的核心联动规则是什么?
四、状态特征与控制点的协同闭环
Broadcast Receive State与Broadcast Audio Scan Control Point形成双向协同闭环:客户端指令下发 → 服务器执行 → 状态特征更新 → 客户端状态感知 → 新指令下发。以手机代助听器接收加密电视广播为例:
- 手机下发Add Source指令,服务器写入广播源标识字段并通知。
- 服务器同步PA后,PA_Sync_State变为0x02,通知手机。
- 检测到加密后,BIG_Encryption设为0x01,手机收到后下发Set Broadcast_Code。
- 服务器解密成功,BIG_Encryption更新为0x02,通知手机。
- 同步BIS后,BIS_Sync_State位图更新,通知手机。

[AFFILIATE_SLOT_1]问题:Broadcast Receive State与Broadcast Audio Scan Control Point的核心协同逻辑是什么?以Add Source指令为例,简述二者的交互流程。
五、开发实战避坑要点
从规范到落地,以下细节必须注意:
- 严格小端序:多字节字段(如BIS_Sync_State[i]、Source_Address)必须按小端序传输。在C++或Java中,使用
ByteBuffer.order(ByteOrder.LITTLE_ENDIAN)确保正确解析。 - 位图边界处理:BIS_Sync_State[i]的4字节位图,Bit0对应BIS_index 1,Bit30对应BIS_index 31。使用Python的
format(value, '032b')或TypeScript的位运算进行调试。 - 空值状态维护:Source_ID未写入时,整个特征值必须为零长度,不可返回空字段或默认值。
- 通知频率控制:实时通知规则要求“立即推送”,但在高频率状态变化场景(如快速重连),需在固件层做去抖处理,避免GATT拥塞。
- 加密状态机实现:BIG_Encryption的状态转换必须与PA_Sync_State联动,使用Go的select或状态机库(如fsm)可简化实现。
六、总结
Broadcast Receive State是BASS广播接收流程的“状态仪表盘”,通过多实例设计、字段级状态机、强联动规则和实时通知机制,实现了对多广播源同步、解密、元数据的精细管理。掌握其12个字段的取值逻辑、三种写入触发方式、以及与控制点的协同闭环,是LE Audio嵌入式开发的关键。开发中务必注意小端序、位图边界、空值维护等细节,确保设备间互联互通。
浙公网安备 33010602011771号