fix(bt): fix A2DP api and btc component issues reported by AI review

This commit is contained in:
yangfeng
2026-03-19 20:01:51 +08:00
parent da26be8864
commit e3782bf2c0
8 changed files with 121 additions and 34 deletions
@@ -77,7 +77,7 @@ esp_err_t esp_a2d_sink_register_stream_endpoint(uint8_t seid, const esp_a2d_mcc_
return ESP_ERR_INVALID_STATE;
}
if (seid >= ESP_A2D_MAX_SEPS) {
if (mcc == NULL || seid >= ESP_A2D_MAX_SEPS) {
return ESP_ERR_INVALID_ARG;
}
@@ -209,6 +209,7 @@ esp_err_t esp_a2d_sink_disconnect(esp_bd_addr_t remote_bda)
msg.pid = BTC_PID_A2DP;
msg.act = BTC_AV_SINK_API_DISCONNECT_EVT;
memset(&arg, 0, sizeof(btc_av_args_t));
/* Switch to BTC context */
memcpy(&(arg.disconn), remote_bda, sizeof(bt_bdaddr_t));
stat = btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL, NULL);
@@ -292,7 +293,7 @@ esp_err_t esp_a2d_media_ctrl(esp_a2d_media_ctrl_t ctrl)
return ESP_ERR_INVALID_STATE;
}
if (ctrl > ESP_A2D_MEDIA_CTRL_SUSPEND) {
if (ctrl <= ESP_A2D_MEDIA_CTRL_NONE || ctrl > ESP_A2D_MEDIA_CTRL_SUSPEND) {
return ESP_ERR_INVALID_ARG;
}
@@ -388,7 +389,7 @@ esp_err_t esp_a2d_source_register_stream_endpoint(uint8_t seid, const esp_a2d_mc
return ESP_ERR_INVALID_STATE;
}
if (seid >= ESP_A2D_MAX_SEPS) {
if (mcc == NULL || seid >= ESP_A2D_MAX_SEPS) {
return ESP_ERR_INVALID_ARG;
}
@@ -309,6 +309,7 @@ void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk,
/* Sanity check : this should never happen */
if (p_peer->opened) {
APPL_TRACE_ERROR("bta_av_co_audio_disc_res peer already opened");
return;
}
/* Copy the discovery results */
@@ -359,6 +360,7 @@ void bta_av_co_audio_cfg_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk,
/* Sanity check : this should never happen */
if (p_peer->opened) {
APPL_TRACE_ERROR("bta_av_co_audio_cfg_res peer already opened");
return;
}
/* Copy the discovery results */
@@ -403,6 +405,8 @@ void bta_av_build_src_cfg (UINT8 *p_pref_cfg, UINT8 *p_src_cap)
return ;
}
memcpy(&pref_cap, &src_cap, sizeof(tA2D_SBC_CIE));
if (src_cap.samp_freq & A2D_SBC_IE_SAMP_FREQ_48) {
pref_cap.samp_freq = A2D_SBC_IE_SAMP_FREQ_48;
} else if (src_cap.samp_freq & A2D_SBC_IE_SAMP_FREQ_44) {
@@ -751,6 +755,8 @@ void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
/* Sanity check: should not be opened at this point */
if (p_peer->opened) {
APPL_TRACE_ERROR("bta_av_co_audio_setconfig peer already in use");
bta_av_ci_setconfig(hndl, A2D_BUSY, AVDT_ASC_CODEC, 0, NULL, FALSE, avdt_handle);
return;
}
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
@@ -996,7 +1002,7 @@ void *bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type, UINT32 *p_len,
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
{
UINT8 *p;
if (bta_av_co_cp_is_active()) {
if (bta_av_co_cp_is_active() && p_buf->offset > 0) {
p_buf->len++;
p_buf->offset--;
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
@@ -78,7 +78,9 @@ static void btc_a2dp_datapath_open(void)
}
#endif
#if (BTC_AV_SINK_INCLUDED == TRUE)
btc_aa_ctrl_cb.data_channel_open = TRUE;
if (btc_av_get_peer_sep() == AVDT_TSEP_SRC && btc_av_get_service_id() == BTA_A2DP_SINK_SERVICE_ID) {
btc_aa_ctrl_cb.data_channel_open = TRUE;
}
#endif
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -411,6 +411,7 @@ static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg
a2dp_sink_local_param.btc_aa_snk_cb.channel_count, FALSE, FALSE);
if (!OI_SUCCESS(status)) {
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
return;
}
btc_a2dp_control_set_datachnl_stat(TRUE);
@@ -521,13 +522,22 @@ static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg
*******************************************************************************/
static void btc_a2dp_sink_handle_inc_media(BT_HDR *p_msg)
{
UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
UINT8 *sbc_start_frame;
int count;
UINT32 pcmBytes, availPcmBytes;
OI_INT16 *pcmDataPointer = a2dp_sink_local_param.pcmData; /*Will be overwritten on next packet receipt*/
OI_STATUS status;
int num_sbc_frames = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
UINT32 sbc_frame_len = p_msg->len - 1;
int num_sbc_frames;
UINT32 sbc_frame_len;
if (p_msg->len < 1) {
osi_free(p_msg);
return;
}
sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
num_sbc_frames = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
sbc_frame_len = (UINT32)p_msg->len - 1U;
availPcmBytes = sizeof(a2dp_sink_local_param.pcmData);
/* XXX: Check if the below check is correct, we are checking for peer to be sink when we are sink */
@@ -569,8 +579,6 @@ static void btc_a2dp_sink_handle_inc_media(BT_HDR *p_msg)
}
availPcmBytes -= pcmBytes;
pcmDataPointer += pcmBytes / 2;
p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
p_msg->len = sbc_frame_len + 1;
}
if (count != num_sbc_frames || sbc_frame_len) {
APPL_TRACE_WARNING("Potential decoding error, cnt:%d, num:%d, len:%d. Please ignore if playback is normal.",
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -118,6 +118,17 @@ bool btc_a2dp_sink_startup(void)
osi_event_bind(data_event, a2dp_sink_local_param.btc_aa_snk_task_hdl, BTC_A2DP_SNK_DATA_QUEUE_IDX);
a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = data_event;
a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q = fixed_queue_new(QUEUE_SIZE_MAX);
if (a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q == NULL) {
osi_event_delete(data_event);
a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = NULL;
a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL;
#if A2D_DYNAMIC_MEMORY == TRUE
osi_free(a2dp_sink_local_param_ptr);
a2dp_sink_local_param_ptr = NULL;
#endif
return false;
}
btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_ON;
btc_a2dp_control_init();
@@ -220,9 +231,18 @@ static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context)
static void btc_a2dp_sink_handle_inc_media(BT_HDR *p_msg)
{
UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
int num_sbc_frames = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
UINT32 sbc_frame_len = p_msg->len - 1;
UINT8 *sbc_start_frame;
int num_sbc_frames;
UINT32 sbc_frame_len;
UINT32 timestamp;
if (p_msg->len < 1) {
osi_free(p_msg);
return;
}
sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
num_sbc_frames = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
sbc_frame_len = (UINT32)p_msg->len - 1U;
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush) {
osi_free(p_msg);
@@ -249,7 +269,7 @@ static void btc_a2dp_sink_handle_inc_media(BT_HDR *p_msg)
APPL_TRACE_DEBUG("Number of sbc frames %d, frame_len %d\n", num_sbc_frames, sbc_frame_len);
UINT32 timestamp = *((UINT32 *) (p_msg + 1));
memcpy(&timestamp, (UINT8 *)(p_msg + 1), sizeof(UINT32));
UINT16 conn_hdl = btc_a2d_conn_handle_get();
btc_a2d_audio_data_cb_to_app(conn_hdl, (uint8_t *)p_msg, sbc_start_frame, sbc_frame_len, num_sbc_frames, timestamp);
/* dont free p_msg here */
@@ -262,6 +282,11 @@ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt)
return 0;
}
if (a2dp_sink_local_param.btc_aa_snk_cb.audio_rx_q == NULL) {
osi_free(p_pkt);
return 0;
}
if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) {
/* Flush enabled, do not enqueue */
osi_free(p_pkt);
@@ -371,10 +371,12 @@ void btc_a2dp_source_on_stopped(tBTA_AV_SUSPEND *p_av)
void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av)
{
/* check for status failures */
if (p_av->status != BTA_AV_SUCCESS) {
if (p_av->initiator == TRUE) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
if (p_av != NULL) {
/* check for status failures */
if (p_av->status != BTA_AV_SUCCESS) {
if (p_av->initiator == TRUE) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
}
}
}
@@ -699,15 +701,24 @@ static void btc_a2dp_source_encoder_init(void)
/* lookup table to convert freq */
UINT16 freq_block_tbl[5] = { SBC_sf48000, SBC_sf44100, SBC_sf32000, 0, SBC_sf16000 };
UINT8 block_idx, mode_idx, freq_idx;
APPL_TRACE_DEBUG("%s", __FUNCTION__);
/* Retrieve the current SBC configuration (default if currently not used) */
bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
msg.NumOfSubBands = (sbc_config.num_subbands == A2D_SBC_IE_SUBBAND_4) ? 4 : 8;
msg.NumOfBlocks = codec_block_tbl[sbc_config.block_len >> 5];
block_idx = sbc_config.block_len >> 5;
msg.NumOfBlocks = (block_idx < 5) ? codec_block_tbl[block_idx] : 16;
msg.AllocationMethod = (sbc_config.alloc_mthd == A2D_SBC_IE_ALLOC_MD_L) ? SBC_LOUDNESS : SBC_SNR;
msg.ChannelMode = codec_mode_tbl[sbc_config.ch_mode >> 1];
msg.SamplingFreq = freq_block_tbl[sbc_config.samp_freq >> 5];
mode_idx = sbc_config.ch_mode >> 1;
msg.ChannelMode = (mode_idx < 5) ? codec_mode_tbl[mode_idx] : SBC_JOINT_STEREO;
freq_idx = sbc_config.samp_freq >> 5;
msg.SamplingFreq = (freq_idx < 5) ? freq_block_tbl[freq_idx] : SBC_sf44100;
msg.MtuSize = minmtu;
APPL_TRACE_EVENT("msg.ChannelMode %x", msg.ChannelMode);
@@ -1140,6 +1151,10 @@ static UINT8 btc_get_num_aa_frame(void)
a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel *
a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
if (pcm_bytes_per_frame == 0) {
break;
}
UINT32 us_this_tick = BTC_MEDIA_TIME_TICK_MS * 1000;
UINT64 now_us = time_now_us();
if (a2dp_source_local_param.last_frame_us != 0) {
@@ -1334,9 +1349,9 @@ BOOLEAN btc_media_aa_read_feeding(void)
a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue -= bytes_needed;
if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue != 0) {
memcpy((UINT8 *)up_sampled_buffer,
(UINT8 *)up_sampled_buffer + bytes_needed,
a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue);
memmove((UINT8 *)up_sampled_buffer,
(UINT8 *)up_sampled_buffer + bytes_needed,
a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue);
}
return TRUE;
}
@@ -1456,7 +1471,10 @@ static void btc_a2dp_source_prep_2_send(UINT8 nb_frame)
}
while (fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ) > (MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame)) {
osi_free(fixed_queue_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, 0));
void *p_drop = fixed_queue_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, 0);
if (p_drop != NULL) {
osi_free(p_drop);
}
}
// Transcode frame
@@ -135,10 +135,15 @@ void btc_a2dp_source_set_tx_flush(BOOLEAN enable)
void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av)
{
/* check for status failures */
if (p_av == NULL) {
return;
}
if (p_av->status != BTA_AV_SUCCESS) {
if (p_av->initiator == TRUE) {
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
}
return;
}
/* stop tx, ack to cmd, flush tx queue */
@@ -202,6 +207,8 @@ bool btc_a2dp_source_startup(void)
error_exit:;
APPL_TRACE_ERROR("%s A2DP source start up failed", __func__);
btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_OFF;
#if A2D_DYNAMIC_MEMORY == TRUE
osi_free(a2dp_source_local_param_ptr);
a2dp_source_local_param_ptr = NULL;
@@ -330,6 +330,7 @@ static void btc_report_audio_state(esp_a2d_audio_state_t state, bt_bdaddr_t *bd_
static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data)
{
esp_a2d_cb_param_t param;
memset(&param, 0, sizeof(esp_a2d_cb_param_t));
BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
dump_av_sm_event_name(event), btc_av_cb.flags);
@@ -415,6 +416,10 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data)
*/
#if BTC_AV_SRC_INCLUDED
BTC_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
if (btc_av_cb.tle_av_open_on_rc) {
osi_alarm_free(btc_av_cb.tle_av_open_on_rc);
btc_av_cb.tle_av_open_on_rc = NULL;
}
btc_av_cb.tle_av_open_on_rc = osi_alarm_new("AVconn", btc_initiate_av_open_tmr_hdlr, NULL, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000);
osi_alarm_set(btc_av_cb.tle_av_open_on_rc, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000);
#endif /* BTC_AV_SRC_INCLUDED */
@@ -513,7 +518,8 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
if (p_bta_data->open.status == BTA_AV_SUCCESS) {
btc_av_cb.edr = p_bta_data->open.edr;
btc_av_cb.peer_sep = p_bta_data->open.sep;
mtu = p_bta_data->open.mtu - BTC_AV_AUDIO_MTU_RESERVE;
mtu = (p_bta_data->open.mtu > BTC_AV_AUDIO_MTU_RESERVE) ?
(p_bta_data->open.mtu - BTC_AV_AUDIO_MTU_RESERVE) : 0;
conn_stat = ESP_A2D_CONNECTION_STATE_CONNECTED;
av_state = BTC_AV_STATE_OPENED;
} else {
@@ -573,19 +579,21 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
btc_a2d_cb_to_app(ESP_A2D_AUDIO_CFG_EVT, &param);
} break;
case BTC_AV_CONNECT_REQ_EVT:
case BTC_AV_CONNECT_REQ_EVT: {
btc_av_connect_req_t *connect_req = (btc_av_connect_req_t *)p_data;
// Check for device, if same device which moved to opening then ignore callback
if (memcmp ((bt_bdaddr_t *)p_data, &(btc_av_cb.peer_bda),
if (memcmp (&connect_req->target_bda, &(btc_av_cb.peer_bda),
sizeof(btc_av_cb.peer_bda)) == 0) {
BTC_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Connect Req\n", __func__);
btc_queue_advance();
break;
} else {
BTC_TRACE_DEBUG("%s: Moved from idle by Incoming Connection request\n", __func__);
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, (bt_bdaddr_t *)p_data, 0, 0);
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &connect_req->target_bda, 0, 0);
btc_queue_advance();
break;
}
}
case BTA_AV_PENDING_EVT:
// Check for device, if same device which moved to opening then ignore callback
@@ -644,6 +652,7 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *p_data)
{
esp_a2d_cb_param_t param;
memset(&param, 0, sizeof(esp_a2d_cb_param_t));
BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
dump_av_sm_event_name(event), btc_av_cb.flags);
@@ -731,6 +740,7 @@ static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *p_data)
static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
{
esp_a2d_cb_param_t param;
memset(&param, 0, sizeof(esp_a2d_cb_param_t));
tBTA_AV *p_av = (tBTA_AV *)p_data;
BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
@@ -882,17 +892,19 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
}
break;
case BTC_AV_CONNECT_REQ_EVT:
if (memcmp (&((btc_av_connect_req_t *)p_data)->target_bda, &(btc_av_cb.peer_bda),
case BTC_AV_CONNECT_REQ_EVT: {
btc_av_connect_req_t *connect_req = (btc_av_connect_req_t *)p_data;
if (memcmp (&connect_req->target_bda, &(btc_av_cb.peer_bda),
sizeof(btc_av_cb.peer_bda)) == 0) {
BTC_TRACE_DEBUG("%s: Ignore BTC_AVCONNECT_REQ_EVT for same device\n", __func__);
} else {
BTC_TRACE_DEBUG("%s: Moved to opened by Other Incoming Conn req\n", __func__);
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED,
(bt_bdaddr_t *)p_data, 0, ESP_A2D_DISC_RSN_NORMAL);
&connect_req->target_bda, 0, ESP_A2D_DISC_RSN_NORMAL);
}
btc_queue_advance();
break;
}
CHECK_RC_EVENT(event, p_data);
@@ -936,6 +948,7 @@ static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data)
{
tBTA_AV *p_av = (tBTA_AV *)p_data;
esp_a2d_cb_param_t param;
memset(&param, 0, sizeof(esp_a2d_cb_param_t));
BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
dump_av_sm_event_name(event), btc_av_cb.flags);
@@ -2101,6 +2114,13 @@ uint16_t btc_a2d_conn_handle_get(void)
void btc_av_audio_buff_alloc(uint16_t size, uint8_t **pp_buff, uint8_t **pp_data)
{
/* todo */
if (pp_buff == NULL || pp_data == NULL) {
return;
}
*pp_buff = NULL;
*pp_data = NULL;
BT_HDR *p_buf= (BT_HDR *)osi_calloc(sizeof(BT_HDR) + BTC_AUDIO_BUFF_OFFSET + size);
if (p_buf != NULL) {
*pp_buff = (uint8_t *)p_buf;