AVCTP消息处理
avrc_msg_cback
/packages/modules/Bluetooth/system/stack/avrc/avrc_api.cc
/******************************************************************************** Function avrc_msg_cback** Description This is the callback function used by AVCTP to report* received AV control messages.** Returns Nothing.******************************************************************************/
static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,BT_HDR* p_pkt) {uint8_t opcode;tAVRC_MSG msg;uint8_t* p_data;uint8_t* p_begin;bool drop = false;bool do_free = true;BT_HDR* p_rsp = NULL;uint8_t* p_rsp_data;int xx;bool reject = false;const char* p_drop_msg = "dropped";tAVRC_MSG_VENDOR* p_msg = &msg.vendor;if (cr == AVCT_CMD && (p_pkt->layer_specific & AVCT_DATA_CTRL &&p_pkt->len > AVRC_PACKET_LEN)) {log::warn("Command length {} too long: must be at most {}", p_pkt->len,AVRC_PACKET_LEN);osi_free(p_pkt);return;}// 1. 消息类型校验与初步处理if (cr == AVCT_REJ) { // 拒绝消息/* The peer thinks that this PID is no longer open - remove this handle *//* */osi_free(p_pkt);AVCT_RemoveConn(handle); // 移除无效连接return;} else if (cr == AVCT_RSP) { // 响应消息/* Received response. Stop command timeout timer */log::verbose("AVRC: stopping timer (handle=0x{:02x})", handle);alarm_cancel(avrc_cb.ccb_int[handle].tle); // 停止命令超时定时器}// 2. 消息头解析与操作码提取p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;memset(&msg, 0, sizeof(tAVRC_MSG));if (p_pkt->layer_specific == AVCT_DATA_BROWSE) {opcode = AVRC_OP_BROWSE; // 浏览消息特殊处理msg.browse.hdr.ctype = cr;msg.browse.p_browse_data = p_data;msg.browse.browse_len = p_pkt->len;msg.browse.p_browse_pkt = p_pkt;} else {if (p_pkt->len < AVRC_AVC_HDR_SIZE) {log::warn("message length {} too short: must be at least {}", p_pkt->len,AVRC_AVC_HDR_SIZE);osi_free(p_pkt);return; // 消息过短,直接丢弃}msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK; // 提取消息类型(命令/响应)log::verbose("handle:{}, ctype:{}, offset:{}, len: {}", handle,msg.hdr.ctype, p_pkt->offset, p_pkt->len);msg.hdr.subunit_type =(p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT; // 子单元类型msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK; // 子单元 IDopcode = p_data[2]; // 操作码(如 UNIT_INFO, SUB_INFO, VENDOR 等)}// 3. 操作码分类处理if (((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP))) {switch (opcode) {case AVRC_OP_UNIT_INFO: // 单元信息(AVRC_OP_UNIT_INFO)if (cr == AVCT_CMD) {// 生成响应包:返回设备支持的单元类型(如面板子单元)/* send the response to the peer */p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);p_rsp_data = avrc_get_data_ptr(p_rsp);*p_rsp_data = AVRC_RSP_IMPL_STBL;/* check & set the offset. set response code, set subunit_type &subunit_id,set AVRC_OP_UNIT_INFO *//* 3 bytes: ctype, subunit*, opcode */p_rsp_data += AVRC_AVC_HDR_SIZE;*p_rsp_data++ = 7;/* Panel subunit & id=0 */*p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);p_rsp->len =(uint16_t)(p_rsp_data - (uint8_t*)(p_rsp + 1) - p_rsp->offset);cr = AVCT_RSP;p_drop_msg = "auto respond";} else { / 解析响应:提取对端子单元类型和公司 ID/* parse response */if (p_pkt->len < AVRC_OP_UNIT_INFO_RSP_LEN) {log::warn("message length {} too short: must be at least {}",p_pkt->len, AVRC_OP_UNIT_INFO_RSP_LEN);drop = true;p_drop_msg = "UNIT_INFO_RSP too short";break;}p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/msg.unit.unit_type =(*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;msg.unit.unit = *p_data & AVRC_SUBID_MASK;p_data++;AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);}break;case AVRC_OP_SUB_INFO:if (cr == AVCT_CMD) {/* send the response to the peer */p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);p_rsp_data = avrc_get_data_ptr(p_rsp);*p_rsp_data = AVRC_RSP_IMPL_STBL;/* check & set the offset. set response code, set (subunit_type &subunit_id),set AVRC_OP_SUB_INFO, set (page & extention code) */p_rsp_data += 4;/* Panel subunit & id=0 */*p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;p_rsp->len =(uint16_t)(p_rsp_data - (uint8_t*)(p_rsp + 1) - p_rsp->offset);cr = AVCT_RSP;p_drop_msg = "auto responded";} else {/* parse response */if (p_pkt->len < AVRC_OP_SUB_UNIT_INFO_RSP_LEN) {log::warn("message length {} too short: must be at least {}",p_pkt->len, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);drop = true;p_drop_msg = "SUB_UNIT_INFO_RSP too short";break;}p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */msg.sub.page =(*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;xx = 0;while (*p_data != AVRC_CMD_OPRND_PAD && xx < AVRC_SUB_TYPE_LEN) {msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)msg.sub.panel = true;xx++;}}break;case AVRC_OP_VENDOR: { // 供应商特定消息p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset; p_begin = p_data;if (p_pkt->len <AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */{if (cr == AVCT_CMD)reject = true;elsedrop = true;break;}p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*,opcode */AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);p_msg->p_vendor_data = p_data;p_msg->vendor_len = p_pkt->len - (p_data - p_begin);uint8_t drop_code = 0;if (p_msg->company_id == AVRC_CO_METADATA) {/* Validate length for metadata message */if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)) {if (cr == AVCT_CMD)reject = true;elsedrop = true;break;}/* Check+handle fragmented messages */drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);if (drop_code > 0) drop = true;}if (drop_code > 0) {if (drop_code != 4) do_free = false;switch (drop_code) {case 1:p_drop_msg = "sent_frag";break;case 2:p_drop_msg = "req_cont";break;case 3:p_drop_msg = "sent_frag3";break;case 4:p_drop_msg = "sent_frag_free";break;default:p_drop_msg = "sent_fragd";}}/* If vendor response received, and did not ask for continuation *//* then check queue for addition commands to send */if ((cr == AVCT_RSP) && (drop_code != 2)) {avrc_send_next_vendor_cmd(handle);}} break;case AVRC_OP_PASS_THRU:if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */{if (cr == AVCT_CMD)reject = true;elsedrop = true;break;}p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*,opcode */msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);if (AVRC_PASS_STATE_MASK & *p_data)msg.pass.state = true;elsemsg.pass.state = false;p_data++;msg.pass.pass_len = *p_data++;if (msg.pass.pass_len != p_pkt->len - 5)msg.pass.pass_len = p_pkt->len - 5;if (msg.pass.pass_len)msg.pass.p_pass_data = p_data;elsemsg.pass.p_pass_data = NULL;break;case AVRC_OP_BROWSE:/* If browse response received, then check queue for addition commands* to send */if (cr == AVCT_RSP) {avrc_send_next_vendor_cmd(handle);}break;default:if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) &&(cr == AVCT_CMD)) {/* reject unsupported opcode */reject = true;}drop = true;break;}} else /* drop the event */{if (opcode != AVRC_OP_BROWSE) drop = true;}// 4. 拒绝与错误处理if (reject) {// 生成拒绝响应:不支持的操作码/* reject unsupported opcode */p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);p_rsp_data = avrc_get_data_ptr(p_rsp);*p_rsp_data = AVRC_RSP_REJ; // 响应码为拒绝p_drop_msg = "rejected";cr = AVCT_RSP;drop = true;}if (p_rsp) {/* set to send response right away */AVCT_MsgReq(handle, label, cr, p_rsp);drop = true;}// 5. 回调分发与内存管理if (!drop) {msg.hdr.opcode = opcode;avrc_cb.ccb[handle].msg_cback.Run(handle, label, opcode, &msg); // 分发给上层回调} else {log::warn("{} msg handle:{}, control:{}, cr:{}, opcode:x{:x}", p_drop_msg,handle, avrc_cb.ccb[handle].control, cr, opcode);}if (opcode == AVRC_OP_BROWSE && msg.browse.p_browse_pkt == NULL) {do_free = false;}if (do_free) osi_free(p_pkt);
}
avrc_msg_cback
是 AVCTP(Audio/Video Control Transport Protocol)的回调函数,用于处理蓝牙 AVRC(Audio/Video Remote Control)接收到的控制消息。其核心功能包括 消息解析、响应生成、分段消息处理 和 回调分发,是 AVRC 协议栈处理远程控制命令的核心入口。
bta_av_rc_msg_cback
packages/modules/Bluetooth/system/bta/av/bta_av_act.cc
/********************************************************************************* Function bta_av_rc_msg_cback** Description AVRCP message callback.** Returns void*******************************************************************************/
static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode,tAVRC_MSG* p_msg) {uint8_t* p_data_src = NULL;uint16_t data_len = 0;log::verbose("handle: {} opcode=0x{:x}", handle, opcode);// 1. 数据载荷提取(供应商 / 透传消息)/* Copy avrc packet into BTA message buffer (for sending to BTA state machine)*//* Get size of payload data (for vendor and passthrough messages only; for* browsing* messages, use zero-copy) */if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL) {p_data_src = p_msg->vendor.p_vendor_data;data_len = (uint16_t)p_msg->vendor.vendor_len;} else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL) {p_data_src = p_msg->pass.p_pass_data;data_len = (uint16_t)p_msg->pass.pass_len;}// 2. BTA 消息缓冲区创建/* Create a copy of the message */tBTA_AV_RC_MSG* p_buf =(tBTA_AV_RC_MSG*)osi_malloc(sizeof(tBTA_AV_RC_MSG) + data_len); // 分配包含 tBTA_AV_RC_MSG 结构体和数据载荷的连续内存,确保数据完整性p_buf->hdr.event = BTA_AV_AVRC_MSG_EVT;p_buf->handle = handle;p_buf->label = label;p_buf->opcode = opcode;memcpy(&p_buf->msg, p_msg, sizeof(tAVRC_MSG));// 3. 数据载荷复制与指针更新/* Copy the data payload, and set the pointer to it */if (p_data_src != NULL) {uint8_t* p_data_dst = (uint8_t*)(p_buf + 1); // 数据载荷紧接在结构体之后memcpy(p_data_dst, p_data_src, data_len);/* Update bta message buffer to point to payload data *//* (Note AVRC_OP_BROWSING uses zero-copy: p_buf->msg.browse.p_browse_data* already points to original avrc buffer) */// 更新 BTA 消息中的数据指针,指向新分配的缓冲区if (opcode == AVRC_OP_VENDOR)p_buf->msg.vendor.p_vendor_data = p_data_dst;else if (opcode == AVRC_OP_PASS_THRU)p_buf->msg.pass.p_pass_data = p_data_dst;}// 4. 浏览消息特殊处理if (opcode == AVRC_OP_BROWSE) {/* set p_pkt to NULL, so avrc would not free the buffer */p_msg->browse.p_browse_pkt = NULL; // 防止 AVRCP 层释放原始缓冲区(BTA 层已处理)}// 5. 消息发送与清理bta_sys_sendmsg(p_buf);
}
bta_av_rc_msg_cback
是 AVRCP(音频 / 视频远程控制协议)的消息回调函数,负责将接收到的 AVRCP 消息转换为 BTA(Bluetooth Application Layer,蓝牙应用层)可处理的消息格式,并通过 bta_sys_sendmsg
发送给 BTA 状态机。其核心逻辑包括 消息解析、数据载荷复制 和 消息格式转换,是连接 AVRCP 层与 BTA 层的桥梁。
bta_sys_sendmsg
(BTA_AV_AVRC_MSG_EVT)
bta_av_rc_msg
packages/modules/Bluetooth/system/bta/av/bta_av_act.cc
/********************************************************************************* Function bta_av_rc_msg** Description Process an AVRCP message from the peer.** Returns void*******************************************************************************/
void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {tBTA_AV_EVT evt = 0;tBTA_AV av;BT_HDR* p_pkt = NULL;tAVRC_MSG_VENDOR* p_vendor = &p_data->rc_msg.msg.vendor;bool is_inquiry = ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ);uint8_t ctype = 0;tAVRC_RESPONSE rc_rsp;rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;// 1. 输入检查if (NULL == p_data) {log::error("Message from peer with no data");return;}log::verbose("opcode={:x}, ctype={:x}", p_data->rc_msg.opcode,p_data->rc_msg.msg.hdr.ctype);// 2. 透传消息处理(AVRC_OP_PASS_THRU)if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU) { // 处理透传命令/* if this is a pass thru command */if ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) ||(p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||(p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ)) {/* check if operation is supported */char avrcp_ct_support[PROPERTY_VALUE_MAX]; // 检查操作是否支持osi_property_get("bluetooth.pts.avrcp_ct.support", avrcp_ct_support,"false");if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) { // 处理供应商特定操作p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_NOT_IMPL;if (p_cb->features & BTA_AV_FEAT_METADATA)p_data->rc_msg.msg.hdr.ctype = bta_av_group_navi_supported(p_data->rc_msg.msg.pass.pass_len,p_data->rc_msg.msg.pass.p_pass_data, is_inquiry);} else if (((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_UP) ||(p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_DOWN)) &&!strcmp(avrcp_ct_support, "true")) {p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_ACCEPT;} else {p_data->rc_msg.msg.hdr.ctype =bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry);}log::verbose("ctype {}", p_data->rc_msg.msg.hdr.ctype);// 发送响应/* send response */if (p_data->rc_msg.msg.hdr.ctype != AVRC_RSP_INTERIM)AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label,&p_data->rc_msg.msg.pass);// 设置回调参数/* set up for callback if supported */if (p_data->rc_msg.msg.hdr.ctype == AVRC_RSP_ACCEPT ||p_data->rc_msg.msg.hdr.ctype == AVRC_RSP_INTERIM) {evt = BTA_AV_REMOTE_CMD_EVT;av.remote_cmd.rc_id = p_data->rc_msg.msg.pass.op_id;av.remote_cmd.key_state = p_data->rc_msg.msg.pass.state;av.remote_cmd.p_data = p_data->rc_msg.msg.pass.p_pass_data;av.remote_cmd.len = p_data->rc_msg.msg.pass.pass_len;memcpy(&av.remote_cmd.hdr, &p_data->rc_msg.msg.hdr, sizeof(tAVRC_HDR));av.remote_cmd.label = p_data->rc_msg.label;}}/* else if this is a pass thru response *//* id response type is not impl, we have to release label */else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL) { // 处理透传响应// 设置回调参数/* set up for callback */evt = BTA_AV_REMOTE_RSP_EVT;av.remote_rsp.rc_id = p_data->rc_msg.msg.pass.op_id;av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state;av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype;av.remote_rsp.label = p_data->rc_msg.label;av.remote_rsp.len = p_data->rc_msg.msg.pass.pass_len;av.remote_rsp.p_data = NULL;/* If this response is for vendor unique command */// // 处理供应商唯一命令的响应if ((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) &&(p_data->rc_msg.msg.pass.pass_len > 0)) {av.remote_rsp.p_data =(uint8_t*)osi_malloc(p_data->rc_msg.msg.pass.pass_len);log::verbose("Vendor Unique data len = {}",p_data->rc_msg.msg.pass.pass_len);memcpy(av.remote_rsp.p_data, p_data->rc_msg.msg.pass.p_pass_data,p_data->rc_msg.msg.pass.pass_len);}}/* must be a bad ctype -> reject*/else {p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_REJ;AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label,&p_data->rc_msg.msg.pass);}}// 3. 供应商特定消息处理(AVRC_OP_VENDOR)/* else if this is a vendor specific command or response */else if (p_data->rc_msg.opcode == AVRC_OP_VENDOR) {/* set up for callback */av.vendor_cmd.code = p_data->rc_msg.msg.hdr.ctype;av.vendor_cmd.company_id = p_vendor->company_id;av.vendor_cmd.label = p_data->rc_msg.label;av.vendor_cmd.p_data = p_vendor->p_vendor_data;av.vendor_cmd.len = p_vendor->vendor_len;// 处理供应商特定命令/* if configured to support vendor specific and it's a command */if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {if ((p_cb->features & BTA_AV_FEAT_METADATA) &&(p_vendor->company_id == AVRC_CO_METADATA)) {av.meta_msg.p_msg = &p_data->rc_msg.msg;rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;evt = bta_av_proc_meta_cmd(&rc_rsp, &p_data->rc_msg, &ctype);} else {evt = BTA_AV_VENDOR_CMD_EVT;}} // 处理供应商特定响应else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL) {/* else if configured to support vendor specific and it's a response */if ((p_cb->features & BTA_AV_FEAT_METADATA) &&(p_vendor->company_id == AVRC_CO_METADATA)) {av.meta_msg.p_msg = &p_data->rc_msg.msg;evt = BTA_AV_META_MSG_EVT;} else {evt = BTA_AV_VENDOR_RSP_EVT;}}// 不支持供应商特定命令的处理else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) &&p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {/* else if not configured to support vendor specific and it's a command */if (p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID) {/* reject it */p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_REJ;p_data->rc_msg.msg.vendor.p_vendor_data[4] = AVRC_STS_BAD_CMD;} else {p_data->rc_msg.msg.hdr.ctype = AVRC_RSP_NOT_IMPL;}AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label,&p_data->rc_msg.msg.vendor);}} // 4. 浏览消息处理else if (p_data->rc_msg.opcode == AVRC_OP_BROWSE) { /* set up for callback */av.meta_msg.rc_handle = p_data->rc_msg.handle;av.meta_msg.company_id = p_vendor->company_id;av.meta_msg.code = p_data->rc_msg.msg.hdr.ctype;av.meta_msg.label = p_data->rc_msg.label;av.meta_msg.p_msg = &p_data->rc_msg.msg;av.meta_msg.p_data = p_data->rc_msg.msg.browse.p_browse_data;av.meta_msg.len = p_data->rc_msg.msg.browse.browse_len;evt = BTA_AV_META_MSG_EVT;}// 5. 响应生成与发送if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP) {if (!p_pkt) {rc_rsp.rsp.opcode = p_data->rc_msg.opcode;AVRC_BldResponse(0, &rc_rsp, &p_pkt);}if (p_pkt)AVRC_MsgReq(p_data->rc_msg.handle, p_data->rc_msg.label, ctype, p_pkt,false);}// 6. 回调函数调用与资源释放/* call callback */if (evt != 0) {av.remote_cmd.rc_handle = p_data->rc_msg.handle;(*p_cb->p_cback)(evt, &av);/* If browsing message, then free the browse message buffer */if (p_data->rc_msg.opcode == AVRC_OP_BROWSE &&p_data->rc_msg.msg.browse.p_browse_pkt != NULL) {bta_av_rc_free_browse_msg(p_cb, p_data);}}
}
处理来自对等设备的 AVRCP(Audio/Video Remote Control Profile)消息。根据消息的操作码(opcode)、消息类型(ctype)以及蓝牙模块的配置特性,对消息进行分类处理,然后设置相应的事件和回调参数,最后调用回调函数将处理结果传递给上层。同时,对于一些需要响应的消息,会生成并发送相应的响应。
bta_av_event_callback
packages/modules/Bluetooth/system/btif/src/btif_av.cc
static void bta_av_event_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {if (btif_av_both_enable()) {BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV));do_in_main_thread(FROM_HERE,base::BindOnce(&btif_av_handle_bta_av_event,AVDT_TSEP_INVALID /* peer_sep */, btif_av_event));return;}if (btif_av_is_sink_enabled()) {return bta_av_sink_callback(event, p_data);}return bta_av_source_callback(event, p_data);
}
btif_av_handle_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) {...}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(蓝牙音频 / 视频相关)或 BTA AVRCP(Audio/Video Remote Control Profile,音频 / 视频远程控制协议)事件。它运行在 JNI(Java Native Interface,Java 本地接口)线程上,首先会对传入的事件相关参数进行提取和初始化,接着在 switch
语句中针对具体事件进行相应处理,最后调用另一个函数 btif_av_handle_event
继续后续的事件处理流程,以此来保障蓝牙音频 / 视频相关事件能够在 JNI 线程环境下有序且正确地被处理,确保整个蓝牙功能的正常运行。
btif_av_handle_event
btif_av_handle_event前文有分析,这里不再展开。
BtifAvStateMachine::StateStarted::ProcessEvent
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 BTIF_AV_ACL_DISCONNECTED:break; // Ignorecase BTIF_AV_START_STREAM_REQ_EVT:log::info("Peer {} : event={} flags={}",ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),BtifAvEvent::EventName(event), peer_.FlagsToString());// We were started remotely, just ACK back the local requestif (peer_.IsSink()) btif_a2dp_on_started(peer_.PeerAddress(), nullptr);break;// FIXME -- use suspend = true always to work around issue with BTA AVcase BTIF_AV_STOP_STREAM_REQ_EVT:case BTIF_AV_SUSPEND_STREAM_REQ_EVT:log::info("Peer {} : event={} flags={}",ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),BtifAvEvent::EventName(event), peer_.FlagsToString());// There is a pending LocalSuspend already, ignore.if (peer_.CheckFlags(BtifAvPeer::kFlagLocalSuspendPending)) {break;}// Set pending flag to ensure the BTIF task is not trying to restart// the stream while suspend is in progress.peer_.SetFlags(BtifAvPeer::kFlagLocalSuspendPending);// If we were remotely suspended but suspend locally, local suspend// always overrides.peer_.ClearFlags(BtifAvPeer::kFlagRemoteSuspend);if (peer_.IsSink() &&(peer_.IsActivePeer() || !btif_av_stream_started_ready())) {// Immediately stop transmission of frames while suspend is pendingif (event == BTIF_AV_STOP_STREAM_REQ_EVT) {btif_a2dp_on_stopped(nullptr);} else {// ensure tx frames are immediately suspendedbtif_a2dp_source_set_tx_flush(true);}} else if (peer_.IsSource()) {btif_a2dp_on_stopped(nullptr);}BTA_AvStop(peer_.BtaHandle(), true);break;case BTIF_AV_DISCONNECT_REQ_EVT:log::info("Peer {} : event={} flags={}",ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),BtifAvEvent::EventName(event), peer_.FlagsToString());// Request AVDTP to closeBTA_AvClose(peer_.BtaHandle());if (peer_.IsSource()) {BTA_AvCloseRc(peer_.BtaHandle());}// Inform the application that we are disconnectingbtif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_DISCONNECTING,bt_status_t::BT_STATUS_SUCCESS, BTA_AV_SUCCESS);// Wait in closing state until fully closedpeer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateClosing);break;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 resumedif (peer_.IsActivePeer() || !btif_av_stream_started_ready()) {btif_a2dp_on_suspended(&p_av->suspend);}// If not successful, remain in current stateif (p_av->suspend.status != BTA_AV_SUCCESS) {peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);if (peer_.IsSink() && peer_.IsActivePeer()) {// Suspend failed, reset back tx flush statebtif_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 Openedpeer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateOpened);} break;case BTA_AV_STOP_EVT:log::info("Peer {} : event={} flags={}",ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),BtifAvEvent::EventName(event), peer_.FlagsToString());peer_.SetFlags(BtifAvPeer::kFlagPendingStop);peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);// Don't change the encoder and audio provider state by a non-active// peer since they are shared between peersif (peer_.IsActivePeer() || !btif_av_stream_started_ready()) {btif_a2dp_on_stopped(&p_av->suspend);}btif_report_audio_state(peer_.PeerAddress(), BTAV_AUDIO_STATE_STOPPED);// If stop was successful, change state to Openif (p_av->suspend.status == BTA_AV_SUCCESS)peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateOpened);break;case BTA_AV_CLOSE_EVT:log::info("Peer {} : event={} flags={}",ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),BtifAvEvent::EventName(event), peer_.FlagsToString());// Inform the application that we are disconnectingbtif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_DISCONNECTING,bt_status_t::BT_STATUS_SUCCESS, BTA_AV_SUCCESS);peer_.SetFlags(BtifAvPeer::kFlagPendingStop);// AVDTP link is closedif (peer_.IsActivePeer()) {btif_a2dp_on_stopped(nullptr);}// Inform the application that we are disconnectedbtif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_DISCONNECTED,bt_status_t::BT_STATUS_SUCCESS, BTA_AV_SUCCESS);peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateIdle);break;case BTIF_AV_OFFLOAD_START_REQ_EVT:if (peer_.CheckFlags(BtifAvPeer::kFlagLocalSuspendPending |BtifAvPeer::kFlagRemoteSuspend |BtifAvPeer::kFlagPendingStop)) {log::warn("Peer {} : event={} flags={}: stream is Suspending",ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),BtifAvEvent::EventName(event), peer_.FlagsToString());btif_a2dp_on_offload_started(peer_.PeerAddress(), BTA_AV_FAIL);break;}BTA_AvOffloadStart(peer_.BtaHandle());break;case BTA_AV_OFFLOAD_START_RSP_EVT:btif_a2dp_on_offload_started(peer_.PeerAddress(), p_av->status);break;case BTIF_AV_SET_LATENCY_REQ_EVT: {const btif_av_set_latency_req_t* p_set_latency_req =static_cast<const btif_av_set_latency_req_t*>(p_data);log::info("Peer {} : event={} flags={} is_low_latency={}",ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),BtifAvEvent::EventName(event), peer_.FlagsToString(),p_set_latency_req->is_low_latency ? "true" : "false");BTA_AvSetLatency(peer_.BtaHandle(), p_set_latency_req->is_low_latency);} break;CHECK_RC_EVENT(event, (tBTA_AV*)p_data);default:log::warn("Peer {} : Unhandled event={}",ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()),BtifAvEvent::EventName(event));return false;}return true;
}
ProcessEvent
函数是 BtifAvStateMachine
中 StateStarted
状态下用于处理各种蓝牙音频 / 视频(AV)相关事件的函数。它接收一个事件标识符 event
和对应的事件数据指针 p_data
,根据不同的事件类型,执行相应的逻辑操作,例如处理连接断开、流启动 / 停止请求、暂停 / 恢复操作、设备关闭以及一些特定的功能请求(如卸载启动、设置延迟等)相关逻辑,同时通过日志记录详细的事件信息及处理过程,以此来维护蓝牙 AV 功能在相应状态下的正确行为和状态转换,确保整个蓝牙音频 / 视频业务流程的顺畅运行。
btif_rc_handle
packages/modules/Bluetooth/system/btif/src/btif_rc.cc
/******************************************************************************* Function btif_rc_handler**** Description RC event handler*****************************************************************************/
void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) {log::verbose("event: {}", dump_rc_event(event));btif_rc_device_cb_t* p_dev = NULL;switch (event) {...// 1. 事件类型判断与回调检查case BTA_AV_META_MSG_EVT: {if (bt_rc_callbacks != NULL) { log::verbose("BTA_AV_META_MSG_EVT code: {} label: {}",p_data->meta_msg.code, p_data->meta_msg.label);log::verbose("company_id: 0x{:x} len: {} handle: {}",p_data->meta_msg.company_id, p_data->meta_msg.len,p_data->meta_msg.rc_handle);/* handle the metamsg command */handle_rc_metamsg_cmd(&(p_data->meta_msg)); // 传统 RC 回调处理(如媒体元数据)/* Free the Memory allocated for tAVRC_MSG */} else if (bt_rc_ctrl_callbacks != NULL) { // Sink + CT + TG 场景(如绝对音量控制)/* This is case of Sink + CT + TG(for abs vol)) */log::verbose("BTA_AV_META_MSG_EVT code:{} label:{} opcode {} ctype {}",p_data->meta_msg.code, p_data->meta_msg.label,p_data->meta_msg.p_msg->hdr.opcode,p_data->meta_msg.p_msg->hdr.ctype);log::verbose("company_id:0x{:x} len:{} handle:{}",p_data->meta_msg.company_id, p_data->meta_msg.len,p_data->meta_msg.rc_handle);switch (p_data->meta_msg.p_msg->hdr.opcode) {case AVRC_OP_VENDOR: / 按响应/命令分类处理供应商消息if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL) &&(p_data->meta_msg.code <= AVRC_RSP_INTERIM)) {/* Its a response */handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));} else if (p_data->meta_msg.code <= AVRC_CMD_GEN_INQ) {/* Its a command */handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));}break;// 3. 浏览消息处理case AVRC_OP_BROWSE: // 按命令/响应分类处理浏览消息if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_CMD) {handle_avk_rc_metamsg_cmd(&(p_data->meta_msg)); // 处理浏览命令(如目录查询)} else if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_RSP) {handle_avk_rc_metamsg_rsp(&(p_data->meta_msg)); // 处理浏览响应(如查询结果)}break;}} else {log::error("Neither CTRL, nor TG is up, drop meta commands");}} break;default:log::verbose("Unhandled RC event : 0x{:x}", event);}
}
btif_rc_handler
函数充当了一个 RC(Remote Control,远程控制)事件的处理枢纽,它接收蓝牙音频 / 视频相关的事件类型(event
)以及对应的事件数据指针(p_data
)作为参数,依据不同的事件类型,特别是针对 BTA_AV_META_MSG_EVT
事件进行处理,通过调用不同的处理函数来应对诸如命令、响应等不同情况,同时进行相应的日志记录,以确保蓝牙远程控制相关的消息事件能够按照既定逻辑被正确处理,保障蓝牙音频 / 视频远程控制功能的正常运作。
AVRC_Ctrl_ParsResponse
packages/modules/Bluetooth/system/stack/avrc/avrc_pars_ct.cc
/********************************************************************************* Function AVRC_Ctrl_ParsResponse** Description This function is a parse response for AVRCP Controller.** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed* successfully.* Otherwise, the error code defined by AVRCP 1.4*******************************************************************************/
tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,uint8_t* p_buf, uint16_t* buf_len) {tAVRC_STS status = AVRC_STS_INTERNAL_ERR;if (p_msg && p_result) {switch (p_msg->hdr.opcode) {case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */status =avrc_ctrl_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf, buf_len);break;case AVRC_OP_BROWSE: /* 0xff Browse commands */status = avrc_pars_browse_rsp(&p_msg->browse, p_result);break;default:log::error("unknown opcode:0x{:x}", p_msg->hdr.opcode);break;}p_result->rsp.opcode = p_msg->hdr.opcode;p_result->rsp.status = status;}return status;
}
AVRC_Ctrl_ParsResponse
是 AVRCP(音频 / 视频远程控制协议)控制器的 响应解析核心函数,负责根据操作码(opcode
)解析不同类型的 AVRCP 响应消息(如供应商特定响应、浏览响应),并将解析结果填充到 tAVRC_RESPONSE
结构体中。其核心逻辑是通过操作码分发到具体解析函数,确保协议消息的正确解析与状态反馈。
操作码与功能映射:
操作码 | 功能分类 | 解析函数 | 典型场景 |
---|---|---|---|
AVRC_OP_VENDOR | 供应商特定命令 / 响应 | avrc_ctrl_pars_vendor_rsp | 绝对音量调节、元数据交互 |
AVRC_OP_BROWSE | 浏览命令 / 响应 | avrc_pars_browse_rsp | 设备间文件目录查询 |
handle_avk_rc_metamsg_rsp
packages/modules/Bluetooth/system/btif/src/btif_rc.cc
/***************************************************************************** Function handle_avk_rc_metamsg_rsp** Description Handle RC metamessage response** Returns void***************************************************************************/
static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) {tAVRC_RESPONSE avrc_response = {0};uint8_t scratch_buf[512] = {0}; // this variable is unuseduint16_t buf_len;tAVRC_STS status;btif_rc_device_cb_t* p_dev = NULL;log::verbose("opcode: {} rsp_code: {}", pmeta_msg->p_msg->hdr.opcode,pmeta_msg->code);p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf,&buf_len);if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode) &&(pmeta_msg->code >= AVRC_RSP_NOT_IMPL) &&(pmeta_msg->code <= AVRC_RSP_INTERIM)) {log::verbose("parse status {} pdu = {} rsp_status = {}", status,avrc_response.pdu, pmeta_msg->p_msg->vendor.hdr.ctype);switch (avrc_response.pdu) {case AVRC_PDU_REGISTER_NOTIFICATION:handle_notification_response(pmeta_msg, &avrc_response.reg_notif);if (pmeta_msg->code == AVRC_RSP_INTERIM) {/* Don't free the transaction Id */clear_cmd_timeout(p_dev, pmeta_msg->label);return;}break;
...log::verbose("release transaction {}", pmeta_msg->label);release_transaction(p_dev, pmeta_msg->label);
}
处理蓝牙音频 / 视频远程控制(RC)相关的消息响应(metamessage response)。对传入的消息响应相关数据进行提取和分析,调用相关函数解析响应内容,依据操作码、响应代码等关键信息进行不同情况的分支处理,比如针对特定的厂商操作码以及响应类型范围进行特定逻辑处理,同时通过日志记录关键信息,最后还会执行释放相关资源(如交易相关资源)的操作,以此来确保对蓝牙 RC 元消息响应的正确处理以及资源的合理管理,保障蓝牙远程控制功能在响应处理方面的正常运行。
handle_notification_response
packages/modules/Bluetooth/system/btif/src/btif_rc.cc
/***************************************************************************** Function handle_notification_response** Description Main handler for notification responses to registered events* 1. Register for unregistered event(in interim response path)* 2. After registering for all supported events, start* retrieving application settings and values* 3. Reregister for events on getting changed response* 4. Run play status timer for getting position when the* status changes to playing* 5. Get the Media details when the track change happens* or track change interim response is received with* valid track id* 6. HAL callback for play status change and application* setting change* Returns None***************************************************************************/
static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg,tAVRC_REG_NOTIF_RSP* p_rsp) {btif_rc_device_cb_t* p_dev =btif_rc_get_device_by_handle(pmeta_msg->rc_handle);if (p_dev == NULL) {log::error("p_dev NULL");return;}if (btif_av_src_sink_coexist_enabled() &&p_rsp->event_id == AVRC_EVT_VOLUME_CHANGE) {log::error("legacy TG don't handle absolute volume change. leave it to new avrcp");return;}const uint32_t* attr_list = get_requested_attributes_list(p_dev);const uint8_t attr_list_size = get_requested_attributes_list_size(p_dev);if (pmeta_msg->code == AVRC_RSP_INTERIM) {btif_rc_supported_event_t* p_event;list_node_t* node;log::verbose("Interim response: 0x{:2X}", p_rsp->event_id);switch (p_rsp->event_id) {case AVRC_EVT_PLAY_STATUS_CHANGE:get_play_status_cmd(p_dev);do_in_jni_thread(FROM_HERE,base::BindOnce(bt_rc_ctrl_callbacks->play_status_changed_cb,p_dev->rc_addr,(btrc_play_status_t)p_rsp->param.play_status));break;case AVRC_EVT_TRACK_CHANGE:if (rc_is_track_id_valid(p_rsp->param.track) != true) {break;} else {uint8_t* p_data = p_rsp->param.track;BE_STREAM_TO_UINT64(p_dev->rc_playing_uid, p_data);get_play_status_cmd(p_dev);get_metadata_attribute_cmd(attr_list_size, attr_list,p_dev);}break;case AVRC_EVT_APP_SETTING_CHANGE:break;case AVRC_EVT_NOW_PLAYING_CHANGE:do_in_jni_thread(FROM_HERE,base::BindOnce(bt_rc_ctrl_callbacks->now_playing_contents_changed_cb,p_dev->rc_addr));break;case AVRC_EVT_AVAL_PLAYERS_CHANGE:log::verbose("AVRC_EVT_AVAL_PLAYERS_CHANGE");do_in_jni_thread(FROM_HERE,base::BindOnce(bt_rc_ctrl_callbacks->available_player_changed_cb,p_dev->rc_addr));break;case AVRC_EVT_ADDR_PLAYER_CHANGE:do_in_jni_thread(FROM_HERE,base::BindOnce(bt_rc_ctrl_callbacks->addressed_player_changed_cb,p_dev->rc_addr, p_rsp->param.addr_player.player_id));break;case AVRC_EVT_PLAY_POS_CHANGED:do_in_jni_thread(FROM_HERE,base::BindOnce(bt_rc_ctrl_callbacks->play_position_changed_cb,p_dev->rc_addr, 0, p_rsp->param.play_pos));break;case AVRC_EVT_UIDS_CHANGE:break;case AVRC_EVT_TRACK_REACHED_END:case AVRC_EVT_TRACK_REACHED_START:case AVRC_EVT_BATTERY_STATUS_CHANGE:case AVRC_EVT_SYSTEM_STATUS_CHANGE:default:log::error("Unhandled interim response: 0x{:2X}", p_rsp->event_id);return;}list_foreach(p_dev->rc_supported_event_list,iterate_supported_event_list_for_interim_rsp,&p_rsp->event_id);node = list_begin(p_dev->rc_supported_event_list);while (node != NULL) {p_event = (btif_rc_supported_event_t*)list_node(node);if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED)) {register_for_event_notification(p_event, p_dev);break;}node = list_next(node);p_event = NULL;}/* Registered for all events, we can request application settings */if (p_event == NULL && !p_dev->rc_app_settings.query_started) {/* we need to do this only if remote TG supports* player application settings*/p_dev->rc_app_settings.query_started = true;if (p_dev->rc_features & BTA_AV_FEAT_APP_SETTING) {list_player_app_setting_attrib_cmd(p_dev);} else {log::verbose("App setting not supported, complete procedure");rc_ctrl_procedure_complete(p_dev);}}} else if (pmeta_msg->code == AVRC_RSP_CHANGED) {btif_rc_supported_event_t* p_event;list_node_t* node;log::verbose("Notification completed: 0x{:2X}", p_rsp->event_id);node = list_begin(p_dev->rc_supported_event_list);while (node != NULL) {p_event = (btif_rc_supported_event_t*)list_node(node);if (p_event != NULL && p_event->event_id == p_rsp->event_id) {p_event->status = eNOT_REGISTERED;register_for_event_notification(p_event, p_dev);break;}node = list_next(node);}switch (p_rsp->event_id) {case AVRC_EVT_PLAY_STATUS_CHANGE:/* Start timer to get play status periodically* if the play state is playing.*/do_in_jni_thread(FROM_HERE,base::BindOnce(bt_rc_ctrl_callbacks->play_status_changed_cb,p_dev->rc_addr,(btrc_play_status_t)p_rsp->param.play_status));break;case AVRC_EVT_TRACK_CHANGE:if (rc_is_track_id_valid(p_rsp->param.track) != true) {break;}get_metadata_attribute_cmd(attr_list_size, attr_list, p_dev);break;case AVRC_EVT_APP_SETTING_CHANGE: {btrc_player_settings_t app_settings;uint16_t xx;app_settings.num_attr = p_rsp->param.player_setting.num_attr;for (xx = 0; xx < app_settings.num_attr; xx++) {app_settings.attr_ids[xx] = p_rsp->param.player_setting.attr_id[xx];app_settings.attr_values[xx] =p_rsp->param.player_setting.attr_value[xx];}do_in_jni_thread(FROM_HERE,base::BindOnce(bt_rc_ctrl_callbacks->playerapplicationsetting_changed_cb,p_dev->rc_addr, app_settings));} break;case AVRC_EVT_NOW_PLAYING_CHANGE:break;case AVRC_EVT_AVAL_PLAYERS_CHANGE:break;case AVRC_EVT_ADDR_PLAYER_CHANGE:break;case AVRC_EVT_PLAY_POS_CHANGED:// handle on interimbreak;case AVRC_EVT_UIDS_CHANGE:break;case AVRC_EVT_TRACK_REACHED_END:case AVRC_EVT_TRACK_REACHED_START:case AVRC_EVT_BATTERY_STATUS_CHANGE:case AVRC_EVT_SYSTEM_STATUS_CHANGE:default:log::error("Unhandled completion response: 0x{:2X}", p_rsp->event_id);return;}}
}
执行bt_rc_ctrl_callbacks->play_status_changed_cb
函数。这个函数是init的时候注册的一个回调,用于处理播放状态改变的事件。
btavrcp_play_status_changed_callback
packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
static void btavrcp_play_status_changed_callback(const RawAddress& bd_addr, btrc_play_status_t play_status) {log::info("");std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);CallbackEnv sCallbackEnv(__func__);if (!sCallbackEnv.valid()) return;if (!sCallbacksObj) {log::error("sCallbacksObj is null");return;}ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));if (!addr.get()) {log::error("Failed to allocate a new byte array");return;}sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),(jbyte*)&bd_addr.address);sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaystatuschanged,addr.get(), (jbyte)play_status);
}
btavrcp_play_status_changed_callback
函数在蓝牙音频 / 视频远程控制功能中扮演着连接底层 C++ 实现与上层 Java 应用的重要角色,特别是针对播放状态改变这一事件。它通过合理运用线程安全锁、仔细检查回调环境及相关对象有效性、将设备地址转换为适合 Java 层的字节数组形式以及最终通过 JNI 调用 Java 方法传递关键信息等一系列操作,保障了播放状态改变的信息能够准确无误地从底层传递到 Java 层,从而使得整个蓝牙远程控制功能在不同层次间能够协同工作,实现诸如界面与实际播放状态同步更新等业务需求。
informAudioFocusStateNative
/packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_a2dp_sink.cpp
static void informAudioFocusStateNative(JNIEnv* env, jobject object,jint focus_state) {if (!sBluetoothA2dpInterface) return;sBluetoothA2dpInterface->set_audio_focus_state((uint8_t)focus_state);
}
充当 Java 层与本地(Native)层之间关于音频焦点(Audio Focus)状态信息传递的桥梁。接收从 Java 层传来的表示音频焦点状态的整数值,先检查是否存在有效的蓝牙 A2DP 接口对象,若存在,则调用该接口对应的方法将音频焦点状态值转换并传递给本地层进行相应处理,以此确保本地层能够知晓并依据音频焦点状态来合理调整音频相关的操作,保障音频播放与系统中其他音频相关应用或功能之间的协调运作。
update_audio_focus_state
packages/modules/Bluetooth/system/btif/src/btif_av.cc
// Updates the final focus state reported by components calling this module
static void update_audio_focus_state(int state) {log::verbose("state={}", state);btif_a2dp_sink_set_focus_state_req((btif_a2dp_sink_focus_state_t)state);
}
btif_a2dp_sink_set_focus_state_req
packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state) {log::info("");tBTIF_MEDIA_SINK_FOCUS_UPDATE* p_buf =reinterpret_cast<tBTIF_MEDIA_SINK_FOCUS_UPDATE*>(osi_malloc(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE)));p_buf->focus_state = state;p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE;btif_a2dp_sink_cb.worker_thread.DoInThread(FROM_HERE,base::BindOnce(btif_a2dp_sink_command_ready, (BT_HDR_RIGID*)p_buf));
}
发起一个设置音频焦点状态的请求操作,负责在接收到音频焦点状态变化请求时,将该请求封装并发送到工作线程进行进一步处理。
- 设置
p_buf->hdr.event
为BTIF_MEDIA_SINK_SET_FOCUS_STATE
,表明这是一个设置音频焦点状态的请求。
packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
static void btif_a2dp_sink_command_ready(BT_HDR_RIGID* p_msg) {log::verbose("event {} {}", p_msg->event, dump_media_event(p_msg->event));switch (p_msg->event) {...case BTIF_MEDIA_SINK_SET_FOCUS_STATE: {btif_a2dp_sink_focus_state_t state =((tBTIF_MEDIA_SINK_FOCUS_UPDATE*)p_msg)->focus_state;btif_a2dp_sink_set_focus_state_event(state);break;}...default:log::error("unknown event {}", p_msg->event);break;}log::verbose("{} DONE", dump_media_event(p_msg->event));osi_free(p_msg);
}
根据传入消息结构体中的事件类型进行相应的处理操作。当接收到的消息事件类型为 BTIF_MEDIA_SINK_SET_FOCUS_STATE
时,会提取出对应的音频焦点状态信息,并调用btif_a2dp_sink_set_focus_state_event
函数实际处理音频焦点状态的变化。
btif_a2dp_sink_set_focus_state_req
packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
static void btif_a2dp_sink_set_focus_state_event(btif_a2dp_sink_focus_state_t state) {log::info("state={}", state);LockGuard lock(g_mutex);log::verbose("setting focus state to {}", state);btif_a2dp_sink_cb.rx_focus_state = state;if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);btif_a2dp_sink_cb.rx_flush = true;} else if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_GRANTED) {btif_a2dp_sink_cb.rx_flush = false;}
}
处理音频焦点状态设置相关的业务逻辑。通过加锁机制保证对共享资源访问的线程安全性,然后将接收到的音频焦点状态值更新到相应的成员变量中,最后根据不同的音频焦点状态值(如焦点未授予或已授予)执行不同的操作,例如清理音频队列或者更新相关的标志位,以此来确保系统在音频焦点状态变化时能做出相应的正确响应,保障音频播放等相关功能与音频焦点状态的协调一致。
informAudioTrackGainNative
/packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_a2dp_sink.cpp
static void informAudioTrackGainNative(JNIEnv* env, jobject object,jfloat gain) {if (!sBluetoothA2dpInterface) return;sBluetoothA2dpInterface->set_audio_track_gain((float)gain);
}
将音频轨道增益(gain
)相关的信息从 Java 层传递到Bluedroid层进行处理。
update_audio_track_gain
packages/modules/Bluetooth/system/btif/src/btif_av.cc
// Updates the track gain (used for ducking).
static void update_audio_track_gain(float gain) {log::verbose("gain={:f}", gain);btif_a2dp_sink_set_audio_track_gain(gain);
}
btif_a2dp_sink_set_audio_track_gain
packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
void btif_a2dp_sink_set_audio_track_gain(float gain) {log::debug("set gain to {:f}", gain);LockGuard lock(g_mutex);#ifdef __ANDROID__BtifAvrcpSetAudioTrackGain(btif_a2dp_sink_cb.audio_track, gain);
#endif
}
通过加锁机制保证在多线程环境下对共享资源访问的线程安全性,最后在满足特定编译条件(__ANDROID__
宏定义存在,在 Android 平台相关的编译环境下)时,调用相应的函数将增益值传递过去,以此来实现对音频轨道增益的实际设置,确保音频播放的音量等相关属性能够按照传入的增益值进行调整。
BtifAvrcpSetAudioTrackGain
packages/modules/Bluetooth/system/btif/src/btif_avrcp_audio_track.cc
void BtifAvrcpSetAudioTrackGain(void* handle, float gain) {if (handle == NULL) {log::info("handle is null.");return;}BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);if (trackHolder != NULL) {const float clampedGain = std::clamp(gain, kMinTrackGain, kMaxTrackGain);if (clampedGain != gain) {log::warn("Out of bounds gain set. Clamping the gain from :{:f} to {:f}",gain, clampedGain);}trackHolder->gain = clampedGain;log::info("Avrcp audio track gain is set to {:f}", trackHolder->gain);}
}
设置音频通路的增益值,同时具备一定的输入合法性检查以及增益值范围限制处理机制。接收一个指向音频轨道相关对象的指针和一个表示增益的浮点数作为参数,首先检查指针是否为空,接着将指针转换为合适的类型并进一步判断对象是否有效,然后对传入的增益值进行范围限制(确保其处于合理的最小和最大增益值范围内),若超出范围则进行相应的日志记录并修正。通过这个函数,可以确保设置的增益值在有效范围内,并更新AVRCP音频通路对象的增益值,从而控制音频设备的音量。