Merge branch 'bugfix/ai_review_avrcp_v6.0' into 'release/v6.0'

fix(bt): Fix the critical and high issues related to AVRCP from AI review report (v6.0)

See merge request espressif/esp-idf!50020
This commit is contained in:
Jiang Jiang Jian
2026-06-29 15:43:53 +08:00
12 changed files with 241 additions and 81 deletions

View File

@@ -246,8 +246,12 @@ void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_nam
if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) {
if (bta_ar_cb.sdp_tg_handle == 0) {
UINT32 sdp_handle = SDP_CreateRecord();
if (sdp_handle == 0) {
return;
}
bta_ar_cb.tg_registered = mask;
bta_ar_cb.sdp_tg_handle = SDP_CreateRecord();
bta_ar_cb.sdp_tg_handle = sdp_handle;
AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_tg_handle, browsing_en);
bta_sys_add_uuid(service_uuid);
}
@@ -257,7 +261,12 @@ void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_nam
bta_ar_cb.ct_categories [mask - 1] = categories;
categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1];
if (bta_ar_cb.sdp_ct_handle == 0) {
bta_ar_cb.sdp_ct_handle = SDP_CreateRecord();
UINT32 sdp_handle = SDP_CreateRecord();
if (sdp_handle == 0) {
bta_ar_cb.ct_categories[mask - 1] = 0;
return;
}
bta_ar_cb.sdp_ct_handle = sdp_handle;
AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_ct_handle, browsing_en);
bta_sys_add_uuid(service_uuid);
} else {

View File

@@ -487,11 +487,15 @@ static void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
if (btc_rc_cb.rc_connected) {
BTC_TRACE_ERROR("Got RC OPEN in connected state, Connected RC: %d \
and Current RC: %d", btc_rc_cb.rc_handle, p_rc_open->rc_handle );
if ((btc_rc_cb.rc_handle != p_rc_open->rc_handle)
&& (bdcmp(btc_rc_cb.rc_addr, p_rc_open->peer_addr))) {
BTC_TRACE_DEBUG("Got RC connected for some other handle");
BTA_AvCloseRc(p_rc_open->rc_handle);
return;
if (btc_rc_cb.rc_handle != p_rc_open->rc_handle) {
if (bdcmp(btc_rc_cb.rc_addr, p_rc_open->peer_addr) == 0) {
/* same device reconnected with new handle - close stale one */
BTA_AvCloseRc(btc_rc_cb.rc_handle);
} else {
BTC_TRACE_DEBUG("Got RC connected for some other handle");
BTA_AvCloseRc(p_rc_open->rc_handle);
return;
}
}
}
memcpy(btc_rc_cb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
@@ -526,7 +530,11 @@ static void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
} else {
BTC_TRACE_ERROR("%s Connect failed with error code: %d",
__FUNCTION__, p_rc_open->status);
btc_rc_cb.rc_connected = FALSE;
/* only clear state if the failure belongs to the active connection */
if (p_rc_open->rc_handle == btc_rc_cb.rc_handle ||
bdcmp(btc_rc_cb.rc_addr, p_rc_open->peer_addr) == 0) {
btc_rc_cb.rc_connected = FALSE;
}
}
}
@@ -541,9 +549,18 @@ static void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
static void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
{
BTC_TRACE_DEBUG("%s: rc_handle: %d", __FUNCTION__, p_rc_close->rc_handle);
if ((p_rc_close->rc_handle != btc_rc_cb.rc_handle)
&& (bdcmp(btc_rc_cb.rc_addr, p_rc_close->peer_addr))) {
BTC_TRACE_ERROR("Got disconnect of unknown device");
if (!btc_rc_cb.rc_connected) {
BTC_TRACE_WARNING("Got disconnect when not connected");
return;
}
if (p_rc_close->rc_handle != btc_rc_cb.rc_handle) {
if (bdcmp(btc_rc_cb.rc_addr, p_rc_close->peer_addr) != 0) {
BTC_TRACE_ERROR("Got disconnect of unknown device");
return;
}
/* ignore disconnect for superseded handle on same device */
BTC_TRACE_DEBUG("Ignoring disconnect for stale rc_handle %d (current %d)",
p_rc_close->rc_handle, btc_rc_cb.rc_handle);
return;
}
@@ -640,6 +657,12 @@ static void handle_rc_attributes_rsp (tAVRC_MSG_VENDOR *vendor_msg)
((uint32_t)vendor_msg->p_vendor_data[1 + attr_index] << 16) |
((uint32_t)vendor_msg->p_vendor_data[attr_index] << 24);
if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(attr_id)) {
BTC_TRACE_WARNING("invalid attr_id 0x%x, skip", attr_id);
attr_index += attr_length + 8;
continue;
}
//Convert to mask id
param[i].meta_rsp.attr_id = (1 << (attr_id - 1));
@@ -1153,6 +1176,11 @@ void btc_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
***************************************************************************/
BOOLEAN btc_rc_get_connected_peer(BD_ADDR peer_addr)
{
#if AVRC_DYNAMIC_MEMORY == TRUE
if (btc_rc_cb_ptr == NULL) {
return FALSE;
}
#endif
if (btc_rc_cb.rc_connected == TRUE) {
bdcpy(peer_addr, btc_rc_cb.rc_addr);
return TRUE;
@@ -1257,7 +1285,7 @@ static void btc_avrc_ct_deinit(void)
static bt_status_t btc_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uint8_t value_id)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
bt_status_t ret = BT_STATUS_UNSUPPORTED;
#if (AVRC_METADATA_INCLUDED == TRUE)
CHECK_ESP_RC_CONNECTED;
@@ -1265,6 +1293,7 @@ static bt_status_t btc_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t att
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
tAVRC_APP_SETTING values = {0};
tAVRC_STS cmd_status;
values.attr_id = attr_id;
values.attr_val = value_id;
@@ -1276,13 +1305,15 @@ static bt_status_t btc_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t att
avrc_cmd.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE;
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (status == AVRC_STS_NO_ERROR) {
cmd_status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (cmd_status == AVRC_STS_NO_ERROR) {
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, BTA_AV_CMD_CTRL, p_msg);
status = BT_STATUS_SUCCESS;
ret = BT_STATUS_SUCCESS;
} else {
ret = BT_STATUS_FAIL;
}
} else {
status = BT_STATUS_FAIL;
ret = BT_STATUS_FAIL;
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
}
@@ -1290,18 +1321,19 @@ static bt_status_t btc_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t att
BTC_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
#endif
return status;
return ret;
}
static bt_status_t btc_avrc_ct_send_get_rn_caps_cmd(uint8_t tl)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
bt_status_t ret = BT_STATUS_UNSUPPORTED;
#if (AVRC_METADATA_INCLUDED == TRUE)
CHECK_ESP_RC_CONNECTED;
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
tAVRC_STS cmd_status;
avrc_cmd.get_caps.opcode = AVRC_OP_VENDOR;
avrc_cmd.get_caps.status = AVRC_STS_NO_ERROR;
@@ -1309,13 +1341,15 @@ static bt_status_t btc_avrc_ct_send_get_rn_caps_cmd(uint8_t tl)
avrc_cmd.get_caps.capability_id = AVRC_CAP_EVENTS_SUPPORTED;
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (status == AVRC_STS_NO_ERROR) {
cmd_status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (cmd_status == AVRC_STS_NO_ERROR) {
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_STATUS, p_msg);
status = BT_STATUS_SUCCESS;
ret = BT_STATUS_SUCCESS;
} else {
ret = BT_STATUS_FAIL;
}
} else {
status = BT_STATUS_FAIL;
ret = BT_STATUS_FAIL;
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
}
@@ -1323,18 +1357,19 @@ static bt_status_t btc_avrc_ct_send_get_rn_caps_cmd(uint8_t tl)
BTC_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
#endif
return status;
return ret;
}
static bt_status_t btc_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_id, uint32_t event_parameter)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
bt_status_t ret = BT_STATUS_UNSUPPORTED;
#if (AVRC_METADATA_INCLUDED == TRUE)
CHECK_ESP_RC_CONNECTED;
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
tAVRC_STS cmd_status;
avrc_cmd.reg_notif.opcode = AVRC_OP_VENDOR;
avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
@@ -1343,13 +1378,15 @@ static bt_status_t btc_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_
avrc_cmd.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (status == AVRC_STS_NO_ERROR) {
cmd_status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (cmd_status == AVRC_STS_NO_ERROR) {
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_NOTIF, p_msg);
status = BT_STATUS_SUCCESS;
ret = BT_STATUS_SUCCESS;
} else {
ret = BT_STATUS_FAIL;
}
} else {
status = BT_STATUS_FAIL;
ret = BT_STATUS_FAIL;
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
}
@@ -1357,18 +1394,19 @@ static bt_status_t btc_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_
BTC_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
#endif
return status;
return ret;
}
static bt_status_t btc_avrc_ct_send_set_absolute_volume_cmd(uint8_t tl, uint8_t volume)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
bt_status_t ret = BT_STATUS_UNSUPPORTED;
#if (AVRC_METADATA_INCLUDED == TRUE)
CHECK_ESP_RC_CONNECTED;
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
tAVRC_STS cmd_status;
avrc_cmd.volume.opcode = AVRC_OP_VENDOR;
avrc_cmd.volume.status = AVRC_STS_NO_ERROR;
@@ -1376,13 +1414,15 @@ static bt_status_t btc_avrc_ct_send_set_absolute_volume_cmd(uint8_t tl, uint8_t
avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (status == AVRC_STS_NO_ERROR) {
cmd_status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (cmd_status == AVRC_STS_NO_ERROR) {
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_CTRL, p_msg);
status = BT_STATUS_SUCCESS;
ret = BT_STATUS_SUCCESS;
} else {
ret = BT_STATUS_FAIL;
}
} else {
status = BT_STATUS_FAIL;
ret = BT_STATUS_FAIL;
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
}
@@ -1390,12 +1430,12 @@ static bt_status_t btc_avrc_ct_send_set_absolute_volume_cmd(uint8_t tl, uint8_t
BTC_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
#endif
return status;
return ret;
}
static bt_status_t btc_avrc_ct_send_metadata_cmd (uint8_t tl, uint8_t attr_mask)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
bt_status_t ret = BT_STATUS_UNSUPPORTED;
#if (AVRC_METADATA_INCLUDED == TRUE)
CHECK_ESP_RC_CONNECTED;
@@ -1403,6 +1443,7 @@ static bt_status_t btc_avrc_ct_send_metadata_cmd (uint8_t tl, uint8_t attr_mask)
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
tAVRC_STS cmd_status;
avrc_cmd.get_elem_attrs.opcode = AVRC_OP_VENDOR;
avrc_cmd.get_elem_attrs.status = AVRC_STS_NO_ERROR;
@@ -1418,13 +1459,15 @@ static bt_status_t btc_avrc_ct_send_metadata_cmd (uint8_t tl, uint8_t attr_mask)
avrc_cmd.get_elem_attrs.num_attr = index;
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (status == AVRC_STS_NO_ERROR) {
cmd_status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (cmd_status == AVRC_STS_NO_ERROR) {
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_STATUS, p_msg);
status = BT_STATUS_SUCCESS;
ret = BT_STATUS_SUCCESS;
} else {
ret = BT_STATUS_FAIL;
}
} else {
status = BT_STATUS_FAIL;
ret = BT_STATUS_FAIL;
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
}
@@ -1432,31 +1475,34 @@ static bt_status_t btc_avrc_ct_send_metadata_cmd (uint8_t tl, uint8_t attr_mask)
BTC_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
#endif
return status;
return ret;
}
static bt_status_t btc_avrc_ct_send_get_play_status_cmd(uint8_t tl)
{
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
bt_status_t ret = BT_STATUS_UNSUPPORTED;
#if (AVRC_METADATA_INCLUDED == TRUE)
CHECK_ESP_RC_CONNECTED;
tAVRC_COMMAND avrc_cmd = {0};
BT_HDR *p_msg = NULL;
tAVRC_STS cmd_status;
avrc_cmd.get_play_status.opcode = AVRC_OP_VENDOR;
avrc_cmd.get_play_status.status = AVRC_STS_NO_ERROR;
avrc_cmd.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (status == AVRC_STS_NO_ERROR) {
cmd_status = AVRC_BldCommand(&avrc_cmd, &p_msg);
if (cmd_status == AVRC_STS_NO_ERROR) {
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_STATUS, p_msg);
status = BT_STATUS_SUCCESS;
ret = BT_STATUS_SUCCESS;
} else {
ret = BT_STATUS_FAIL;
}
} else {
status = BT_STATUS_FAIL;
ret = BT_STATUS_FAIL;
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
}
@@ -1464,7 +1510,7 @@ static bt_status_t btc_avrc_ct_send_get_play_status_cmd(uint8_t tl)
BTC_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
#endif
return status;
return ret;
}
static bt_status_t btc_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state)
@@ -1758,6 +1804,8 @@ void btc_avrc_ct_call_handler(btc_msg_t *msg)
default:
BTC_TRACE_WARNING("%s : unhandled event: %d\n", __FUNCTION__, msg->act);
}
btc_avrc_arg_deep_free(msg);
}
void btc_avrc_tg_call_handler(btc_msg_t *msg)

