公司动态

Sniff 省电模式参数调优——续航与音频稳定性平衡实操

📅 2026/8/1 10:21:07
Sniff 省电模式参数调优——续航与音频稳定性平衡实操
Sniff 是经典蓝牙三个节能模式里用得最多的一个。TWS 耳机待机时能不能省电、A2DP 播放时会不会断音都和 Sniff 参数直接相关。这篇拆解 Sniff 的三个核心参数以及 TWS 场景下怎么调才平衡。TL;DRSniff 模式让从设备周期性醒来监听其余时间休眠。三个参数Interval醒的周期、Attempt醒多久、Timeout额外等多久。参数调优的核心矛盾Interval 越大越省电但响应延迟越高Attempt 越大越稳但功耗越高。TWS 待机场景 Interval 可以拉到 500ms-1sA2DP 播放场景要压到 40ms 左右HFP 通话不能用 Sniff。Sniff Subrating 允许在不退出 Sniff 的情况下动态调整 Interval实现待机省电、有数据快速响应。目录为什么要用 Sniff 模式Sniff 的工作原理三个核心参数详解Sniff Subrating 机制HCI 命令与 LMP 交互TWS 场景参数调优抓包分析 Sniff常见问题排查1. 为什么要用 Sniff 模式经典蓝牙的 ACL 链路在 Active 状态下从设备每个时隙都要监听主设备是否发数据——即使没有数据RF 和基带也一直开着。这对于电池供电的设备TWS 耳机、手表、传感器是巨大的功耗浪费。蓝牙定义了三个节能模式来降低功耗模式功耗响应延迟适用场景Hold中中短时间挂起如协商加密Sniff低可调长时间连接但数据稀疏TWS 待机、传感器Park极低高已基本不用BLE 取代Sniff 是实际项目中最常用的——它保持 ACL 链路不断开但从设备大部分时间在休眠只在约定的时隙醒来监听。TWS 耳机待机时能撑好几天核心就是 Sniff 在工作。为什么不用 HoldHold 是约定一段时间不通信到期后自动恢复 Active。它适合临时挂起比如切换加密模式时不适合长期待机——因为 Hold 期间完全不能收数据到期恢复 Active 后又回到全时监听。为什么不用 ParkPark 几乎完全休眠只保留 beacon 监听但响应延迟太大秒级而且 Park 模式下设备没有 AM_ADDR不能直接收发数据必须先 Unpark。现在 BLE 已经取代了 Park 的大多数场景经典蓝牙里 Park 基本不用了。2. Sniff 的工作原理Sniff 模式下主从双方约定一个Sniff Interval嗅探间隔。每隔这个间隔从设备醒来一段窗口Sniff Attempt监听主设备是否发数据。如果在这段窗口里收到数据从设备保持唤醒继续收发如果没收到从设备重新休眠等下一个 Interval。时间轴 → 主设备: ──[发数据]──────────────────────────[发数据]── 从设备: ▏醒▕─────────睡─────────▏醒▕─────────睡─────────▏醒▕ │←Attempt→│←Interval-Attempt→│←Attempt→│←Interval-Attempt→│ Active 模式对比: 从设备: ▏醒▕醒▕醒▕醒▕醒▕醒▕醒▕醒▕醒▕醒▕醒▕醒▕醒▕醒▕醒▕ ← 全时监听关键点主设备也必须在 Sniff 窗口才能给从设备发数据。Sniff 是双方约定的——主设备不能在从设备休眠时发数据否则从设备收不到。这意味着 Sniff 参数影响的不只是从设备的功耗还有链路的传输能力。3. 三个核心参数详解3.1 Sniff Interval嗅探间隔从设备两次醒来之间的时间间隔。取值范围0x0004 - 0x4000单位 0.625ms即 2.5ms - 10.24s对功耗的影响越大越省电休眠时间越长对延迟的影响越大延迟越高主设备要等到下一个窗口才能发数据对吞吐的影响越大有效带宽越低传输机会少典型值场景Interval理由TWS 待机500ms - 1s无数据传输最大化省电A2DP 播放40ms - 60ms匹配音频帧周期SBC 约 20ms/帧保证及时传输HID 键盘100ms - 200ms按键响应延迟 200ms 用户可接受传感器上报1s - 4s数据稀疏延迟可接受3.2 Sniff Attempt嗅探尝试窗口从设备每次醒来后持续监听的时长。取值范围0x0001 - 0x7FFF单位 0.625ms对功耗的影响越大越耗电醒着的时间长对稳定性的影响越大越稳给链路更多时间重传/同步Attempt 不能为 0——至少要醒一个时隙才能判断主设备有没有发数据。Attempt 通常设置成能覆盖若干个跳频时隙每个时隙 625μs确保即使遇到跳频干扰也能收到。典型值场景Attempt理由TWS 待机4 - 8 时隙2.5ms - 5ms只需确认有无数据短窗口够A2DP 播放16 - 32 时隙10ms - 20ms要收完整个 SBC 帧包弱信号环境加大到 32 - 64 时隙给重传留余量3.3 Sniff Timeout嗅探超时从设备在 Attempt 窗口内收到数据后额外延长监听的时间。取值范围0x0000 - 0x7FFF单位 0.625ms作用如果 Attempt 窗口里收到了数据说明有通信需求从设备继续醒着 Timeout 时长看主设备是否还有后续数据Timeout0Attempt 结束立即休眠不管有没有收到数据这个参数解决的是突发数据场景——主设备可能连续发多个包如果每个包都要等下一个 Interval延迟会累积。Timeout 让从设备在收到数据后多醒一会儿避免频繁休眠-唤醒。典型值场景Timeout理由TWS 待机0 或 4 时隙无突发数据不需额外等待A2DP 播放16 - 32 时隙连续媒体包需要延长接收窗口大数据传输64 时阶临时退出 Sniff 更好见下一节3.4 三个参数的关系│←───────────────── Sniff Interval ─────────────────→│ │ │ │ │← Attempt →│← Timeout →│ │ │ │ (仅收到数据时) │ │ ▏醒▕─────────睡────────────────────────────────────── │ │ │ 下一个 Interval 开始 │ │← Attempt →│← Timeout →│ │ ▏醒▕─────────睡──────────────────────────────────────三个参数的工程意义Interval决定省电程度宏观Attempt决定基础可用性微观Timeout决定突发处理能力弹性调参的核心逻辑先定 Interval决定省电目标再定 Attempt保证基础通信最后用 Timeout 优化突发场景。4. Sniff Subrating 机制4.1 问题频繁进出 Sniff 的开销TWS 耳机在待机 - 来电 - 通话 - 挂断 - 待机这种场景里状态频繁切换。每次切换如果都要 Exit Sniff → Active → 重新 Enter Sniff开销很大LMP_unsniff LMP_sniff 两次握手状态机切换的时序约束重新协商参数的延迟4.2 Subrating 的解法Sniff Subratingopcode 0x54允许在不退出 Sniff的情况下动态调整有效 Sniff Interval。原理是引入一个基础 Interval和子速率概念基础 Interval 保持较短如 40ms保证低延迟响应能力实际运行时通过 Subrating 把有效 Interval 拉长到 N 倍如 N16有效 Interval640ms一旦有数据要传立刻回到基础 Interval无需重新协商无 Subrating: Interval640ms ▏醒▕──────────────────────────────────────睡────── ↑ 来数据了但要等 640ms 才能响应 有 Subrating (base40ms, subrate16): 基础周期: ▏醒▕────▏醒▕────▏醒▕──── ... 共 16 次 ↑ 第 1 次就收到数据立即保持 40ms 的活跃 Interval 无需 LMP 重新协商 无数据时: 有效周期: ▏醒▕────────────────────────────睡────── (640ms) ↑ 每 16 个基础周期才真正醒一次4.3 Subrating 参数HCI_Sniff_Subrating 命令Opcode 0x0C11的参数参数含义Max_Latency最大允许的有效 Interval×0.625ms即子速率后的最大间隔Min_Remote_Timeout对端的最小 Sniff TimeoutMin_Local_Timeout本端的最小 Sniff TimeoutMax_Latency 是核心参数——它告诉控制器有效 Interval 可以拉到多大但基础 Interval 保持不变。控制器根据链路活动自动决定实际 Interval有数据时用基础 Interval无数据时逐步拉长到 Max_Latency。4.4 适用场景Subrating 非常适合间歇性活动的设备TWS 耳机待机时拉长 Interval 省电有来电/通知时立刻回到短 Interval 响应HID 设备无输入时长 Interval按键时短 Interval 低延迟健康传感器周期性上报数据上报期间短 Interval其余时间长 Interval5. HCI 命令与 LMP 交互5.1 进入 Sniff 的 HCI 命令Host 通过 HCI_Sniff_Mode 命令Opcode 0x0803让 Controller 发起 Sniff// HCI_Sniff_Mode 命令参数structhci_sniff_mode_cmd{uint16_thandle;// ACL 连接句柄uint16_tsniff_interval;// 嗅探间隔 (×0.625ms)uint16_tsniff_attempt;// 嗅探尝试 (×0.625ms)uint16_tsniff_timeout;// 嗅探超时 (×0.625ms)};// 示例进入 SniffInterval100ms, Attempt5ms, Timeout0structhci_sniff_mode_cmdcmd{.handleacl_handle,.sniff_interval160,// 100ms / 0.625ms 160.sniff_attempt8,// 5ms / 0.625ms ≈ 8.sniff_timeout0,// 不额外等待};hci_send_cmd(HCI_SNIFF_MODE,cmd,sizeof(cmd));5.2 底层 LMP 交互Controller 收到 HCI 命令后发起 LMP 交互Host (B)Controller BController AHost (A)Host (B)Controller BController AHost (A)双方进入 Sniff 模式HCI_Sniff_Mode(Interval, Attempt, Timeout)LMP_sniff(D_Sniff, T_Sniff, D_Sniff_Attempt, T_Sniff_Attempt)HCI_Sniff_Mode_Request 事件通知 Host BHCI_Accept_Sniff_Mode_Request或拒绝LMP_accepted(LMP_sniff)HCI_Command_Complete (Sniff_Mode)HCI_Mode_Change 事件注意LMP_sniff 是 Master 发起的。如果 Slave 想进入 Sniff它发 HCI 命令给自己的 ControllerController 会通过 LMP 通知 Master由 Master 决定是否发起 Sniff 协商。5.3 退出 Sniff退出 Sniff 用 HCI_Exit_Sniff_ModeOpcode 0x0804底层走 LMP_unsniffControllerHostControllerHost对端回 LMP_acceptedHCI_Exit_Sniff_Mode(handle)发送 LMP_unsniffHCI_Mode_Change 事件 (ModeActive)5.4 Sniff Subrating 的 HCI 命令// HCI_Sniff_Subrating 命令structhci_sniff_subrating_cmd{uint16_thandle;// ACL 连接句柄uint16_tmax_latency;// 最大有效 Interval (×0.625ms)uint16_tmin_remote_timeout;// 对端最小 Timeout (×0.625ms)uint16_tmin_local_timeout;// 本端最小 Timeout (×0.625ms)};这个命令可以在 Sniff 模式下随时发不触发状态切换。6. TWS 场景参数调优6.1 TWS 耳机的四种工作状态状态链路活动推荐参数待机充电盒外偶尔有通知Interval500ms-1s, Attempt8, Timeout0A2DP 播放持续媒体流Interval40-60ms, Attempt16, Timeout16HFP 通话SCO/eSCO 占用不能用 Sniff见下文来电响铃突发信令用 Subratingbase40ms, max200ms6.2 为什么 HFP 通话不能用 SniffHFP 通话走 SCO 或 eSCO 链路SCO/eSCO 是同步链路时隙是预留的。ACL 链路在通话期间仍然存在但实际数据量很少只有 HFP 控制信令。理论上 ACL 可以进 Sniff但实际实现中SCO/eSCO 已经占用了大量时隙剩余的 ACL 时隙很少Sniff 协商的 Interval 可能和 SCO 时隙冲突大多数芯片厂商在 SCO 激活时不允许 ACL 进 Sniff所以 TWS 通话期间ACL 保持 Active靠 SCO 的预留时隙机制省电。通话结束后再切回 Sniff。6.3 A2DP 播放时的 Sniff 参数A2DP 播放时媒体流通过 ACL 传输Sniff 参数直接影响音频稳定性Interval 的选择SBC 帧周期约 20ms48kHz × 16 blocks。一个 RTP 包通常含 2-6 个 SBC 帧即每 40-120ms 发一个 RTP 包。Interval 应该小于 RTP 包间隔否则可能错过传输窗口。推荐 Interval 40-60ms覆盖 1-2 个 RTP 包周期。Attempt 的选择Attempt 要足够收完一个 RTP 包。RTP 包 L2CAP 头约 700-1000 字节EDR 2Mbps 下传输约 4ms。考虑重传Attempt 设 16 时隙10ms比较稳妥。Timeout 的选择A2DP 是连续流一个 RTP 包后面可能紧跟着另一个。Timeout 设 16 时隙10ms让从设备在收完一个包后多醒一会儿收下一个。A2DP Sniff 参数推荐 Interval 40ms (64 × 0.625ms) Attempt 10ms (16 × 0.625ms) Timeout 10ms (16 × 0.625ms) 时间线 │←── Interval 40ms ──→│←── Interval 40ms ──→│ │←AttemptTimeout20ms→│ ▏醒▕────收RTP────────────▏醒▕────收RTP──────────── ↑ 连续收完媒体包后休眠6.4 待机时的 Sniff 参数待机时没有持续数据只需要偶尔收控制信令如 AVRCP 按键待机 Sniff 参数推荐 Interval 800ms (1280 × 0.625ms) Attempt 2.5ms (4 × 0.625ms) Timeout 0 (不额外等待) 时间线 │←────────── Interval 800ms ──────────→│ │←2.5ms→│ ▏醒▕─────────────睡───────────────────── ↑ 确认无数据立即休眠待机时 Interval 可以拉得很大但要考虑两个约束链路监督超时Supervision TimeoutInterval 必须 Supervision Timeout否则链路会被判超时断开。通常 Supervision Timeout 设 5-10sInterval 最大不超过它的一半。应用响应延迟如果用户按按键响应延迟 ≈ Interval。Interval800ms 意味着按键响应最多延迟 800ms——这对 AVRCP 不可接受。解决响应延迟的方法用 Sniff Subrating。基础 Interval40ms低延迟响应Max_Latency800ms待机时拉长。有按键时立刻回到 40ms无数据时逐步拉到 800ms。6.5 主从切换时的 Sniff 处理TWS 耳机主从切换时Sniff 参数需要重新协商主从切换前先 Exit Sniff 回到 Active执行角色切换LMP_switch_req切换完成后新主设备重新发起 Sniff 协商如果直接在 Sniff 状态下做角色切换可能因为 Sniff 窗口不对齐导致切换失败。稳妥的做法是先 Exit Sniff。7. 抓包分析 Sniff7.1 HCI 层抓包用 btmon 或 hcidump 抓 HCI 层能看到 Host 和 Controller 的交互# btmon 抓包sudobtmon-wsniff.pcap# 触发 Sniff 进入/退出# ...# 停止sudopkillbtmonWireshark 过滤 Sniff 相关事件# Sniff 模式切换事件 bt HCI_EVT_Mode_Change # Sniff 命令 btcmd.opcode 0x0803 # HCI_Sniff_Mode btcmd.opcode 0x0804 # HCI_Exit_Sniff_Mode btcmd.opcode 0x0C11 # HCI_Sniff_SubratingHCI 层抓包看到的是Host 下命令 → Controller 确认 → Mode_Change 事件看不到具体的 LMP 交互。7.2 空口抓包看 LMP要看 Sniff 的 LMP 交互需要空口抓包仪Ellisys / Frontline。关键 LMP PDUOpcode命令抓包看什么0x08LMP_sniff参数协商D_Sniff, T_Sniff, D_Sniff_Attempt, T_Sniff_Attempt0x09LMP_unsniff退出 Sniff0x54LMP_sniff_subrating子速率协商0x00LMP_accepted接受 Sniff 请求空口抓包还能看到 Sniff 模式下的实际时隙占用——主设备只在 Sniff 窗口发数据其余时隙静默。这是验证参数是否生效的最直接方法。7.3 验证 Sniff 是否生效抓包看三个信号HCI_Mode_Change 事件Mode 字段从 0x00Active变成 0x02Sniff说明进入 Sniff 成功ACL 数据包的时间分布Sniff 模式下ACL 包应该集中在 Sniff 窗口附近非窗口期应该没有包电流测试用功耗分析仪测电流Sniff 模式下应该看到周期性的电流脉冲Attempt 窗口其余时间电流极低8. 常见问题排查8.1 进入 Sniff 失败现象发 HCI_Sniff_Mode 后收到HCI_Command_Status (StatusERROR)或长时间无 Mode_Change 事件。排查检查参数合法性Interval ≥ 0x0004Attempt ≥ 0x0001检查连接状态链路必须是 Active 才能进 Sniff检查是否有 SCO 激活SCO 激活时通常不允许进 Sniff检查对端是否支持 Sniff查 LMP featuresPage 0 bit 58.2 Sniff 模式下音频卡顿现象A2DP 播放时进入 Sniff 后音频周期性卡顿。原因Interval 太大或 Attempt 太小导致 RTP 包传输不及时。调参方向缩小 Interval如从 100ms 降到 40ms加大 Attempt如从 8 时隙加到 16 时隙加大 Timeout如从 0 加到 16 时隙8.3 Sniff 模式下链路断开现象Sniff 模式下链路突然断开日志显示 Supervision Timeout。原因Sniff Interval Supervision Timeout或者信号质量差导致 Sniff 窗口里收不到数据累计超时。调参方向检查 Interval 是否 Supervision Timeout / 2弱信号环境下加大 Attempt增加接收成功率适当缩短 Interval增加链路存活机会8.4 待机功耗没降现象进了 Sniff但整机功耗没明显下降。排查确认 Sniff 真的生效看 Mode_Change 事件测控制器电流如果控制器电流没降可能是 RF 没真正休眠检查硬件设计检查其他耗电大户传感器、LED、充电电路等可能抵消 Sniff 的省电效果Interval 是否足够大Interval100ms 省电效果不明显至少 500ms 以上8.5 Sniff Subrating 不生效现象发了 HCI_Sniff_Subrating但有效 Interval 没变化。排查确认双方都支持 Sniff SubratingLMP features Page 0 bit 15检查 Max_Latency 是否 当前 Interval否则没有拉长空间检查链路状态必须在 Sniff 模式下才能用 Subrating查控制器实现某些低端芯片的 Subrating 实现有 bug需要厂商确认