博主简介
byte轻骑兵,现就职于国内知名科技企业,专注于嵌入式系统研发,深耕 Android、Linux、RTOS、通信协议、AIoT、物联网及 C/C++ 等领域。乐于技术分享与交流,欢迎关注互动!
主页与联系方式
CSDN:https://blog.csdn.net/weixin_37800531
知乎:https://www.zhihu.com/people/38-72-36-20-51
微信公众号:嵌入式硬核研究所
邮箱:byteqqb@163.com(技术咨询或合作请备注需求)
⚠️ 版权声明
本文为原创内容,未经授权禁止转载。商业合作或内容授权请联系邮箱并备注来意。
本文详细解析蓝牙 AVDTP(Audio/Video Distribution Transport Protocol)协议中 Suspend Accept 响应的完整处理流程。Suspend Accept 由对端设备在成功处理 Suspend Command 后返回,用于确认流端点暂停完成。流程从 L2CAP 层接收响应开始,经 AVDTP 层消息重组与解析、CCB/SCB 事件处理,到 BTA 层状态更新、BTIF 层状态机转换,最终通知应用层。通过分层协作与严格的验证机制,确保流暂停状态的一致性与可靠性,为蓝牙音视频流控制提供关键支撑。
一、概述
Suspend Accept 是对端设备对 Suspend Command 的确认响应,标志着流端点(SEP)已成功暂停媒体传输。其处理流程体现了蓝牙协议栈的分层设计,核心环节如下:
1. 底层接收(L2CAP 层):对端发送的 Suspend Accept 经蓝牙射频层传输至本地,由acl_rcv_acl_data
接收后,通过l2c_rcv_acl_data
转发至 L2CAP 通道,最终触发 AVDTP 的回调avdt_l2c_data_ind_cback
,完成从物理层到协议层的初步路由。
2. 消息验证与重组(AVDTP 层):
avdt_ad_tc_data_ind
将信号通道(AVDT_CHAN_SIG
)的消息路由至avdt_msg_ind
,后者首先通过avdt_msg_asmbl
重组分片消息(若有),确保消息完整性。解析消息头部(
AVDT_MSG_PRS_HDR
)提取标签(Label)、包类型、消息类型,验证标签与本地发送的 Suspend Command 匹配(确保响应对应同一请求),并校验信号 ID(AVDT_SIG_ACCEPT
)的合法性。
3. 事件分发与流状态更新(AVDTP 层):
验证通过后,
avdt_msg_ind
触发 SCB(流控制块)事件AVDT_SCB_MSG_SUSPEND_RSP_EVT
,由avdt_scb_hdl_suspend_rsp
调用应用层回调AVDT_SUSPEND_CFM_EVT
,通知流暂停确认。SCB 更新流状态为 “非传输态”,释放编码器等资源。
4. 中间层处理(BTA 层):
bta_av_proc_stream_evt
将 AVDTP 事件转换为 BTA 层事件BTA_AV_STR_SUSPEND_CFM_EVT
,触发bta_av_better_stream_state_machine
状态机。bta_av_suspend_cfm
处理暂停结果:成功则标记流为 “未启动”,停止硬件卸载与协处理器,恢复链路低功耗模式(如 Sniff);失败则关闭连接。
5. 上层通知(BTIF 层→应用层):
BTA 层事件经
bta_av_source_callback
转发至 BTIF 层,btif_av_handle_event
定位对端设备实例(BtifAvPeer
)。状态机从 “已启动”(
StateStarted
)转换为 “已打开”(kStateOpened
),通过btif_report_audio_state
通知应用层更新音频状态(如 “远程暂停” 或 “已停止”)。
二、源码解析
Suspend Accept
Suspend Accept由对端设备在收到 Suspend Command 后返回,用于确认 “已成功暂停指定的流端点”,通知控制端暂停操作完成。
1. 触发条件
对端设备成功处理 Suspend Command:
验证所有请求暂停的 SEID 均有效且处于传输状态。
停止对应流的媒体传输(如关闭编码器输出、释放传输资源)。
更新本地流状态为 “暂停”(非传输状态)。
2. 协议格式
Suspend Accept 同样是 AVDTP 信号消息,格式与 Command 呼应,核心字段包括:
标签(Label):与对应 Suspend Command 的标签一致(确保匹配)。
信号 ID(Sig ID):固定为 “接受” 类型(通常对应
AVDT_SIG_ACCEPT
,具体值由协议规范定义)。SEID 列表:与 Command 中的 SEID 列表一致,确认哪些流已被暂停。
3. 控制端确认
控制端收到 Accept 后,通过回调(如AVDT_SUSPEND_CFM_EVT
)通知应用层,并更新本地流状态(p_scb->state
)为暂停。
acl_rcv_acl_data
l2c_rcv_acl_data(L2CEVT_L2CAP_DATA)
l2c_csm_execute(L2CEVT_L2CAP_DATA)
l2c_csm_open
p_rcb->api.pL2CA_DataInd_Cb (avdt_l2c_data_ind_cback)
packages/modules/Bluetooth/system/stack/avdt/avdt_l2c.cc
/*******************************************************************************
*
* Function avdt_l2c_data_ind_cback
*
* Description This is the L2CAP data indication callback function.
*
*
* Returns void
*
******************************************************************************/
void avdt_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
AvdtpTransportChannel* p_tbl;
// 通过 LCID 查找 AVDTP 传输通道
/* look up info for this channel */
p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
if (p_tbl != NULL) {
avdt_ad_tc_data_ind(p_tbl, p_buf);
} else /* prevent buffer leak */
osi_free(p_buf);
}
// 通过 L2CAP 通道 ID(LCID,Logical Channel ID)查找 AVDTP 适配层(Adaptation Layer)的传输通道表项,建立底层 L2CAP 通道与上层 AVDTP 传输通道的映射
packages/modules/Bluetooth/system/stack/avdt/avdt_ad.cc
/*******************************************************************************
*
* Function avdt_ad_tc_tbl_by_lcid
*
* Description Find adaption layer transport channel table entry by LCID.
*
*
* Returns Pointer to entry.
*
******************************************************************************/
AvdtpTransportChannel* avdt_ad_tc_tbl_by_lcid(uint16_t lcid) {
if (avdtp_cb.ad.lcid_tbl.count(lcid) != 0) {
uint8_t idx = avdtp_cb.ad.lcid_tbl[lcid];
return &avdtp_cb.ad.tc_tbl[idx];
} else {
return nullptr;
}
}
L2CAP的数据指示回调函数。当 L2CAP 层接收到数据并需要通知上层(AVDTP 协议)时,会调用此函数。
avdt_ad_tc_data_ind
packages/modules/Bluetooth/system/stack/avdt/avdt_ad.cc
/*******************************************************************************
*
* Function avdt_ad_tc_data_ind
*
* Description This function is called by the L2CAP interface layer when
* incoming data is received from L2CAP. It looks up the CCB
* or SCB for the channel and routes the data accordingly.
*
*
* Returns Nothing.
*
******************************************************************************/
void avdt_ad_tc_data_ind(AvdtpTransportChannel* p_tbl, BT_HDR* p_buf) {
AvdtpCcb* p_ccb;
AvdtpScb* p_scb;
// 存储通道类型到缓冲区
/* store type (media, recovery, reporting) */
p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
// 处理信号通道数据
// 用于传输控制命令及响应(如 Suspend Command/Accept、Start Command 等)
/* if signaling channel, handle control message */
if (p_tbl->tcid == 0) {
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
avdt_msg_ind(p_ccb, p_buf);
return;
}
// 处理媒体 / 其他通道数据(TCID≠0)
/* if media or other channel, send event to scb */
p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
if (p_scb == nullptr) {
log::error("Cannot find AvdtScb entry: ccb_idx:{} tcid:{}", p_tbl->ccb_idx,
p_tbl->tcid);
osi_free(p_buf);
log::error("buffer freed");
return;
}
avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT*)&p_buf);
}
// 将 AVDTP 内部的传输通道 ID(TCID)转换为对应的通道类型(channel type)
// 是avdt_ad_type_to_tcid的逆操作(前者将类型转为 TCID,后者将 TCID 还原为类型)
packages/modules/Bluetooth/system/stack/avdt/avdt_ad.cc
/*******************************************************************************
*
* Function avdt_ad_tcid_to_type
*
* Description Derives the channel type from the TCID.
*
*
* Returns Channel type value.
*
******************************************************************************/
static uint8_t avdt_ad_tcid_to_type(uint8_t tcid) {
uint8_t type;
if (tcid == 0) {
type = AVDT_CHAN_SIG;
} else {
/* tcid translates to type based on number of channels, as follows:
** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1...
** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2...
** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3...
*/
type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
}
log::verbose("tcid: {}, type: {}", tcid, type);
return type;
}
// 通过 CCB(Connection Control Block,连接控制块)的索引查找并返回对应的 CCB 指针
packages/modules/Bluetooth/system/stack/avdt/avdt_ccb.cc
/*******************************************************************************
*
* Function avdt_ccb_by_idx
*
* Description Return ccb pointer based on ccb index.
*
*
* Returns pointer to the ccb, or NULL if none found.
*
******************************************************************************/
AvdtpCcb* avdt_ccb_by_idx(uint8_t idx) {
AvdtpCcb* p_ccb;
/* verify index */
if (idx < AVDT_NUM_LINKS) {
p_ccb = &avdtp_cb.ccb[idx];
} else {
p_ccb = NULL;
log::warn("No ccb for idx {}", idx);
}
return p_ccb;
}
将 L2CAP 层接收到的数据(通过avdt_l2c_data_ind_cback
回调传入)路由到对应的上层处理逻辑(CCB 或 SCB)。
Suspend Accept 对应对应信号通道(AVDT_CHAN_SIG
),调用avdt_msg_ind
将信号消息交给消息指示函数处理。
avdt_msg_ind
packages/modules/Bluetooth/system/stack/avdt/avdt_msg.cc
/*******************************************************************************
*
* Function avdt_msg_ind
*
* Description This function is called by the adaption layer when an
* incoming message is received on the signaling channel.
* It parses the message and sends an event to the appropriate
* SCB or CCB for the message.
*
*
* Returns Nothing.
*
******************************************************************************/
void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) {
AvdtpScb* p_scb;
uint8_t* p;
bool ok = true;
bool handle_rsp = false;
bool gen_rej = false;
uint8_t label;
uint8_t pkt_type;
uint8_t msg_type;
uint8_t sig = 0;
tAVDT_MSG msg{};
AvdtpSepConfig cfg{};
uint8_t err;
uint8_t evt = 0;
uint8_t scb_hdl;
/* 重组消息;若仍在接收分片(p_buf为NULL),则返回 */
/* reassemble message; if no message available (we received a fragment) return
*/
p_buf = avdt_msg_asmbl(p_ccb, p_buf);
if (p_buf == NULL) {
return;
}
// 解析消息头部
p = (uint8_t*)(p_buf + 1) + p_buf->offset; // 定位到消息内容起始位置
/* parse the message header */
AVDT_MSG_PRS_HDR(p, label, pkt_type, msg_type); /* 解析消息头部(标签、包类型、消息类型) */
log::verbose("msg_type={}, sig={}", msg_type, sig);
/* set up label and ccb_idx in message hdr */
msg.hdr.label = label;
msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
// 消息类型验证(通用拒绝处理)
/* verify msg type */
if (msg_type == AVDT_MSG_TYPE_GRJ) {
log::warn("Dropping msg msg_type={}", msg_type);
ok = false;
}
/* check for general reject */
else if ((msg_type == AVDT_MSG_TYPE_REJ) &&
(p_buf->len == AVDT_LEN_GEN_REJ)) {
gen_rej = true;
if (p_ccb->p_curr_cmd != NULL) { // 若存在等待响应的命令
msg.hdr.sig_id = sig = (uint8_t)p_ccb->p_curr_cmd->event; // 关联命令的信号ID
evt = avdt_msg_rej_2_evt[sig - 1]; // 映射拒绝事件
msg.hdr.err_code = AVDT_ERR_NSC; // 错误码:不支持的命令
msg.hdr.err_param = 0;
}
}
//信号 ID 解析与验证
else /* not a general reject */
{
/* get and verify signal */
AVDT_MSG_PRS_SIG(p, sig); // 从消息中解析信号ID(如暂停命令的AVDT_SIG_SUSPEND=9)
msg.hdr.sig_id = sig;
if ((sig == 0) || (sig > AVDT_SIG_MAX)) {
log::warn("Dropping msg sig={} msg_type:{}", sig, msg_type);
ok = false;
/* send a general reject */
if (msg_type == AVDT_MSG_TYPE_CMD) { /* 若为命令消息,返回通用拒绝 */
avdt_msg_send_grej(p_ccb, sig, &msg);
}
}
}
// 消息内容解析(命令 / 响应 / 拒绝)
if (ok && !gen_rej) {
/* skip over header (msg length already verified during reassembly) */
p_buf->len -= AVDT_LEN_TYPE_SINGLE; /* 跳过头部长度(重组时已验证消息长度) */
/* set up to parse message */
if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_DISCOVER)) {
// 解析“发现响应”消息(关联应用层提供的SEP信息结构体)
/* parse discover rsp message to struct supplied by app */
msg.discover_rsp.p_sep_info = (tAVDT_SEP_INFO*)p_ccb->p_proc_data;
msg.discover_rsp.num_seps = p_ccb->proc_param;
} else if ((msg_type == AVDT_MSG_TYPE_RSP) &&
((sig == AVDT_SIG_GETCAP) || (sig == AVDT_SIG_GET_ALLCAP))) {
/* parse discover rsp message to struct supplied by app */
msg.svccap.p_cfg = (AvdtpSepConfig*)p_ccb->p_proc_data;
} else if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_GETCONFIG)) {
/* parse get config rsp message to struct allocated locally */
msg.svccap.p_cfg = &cfg;
} else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_SETCONFIG)) {
/* parse config cmd message to struct allocated locally */
msg.config_cmd.p_cfg = &cfg;
} else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_RECONFIG)) {
/* parse reconfig cmd message to struct allocated locally */
msg.reconfig_cmd.p_cfg = &cfg;
}
/* parse message; while we're at it map message sig to event */
if (msg_type == AVDT_MSG_TYPE_CMD) {
msg.hdr.err_code = err =
(*avdt_msg_prs_cmd[sig - 1])(&msg, p, p_buf->len);
evt = avdt_msg_cmd_2_evt[sig - 1];
} else if (msg_type == AVDT_MSG_TYPE_RSP) { // 解析响应消息
msg.hdr.err_code = err =
(*avdt_msg_prs_rsp[sig - 1])(&msg, p, p_buf->len);
evt = avdt_msg_rsp_2_evt[sig - 1];
} else /* msg_type == AVDT_MSG_TYPE_REJ */
{
err = avdt_msg_prs_rej(&msg, p, p_buf->len, sig);
evt = avdt_msg_rej_2_evt[sig - 1];
}
/* 解析失败处理 */
/* if parsing failed */
if (err != 0) {
log::warn("Parsing failed sig={} err=0x{:x}", sig, err);
/* if its a rsp or rej, drop it; if its a cmd, send a rej;
** note special case for abort; never send abort reject
*/
ok = false;
if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig != AVDT_SIG_ABORT)) {
avdt_msg_send_rej(p_ccb, sig, &msg);
}
}
}
/* if its a rsp or rej, check sent cmd to see if we're waiting for
** the rsp or rej. If we didn't send a cmd for it, drop it. If
** it does match a cmd, stop timer for the cmd.
*/
/* 对响应/拒绝消息,验证是否与当前等待的命令匹配 */
if (ok) {
if ((msg_type == AVDT_MSG_TYPE_RSP) || (msg_type == AVDT_MSG_TYPE_REJ)) {
// 检查:存在等待的命令、信号ID匹配、标签匹配
if ((p_ccb->p_curr_cmd != NULL) && (p_ccb->p_curr_cmd->event == sig) &&
(AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_cmd->layer_specific) == label)) {
/* stop timer */
alarm_cancel(p_ccb->idle_ccb_timer);
alarm_cancel(p_ccb->ret_ccb_timer);
alarm_cancel(p_ccb->rsp_ccb_timer);
/* clear retransmission count */
p_ccb->ret_count = 0;
/* later in this function handle ccb event */
handle_rsp = true;
} else {
ok = false;
log::warn("Cmd not found for rsp sig={} label={}", sig, label);
}
}
}
// 事件分发(CCB 或 SCB)
if (ok) {
/* if it's a ccb event send to ccb */
if (evt & AVDT_CCB_MKR) {
tAVDT_CCB_EVT avdt_ccb_evt;
avdt_ccb_evt.msg = msg;
avdt_ccb_event(p_ccb, (uint8_t)(evt & ~AVDT_CCB_MKR), &avdt_ccb_evt);
}
/* if it's a scb event */
else {
/* Scb events always have a single seid. For cmd, get seid from
** message. For rej and rsp, get seid from p_curr_cmd.
*/
/* SCB事件通常关联单个流:命令消息从消息中取SEID,响应/拒绝从当前命令中取 */
if (msg_type == AVDT_MSG_TYPE_CMD) {
scb_hdl = msg.single.seid;
} else {
scb_hdl = *((uint8_t*)(p_ccb->p_curr_cmd + 1));
}
/* Map seid to the scb and send it the event. For cmd, seid has
** already been verified by parsing function.
*/
/* 通过SEID查找SCB,发送事件 */
if (evt) {
p_scb = avdt_scb_by_hdl(scb_hdl);
if (p_scb != NULL) {
tAVDT_SCB_EVT avdt_scb_evt;
avdt_scb_evt.msg = msg;
avdt_scb_event(p_scb, evt, &avdt_scb_evt); // 触发SCB事件
}
}
}
}
/* free message buffer */
osi_free(p_buf);
/* if its a rsp or rej, send event to ccb to free associated
** cmd msg buffer and handle cmd queue
*/
/* 若为匹配的响应/拒绝,触发事件释放命令缓冲区并处理命令队列 */
if (handle_rsp) {
avdt_ccb_event(p_ccb, AVDT_CCB_RCVRSP_EVT, NULL);
}
}
AVDTP 协议处理接收信号通道消息的核心入口。当适配层(avdt_ad_tc_data_ind
)收到信号通道(AVDT_CHAN_SIG
)的消息时,会调用此函数解析消息并分发事件到对应的 CCB(连接控制块)或 SCB(流控制块)。
AVDT_MSG_PRS_HDR
#define AVDT_MSG_PRS_HDR(p, lbl, pkt, msg) \
do { \
(lbl) = (*(p) >> 4) & 0x0F; \
(pkt) = (*(p) >> 2) & 0x03; \
(msg) = *(p)++ & 0x03; \
} while (0)
从 AVDTP 消息的头部字节中解析出三个关键字段 ——标签(label)、包类型(packet type)、消息类型(message type)
假设头部字节为0bABCDEFGH
(8 位,A 为最高位,H 为最低位):
7 6 5 4 | 3 2 | 1 0 (位索引,从0开始)
--------|-----|-----
A B C D | E F | G H (位值)
标签(lbl) 包类型(pkt) 消息类型(msg)
(4位) (2位) (2位)
avdt_msg_asmbl
packages/modules/Bluetooth/system/stack/avdt/avdt_msg.cc
/*******************************************************************************
*
* Function avdt_msg_asmbl
*
* Description Reassemble incoming message.
*
*
* Returns Pointer to reassembled message; NULL if no message
* available.
*
******************************************************************************/
BT_HDR* avdt_msg_asmbl(AvdtpCcb* p_ccb, BT_HDR* p_buf) {
uint8_t* p;
uint8_t pkt_type;
BT_HDR* p_ret;
// 1. 消息头部解析与基础校验
/* parse the message header */
p = (uint8_t*)(p_buf + 1) + p_buf->offset;
/* Check if is valid length */
if (p_buf->len len p_rx_msg != NULL) log::warn("Got single during reassembly");
osi_free_and_reset((void**)&p_ccb->p_rx_msg);
p_ret = p_buf;
}
// 4. 处理起始分片
/* start packet */
else if (pkt_type == AVDT_PKT_TYPE_START) {
/* if reassembly in progress drop message and process new single */
if (p_ccb->p_rx_msg != NULL) log::warn("Got start during reassembly");
osi_free_and_reset((void**)&p_ccb->p_rx_msg);
/*
* Allocate bigger buffer for reassembly. As lower layers are
* not aware of possible packet size after reassembly, they
* would have allocated smaller buffer.
*/
if (sizeof(BT_HDR) + p_buf->offset + p_buf->len > BT_DEFAULT_BUFFER_SIZE) {
osi_free(p_buf);
p_ret = NULL;
return p_ret;
}
p_ccb->p_rx_msg = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
memcpy(p_ccb->p_rx_msg, p_buf, sizeof(BT_HDR) + p_buf->offset + p_buf->len);
/* Free original buffer */
osi_free(p_buf);
/* 更新指针到重组缓冲区的消息内容起始位置 */
/* update p to point to new buffer */
p = (uint8_t*)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset;
/* 调整头部:将首字节(包含标签、包类型等)复制到下一字节(覆盖后续分片数量字段) */
/* copy first header byte over nosp */
*(p + 1) = *p;
/* 设置重组缓冲区的偏移:指向下次分片数据的写入位置 */
/* set offset to point to where to copy next */
p_ccb->p_rx_msg->offset += p_ccb->p_rx_msg->len;
/* 调整长度:减去起始分片特有的1字节头部(后续分片不再需要) */
/* adjust length for packet header */
p_ccb->p_rx_msg->len -= 1;
p_ret = NULL;
}
// 8. 中间分片或结束分片
/* continue or end */
else {
/* if no reassembly in progress drop message */
if (p_ccb->p_rx_msg == NULL) {
osi_free(p_buf);
log::warn("Pkt type={} out of order", pkt_type);
p_ret = NULL;
} else {
/* get size of buffer holding assembled message */
/*
* NOTE: The buffer is allocated above at the beginning of the
* reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
*/
size_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
/* adjust offset and len of fragment for header byte */
p_buf->offset += AVDT_LEN_TYPE_CONT;
p_buf->len -= AVDT_LEN_TYPE_CONT;
/* verify length */
if (((size_t) p_ccb->p_rx_msg->offset + (size_t) p_buf->len) > buf_len) {
/* won't fit; free everything */
log::warn("Fragmented message too big!");
osi_free_and_reset((void**)&p_ccb->p_rx_msg);
osi_free(p_buf);
p_ret = NULL;
} else {
/* copy contents of p_buf to p_rx_msg */
memcpy((uint8_t*)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset,
(uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
if (pkt_type == AVDT_PKT_TYPE_END) {
p_ccb->p_rx_msg->offset -= p_ccb->p_rx_msg->len;
p_ccb->p_rx_msg->len += p_buf->len;
p_ret = p_ccb->p_rx_msg;
p_ccb->p_rx_msg = NULL;
} else {
p_ccb->p_rx_msg->offset += p_buf->len;
p_ccb->p_rx_msg->len += p_buf->len;
p_ret = NULL;
}
osi_free(p_buf);
}
}
}
return p_ret;
}
消息重组函数,负责将接收的分片消息(起始分片、中间分片、结束分片)拼接为完整消息,或直接处理单包消息。
avdt_ccb_event (MSG_SUSPEND_RSP_EVT)
见前文分析,直接看其对应的action函数。
avdt_scb_hdl_suspend_rsp
packages/modules/Bluetooth/system/stack/avdt/avdt_scb_act.cc
/*******************************************************************************
*
* Function avdt_scb_hdl_suspend_rsp
*
* Description This function calls the application callback with a suspend
* confirm.
*
* Returns Nothing.
*
******************************************************************************/
void avdt_scb_hdl_suspend_rsp(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
(*p_scb->stream_config.p_avdt_ctrl_cback)(
avdt_scb_to_hdl(p_scb),
p_scb->p_ccb ? p_scb->p_ccb->peer_addr : RawAddress::kEmpty,
AVDT_SUSPEND_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr,
p_scb->stream_config.scb_index);
}
将暂停操作的确认结果通知给应用层(如蓝牙音频播放器、视频播放器等)。
bta_av_proc_stream_evt(AVDT_SUSPEND_CFM_EVT)
packages/modules/Bluetooth/system/bta/av/bta_av_aact.cc
/*******************************************************************************
*
* Function bta_av_proc_stream_evt
*
* Description Utility function to compose stream events.
*
* Returns void
*
******************************************************************************/
void bta_av_proc_stream_evt(uint8_t handle, const RawAddress& bd_addr,
uint8_t event, tAVDT_CTRL* p_data,
uint8_t scb_index) {
// 1. 边界检查与流控制块获取
CHECK_LT(scb_index, BTA_AV_NUM_STRS);
tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[scb_index];
uint16_t sec_len = 0;
log::verbose(
"peer_address: {} avdt_handle: {} event=0x{:x} scb_index={} p_scb={}",
ADDRESS_TO_LOGGABLE_CSTR(bd_addr), handle, event, scb_index,
fmt::ptr(p_scb));
// 2. 安全事件数据长度处理
if (p_data) {
if (event == AVDT_SECURITY_IND_EVT) {
sec_len = (p_data->security_ind.len security_ind.len
: BTA_AV_SECURITY_MAX_LEN;
} else if (event == AVDT_SECURITY_CFM_EVT && p_data->hdr.err_code == 0) {
sec_len = (p_data->security_cfm.len security_cfm.len
: BTA_AV_SECURITY_MAX_LEN;
}
}
// 3. 构建 BTA 层事件消息(核心逻辑)
if (p_scb) {
tBTA_AV_STR_MSG* p_msg =
(tBTA_AV_STR_MSG*)osi_malloc(sizeof(tBTA_AV_STR_MSG) + sec_len);
/* copy event data, bd addr, and handle to event message buffer */
p_msg->hdr.offset = 0;
p_msg->bd_addr = bd_addr;
p_msg->scb_index = scb_index;
log::verbose("stream event bd_addr: {} scb_index: {}",
ADDRESS_TO_LOGGABLE_CSTR(p_msg->bd_addr), scb_index);
// 4. 填充事件具体数据(根据事件类型)
if (p_data != NULL) {
memcpy(&p_msg->msg, p_data, sizeof(tAVDT_CTRL));
// 根据事件类型处理特定数据(如配置、安全数据等)
/* copy config params to event message buffer */
switch (event) {
case AVDT_CONFIG_IND_EVT:
p_msg->cfg = *p_data->config_ind.p_cfg;
break;
case AVDT_SECURITY_IND_EVT:
p_msg->msg.security_ind.p_data = (uint8_t*)(p_msg + 1);
memcpy(p_msg->msg.security_ind.p_data, p_data->security_ind.p_data,
sec_len);
break;
case AVDT_SECURITY_CFM_EVT:
p_msg->msg.security_cfm.p_data = (uint8_t*)(p_msg + 1);
if (p_data->hdr.err_code == 0) {
memcpy(p_msg->msg.security_cfm.p_data, p_data->security_cfm.p_data,
sec_len);
}
break;
case AVDT_SUSPEND_IND_EVT:
p_msg->msg.hdr.err_code = 0;
break;
case AVDT_CONNECT_IND_EVT:
p_scb->recfg_sup = true;
p_scb->suspend_sup = true;
break;
default:
break;
}
} else {
p_msg->msg.hdr.err_code = 0;
}
// 5. 确定 BTA 层事件类型(成功 / 失败)
/* 映射AVDTP事件到BTA层事件(成功/失败) */
/* look up application event */
if ((p_data == NULL) || (p_data->hdr.err_code == 0)) {
p_msg->hdr.event = bta_av_stream_evt_ok[event];
} else {
p_msg->hdr.event = bta_av_stream_evt_fail[event];
}
// 6. 补充消息字段并发送
p_msg->initiator = false;
if (event == AVDT_SUSPEND_CFM_EVT) p_msg->initiator = true;
log::verbose("bta_handle:0x{:x} avdt_handle:{}", p_scb->hndl, handle);
p_msg->hdr.layer_specific = p_scb->hndl;
p_msg->handle = handle;
p_msg->avdt_event = event;
bta_sys_sendmsg(p_msg);
}
// 7. 连接回调处理
if (p_data) {
bta_av_conn_cback(handle, bd_addr, event, p_data, scb_index);
} else {
log::error("p_data is null");
}
}
将底层 AVDTP 协议栈的流事件(如暂停、配置、安全指示等)转换为 BTA 层的事件消息,并发送给上层应用处理。
bta_sys_sendmsg(BTA_AV_STR_SUSPEND_CFM_EVT)
bta_sys_sendmsg消息发送机制多次讲过,不再赘述,直接看对应的事件处理函数。
bta_av_better_stream_state_machine
packages/modules/Bluetooth/system/bta/av/bta_av_ssm.cc
static void bta_av_better_stream_state_machine(tBTA_AV_SCB* p_scb,
uint16_t event,
tBTA_AV_DATA* p_data) {
uint8_t previous_state = p_scb->state;
tBTA_AV_ACT event_handler1 = nullptr;
tBTA_AV_ACT event_handler2 = nullptr;
switch (p_scb->state) {
...
case BTA_AV_OPEN_SST:
switch (event) {
...
case BTA_AV_STR_SUSPEND_CFM_EVT:
event_handler1 = &bta_av_suspend_cfm;
break;
...
if (previous_state != p_scb->state) {
log::info(
"peer {} p_scb={:#x}({}) AV event=0x{:x}({}) state={}({}) -> {}({})",
ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl,
fmt::ptr(p_scb), event, bta_av_evt_code(event), previous_state,
bta_av_sst_code(previous_state), p_scb->state,
bta_av_sst_code(p_scb->state));
} else {
log::verbose("peer {} p_scb={:#x}({}) AV event=0x{:x}({}) state={}({})",
ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl,
fmt::ptr(p_scb), event, bta_av_evt_code(event), p_scb->state,
bta_av_sst_code(p_scb->state));
}
if (event_handler1 != nullptr) {
event_handler1(p_scb, p_data);
}
if (event_handler2 != nullptr) {
event_handler2(p_scb, p_data);
}
}
bta_av_suspend_cfm
packages/modules/Bluetooth/system/bta/av/bta_av_aact.cc
/*******************************************************************************
*
* Function bta_av_suspend_cfm
*
* Description process the suspend response
*
* Returns void
*
******************************************************************************/
void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
tBTA_AV_SUSPEND suspend_rsp = {};
uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
log::verbose("peer {} bta_handle:0x{:x} audio_open_cnt:{} err_code:{}",
ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), p_scb->hndl,
bta_av_cb.audio_open_cnt, err_code);
// 1. 处理已暂停状态(避免重复操作)
if (!p_scb->started) {
/* handle the condition where there is a collision of SUSPEND req from
*either side
** Second SUSPEND req could be rejected. Do not treat this as a failure
*/
log::warn("already suspended, ignore, err_code {}", err_code);
return;
}
// 2. 暂停结果处理(成功 / 失败分支)
suspend_rsp.status = BTA_AV_SUCCESS;
if (err_code && (err_code != AVDT_ERR_BAD_STATE)) {
suspend_rsp.status = BTA_AV_FAIL;
log::error("suspend failed, closing connection");
/* SUSPEND failed. Close connection. */
bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
} else {
/* only set started to false when suspend is successful */
p_scb->started = false; /* 暂停成功:标记流为"未启动"状态 */
}
// 3. 角色与拥塞状态重置
if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
p_scb->role &= ~BTA_AV_ROLE_SUSPEND;
p_scb->cong = false;
}
// 4. 系统状态与模式恢复
bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
// 解除角色切换和嗅探模式阻塞
BTM_unblock_role_switch_and_sniff_mode_for(p_scb->PeerAddress());
// 5. 协处理器与音频卸载停止(硬件相关)
/* in case that we received suspend_ind, we may need to call co_stop here */
if (p_scb->co_started) {
// 若当前流是正在卸载的音频流,停止硬件卸载
if (bta_av_cb.offload_started_hndl == p_scb->hndl) {
bta_av_vendor_offload_stop();
bta_av_cb.offload_started_hndl = BTA_AV_INVALID_HANDLE;
}
// 若当前流是待启动卸载的音频流,取消 pending 的卸载
else if (bta_av_cb.offload_start_pending_hndl == p_scb->hndl) {
log::warn("Stop pending offload start command");
bta_av_vendor_offload_stop();
bta_av_cb.offload_start_pending_hndl = BTA_AV_INVALID_HANDLE;
}
bta_av_stream_chg(p_scb, false); // 通知流状态变化(从启动→暂停)
{
p_scb->co_started = false; // 标记协处理器已停止
p_scb->p_cos->stop(p_scb->hndl, p_scb->PeerAddress()); // 调用协处理器停止接口
}
}
// 6. 通知应用层暂停结果
{
suspend_rsp.chnl = p_scb->chnl;
suspend_rsp.hndl = p_scb->hndl;
suspend_rsp.initiator = p_data->str_msg.initiator;
tBTA_AV bta_av_data;
bta_av_data.suspend = suspend_rsp;
(*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, &bta_av_data); // 回调应用层
}
}
接收底层 AVDTP 层的暂停响应结果,更新流状态,处理成功 / 失败逻辑,并通知应用层最终结果。
BTM_unblock_role_switch_and_sniff_mode_for
packages/modules/Bluetooth/system/stack/acl/btm_acl.cc
/* Policy settings status */
typedef enum : uint16_t {
HCI_DISABLE_ALL_LM_MODES = 0,
HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH = (1u link_policy & ~flag);
}
// 清除flag对应的策略位(关闭指定模式)
void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy) {
conn->link_policy = policy;
check_link_policy(&conn->link_policy);
// 特殊处理:若启用主从切换,且设备需禁用嗅探模式(互操作配置),则强制关闭嗅探
if ((conn->link_policy & HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH) &&
interop_match_addr(INTEROP_DISABLE_SNIFF, &(conn->remote_addr))) {
conn->link_policy &= (~HCI_ENABLE_SNIFF_MODE);
}
// 发送HCI命令,将策略写入控制器(硬件层面生效)
btsnd_hcic_write_policy_set(conn->hci_handle,
static_cast(conn->link_policy));
}
在流暂停完成后调用,恢复设备的低功耗能力和角色灵活性(流传输时为保证实时性阻塞这些模式)。
HCI Write Link Policy Settings (Connection=0x0080, Settings=Role Switch | Sniff Mode)
bta_av_stream_chg
packages/modules/Bluetooth/system/bta/av/bta_av_act.cc
/*******************************************************************************
*
* Function bta_av_stream_chg
*
* Description audio streaming status changed.
*
* Returns void
*
******************************************************************************/
void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started) {
uint8_t started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
log::verbose("peer {} started:{} started_msk:0x{:x}",
ADDRESS_TO_LOGGABLE_CSTR(p_scb->PeerAddress()), logbool(started),
started_msk);
if (started) {
/* Let L2CAP know this channel is processed with high priority */
L2CA_SetAclPriority(p_scb->PeerAddress(), L2CAP_PRIORITY_HIGH);
} else {
/* Let L2CAP know this channel is processed with low priority */
L2CA_SetAclPriority(p_scb->PeerAddress(), L2CAP_PRIORITY_NORMAL);
}
}
当流启动(started=true
)或停止 / 暂停(started=false
)时,调整底层 L2CAP 链路的优先级,以优化实时音频传输。
L2CAP 优先级调整:
L2CA_SetAclPriority
:L2CAP 层的函数,用于设置 ACL链路的传输优先级。ACL 是蓝牙中用于传输非实时和实时数据的基础链路(音频流通常通过 ACL 传输)。流启动(
started=true
):设置为L2CAP_PRIORITY_HIGH
(高优先级),确保音频流数据在蓝牙链路上被优先调度,减少延迟(实时音频对延迟敏感,高优先级可避免卡顿)。流停止 / 暂停(
started=false
):设置为L2CAP_PRIORITY_NORMAL
(正常优先级),释放高优先级资源,避免占用过多带宽,不影响其他低优先级数据(如文件传输)的传输。
p_scb->p_cos->stop(bta_av_co_audio_stop)
packages/modules/Bluetooth/system/btif/co/bta_av_co.cc
void bta_av_co_audio_stop(tBTA_AV_HNDL bta_av_handle,
const RawAddress& peer_address) {
bta_av_co_cb.ProcessStop(bta_av_handle, peer_address);
}
void BtaAvCo::ProcessStop(tBTA_AV_HNDL bta_av_handle,
const RawAddress& peer_address) {
log::verbose("peer {} bta_av_handle: 0x{:x}",
ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle);
// Nothing to do
}
(*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, &bta_av_data)
bta_av_source_callback
packages/modules/Bluetooth/system/btif/src/btif_av.cc
static void bta_av_source_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {
BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV)); // 封装事件信息
log::verbose("event={}", btif_av_event.ToString());
// 将事件处理调度到主线程执行
do_in_main_thread(
FROM_HERE, base::BindOnce(&btif_av_handle_bta_av_event,
AVDT_TSEP_SNK /* peer_sep */, btif_av_event));
}
/**
* Process BTA AV or BTA AVRCP events. The processing is done on the JNI
* thread.
*
* @param peer_sep the corresponding peer's SEP: AVDT_TSEP_SRC if the peer
* is A2DP Source, or AVDT_TSEP_SNK if the peer is A2DP Sink.
* @param btif_av_event the corresponding event
*/
static void btif_av_handle_bta_av_event(uint8_t peer_sep,
const BtifAvEvent& btif_av_event) {
RawAddress peer_address = RawAddress::kEmpty;
tBTA_AV_HNDL bta_handle = kBtaHandleUnknown;
tBTA_AV_EVT event = btif_av_event.Event();
tBTA_AV* p_data = (tBTA_AV*)btif_av_event.Data();
std::string msg;
log::debug(
"jni_thread: Handle BTA AV or AVRCP event {}: peer_sep={} event={}",
peer_stream_endpoint_text(peer_sep), peer_sep, btif_av_event.ToString());
switch (event) {
...
case BTA_AV_SUSPEND_EVT:
case BTA_AV_STOP_EVT: {
const tBTA_AV_SUSPEND& suspend = p_data->suspend; // 提取暂停/停止事件数据
bta_handle = suspend.hndl; // 获取流句柄(标识具体的音频流)
msg = "Stream stopped"; // 事件描述消息(暂停/停止均视为流停止状态)
break;
}
...
if (!msg.empty()) {
BTM_LogHistory(kBtmLogHistoryTag, peer_address, msg,
btif_av_event.ToString());
}
// 将事件转发给更上层处理函数
btif_av_handle_event(peer_sep, peer_address, bta_handle, btif_av_event);
}
当 BTA 层发生 AV 相关事件(如流暂停、停止、配置变化等)时,会触发此回调,将事件传递到 BTIF(Bluetooth Interface,蓝牙接口层)处理。
btif_av_handle_event
packages/modules/Bluetooth/system/btif/src/btif_av.cc
/**
* Process BTIF or BTA AV or BTA AVRCP events. The processing is done on the
* JNI thread.
*
* @param peer_sep the corresponding peer's SEP: AVDT_TSEP_SRC if the peer
* is A2DP Source, or AVDT_TSEP_SNK if the peer is A2DP Sink.
* @param peer_address the peer address if known, otherwise RawAddress::kEmpty
* @param bta_handle the BTA handle for the peer if known, otherwise
* kBtaHandleUnknown
* @param btif_av_event the corresponding event
*/
static void btif_av_handle_event(uint8_t peer_sep,
const RawAddress& peer_address,
tBTA_AV_HNDL bta_handle,
const BtifAvEvent& btif_av_event) {
log::debug("Handle event peer_address={} bta_handle=0x{:x}",
ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle);
BtifAvPeer* peer = nullptr; // 对端设备在BTIF层的抽象实例(存储连接状态、配置等)
// 查找或创建对端设备实例(BtifAvPeer)
// Find the peer
if (btif_av_src_sink_coexist_enabled()) {
peer = btif_av_handle_both_peer(peer_sep, peer_address, bta_handle);
} else {
if (peer_address != RawAddress::kEmpty) {
if (peer_sep == AVDT_TSEP_SNK) {
peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle);
} else if (peer_sep == AVDT_TSEP_SRC) {
peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle);
}
} else if (bta_handle != kBtaHandleUnknown) {
if (peer_sep == AVDT_TSEP_SNK) {
peer = btif_av_source.FindPeerByHandle(bta_handle);
} else if (peer_sep == AVDT_TSEP_SRC) {
peer = btif_av_sink.FindPeerByHandle(bta_handle);
}
}
}
if (peer == nullptr) {
log::error(
"jni_thread: Cannot find or create {} peer for peer_address={} "
"bta_handle=0x{:x} : event dropped: {}",
peer_stream_endpoint_text(peer_sep),
ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle,
btif_av_event.ToString());
return;
}
// 触发 peer 状态机处理事件
peer->StateMachine().ProcessEvent(btif_av_event.Event(),
btif_av_event.Data());
}
/**
* Process an event.
* TODO: The arguments are wrong - used for backward compatibility.
* Will be replaced later.
*
* @param event the event type
* @param p_data the event data
* @return true if the processing was completed, otherwise false
*/
bool ProcessEvent(uint32_t event, void* p_data) {
if (current_state_ == nullptr) return false;
return current_state_->ProcessEvent(event, p_data); // 调用当前状态的事件处理方法
}
将事件分发到对应的对端设备实例(BtifAvPeer
),由其状态机处理。
FindOrCreatePeer
packages/modules/Bluetooth/system/btif/src/btif_av.cc
BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address,
tBTA_AV_HNDL bta_handle) {
std::unique_lock lock1(mutex_);
log::verbose("peer_address={} bta_handle=0x{:x}",
ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle);
// 1. 查找已有对端实例(优先查找)
BtifAvPeer* peer = FindPeer(peer_address);
if (peer != nullptr) return peer;
// 2. 分配唯一的peer_id(对端标识)
// Find next availabie Peer ID to use
uint8_t peer_id;
for (peer_id = kPeerIdMin; peer_id second == kBtaHandleUnknown) {
log::error(
"Cannot create peer for peer_address={} : cannot convert Peer ID={} "
"to unique BTA Handle",
ADDRESS_TO_LOGGABLE_CSTR(peer_address), peer_id);
return nullptr;
}
bta_handle = it->second;
}
// 4. 创建并初始化对端实例
log::info("Create peer: peer_address={} bta_handle=0x{:x} peer_id={}",
ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle, peer_id);
peer = new BtifAvPeer(peer_address, AVDT_TSEP_SNK, bta_handle, peer_id);
peers_.insert(std::make_pair(peer_address, peer));
peer->Init();
return peer;
}
BtifAvSource
中查找或创建对端设备实例(BtifAvPeer
) 的方法。用于确保每个对端设备(如蓝牙耳机)在 BTIF 层有唯一的抽象实例,统一管理其连接状态、流配置等。
BtifAvStateMachine::StateStarted::ProcessEvent (BTA_AV_SUSPEND_EVT)
packages/modules/Bluetooth/system/btif/src/btif_av.cc
bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event,
void* p_data) {
tBTA_AV* p_av = (tBTA_AV*)p_data;
log::verbose("Peer {} : event={} flags={} active_peer={}",
ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),
BtifAvEvent::EventName(event), peer_.FlagsToString(),
logbool(peer_.IsActivePeer()));
switch (event) {
...
case BTA_AV_SUSPEND_EVT: {
log::info("Peer {} : event={} status={} initiator={} flags={}",
ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),
BtifAvEvent::EventName(event), p_av->suspend.status,
p_av->suspend.initiator, peer_.FlagsToString());
// A2DP suspended, stop A2DP encoder / decoder until resumed
if (peer_.IsActivePeer() || !btif_av_stream_started_ready()) {
btif_a2dp_on_suspended(&p_av->suspend);
}
// 处理暂停失败的情况
// If not successful, remain in current state
if (p_av->suspend.status != BTA_AV_SUCCESS) {
peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);
if (peer_.IsSink() && peer_.IsActivePeer()) {
// Suspend failed, reset back tx flush state
// 若为接收端且活跃,重置发送刷新状态(避免数据残留)
btif_a2dp_source_set_tx_flush(false);
}
return false;
}
// 确定音频状态(本地 / 远程暂停区分)
btav_audio_state_t state = BTAV_AUDIO_STATE_REMOTE_SUSPEND;
if (p_av->suspend.initiator != true) {
// Remote suspend, notify HAL and await audioflinger to
// suspend/stop stream.
//
// Set remote suspend flag to block media task from restarting
// stream only if we did not already initiate a local suspend.
if (!peer_.CheckFlags(BtifAvPeer::kFlagLocalSuspendPending))
peer_.SetFlags(BtifAvPeer::kFlagRemoteSuspend);
} else {
state = BTAV_AUDIO_STATE_STOPPED; // 本地发起的暂停:状态标记为“已停止”
}
// 报告状态并转换状态机
btif_report_audio_state(peer_.PeerAddress(), state);
// Suspend completed, clear local pending flags while entering Opened
peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateOpened);
} break;
...
default:
log::warn("Peer {} : Unhandled event={}",
ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),
BtifAvEvent::EventName(event));
return false;
}
return true;
}
packages/modules/Bluetooth/system/btif/src/btif_a2dp_source.cc
/* when true media task discards any tx frames */
void btif_a2dp_source_set_tx_flush(bool enable) {
log::info("enable={} state={}", (enable) ? "true" : "false",
btif_a2dp_source_cb.StateStr());
btif_a2dp_source_cb.tx_flush = enable;
}
在 “已启动”(StateStarted
)状态下处理BTA_AV_SUSPEND_EVT
(暂停事件)的核心逻辑是:
资源释放:停止 A2DP 编码 / 解码资源,避免暂停期间的无效消耗。btif_a2dp_on_suspended
失败处理:暂停失败时保持当前状态,清理标志位,确保状态一致性。
状态区分:根据发起方(本地 / 远程)设置不同的音频状态,并用标志位控制流的重启权限。
状态转换:暂停成功后,从 “已启动” 转为 “已打开”,完成状态闭环,并通知上层更新 UI。
btif_report_audio_state
packages/modules/Bluetooth/system/btif/src/btif_av.cc
/**
* Report the audio state of the A2DP connection.
* The state is updated when either the remote ends starts streaming
* (Started state) or whenever it transitions out of Started state
* (to Opened or Streaming state).
*
* @param peer_address the peer address
* @param state the audio state
*/
static void btif_report_audio_state(const RawAddress& peer_address,
btav_audio_state_t state) {
log::info("peer_address={} state={}", ADDRESS_TO_LOGGABLE_CSTR(peer_address),
state);
if (btif_av_both_enable()) {
BtifAvPeer* peer = btif_av_find_peer(peer_address);
if (peer->IsSink()) {
do_in_jni_thread(
FROM_HERE, base::BindOnce(btif_av_source.Callbacks()->audio_state_cb,
peer_address, state));
} else if (peer->IsSource()) {
do_in_jni_thread(FROM_HERE,
base::BindOnce(btif_av_sink.Callbacks()->audio_state_cb,
peer_address, state));
}
return;
}
if (btif_av_source.Enabled()) {
do_in_jni_thread(FROM_HERE,
base::BindOnce(btif_av_source.Callbacks()->audio_state_cb,
peer_address, state));
} else if (btif_av_sink.Enabled()) {
do_in_jni_thread(FROM_HERE,
base::BindOnce(btif_av_sink.Callbacks()->audio_state_cb,
peer_address, state));
}
// 记录 A2DP 播放事件(统计与调试)
// 定义A2DP播放状态和编码模式枚举
using android::bluetooth::a2dp::AudioCodingModeEnum;
using android::bluetooth::a2dp::PlaybackStateEnum;
PlaybackStateEnum playback_state = PlaybackStateEnum::PLAYBACK_STATE_UNKNOWN;
// 将btav_audio_state_t转换为PlaybackStateEnum(播放状态枚举)
switch (state) {
case BTAV_AUDIO_STATE_STARTED:
playback_state = PlaybackStateEnum::PLAYBACK_STATE_PLAYING;
break;
case BTAV_AUDIO_STATE_STOPPED:
playback_state = PlaybackStateEnum::PLAYBACK_STATE_NOT_PLAYING;
break;
default:
break;
}
// 确定音频编码模式(硬件卸载/软件编码)
AudioCodingModeEnum audio_coding_mode =
btif_av_is_a2dp_offload_running()
? AudioCodingModeEnum::AUDIO_CODING_MODE_HARDWARE
: AudioCodingModeEnum::AUDIO_CODING_MODE_SOFTWARE;
// 记录A2DP播放事件(用于统计、调试或日志分析)
log_a2dp_playback_event(peer_address, playback_state, audio_coding_mode);
}
当 A2DP 流状态发生变化(如从 “播放中” 转为 “暂停”“停止”)时,调用此函数通知上层,触发 UI 更新或逻辑处理。
三、时序图
四、流程图
Suspend Accept 的处理流程展现了蓝牙协议栈的严谨性与分层协作特性,核心特点包括:
严格的消息验证:通过标签匹配(确保响应与请求对应)、信号 ID 校验(确认响应合法性)、流状态验证(仅处理活跃流的响应),避免无效或乱序消息。
分层责任清晰:L2CAP 层负责传输,AVDTP 层处理协议解析与重组,BTA 层管理连接与资源,BTIF 层桥接至应用层,每层通过事件驱动实现松耦合协作。
状态一致性保障:从 AVDTP 的 SCB 状态更新,到 BTA 层的流标志重置,再到 BTIF 层的状态机转换,确保全链路状态同步,避免资源泄漏(如未释放的编码器)。
可靠性增强:支持消息分片重组(
avdt_msg_asmbl
)、定时器管理(取消重传定时器),适配无线环境的不确定性。
该流程是蓝牙音视频流 “暂停 - 确认” 机制的核心,为用户交互(如暂停播放)提供了稳定的技术支撑,确保媒体传输的可控性与实时性。
logcat关键字:
MSG_SUSPEND_RSP_EVT|avdt_ad_tcid_to_type|avdt_msg_ind|avdt_msg_asmbl|event=0x7|bta_av_proc_stream_evt|bta_av_better_stream_state_machine|bta_av_suspend_cfm|bta_av_stream_chg|ProcessStop|bta_av_source_callback|BTA_AV_SUSPEND_EVT|btif_av_handle_event|FindOrCreatePeer|btif_report_audio_state
行 797894: 08-15 10:43:40.483 12215 12277 V bluetooth: avdt_ad_tcid_to_type: tcid: 0, type: 0
行 797895: 08-15 10:43:40.483 12215 12277 V bluetooth: avdt_msg_ind: msg_type=2, sig=0
行 797896: 08-15 10:43:40.483 12215 12277 V bluetooth: avdt_ccb_event: event=MSG_SUSPEND_RSP_EVT state=CCB_OPEN_ST action=10
行 797898: 08-15 10:43:40.483 12215 12277 V bt_bta_av: bta_av_proc_stream_evt: peer_address: xx:xx:xx:xx:22:a7 avdt_handle: 1 event=0x7 scb_index=0 p_scb=0xedec7db0
行 797899: 08-15 10:43:40.483 12215 12277 V bt_bta_av: bta_av_proc_stream_evt: stream event bd_addr: xx:xx:xx:xx:22:a7 scb_index: 0
行 797900: 08-15 10:43:40.483 12215 12277 V bt_bta_av: bta_av_proc_stream_evt: bta_handle:0x41 avdt_handle:1
行 797904: 08-15 10:43:40.483 12215 12277 V bluetooth: avdt_ccb_event: event=MSG_SUSPEND_RSP_EVT state=CCB_OPEN_ST action=36
行 797910: 08-15 10:43:40.484 12215 12277 V bt_bta_av: bta_av_better_stream_state_machine: peer xx:xx:xx:xx:22:a7 p_scb=0x41(0xedec7db0) AV event=0x1223(STR_SUSPEND_CFM) state=3(OPEN)
行 797911: 08-15 10:43:40.484 12215 12277 V bt_bta_av: bta_av_suspend_cfm: peer xx:xx:xx:xx:22:a7 bta_handle:0x41 audio_open_cnt:1 err_code:0
行 797927: 08-15 10:43:40.485 12215 12277 D btif_av : btif_av_handle_bta_av_event: jni_thread: Handle BTA AV or AVRCP event Invalid: peer_sep=3 event=BTA_AV_SUSPEND_EVT(0xf)
行 797928: 08-15 10:43:40.485 12215 12277 D btif_av : btif_av_handle_event: Handle event peer_address=00:00:00:00:00:00 bta_handle=0x41
行 797929: 08-15 10:43:40.485 12215 12277 V btif_av : ProcessEvent: Peer xx:xx:xx:xx:22:a7 : event=BTA_AV_SUSPEND_EVT(0xf) flags=0x1(LOCAL_SUSPEND_PENDING) active_peer=true
行 797930: 08-15 10:43:40.485 12215 12277 I btif_av : ProcessEvent: Peer xx:xx:xx:xx:22:a7 : event=BTA_AV_SUSPEND_EVT(0xf) status=0 initiator=true flags=0x1(LOCAL_SUSPEND_PENDING)
行 797936: 08-15 10:43:40.485 12215 12277 I btif_av : btif_report_audio_state: peer_address=xx:xx:xx:xx:22:a7 state=1
行 798586: 08-15 10:43:42.064 12215 12277 D btif_av : btif_av_handle_event: Handle event peer_address=xx:xx:xx:xx:22:a7 bta_handle=0x0
行 798595: 08-15 10:43:42.065 12215 12277 V bt_bta_av: bta_av_better_stream_state_machine: peer xx:xx:xx:xx:22:a7 p_scb=0x41(0xedec7db0) AV event=0x120b(AP_START) state=3(OPEN)
行 798654: 08-15 10:43:42.185 12215 12277 V bluetooth: avdt_ad_tcid_to_type: tcid: 0, type: 0
行 798655: 08-15 10:43:42.185 12215 12277 V bluetooth: avdt_msg_ind: msg_type=2, sig=0
行 798658: 08-15 10:43:42.185 12215 12277 V bt_bta_av: bta_av_proc_stream_evt: peer_address: xx:xx:xx:xx:22:a7 avdt_handle: 1 event=0x5 scb_index=0 p_scb=0xedec7db0
行 798659: 08-15 10:43:42.186 12215 12277 V bt_bta_av: bta_av_proc_stream_evt: stream event bd_addr: xx:xx:xx:xx:22:a7 scb_index: 0
行 798660: 08-15 10:43:42.186 12215 12277 V bt_bta_av: bta_av_proc_stream_evt: bta_handle:0x41 avdt_handle:1
行 798667: 08-15 10:43:42.186 12215 12277 V bt_bta_av: bta_av_better_stream_state_machine: peer xx:xx:xx:xx:22:a7 p_scb=0x41(0xedec7db0) AV event=0x121c(STR_START_OK) state=3(OPEN)
行 798695: 08-15 10:43:42.187 12215 12277 V bt_bta_av: bta_av_stream_chg: peer xx:xx:xx:xx:22:a7 started:true started_msk:0x1
行 798708: 08-15 10:43:42.187 12215 12277 D btif_av : btif_av_handle_event: Handle event peer_address=00:00:00:00:00:00 bta_handle=0x41
行 798731: 08-15 10:43:42.189 12215 12277 I btif_av : btif_report_audio_state: peer_address=xx:xx:xx:xx:22:a7 state=2