View File

@@ -118,6 +118,9 @@ void AVCT_Deregister(void)
/* deregister PSM with L2CAP */
L2CA_Deregister(AVCT_PSM);
#if (AVCT_BROWSE_INCLUDED == TRUE)
L2CA_Deregister(AVCT_BR_PSM);
#endif
}
/*******************************************************************************
@@ -173,9 +176,14 @@ UINT16 AVCT_CreateConn(UINT8 *p_handle, tAVCT_CC *p_cc, BD_ADDR peer_addr)
if (result == AVCT_SUCCESS) {
/* bind lcb to ccb */
tAVCT_LCB_EVT evt;
p_ccb->p_lcb = p_lcb;
AVCT_TRACE_DEBUG("ch_state: %d", p_lcb->ch_state);
avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
evt.p_ccb = p_ccb;
avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, &evt);
if (!p_ccb->allocated) {
result = AVCT_NOT_OPEN;
}
}
}
}
@@ -212,7 +220,9 @@ UINT16 AVCT_RemoveConn(UINT8 handle)
}
/* send unbind event to lcb */
else {
avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
tAVCT_LCB_EVT evt;
evt.p_ccb = p_ccb;
avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT, &evt);
}
return result;
}

View File

@@ -234,6 +234,9 @@ void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
lcid, p_lcb->ch_state, p_cfg->result);
if (p_lcb->conflict_lcid == lcid) {
return;
}
/* if in correct state */
if (p_lcb->ch_state == AVCT_CH_CFG) {
/* if result successful */
@@ -294,6 +297,10 @@ void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
p_cfg->result = L2CAP_CFG_OK;
L2CA_ConfigRsp(lcid, p_cfg);
if (p_lcb->conflict_lcid == lcid) {
return;
}
/* if first config ind */
if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
/* update flags */
@@ -322,7 +329,7 @@ void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
{
tAVCT_LCB *p_lcb;
UINT16 result = AVCT_RESULT_FAIL;
tAVCT_LCB_EVT evt;
/* look up lcb for this channel */
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
@@ -332,7 +339,13 @@ void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
L2CA_DisconnectRsp(lcid);
}
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
if (p_lcb->conflict_lcid == lcid) {
p_lcb->conflict_lcid = 0;
return;
}
evt.result = AVCT_RESULT_FAIL;
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &evt);
AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
}
}
@@ -356,6 +369,10 @@ void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
lcid, p_lcb->ch_state, result);
if (p_lcb->conflict_lcid == lcid) {
p_lcb->conflict_lcid = 0;
return;
}
/* result value may be previously stored */
res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
p_lcb->ch_result = 0;

