记录一次调试A2DP无法播放音乐问题的过程

本文描述了一位技术人员在测试公司自研蓝牙协议栈与Thinkpad笔记本电脑连接时遇到的音乐播放问题。通过排除法,确定问题源于AVRCP交互中的错误,具体是AVRCP发送Get_Capabilities响应时多出4个字节,导致电脑不启动A2DP媒体流。修复此问题后,连接恢复正常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一次测试公司自研的蓝牙协议栈同自己的笔记本电脑(Thinkpad)连接时,发现连接成功后,无法播放音乐,点击电脑右下角的喇叭图标,只有一个Hands-Free AG audio图标,没有A2DP Stereo audio图标,如图:
在这里插入图片描述
抓取协议栈hci log进一步分析发现,HFP、AVRCP、AVDTP signaling channel、AVDTP Media Channel均有连上,AVDTP Signaling channel上也有正常的配置交互流程,但是在电脑上播放音乐,电脑不会发送AVDTP_START命令:
在这里插入图片描述
继续追AVDTP signaling channel & AVDTP media channel l2cap建立的过程,也没有发现问题:
signaling channel:
signaling channel l2cap建立过程
media channel:
media channel l2cap建立过程
查看SDP的交互流程,
对端设备有成功获取A2DP Sink Attribute, AVRCP Controller Attribute,AVRCP Target Attribute,HFP Attribute:
A2DP Sink SDK Attribute

AVRCP Controller SDP Attribute

AVRCP Target SDP Attribute

HFP SDP Attribute

到此,所有的流程和配置均没有发现问题,且使用此协议栈同手机连接,可以正常打电话和播音乐。

我有以下几个猜想:

1.是否是我用的这台电脑的蓝牙有问题?
有可能这台电脑蓝牙所使用的协议栈,驱动,或者硬件有问题,虽然概率极低,但是也不能排除,于是我用自己的漫步者蓝牙耳机同电脑连接,发现一切正常,可以打电话、播放音乐。
在这里插入图片描述

可以排除这个猜想。

2.是否是本端Controller的问题?
我们公司的Controller chip量产时间不久,测试覆盖面不大,没有和这一类笔记本电脑测试过,在之前的测试中也遇到因为Controller不完全遵循BT Spec导致的一些问题,所以也可以猜想是否是类似的原因。
于是我将bluekitchen btstack 移植到了我们的RTOS SDK中(在移植之前,我用btstack搭配高通csr8311蓝牙模块做了简单的测试,以确保btstack在配置上没有问题),测试发现,btstack搭配我们公司的controller,连接笔记本电脑,依旧没有问题,可以正常的打电话、播音乐。
在这里插入图片描述
Controller有问题的猜想也可以排除,由此可以确定是Host的问题。

3.确定是本端Host的问题
我在上一步测试中,抓取了btstack的hci log,通过对比我们协议栈的hci log 和 btstack hci log,尝试从中找出不同的地方,来进一步定位问题点。
以下是不同点:
(1)在建立ACL链接时设置的Role不同
our stack role: master
在这里插入图片描述
在这里插入图片描述
btstack role: slave
在这里插入图片描述在这里插入图片描述
这里不同的Role设置会带来什么影响呢?我也不清楚,只能去查下Core Spec:
HCI_ACCEPT_CONNECTION_REQUEST_CMD:
在这里插入图片描述
在这里插入图片描述
HCI_SWITCH_ROLE_CMD:
在这里插入图片描述
HCI_ROLE_CHANGE_EVT:
在这里插入图片描述
HCI_ERR_CODE_ROLE_CHANGE_NOT_ALLOWED:
在这里插入图片描述
将role也改为slave,再次测试,还是没有效果,这个差异带来的影响可以排除。

(2)SDP Request Response方式不同,导致Profile建立的顺序不同
在收到对端发来的SDP Search/Attribute Request后,our stack每次只回复1-2个SDP attribute,然后对端继续发送SDP Search/Attribute Request,直到获取所有的SDP attribute,而btstack一次性回复所有的SDP attribute。
经过仔细对比,发现在建立SDP l2cap channel时,l2cap configuration流程中,our stack给SDP l2cap channel配置的mtu size为128,而btstack配置的mtu size为1024。
our stack:
在这里插入图片描述
在这里插入图片描述
btstack:
在这里插入图片描述
将SDP MTU改为1024后,再次测试,SDP交互流程已经和btstack相同,且profile建立顺序也一样,但依然没有效果,这个差异带来的影响可以排除。

(3)AVRCP交互流程不同
our stack:
在这里插入图片描述
btstack:
在这里插入图片描述
查看代码发现,our stack中AVRCP配置为CT角色,而btstack中AVRCP配置为CT & TG双角色,想要快速定位是否是AVRCP带来的问题,直接关闭AVRCP feature就好。
关闭AVRCP feature后,再次测试,奇迹出现了,A2DP stereo出现了,可以正常播放音乐,打电话。
在这里插入图片描述
到此,终于定位到了问题来源是AVRCP,经过仔细查阅AVRCP SPEC,发现并没有强制要求设置为双角色,只要行为和角色定义一致就行。并且我将AVRCP role和交互流程改为和btstack相同之后,问题仍未解决。

最终经过仔细对比our stack & btstack AVRCP hci log,发现our stack在回复电脑发来的AVRCP Get_Capabilities时,l2cap layer多发送了4个字节0x00
在这里插入图片描述
最后查看代码,发现是在填写avrcp_send_get_cap_resp的buffer length时,多给了4个byte,将buffer length纠正之后,问题就解决了。
这里不得不吐槽下这段祖传代码,这么重要的length参数居然写的hard-code,可见代码规范是多么的重要啊!

bt_status_t avrcp_send_get_cap_resp(bt_conn_t *p_conn)
{
    UINT32 ret;
    hci_data_t *h_buff;
    BTD("[avrcp]%s\n", __func__);

    ret = l2cap_get_write_buffer(p_conn->avrcp->cid, 15, &h_buff);

    if (ret != BT_SUCCESS) {
        return BT_NORESOURCES;
    }
	/*部分代码略。。。*/
    return l2cap_write(p_conn->avrcp->cid, h_buff);
}

总结
秉着大胆猜想,小心求证的调试原则,层层抽丝剥茧,逐个排除可疑点,发现AVRCP Get Capabilities的response packet尾部多了4个byte 0x00,竟然会导致电脑端不发送A2DP Media stream,而我测试了几只手机,它们却忽略尾部多余的4 byte 0x00,蓝牙协议栈的调试实在是太有趣了。最开始我还在怀疑是否是Thinkpad蓝牙协议栈做的不太规范,结果发现是因为人家做的太规范了,这里给Thinkpad点赞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值