中科蓝讯SDK开发-BT893x 面条耳机连接vivo手机后连接APP端,最后手机端设置页面手动断开蓝牙连接,此时耳机端假断开

前言

现在为止也开发了许多杰理和中科蓝讯蓝牙芯片的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`

制作不易!喜欢的小伙伴给个小赞赞!喜欢我的小伙伴点个关注!有不懂的地方和需要的资源随时问我哟!

相关推荐
m0_3807438722 分钟前
PHP7.1项目升级到8.3报错怎么解决
开发语言·php
wulechun25 分钟前
跨越传统搜索引擎的信息壁垒:深度解析Last30Days-skill开源项目架构、信号评分体系与实战使用方法
智能手机
企业解惑小助手30 分钟前
电脑数据防泄密软件架构设计:从业务需求到落地运营全方案
电脑
泡海椒36 分钟前
JQuick-Excel 字段映射实战:用 MAPPING 固化 Excel 表头与业务字段契约
xml·java·开发语言·excel
lcj251137 分钟前
【C++】set和map——详细使用说明
开发语言·c++·笔记·面试
潼心1412o38 分钟前
C++初阶(长期更新)第3讲:类和对象(中)
开发语言·c++
zhangrelay39 分钟前
Arduino-MEGA单片机智能大模型解答案例对比-正反
单片机·嵌入式硬件
NYFEA44 分钟前
NYFEA徕飞5.5V 2.5F模组式超级法拉电容NM系列:大容量储能的多元应用场景
物联网
华允物联-HUAIOT1 小时前
插卡式 SIM 和贴片式 SIM 怎么选?从项目需求到长期运维一次讲清楚
物联网
外收内放1 小时前
Python基础语法练习题(40-42)
开发语言·python