View File

@@ -364,7 +364,7 @@ void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
AVCT_TRACE_DEBUG("%s Freeing LCB", __func__);
osi_free(p_lcb->p_rx_msg);
fixed_queue_free(p_lcb->tx_q, NULL);
fixed_queue_free(p_lcb->tx_q, osi_free_func);
memset(p_lcb, 0, sizeof(tAVCT_LCB));
}

View File

@@ -425,7 +425,12 @@ void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UNUSED(p_data);
L2CA_DisconnectReq(p_lcb->ch_lcid);
tAVCT_LCB_EVT evt;
if (!L2CA_DisconnectReq(p_lcb->ch_lcid)) {
evt.result = AVCT_RESULT_FAIL;
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, &evt);
}
}
/*******************************************************************************
@@ -474,6 +479,7 @@ void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
{
p_lcb->cong = TRUE;
event = AVCT_CONG_IND_EVT;
}
}
}

View File

@@ -64,6 +64,31 @@ static const UINT8 avrc_ctrl_event_map[] = {
#define AVRC_OP_SUB_UNIT_INFO_RSP_LEN 8
#define AVRC_OP_REJ_MSG_LEN 11
#if (AVRC_METADATA_INCLUDED == TRUE)
/******************************************************************************
**
** Function avrc_free_far_cb
**
** Description Free fragmentation/reassembly buffers for a connection.
**
******************************************************************************/
static void avrc_free_far_cb(UINT8 handle)
{
if (handle >= AVCT_NUM_CONN) {
return;
}
if (avrc_cb.fcb[handle].p_fmsg) {
osi_free(avrc_cb.fcb[handle].p_fmsg);
avrc_cb.fcb[handle].p_fmsg = NULL;
}
avrc_cb.fcb[handle].frag_enabled = FALSE;
if (avrc_cb.rcb[handle].p_rmsg) {
osi_free(avrc_cb.rcb[handle].p_rmsg);
avrc_cb.rcb[handle].p_rmsg = NULL;
}
}
#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
/******************************************************************************
**
** Function avrc_ctrl_cback
@@ -83,6 +108,13 @@ static void avrc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result,
return;
}
/* Release pending fragment/reassembly buffers on disconnect */
if (event == AVCT_DISCONNECT_CFM_EVT || event == AVCT_DISCONNECT_IND_EVT) {
#if (AVRC_METADATA_INCLUDED == TRUE)
avrc_free_far_cb(handle);
#endif
}
if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback) {
avrc_event = avrc_ctrl_event_map[event];
if (event == AVCT_CONNECT_CFM_EVT) {
@@ -298,6 +330,11 @@ static BT_HDR *avrc_proc_vendor_command(UINT8 handle, UINT8 label,
if (p_msg->company_id == AVRC_CO_METADATA) {
switch (*p_data) {
case AVRC_PDU_ABORT_CONTINUATION_RSP:
if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_ABORT_CONTINUATION_RSP_CMD_SIZE)) {
status = AVRC_STS_INTERNAL_ERR;
abort_frag = TRUE;
break;
}
/* aborted by CT - send accept response */
abort_frag = TRUE;
p_begin = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
@@ -315,6 +352,11 @@ static BT_HDR *avrc_proc_vendor_command(UINT8 handle, UINT8 label,
break;
case AVRC_PDU_REQUEST_CONTINUATION_RSP:
if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_REQUEST_CONTINUATION_RSP_CMD_SIZE)) {
status = AVRC_STS_INTERNAL_ERR;
abort_frag = TRUE;
break;
}
if (*(p_data + 4) == p_fcb->frag_pdu) {
avrc_send_continue_frag(handle, label);
p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
@@ -435,18 +477,17 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
/* Free original START packet, replace with pointer to reassembly buffer */
osi_free(p_pkt);
*pp_pkt = p_rcb->p_rmsg;
} else {
/* Unable to allocate buffer for fragmented avrc message. Reuse START
buffer for reassembly (re-assembled message may fit into ACL buf) */
AVRC_TRACE_DEBUG ("Unable to allocate buffer for fragmented avrc message, \
reusing START buffer for reassembly");
p_rcb->rasm_offset = p_pkt->offset;
p_rcb->p_rmsg = p_pkt;
}
/* set offset to point to where to copy next - use the same re-asm logic as AVCT */
p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
req_continue = TRUE;
/* set offset to point to where to copy next - use the same re-asm logic as AVCT */
p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
req_continue = TRUE;
} else {
/* do not reuse START buffer; it is smaller than BT_DEFAULT_BUFFER_SIZE */
AVRC_TRACE_ERROR("Unable to allocate buffer for fragmented avrc message");
drop_code = 5;
osi_free(p_pkt);
*pp_pkt = NULL;
}
} else if (p_rcb->p_rmsg == NULL) {
/* Received a CONTINUE/END, but no corresponding START
(or previous fragmented response was dropped) */
@@ -521,6 +562,14 @@ static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_
if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR) {
drop_code = 2;
AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd);
} else {
AVRC_TRACE_ERROR("Failed to build continuation command");
if (p_rcb->p_rmsg) {
osi_free(p_rcb->p_rmsg);
p_rcb->p_rmsg = NULL;
*pp_pkt = NULL;
}
drop_code = 5;
}
}
}
@@ -953,6 +1002,8 @@ UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
if (status == AVCT_SUCCESS) {
memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
#if (AVRC_METADATA_INCLUDED == TRUE)
/* free fragmentation/reassembly buffers before memset clears pointers */
avrc_free_far_cb(*p_handle);
memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
#endif
@@ -984,6 +1035,10 @@ UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
UINT16 AVRC_Close(UINT8 handle)
{
AVRC_TRACE_DEBUG("AVRC_Close handle:%d", handle);
#if (AVRC_METADATA_INCLUDED == TRUE)
/* release pending fragment/reassembly buffers before removing connection */
avrc_free_far_cb(handle);
#endif
return AVCT_RemoveConn(handle);
}
@@ -1067,7 +1122,7 @@ UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
/* AVRCP spec has not defined any control channel commands that needs fragmentation at this level
* check for fragmentation only on the response */
if ((cr == AVCT_RSP) && (chk_frag == TRUE)) {
if ((cr == AVCT_RSP) && (chk_frag == TRUE) && (p_pkt->event == AVRC_OP_VENDOR)) {
if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) {
int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
p_pkt_new = (BT_HDR *)osi_malloc((UINT16)(AVRC_PACKET_LEN + offset_len
@@ -1099,6 +1154,9 @@ UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
p_pkt->len, len, p_fcb->p_fmsg->len );
} else {
AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation" );
if (p_pkt_new) {
osi_free(p_pkt_new);
}
osi_free(p_pkt);
return AVRC_NO_RESOURCES;
}

View File

@@ -336,9 +336,11 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
status = avrc_bld_get_play_status_cmd(&p_cmd->get_play_status, p_pkt);
break;
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
status = avrc_bld_register_change_notfn(p_cmd->reg_notif.event_id, p_cmd->reg_notif.param, p_pkt);
break;
#endif
case AVRC_PDU_GET_CAPABILITIES:
status = avrc_bld_get_caps_cmd(&p_cmd->get_caps, p_pkt);
break;

View File

@@ -87,15 +87,17 @@ static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR
}
len += count * 3;
} else {
UINT8 valid_count = 0;
p_event_id = p_rsp->param.event_id;
*p_count = 0;
*p_count -= count;
for (xx = 0; xx < count; xx++) {
if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx])) {
(*p_count)++;
valid_count++;
UINT8_TO_BE_STREAM(p_data, p_event_id[xx]);
}
}
len += (*p_count);
*p_count += valid_count;
len += valid_count;
}
UINT16_TO_BE_STREAM(p_len, len);
p_pkt->len = (p_data - p_start);
@@ -314,12 +316,6 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rs
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
p_data = p_len = p_start + 2; /* pdu + rsvd */
/*
* NOTE: The buffer is allocated within avrc_bld_init_rsp_buffer(), and is
* always of size BT_DEFAULT_BUFFER_SIZE.
*/
len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE - p_pkt->offset - p_pkt->len;
BE_STREAM_TO_UINT16(len, p_data);
p_count = p_data;
@@ -331,6 +327,7 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rs
}
for (xx = 0; xx < p_rsp->num_attr; xx++) {
len_left = (UINT16)(((UINT8 *)p_pkt + BT_DEFAULT_BUFFER_SIZE) - p_data);
if (len_left < (p_rsp->p_attrs[xx].str_len + 4)) {
AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp out of room %d(str_len:%d, left:%d)",
xx, p_rsp->p_attrs[xx].str_len, len_left);
@@ -926,6 +923,10 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
status = avrc_bld_set_absolute_volume_rsp(&p_rsp->volume, p_pkt);
break;
default:
status = AVRC_STS_BAD_PARAM;
break;
}
if (alloc && (status != AVRC_STS_NO_ERROR) ) {

View File

@@ -52,9 +52,6 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
tAVRC_APP_SETTING *p_app_set;
/* Check the vendor data */
if (p_msg->vendor_len == 0) {
return AVRC_STS_NO_ERROR;
}
if ((p_msg->p_vendor_data == NULL) || (p_msg->vendor_len < AVRC_CMD_FIXED_SIZE)) {
return AVRC_STS_INTERNAL_ERR;
}

View File

@@ -199,6 +199,11 @@ UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
/* perform service search */
result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback);
if (!result) {
avrc_cb.service_uuid = 0;
avrc_cb.p_db = NULL;
avrc_cb.p_cback = NULL;
}
}
return (result ? AVRC_SUCCESS : AVRC_FAIL);
@@ -413,6 +418,17 @@ void AVRC_Deinit(void)
{
#if AVRC_DYNAMIC_MEMORY
if (avrc_cb_ptr){
#if (AVRC_METADATA_INCLUDED == TRUE)
UINT8 i;
for (i = 0; i < AVCT_NUM_CONN; i++) {
if (avrc_cb_ptr->fcb[i].p_fmsg) {
osi_free(avrc_cb_ptr->fcb[i].p_fmsg);
}
if (avrc_cb_ptr->rcb[i].p_rmsg) {
osi_free(avrc_cb_ptr->rcb[i].p_rmsg);
}
}
#endif
osi_free(avrc_cb_ptr);
avrc_cb_ptr = NULL;
}

View File

@@ -325,10 +325,6 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
esp_avrc_ct_init();
esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
esp_avrc_rn_evt_cap_mask_t evt_set = {0};
esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
ESP_ERROR_CHECK(esp_avrc_tg_set_rn_evt_cap(&evt_set));
esp_a2d_source_init();
esp_a2d_register_callback(&bt_app_a2d_cb);
esp_a2d_source_register_data_callback(bt_app_a2d_data_cb);