前言
现在为止也开发了许多杰理和中科蓝讯蓝牙芯片的TWS蓝牙耳机、音响项目 SDK 的案子,在调试案子时不断的向前辈们学习到了很多关于蓝牙音响、蓝牙TWS耳机专业的知识。想在这里做一个学习汇总,方便各位同行和对中科蓝汛芯片SDK感兴趣的小伙伴们学习;
本章详细讲解BT893x 面条耳机连接vivo手机后连接APP端,最后手机端设置页面手动断开蓝牙连接,此时耳机端假断开
相关信息
- 项目型号:AKR255PRO
- SDK版本:sdk_bt893x_headset_v018_s13402_20260722
- 工 程 师 :李永奉
- 提交日期:2026-09-09
问题描述
- 情况1:面条耳机连接vivo手机后连接APP端,再手机端设置页面手动断开蓝牙连接,此时耳机端只关闭音频流,并没有断开蓝牙连接;现象:断开提示音未播放、灯效依旧是蓝牙连接成功灯效蓝灯慢闪、手机APP端依旧显示连接中、手机端播放歌曲声音却是外放的;
- 情况2:面条耳机连接华为手机后连接APP端,再手机端设置页面手动断开蓝牙连接,此时耳机端成功断开蓝牙连接;现象:断开提示音播放、灯效为:等待蓝牙连接灯效红蓝交替闪、手机APP端显示未连接;
原因分析
一、先补充一个讲解技术背景:耳机和手机之间的连接是"一条线 + 多个业务"
手机和耳机之间,蓝牙底层先建立一条链路(可以理解成一根"网线",日志里的 acl/num/nor 就是描述它的),在这根"网线"上再跑几个"业务通道":
| 业务 | 作用 | 日志里的代号 |
|---|---|---|
| A2DP | 传音乐(音频流) | a2dp |
| AVRCP | 传播放/暂停/切歌控制指令 | avctp |
| SPP | 传 APP 数据(AB-Mate APP 走这条) | spp0 |
| BLE | APP 的另一条低功耗通道 | ble |
"正常断开" = 整根网线被拔掉(所有业务一起没),耳机立刻收到断开通知,于是播放断开提示音、灯效切红蓝闪、通知 APP。 "假断开" = 只停了音乐业务,网线还插着------耳机只收到"音乐流停止",收不到断开通知,自然什么都不做。
二、那么vivo手机是怎么做造成了这个BUG
1、vivo手机断开前,一切都正常;所有状态都正常
`[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=1, play=0, avctp=1, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=1, play=0, avctp=1, spp0=1, ble=1`
2、vivo手机页面设置点击断开蓝牙的那一刻
`CLOSE //手机开始关闭媒体
avdtp_end_of_play 0:hdl ffff //音频流结束了
[ZDY-DBG] notice-MUSIC_STOP: disp=6, acl=0, nor=1, num=1, a2dp=1, play=0, avctp=0, spp0=1, ble=1 //AVRCP 控制通道先被拆了
[ZDY-DBG] EVT-MUSIC_STOP: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1 //A2DP音乐通道也被拆了`
3、点击断开蓝牙操作后10秒
`[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1
[ZDY-DBG] 1S-trace: disp=6, acl=0, nor=1, num=1, a2dp=0, play=0, avctp=0, spp0=1, ble=1`
这10行每秒一次的状态,10秒纹丝未动
1、a2dp=0, avctp=0:媒体业务确实被 vivo 关了(所以手机声音外放了)
2、但 num=1, nor=1:整条"网线"(ACL 链路)还好好插着
3、spp0=1, ble=1:APP 的 SPP/BLE 通道还活着(所以 APP 一直显示"已连接")
整段日志里从头到尾没有出现 BT_NOTICE_DISCONNECT------耳机压根没收到断开通知。
三、结论
vivo 在设置页点"断开"时,看到 APP 的 SPP/BLE 通道还在用,就只拆了媒体业务(A2DP/AVRCP),把整条链路留了下来。耳机端只收到"音乐流停止"一个事件,于是:
显示状态还停在"已连接"(disp=6)→ 蓝灯低频慢闪(连接灯效)
1、没有断开事件 → 不播断开提示音
2、SPP 还连着 → APP 不显示断开
3、A2DP 已关 → 声音回手机外放
而华为手机是另一套做法:设置页断开蓝牙连接后直接拔整根网线,断开通知完整到达耳机,所以华为一切正常。差异在手机端策略,不在耳机,耳机想等通知永远等不到------只能靠自己判断后主动断。
解决方案
1.抓住可疑时刻(EVT_A2DP_MUSIC_STOP事件)

`#if LYF_APP_VIVO_BT_DISCONNECT_BUG
static u8 zdy_vivo_fake_disc_flag = 0; //vivo假断开复查标志(1=EVT_A2DP_MUSIC_STOP时A2DP profile已断)
#endif // LYF_APP_VIVO_BT_DISCONNECT_BUG`
vivo 假断开时,流停止事件必定会送到消息层(L123 的 EVT-MUSIC_STOP)。在这里查一眼:

`#if LYF_APP_VIVO_BT_DISCONNECT_BUG
//vivo等手机设置页断开只关A2DP/AVRCP不断ACL: 流停止时profile已断即疑似假断开, 1S后复查确认
if (a2dp_is_connect() == 0) {
zdy_vivo_fake_disc_flag = 1;
printf("[ZDY-DBG] fake-disc suspect: num=%d\n", bt_get_connected_num());
}
#endif // LYF_APP_VIVO_BT_DISCONNECT_BUG`
2. 1秒后复查(借用每秒一次的MSG_SYS_1S的消息)
光有步骤1还不够-其它手机断开时也会先经历A2DP音频数据流被终止"",所以等1秒再查三个条件:
|-----------------------------|------------------------------|----------------------|
| bt_get_connected_num() > 0 | 手机跟耳机的整条链路还连着(连接数 ≥1) | 排除华为式已正常断开(那时 num=0) |
| a2dp_is_connect() == 0 | A2DP 音乐通道依然是断的(1 秒过去没恢复) | 排除只是短暂断流后又恢复 |
| !bt_is_calling() | 不在通话中 (!=取反,即"不是正在通话") | 排除通话场景,通话时绝不能乱断 |

`#if LYF_APP_VIVO_BT_DISCONNECT_BUG
//假断开复查: 链路仍在且A2DP已断且不在通话 → 主动断开整条链路(0xff=断开不关机)
if (zdy_vivo_fake_disc_flag) {
zdy_vivo_fake_disc_flag = 0;
if (bt_get_connected_num() > 0 && a2dp_is_connect() == 0 && !bt_is_calling()) {
printf("[ZDY-DBG] fake-disc confirmed, bt_disconnect(0xff)\n");
bt_disconnect(0xff);
}
}
#endif // LYF_APP_VIVO_BT_DISCONNECT_BUG`
制作不易!喜欢的小伙伴给个小赞赞!喜欢我的小伙伴点个关注!有不懂的地方和需要的资源随时问我哟!