ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于BT2106C的Auracast广播音频设计与实践

基于BT2106C的Auracast广播音频设计与实践 1. 内容整体设计与思路拆解1.1 这次项目要解决的问题是什么做蓝牙开发这么久我一直觉得“一对一连接”这件事限制了蓝牙的想象力。无论耳机、音箱还是助听器蓝牙音频走的基本都是经典蓝牙A2DP或者现在的LE Audio点对点连接。两个设备之间必须先握手、配对、建立连接然后才能传声音。这个链路稳定是稳定但在某些场景里真的不够用——比如一群人想同时听同一段广播比如观众席里想听同传翻译比如机场里想听某个登机口的最新通知靠点对点连接完全没戏。Auracast就是补上这个短板的方案。它是LE Audio里的广播音频技术核心是把音频流以广播的形式发出去周围任何支持Auracast的设备都可以“订阅”收听不需要配对不需要握手来多少设备就能服务多少设备。BT2106C就是一颗支持这套协议栈的蓝牙SoC模组我们要做的这块板子就是让音频信号通过模组转换成Auracast广播再用手机或耳机验证实际收听效果。这个项目适合谁看一个是正在做音频类硬件、想把广播音频加进来的嵌入式工程师另一个是想评估Auracast能不能落地到自己产品里的产品经理或技术负责人。我会把从模块选型、硬件设计、协议栈配置到实测踩坑的完整过程都过一遍很多细节是单看datasheet和SDK文档发现不了的。1.2 为什么选BT2106C而不是自研方案先说结论这个项目的时间窗口很紧张自研方案的第一版流片风险完全不可控所以直接选了模组方案。BT2106C这块模组的核心优势首先是协议栈完整度Auracast必须依赖LE Audio的同步广播链路也就是BISBroadcast Isochronous Stream模组SDK里已经把同步广播的收发链路封装好了省掉了从零啃协议栈的周期其次是射频性能PCBA上的天线匹配和生产一致性已经调好比自己做板子再花两周调天线要省心得多。模块党还有个隐藏好处在于认证。产品要做BQB认证和各类无线认证用模组可以直接继承模组厂做过的射频认证报告自己整板只需要关注产品层面的EMC和音频指标。这是很多团队第一次做蓝牙音频品类时容易忽略的成本项别小看这份报告它能省下好几万认证费和两三周整改时间。模块本身主要关注这几个维度就够了内核主频和Flash/RAM大小决定功能扩展空间是否内置音频Codec或者需要外挂以及SDK是否支持后续OTA升级。我这边因为要同时兼顾低功耗和后期算法迭代所以选了性能稍高一点的版本Flash留余量很重要后期想加个EQ、降噪算法都方便别把存储卡太死。2. 核心细节解析与实操要点2.1 硬件层容易被低估的三个地方第一是晶振精度。Auracast广播依赖接收设备在指定时间窗口内同步接收数据包如果发射端晶振漂移太厉害接收端同步就会断续甚至丢包。BLE音频相关模块一般要求32.768kHz的RTC晶振和32MHz的主晶振精度尽量做到±20ppm以内这个不能贪便宜普通晶振贴上去实测距离一拉开就掉同步很难排查。第二是射频周边。Wi-Fi/BLE共存的天线布局要提前想清楚BT2106C这类模组一般引出RF pin外接天线或者直接使用板载PCB天线。如果产品里还有4G模组或者WLAN模块注意分时控发以及天线隔离度否则互扰情况下Auracast广播会周期性丢失表现就是“滋滋啦啦”。第三是音频输入链路。我这块板子的输入源是Line In和板载驻极体麦克风两颗都进了一颗外置Audio CodecI2S接口再送给BT2106C编码广播。这个链路里最容易踩坑的是模拟地分割和Codec供电纹波Codec的模拟Vref如果贴着DCDC的开关噪声SNR会被吃掉好几个dB听感上就是底噪明显。第一次打板我把Codec供电直接挂在系统3.3V上底噪达到了难以接受的水平后来换成独立LDO再加磁珠隔离才把底噪压下去。硬件上还有一个好习惯预留Type-C接口的USB调试串口。Auracast开发过程中需要反复看协议栈日志没串口等于瞎调。我把UART和SWD都引到了Type-C座一根线供电、烧录、看日志全搞定开发效率提升非常明显。2.2 协议栈配置里最容易踩的坑Auracast的协议栈分层可以简单理解为一个“发广播”的外层广播加一个“传音频”的内层同步流。设备首先要周期性广播一组“音频广播的元数据”内容包括广播名、语言、音频参数等接收端比如手机扫描到之后才会去同步对应的BIS流。关键配置在于三个地方。第一个是广播与同步广播的数据包间隔。这个影响的是端到端延迟与抗干扰能力。间隔越大延迟越高但同时功耗越低、抗同频干扰能力也相对好。我们最后采用广播间隔100ms、BIS同步间隔10ms的配置延迟体感大约在100~200ms之间这个规格我认为是目前功耗、延迟、稳定性比较平衡的一组值。第二个是LC3编码器参数。Auracast广播音频统一用LC3编码我们用的是48kHz采样、单声道、80ms帧间隔、96kbps码率。这个码率在语音广播和音乐广播里都够用单声道也合理——耳机端本来就是双耳接收同一路广播没必要发双声道浪费带宽。如果想提升听感可以上128kbps但距离和抗干扰余量会小一点。第三个是广播元数据的规范命名。你不起一个规范的广播名和分类手机上的Auracast扫描界面很难把频道识别成“公开广播”还是“私人广播”。演示给别人看的时候一个乱码的广播名会显得很不专业。我建议把广播名设置成产品名加语言代码比如“Meeting Room CN”方便后续对接Auracast App等工具的过滤。2.3 用到的测试工具与整体环境调试阶段强烈建议准备三样东西一台支持LE Audio的Android手机Android 13以上、一台iPhoneiOS 17以上以及一台支持Auracast接收的TWS耳机。Android这边我用的nRF Connect做底层广播观测再加Auracast官方的Scratch app做订阅收听iPhone的Experience Auracast app也可以两者功能差异不大但Android能看到更多底层参数所以我主力用安卓调试。有人会问没有Auracast耳机怎么办其实不完全依赖耳机也能验证链路。先用能接收的耳机确认“广播音频依然可用”再用手机App确认“扫描并订阅Auracast广播”这两个能力基本能覆盖链路的主要节点。耳机端如果提示“广播暂时不可用”多半是接收端兼容性问题跟发射端链路不一定直接相关要独立排查。3. 实操过程与核心环节实现3.1 开发环境搭建与工程结构BT2106C的SDK是厂商基于Zephyr RTOS定制的编译工具链用west GNU Arm Embedded Toolchain。这个组合对于用惯了STM32裸机开发的人会有点陡峭但别慌本质上就是“配置设备树 写应用层回调”。我这边工程结构大致是这样board目录放板级设备树改I2S、GPIO、电源引脚audio目录放Codec驱动适配层broadcast目录放Auracast广播参数配置和应用回调。编译一次大约两分钟迭代效率完全能接受。烧录方式两种一种是用J-Link通过SWD直接烧另一种是生成量产固件后用串口OTA。OTA一定要在开发早期就接入否则每次改参数都得开壳接线会让人崩溃。3.2 广播配置核心代码思路下面是广播链路初始化的关键配置思路我注释了每个参数在实测中的表现影响大家可以根据自己场景改数值。代码只是示意简化版完整实现还是要看SDK里的broadcast_demo。/* 周期性广播参数决定接收端能否稳定发现广播 */ static const struct bt_le_adv_param adv_param { .id BT_ID_DEFAULT, .options BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_EXT_ADV, .interval_min 100, /* 广播间隔实测100ms比较稳 */ .interval_max 100, }; /* BIS同步流参数决定音频数据包发送节奏 */ static struct bt_audio_broadcast_create_param broadcast_param { .subgroup_count 1, .subgroup subgroup_param, .stream_param stream_param, /* framing BT_AUDIO_FRAMING_LE, LC3配置见stream_param */ }; /* LC3编码参数48kHz/单声道/80ms帧/96kbps */ static struct bt_audio_codec_cap codec_cap { .id BT_AUDIO_CODEC_LC3, .data lc3_preset_data, };这里有三个细节广播间隔别贪小曾经为了“被扫描到更快”改成30ms结果功耗飙升接收端在嘈杂环境里反而更容易丢同步BT_LE_ADV_OPT_CONNECTABLE这一步不是必须的但如果之后想用手机App做参数配置或固件升级保留连接广播能给后续开发留口子音频帧间隔80ms和LC3编码器内部的帧长度是配套的改动要同时看两端只改一边会直接起不了流。3.3 广播启动与音频采集联动音频采集侧我单独跑了一个线程从Codec的I2S RX读PCM数据经过重采样和增益处理后塞进环形缓冲区广播任务再从缓冲区取数据交LC3编码并送入协议栈。这里最核心的联动是缓冲区的容量设计和回调节奏不能让音频任务写溢出也不能让广播任务长时间读空。我调试时用了一个笨但有效的办法先在缓冲区写一个固定的正弦波序列不接真实音源广播后用耳机听播放出来的音调正不正常。如果音调对了说明整条链路时序正常如果音调变调或出现“嚓嚓”声说明采样率或帧长度设置有偏差。这个方法强烈推荐它能在没有音频分析仪器的情况下快速区分是“数字链路问题”还是“模拟前端问题”。音频数据从PCM到LC3是固定码率的所以网络带宽很稳定。下面这段是实际运行时开启广播音频流的关键调用顺序缺少任何一步都会导致“广播发出来了但耳机收不到声音”。/* 1. 创建广播音频流并注册回调 */ bt_audio_broadcast_create(create_param, bcast); /* 2. 启动周期性广播接收端才能发现广播 */ bt_le_adv_start(adv_param, adv_data, adv_data_len, NULL, 0); /* 3. 更新广播元数据广播名、语言等 */ bt_audio_broadcast_update_base(bcast, base_param); /* 4. 提交音频数据到编码器 */ while (1) { pcm_read(buf); /* 从I2S取得PCM数据 */ lc3_encode(buf, out_packet); bt_audio_broadcast_send(bcast, out_packet, size); }出错最多的就是第3步有人把所有步骤都写了但没更新广播Base信息结果手机App能看到一个空广播没有音频参数订阅按钮是灰的。排查这类问题看SDK日志里的base update status基本一查一个准。注解里写的需求我尽量给了直接可用的代码但不同SDK版本API名会有差异还是以你的SDK版本文档为准。3.4 性能实测数据测试场地在一块相对空旷的办公区手机和模块之间没有金属隔断。实测数据如下测试项测试条件结果广播发现距离空旷区域手机扫描约25米内稳定可见音频播放距离空旷区域Auracast耳机接收18米内无断续穿越一堵隔墙5米距离隔混凝土墙可听但偶有卡顿延迟体感播放节拍器信号约120ms感知明显但可接受连续播放稳定性1小时持续播放无掉线、无同步丢失空旷区域能跑到18米其实已经超出预期但穿墙衰减依然明显这是蓝牙2.4G频段的物理特性决定的。如果产品定位是公共广播发射端功率可以再往上调但注意当地法规对蓝牙发射功率的上限要求不要盲目加大。中等距离下的稳定性优先级高于绝对距离我的建议是先保证20米内极稳定再去挑战30米。4. 常见问题与排查技巧实录4.1 手机完全搜不到Auracast广播这个问题出现频率最高。先别怀疑模块从接收端开始排查手机是否支持LE AudioAndroid手机对Auracast的支持受厂商定制影响很大系统更新之后也有可能被砍功能手机系统设置里是否开启了“扫描附近设备”权限如果你用的是国行手机部分品牌默认没有开启蓝牙广播扫描的功能需要在开发者选项里单独打开。排除了手机之后用nRF Connect看模块有没有发出周期性广播。如果能看到周期性广播但看不到Audio Broadcast就说明广播扩展包有问题重点检查bt_audio_broadcast_update_base。如果周期性广播都没有回到配置来看adv是否启动成功这个一般日志里能看出来。4.2 能搜索到广播但耳机没声音能搜到广播说明元数据链路是通的耳机没声音大概率是BIS流同步或音频格式不匹配。最典型的例子是LC3采样率和帧间隔不匹配。耳机端如果只支持48kHz/10ms帧你SDK里配了48kHz/80ms帧常规情况下它也会尝试解码但耳机的软件实现可能对长帧支持并不完整。另外检查是不是把双声道数据发到了单声道接收的链路。有些TWS耳机在Auracast模式下默认按单声道解析你发了立体声LC3它会解出来但声音很奇怪。我的建议是广播一律用单声道兼容性比立体声好太多。如果之后必须做立体声一定要用支持对应参数的耳机测试。4.3 播放一会儿后周期性卡顿这种“间歇性卡顿”我排查了好几天最终定位到两个原因。第一个是周围Wi-Fi频段干扰。2.4G Wi-Fi的20MHz带宽信道和蓝牙广播信道的频率存在交叠可能尤其办公区路由器密集。解决办法是通过产品配置软件把广播信道调整到相对干净的信道上或者开启模组的共存机制让Wi-Fi和蓝牙分时调度。硬件上如果天线位置冲突干扰会比软件更严重需要检查天线布局。第二个是缓冲区水位管理问题。我的音频采集线程和广播发送线程速率如果有微小偏差长时间运行后缓冲区要么溢出要么读空听起来就是每隔几十秒卡一下。解决方法是把环形缓冲区加大到能容纳400ms以上的音频数据并做动态水位补偿水位低于20%时发送端把帧间隔适当拉长水位高于80%时加快读取。这个策略调好之后连续播放1小时再没出现卡顿。业余条件下可以用长时播放录音来定位卡顿的周期再结合日志确认是不是水位触发。4.4 手机App显示订阅成功但延迟很大延迟取决于整条链路采集端缓冲、LC3编码器算法延迟、BIS广播间隔、接收端解码与耳机缓冲。模块这边的可调项主要是BIS同步间隔。如果应用场景是口译广播延迟超过150ms就建议改成5ms或更密的广播间隔但功耗会上升抗干扰余量也会下降。取舍逻辑很简单延迟敏感场景优先保延迟稳定优先场景保间隔。接收端耳机的缓冲策略你控制不了有的耳机为了抗干扰故意做了较大的缓冲这会造成一部分延迟。所以做延迟对比测试时用同一副耳机测不同模块参数才有横向可比性千万别拿一副耳机延迟去对标另一副耳机的数据产品实测时对这个差异要保持清醒。4.5 想要产品化还需要做什么开发板跑通只是第一步。真正要落地成产品还要做这些事情第一整合低功耗策略Auracast广播如果一直满功率发送功耗会比较可观需要考虑触发式广播、多状态电源管理第二把配置工具从调试串口升级成BLE连接配置用户通过App改广播名、改语言、调整音量增益都走无线通道第三申请BQB认证时产品清单里明确用到的模块型号和固件版本模组认证能简化流程但不能完全替代产品认证第四量产测试不能只测射频指标建议产线上增加“广播能被手机搜索到”的功能测试项避免个别模组贴歪天线或焊接不良导致出厂就哑火。我自己的体会是这个项目最大的收获不在Auracast本身而在于它让我把Zephyr的协议栈、设备树、音频数据通路完整贯通了一遍。Auracast目前还处于早期应用阶段接收端生态正在快速补齐手机上原生的广播扫描已经是标配后续这个方向的应用会越来越多。如果你手头正好有BT2106C或者其他支持LE Audio的模组强烈建议先按我上面的思路跑通一版广播然后加上自己场景里的音频源和交互逻辑你会很快看到这项技术在产品中的真正价值。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进