3、电话音频通路设计:SCO/eSCO链路建立、音频编解码器配置与PCM接口调试
电话音频通路,说白了就是蓝牙耳机里那个「喂喂喂」的声音怎么传过去的。很多刚入行的朋友觉得这步简单,不就是配个PCM时钟嘛。但我在项目里吃过不少亏,有一次样机通话时声音断断续续,查了三天才发现是SCO链路的发包间隔没对齐。
嗯,今天咱们就把这块彻底讲透。
3.1 SCO与eSCO链路:选哪个?
SCO(Synchronous Connection-Oriented)是蓝牙里最早的电话音频传输方式。它固定每两个蓝牙时隙发一个包,说白了就是「定时定点」地传数据。好处是延迟低,坏处是抗干扰差。
eSCO(Enhanced SCO)是后来改进的版本。它允许重传,还能调整发包间隔。我个人习惯,只要芯片支持,优先用eSCO。为什么?
- 重传机制:丢包了可以补发,通话不容易断
- 灵活间隔:可以选6、8、10个时隙发一次,省电
- 兼容性好:大部分现代蓝牙芯片都支持
关键参数对比
| 参数 | SCO | eSCO |
|---|---|---|
| 发包间隔 | 2个时隙(1.25ms) | 6/8/10个时隙 |
| 重传 | 不支持 | 支持(最多4次) |
| 典型延迟 | ~3ms | ~5-10ms |
| 抗干扰 | 差 | 好 |
你想想看,在车里打电话,周围Wi-Fi、其他蓝牙设备都在抢2.4G频段。用SCO的话,一个干扰包过来,声音就「咔」一下断了。eSCO能重传,体验好很多。
3.2 链路建立流程:从连接到通话
建立一条电话音频链路,其实就三步。我当年刚做车载项目时,以为配好PCM就完事了,结果发现链路根本没连上——嗯,顺序搞反了。
- ACL连接建立:先让手机和车机连上基础链路
- SCO/eSCO连接建立:在ACL基础上,发起音频链路
- 音频流启动:开始传PCM数据
代码里怎么配?以CSR8670为例,关键就这几行:
/* 配置eSCO参数 */
#define ESCO_PACKET_TYPE EDR_ESCO_EV3
#define ESCO_TX_INTERVAL 6 /* 6个时隙发一次 */
#define ESCO_RETRANSMIT 2 /* 最多重传2次 */
/* 发起eSCO连接 */
sink_esco_connect(acl_handle, esco_params);
我的经验:EV3包类型在大多数场景下够用。如果信号差,可以换成2-EV3,数据量翻倍但抗干扰更好。
3.3 音频编解码器配置:CVSD还是mSBC?
蓝牙电话音频支持两种编解码器:
- CVSD(Continuous Variable Slope Delta Modulation):老牌编码,64kbps,音质一般
- mSBC(modified Sub-Band Coding):宽带语音,16kHz采样,音质好很多
我曾经在一个项目里,客户投诉通话声音「闷」。查了半天,发现默认用的是CVSD。换成mSBC后,客户说「哎,清楚多了」。
配置mSBC时要注意:
/* mSBC编解码器初始化 */
codec_config_t cfg;
cfg.sample_rate = 16000; /* 16kHz */
cfg.bit_depth = 16; /* 16位 */
cfg.channels = 1; /* 单声道 */
cfg.codec_type = CODEC_MSBC;
codec_init(&cfg);
注意:mSBC需要蓝牙双方都支持。如果手机不支持,会自动降级到CVSD。所以代码里要做好回退处理。
3.4 PCM接口调试:时钟、帧同步和数据
PCM接口是音频编解码器和蓝牙芯片之间的「高速公路」。三条线:
- PCM_CLK:位时钟,决定每个bit的传输速度
- PCM_SYNC:帧同步,标记一帧数据的开始
- PCM_DIN/PCM_DOUT:数据线
调试时最容易出问题的是时钟极性。我遇到过好几次,示波器一看,CLK和SYNC的相位反了,声音全是噪声。
典型配置参数:
| 参数 | 典型值 | 说明 |
|---|---|---|
| 采样率 | 8kHz / 16kHz | CVSD用8k,mSBC用16k |
| 位宽 | 16bit | 标准配置 |
| 帧长 | 16位 × 2通道 = 32位 | 左声道右声道 |
| 时钟极性 | 上升沿采样 | 看芯片手册 |
调试步骤我一般这么走:
- 先看时钟:示波器量PCM_CLK,频率对不对
- 再看同步:PCM_SYNC的周期是不是1/采样率
- 最后看数据:发个正弦波,看DIN/DOUT波形对不对
避坑指南:我曾经在调试时发现PCM_CLK频率是对的,但SYNC信号一直没拉高。查了半天,原来是蓝牙芯片的PCM主从模式没配对。主设备输出时钟,从设备接收时钟,搞反了就没同步信号。
3.5 实战:一个完整的音频通路调试案例
去年做的一个车载项目,问题现象是:打电话时,对方能听到我说话,但我听不到对方。
排查过程:
- 先看链路:eSCO连接建立成功,没问题
- 再看编解码:mSBC配置正确
- 最后看PCM:示波器一量,PCM_DOUT有数据,但PCM_DIN一直是低电平
原因找到了——蓝牙芯片的PCM_DIN引脚虚焊。补焊后,声音正常了。
嗯,有时候问题就这么简单。但你不去量波形,光看代码是看不出来的。
我的习惯:每次新板子回来,先写个PCM回环测试程序。把DIN和DOUT短接,发一段数据看能不能收回来。能回环通过,再跑上层应用。
3.6 小结
电话音频通路设计,说白了就是三件事:
- 选对链路:eSCO优先,抗干扰好
- 配对编解码:mSCD音质好,但要考虑兼容性
- 调对PCM:时钟、同步、极性,一个都不能错
你想想看,车里打电话,信号本来就复杂。要是音频通路再出问题,那体验就太差了。希望今天的内容能帮你少走些弯路。
下一章咱们聊聊蓝牙电话的HFP协议栈实现,那个更绕,但更有意思。