3. TWS连接流程:经典TWS连接建立、LE Audio下的TWS连接、Snoop与Copy模式详解
好,咱们今天聊点硬核的。TWS耳机的连接流程,说白了就是左右耳怎么“勾搭”上,再一起跟手机“握手”。我做了这么多年,发现很多新手工程师在这块栽跟头。今天我把经典蓝牙和LE Audio下的连接流程掰开揉碎了讲,顺便聊聊Snoop和Copy这两种模式——嗯,这可是区分菜鸟和老鸟的分水岭。
3.1 经典TWS连接建立
先说说最传统的方案。经典TWS,左右耳之间用的是蓝牙经典链路(BR/EDR)。流程大概是这样的:
- 配对阶段:耳机从充电仓取出,左右耳自动进入配对模式。左耳(通常作为主耳)会先广播,右耳扫描并连接。
- 角色协商:左右耳通过HCI命令协商谁是主耳(Primary),谁是副耳(Secondary)。主耳负责跟手机通信,副耳听主耳的。
- 链路建立:主耳跟手机建立ACL链路,同时跟副耳也建立一条ACL链路。这时候,音频数据从手机到主耳,主耳再转发给副耳。
我个人习惯把主耳比作“翻译官”——手机说啥,它先听,再转述给副耳。但这里有个坑:转发延迟。我在项目中遇到过,如果主耳转发不及时,左右耳声音就会“一前一后”,用户听着像在听山谷回音。
3.2 LE Audio下的TWS连接
到了LE Audio时代,事情变得有意思了。LE Audio用的是LC3编解码,而且引入了新的连接模型。你想想看,经典蓝牙那种“主耳转发”的方式,功耗高、延迟大,LE Audio直接把它颠覆了。
LE Audio下,TWS连接有两种主流方式:
- 同步组(Broadcast Isochronous Group, BIG):手机直接广播音频流,左右耳各自接收。左右耳之间不需要建立链路,各听各的。
- 连接同步(Connected Isochronous Group, CIG):手机跟左右耳分别建立同步连接(CIS),左右耳之间也可以有辅助链路。
说白了,LE Audio让左右耳“独立”了。我记得第一次调LE Audio的TWS时,发现左右耳同步精度比经典蓝牙高了一个数量级——经典蓝牙做到±20μs就算不错,LE Audio轻松做到±5μs。为什么会这样?因为LE Audio的同步机制是基于时间戳的,而不是基于数据包转发的。
关键点:LE Audio的TWS连接,左右耳之间不再需要实时转发音频数据。这大大降低了功耗和延迟。但代价是,左右耳需要各自维护一个精确的时钟同步。
3.3 Snoop与Copy模式详解
好,接下来是重头戏。Snoop和Copy,这两个词在TWS开发里经常被提起。它们解决的是同一个问题:副耳怎么拿到音频数据?
3.3.1 Snoop模式
Snoop模式,直译就是“偷听模式”。副耳不直接跟手机连接,而是“偷听”主耳和手机之间的通信。具体来说:
- 主耳跟手机建立ACL链路,副耳也加入这个微微网(Piconet)。
- 副耳监听主耳和手机之间的数据包,但只收不发。
- 副耳根据主耳的时钟和跳频序列,同步接收数据。
嗯,这里要注意:Snoop模式要求副耳能解析主耳和手机之间的链路层数据。我刚开始做的时候,以为副耳只要“听”就行了,结果发现副耳必须知道主耳的蓝牙地址和时钟偏移,否则根本解不了包。
个人经验:Snoop模式的好处是延迟低,因为副耳跟主耳几乎同时收到数据。但坏处是,如果主耳和手机之间的链路质量差,副耳也会跟着遭殃。我曾经在一个项目中,主耳离手机3米,副耳在口袋里,结果副耳丢包率高达30%。后来我加了重传机制,才把丢包率压到5%以下。
3.3.2 Copy模式
Copy模式,就是“复制转发模式”。主耳收到手机的数据后,再复制一份发给副耳。流程如下:
- 手机发数据给主耳。
- 主耳解码后,把音频数据复制一份。
- 主耳通过另一条ACL链路,把复制数据发给副耳。
Copy模式的好处是,副耳不需要“偷听”,它只需要跟主耳保持一条稳定的链路就行。但坏处是,主耳的负担重了——既要跟手机通信,又要转发给副耳,功耗和延迟都会增加。
我建议,如果产品追求低功耗,优先考虑Snoop模式;如果追求稳定性,Copy模式更靠谱。当然,现在很多芯片方案支持动态切换——信号好时用Snoop,信号差时切到Copy。嗯,这个思路挺聪明的。
避坑指南:我曾经在Copy模式下踩过一个坑。主耳转发数据时,如果副耳没及时应答,主耳会一直重传,导致主耳功耗飙升。后来我加了超时机制:如果副耳连续3次没应答,主耳就暂停转发,等副耳重新连上再继续。
3.4 两种模式的对比
为了让你看得更清楚,我整理了一个表格:
| 特性 | Snoop模式 | Copy模式 |
|---|---|---|
| 主耳功耗 | 低 | 高 |
| 副耳功耗 | 中 | 低 |
| 延迟 | 低 | 中 |
| 稳定性 | 依赖主-手机链路 | 依赖主-副链路 |
| 实现复杂度 | 高 | 低 |
你想想看,如果产品定位是运动耳机,用户经常把手机放口袋里,主耳和手机之间可能有遮挡,这时候Copy模式更稳。如果是办公耳机,手机就在桌上,Snoop模式更省电。
3.5 代码示例:Snoop模式初始化
最后,给一段伪代码,展示Snoop模式下副耳如何初始化监听:
// 副耳初始化Snoop模式
void snoop_init(uint8_t *master_bd_addr, uint32_t clock_offset) {
// 1. 设置跳频同步
hci_set_afh_channel_map(master_bd_addr, channel_map);
// 2. 同步主耳时钟
hci_set_clock_offset(clock_offset);
// 3. 进入监听状态
hci_set_sniff_mode(0x0012); // 监听间隔:18.75ms
// 4. 注册数据回调
register_snoop_callback(snoop_data_handler);
}
void snoop_data_handler(uint8_t *data, uint16_t len) {
// 解析音频数据
if (is_audio_packet(data)) {
decode_lc3(data, len);
play_audio();
}
}
这段代码看着简单,但实际调起来坑不少。我记得第一次跑Snoop模式时,副耳死活收不到数据。查了半天,发现是时钟偏移没算对——主耳和副耳的晶振有±20ppm的误差,时间一长就漂了。后来我加了周期性时钟同步,每10秒校准一次,问题才解决。
好了,这一章就到这儿。连接流程是TWS的基础,Snoop和Copy是核心设计决策。下一章咱们聊聊音频同步——嗯,那才是真正考验功力的地方。