3. eSCO 增强特性:与 SCO 的差异及数据包选择策略
eSCO(Enhanced Synchronous Connection-Oriented)是蓝牙核心规范 v1.2 引入的增强同步面向连接逻辑传输。与经典 SCO 相比,eSCO 在重传机制、数据包类型和链路质量监控方面做了根本性改进,是高质量音频传输(如宽频语音、A2DP 同步通道)的基础。
3.1 eSCO 与 SCO 的核心差异
下表从链路层机制、重传能力、数据包类型和典型应用四个维度对比 eSCO 与 SCO:
| 对比维度 | SCO | eSCO |
|---|---|---|
| 重传机制 | 无重传;数据包丢失即丢弃 | 支持有限次重传(Retransmission Window) |
| 数据包类型 | HV1 / HV2 / HV3(固定长度) | EV3 / EV4 / EV5 / 2-EV3 / 2-EV5 / 3-EV3 / 3-EV5 |
| 时隙占用 | 固定时隙,无弹性 | 可配置时隙间隔(Tsco)和重传窗口(W) |
| 链路质量反馈 | 无 | 通过 Link Supervision 和 RSSI 动态调整 |
| 典型应用 | 传统窄带语音(CVSD) | 宽频语音(mSBC)、A2DP 同步、LE Audio |
| Linux 驱动支持 | hci_conn->type == SCO_LINK | hci_conn->type == ESCO_LINK |
关键结论: eSCO 通过引入重传窗口和更灵活的数据包类型,将 SCO 的“尽力交付”升级为“有限可靠交付”,这是蓝牙音频从窄带(8 kHz)向宽频(16 kHz)演进的核心推动力。
3.2 重传窗口(Retransmission Window)
重传窗口是 eSCO 区别于 SCO 最关键的链路层参数。它定义了一次 eSCO 交互中,主从设备之间允许进行数据包重传的最大时隙数。
3.2.1 窗口机制原理
在 eSCO 链路中,每个 eSCO 间隔(Tsco)被划分为:
- 初始传输时隙: 主设备发送第一个数据包,从设备回复确认。
- 重传窗口(W 时隙): 如果初始传输失败(NACK 或超时),主/从设备在窗口内重传数据包。
- 空闲时隙: 窗口关闭后,剩余时隙保持空闲,直到下一个 Tsco 开始。
窗口大小影响: W 值越大,抗干扰能力越强,但链路带宽利用率降低,且增加端到端延迟。典型配置 W = 2 ~ 6 时隙。
3.2.2 Linux 内核中的重传窗口配置
在 Linux 蓝牙子系统中,eSCO 重传窗口通过 hci_conn 结构体的 attempt 和 interval 字段间接控制。驱动开发者通过 hci_setup_esco_conn() 函数设置参数:
/* 内核 eSCO 连接参数结构体 */
struct hci_conn_params_esco {
__u8 tx_packet_type; /* 发送数据包类型 */
__u8 rx_packet_type; /* 接收数据包类型 */
__u16 tx_interval; /* 发送间隔(微秒) */
__u16 rx_interval; /* 接收间隔(微秒) */
__u16 retransmission_window; /* 重传窗口(时隙数) */
__u16 tx_packet_length; /* 发送数据包长度 */
__u16 rx_packet_length; /* 接收数据包长度 */
};
/* 典型配置:宽频语音 mSBC 16kHz */
struct hci_conn_params_esco msbc_params = {
.tx_packet_type = ESCO_EV3,
.rx_packet_type = ESCO_EV3,
.tx_interval = 7500, /* 7.5ms 间隔 */
.rx_interval = 7500,
.retransmission_window = 2, /* 2 时隙重传窗口 */
.tx_packet_length = 30, /* 30 字节负载 */
.rx_packet_length = 30,
};
调试注意: 重传窗口设置过大(W > 6)可能导致链路调度冲突,尤其是在多连接场景下。建议在驱动初始化阶段通过
hci_dev->esco_config 读取控制器能力,动态调整窗口大小。
3.3 eSCO 数据包类型与选择策略
eSCO 定义了多种数据包类型,它们在时隙占用、负载长度、FEC 保护和重传能力上各有不同。正确选择数据包类型是音频传输优化的第一步。
3.3.1 数据包类型对比
| 数据包类型 | 时隙数 | 负载长度(字节) | FEC 保护 | 重传支持 | 典型比特率 |
|---|---|---|---|---|---|
| EV3 | 1 | 30 | 无 | 是 | 64 kbps |
| EV4 | 1 | 120 | 2/3 比例 | 否 | 128 kbps |
| EV5 | 1 | 180 | 无 | 是 | 192 kbps |
| 2-EV3 | 2 | 60 | 无 | 是 | 128 kbps |
| 2-EV5 | 2 | 360 | 无 | 是 | 384 kbps |
| 3-EV3 | 3 | 90 | 无 | 是 | 192 kbps |
| 3-EV5 | 3 | 540 | 无 | 是 | 576 kbps |
3.3.2 选择策略与决策流程
数据包类型的选择需要综合考虑以下因素:
- 音频编码格式: CVSD 窄带语音通常使用 EV3;mSBC 宽频语音推荐 2-EV3 或 EV5。
- 链路质量(RSSI / BER): 在低质量链路下优先选择带 FEC 的 EV4,或缩小重传窗口。
- 延迟预算: 多时隙包(2-EV5、3-EV5)增加延迟,不适合对延迟敏感的场景。
- 控制器能力: 部分蓝牙控制器不支持 3 时隙包,需通过
HCI_Read_ESCO_Parameters命令查询。
3.3.3 内核驱动中的包类型选择实现
在 Linux 内核蓝牙驱动中,数据包类型选择通常发生在 hci_conn_params_esco 初始化阶段。以下是一个基于链路质量动态调整的示例:
/* 动态选择 eSCO 数据包类型 */
static u8 select_esco_packet_type(struct hci_conn *conn, s8 rssi)
{
/* RSSI 阈值:-70 dBm 以上视为链路质量好 */
if (rssi > -70) {
/* 高质量链路:使用高吞吐 EV5 或 2-EV5 */
if (conn->features & LMP_ESCO_2EV5)
return ESCO_2EV5;
else
return ESCO_EV5;
} else if (rssi > -85) {
/* 中等质量链路:使用 EV3 配合重传 */
return ESCO_EV3;
} else {
/* 低质量链路:使用带 FEC 的 EV4 */
return ESCO_EV4;
}
}
/* 在 eSCO 连接建立前调用 */
static void setup_esco_params(struct hci_conn *conn)
{
struct hci_conn_params_esco params;
s8 rssi = hci_conn_get_rssi(conn);
params.tx_packet_type = select_esco_packet_type(conn, rssi);
params.rx_packet_type = params.tx_packet_type;
params.retransmission_window = (rssi > -70) ? 2 : 4;
/* 其他参数根据包类型填充 */
hci_setup_esco_conn(conn, ¶ms);
}
优化建议: 在音频传输过程中,可以通过
HCI_Connection_Quality_Report 事件监控链路质量,并触发 hci_conn_change_esco_params() 动态切换数据包类型,实现自适应传输。
3.4 本章小结
- eSCO 核心增强: 重传窗口(W)使蓝牙音频从无重传的 SCO 升级为有限可靠传输,是宽频语音的基础。
- 数据包类型选择: EV3/EV4/EV5 及多时隙变体(2-EV3、2-EV5、3-EV5)覆盖了从 64 kbps 到 576 kbps 的速率范围,选择需平衡吞吐、延迟和链路质量。
- Linux 驱动实践: 通过
hci_conn_params_esco结构体配置参数,结合 RSSI 反馈实现动态包类型切换,是音频传输优化的关键手段。