2. SCO连接建立流程:HCI_Setup_Synchronous_Connection命令详解
SCO(Synchronous Connection Oriented)链路是蓝牙音频传输的基础,用于承载等时(Isochronous)数据流,如HFP(Hands-Free Profile)和HSP(Headset Profile)中的语音数据。建立SCO连接的核心操作是Host Controller发送HCI_Setup_Synchronous_Connection命令。本章将深入解析该命令的构造、参数配置及其对音频质量的影响。
2.1 SCO连接建立流程概览
在ACL(Asynchronous Connection-Less)链路建立之后,Host通过HCI命令向Controller发起SCO连接请求。整个流程分为三个阶段:参数准备、命令下发、连接完成。
2.2 HCI_Setup_Synchronous_Connection命令结构
该命令属于HCI Command Group中的SCO Link Control命令,OpCode为0x0428。命令参数决定了SCO链路的传输特性。
| 参数名称 | 字节数 | 取值范围 | 说明 |
|---|---|---|---|
| Connection_Handle | 2 | 0x0000 - 0x0EFF | 已建立的ACL连接句柄 |
| Tx_Bandwidth | 4 | 0x000000 - 0xFFFFFF | 发送带宽(单位:B/s),通常设为8000 |
| Rx_Bandwidth | 4 | 0x000000 - 0xFFFFFF | 接收带宽(单位:B/s),通常设为8000 |
| Voice_Setting | 2 | Bitmask | 编码格式、采样率、数据路径配置 |
| Max_Latency | 2 | 0x0004 - 0xFFFE | 最大延迟(单位:0.625ms slots) |
| Retransmission_Effort | 1 | 0x00 - 0x02 | 重传策略:0=无重传,1=尽力,2=强制 |
| Packet_Type | 2 | Bitmask | 允许的SCO/eSCO包类型 |
hci_send_cmd()函数下发,参数封装在struct hci_cp_setup_sync_conn结构体中。
2.3 核心参数详解
2.3.1 Tx/Rx带宽配置
带宽参数以字节/秒为单位。对于标准的8kHz采样、16bit量化的PCM语音流,带宽计算如下:
带宽 = 采样率 × 量化位数 × 通道数 / 8
= 8000 × 16 × 1 / 8
= 16000 字节/秒
实际配置中,Tx_Bandwidth和Rx_Bandwidth通常设置为8000(对应8kHz采样率),因为蓝牙协议栈内部会进行带宽换算。若使用CVSD编码,带宽需求会降低。
2.3.2 Voice_Setting(语音编码配置)
Voice_Setting是一个16位的位掩码,控制编码格式、采样率、数据路径等。其结构如下:
常见的Voice_Setting配置值:
| 编码格式 | 采样率 | 采样位数 | Voice_Setting值 | 典型应用 |
|---|---|---|---|---|
| CVSD | 8kHz | 16bit | 0x0060 | HFP/HSP默认 |
| PCM A-law | 8kHz | 8bit | 0x0003 | 传统电话网络 |
| PCM μ-law | 8kHz | 8bit | 0x0007 | 北美/日本 |
| Linear PCM | 8kHz | 16bit | 0x0000 | 高质量音频 |
| Linear PCM | 16kHz | 16bit | 0x0010 | WB语音(WBS) |
2.3.3 重传机制(Retransmission_Effort)
重传机制是eSCO(Extended SCO)相对于传统SCO的核心改进。该参数控制链路层对丢失数据包的重传策略:
- 0x00 (No Retransmission):不进行重传,适用于对延迟极度敏感的场景,如实时对讲。
- 0x01 (Optimize for Power):尽力重传,在延迟和功耗之间平衡,最多重传1-2次。
- 0x02 (Optimize for Quality):强制重传,尽可能保证数据完整性,适用于语音质量优先的场景。
2.4 包类型选择(Packet_Type)
Packet_Type参数决定SCO/eSCO链路上允许使用的数据包格式。不同包类型对应不同的负载大小和抗干扰能力。
| 包类型 | 负载(字节) | FEC | 重传 | 典型延迟 |
|---|---|---|---|---|
| HV1 | 10 | 1/3 | 不支持 | 3.75ms |
| HV2 | 20 | 2/3 | 不支持 | 5ms |
| HV3 | 30 | 无 | 不支持 | 3.75ms |
| EV3 | 30 | 无 | 支持 | 3.75ms |
| EV4 | 120 | 2/3 | 支持 | 5ms |
| EV5 | 180 | 无 | 支持 | 3.75ms |
2.5 Linux内核中的命令构造示例
以下代码展示了在Linux蓝牙驱动中构造HCI_Setup_Synchronous_Connection命令的典型实现:
/* 构造SCO连接参数 */
struct hci_cp_setup_sync_conn cp;
memset(&cp, 0, sizeof(cp));
/* 设置ACL连接句柄 */
cp.handle = cpu_to_le16(conn->handle);
/* 设置Tx/Rx带宽(8kHz采样,16bit,单声道) */
cp.tx_bandwidth = cpu_to_le32(0x00001f40); /* 8000 B/s */
cp.rx_bandwidth = cpu_to_le32(0x00001f40); /* 8000 B/s */
/* 设置语音编码:CVSD,8kHz,16bit */
cp.voice_setting = cpu_to_le16(0x0060);
/* 设置最大延迟:16个slot(10ms) */
cp.max_latency = cpu_to_le16(0x0010);
/* 设置重传策略:尽力重传 */
cp.retransmission_effort = 0x01;
/* 设置包类型:允许EV3/EV4/EV5 */
cp.pkt_type = cpu_to_le16(EV3_PKT | EV4_PKT | EV5_PKT);
/* 下发命令 */
hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
2.6 连接建立后的状态验证
命令下发后,Controller会返回HCI_Connection_Complete事件。通过检查事件参数可以确认SCO链路是否成功建立:
- Status = 0x00:连接建立成功。
- Connection_Handle:新分配的SCO连接句柄(范围0x0000-0x0EFF)。
- Link_Type = 0x01:表示SCO链路。
- Encryption_Mode:加密模式,通常为0x00(不加密)。
btmon或hcidump工具可以实时捕获HCI命令和事件,验证SCO连接参数是否按预期下发。重点关注HCI_Command_Status和HCI_Connection_Complete事件。
2.7 常见配置问题与调试
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 连接建立失败(Status=0x0E) | Max_Latency与重传策略冲突 | 增大Max_Latency或降低重传等级 |
| 音频断续/丢包 | Packet_Type选择不当或重传不足 | 启用EV4/EV5并设置重传为0x02 |
| 延迟过高 | 重传次数过多或包类型负载过大 | 使用EV3包类型并限制重传 |
| 编码不匹配 | Voice_Setting与远端设备不兼容 | 协商使用双方都支持的编码格式 |
/sys/kernel/debug/bluetooth/hci0/目录下可以查看SCO连接状态。使用echo "1" > sco_dbg可以开启SCO调试日志,输出到dmesg。