feat: Add default SBC SEP in A2DP init

This commit is contained in:
yangfeng
2026-08-31 09:40:51 +08:00
parent 826d18c87c
commit b87904e7d9
5 changed files with 104 additions and 11 deletions
@@ -257,6 +257,7 @@ typedef enum {
ESP_A2D_SEP_REG_FAIL, /*!< A2DP stream endpoint register generic fail */
ESP_A2D_SEP_REG_UNSUPPORTED, /*!< A2DP stream endpoint register fail, unsupported codec type or param */
ESP_A2D_SEP_REG_INVALID_STATE, /*!< A2DP stream endpoint register fail, invalid state */
ESP_A2D_SEP_REG_SBC_REQUIRED, /*!< A2DP stream endpoint register fail, at least one SBC SEP must remain */
} esp_a2d_sep_reg_state_t;
/**
@@ -511,7 +512,11 @@ esp_err_t esp_a2d_sink_init(void);
* SEP index repeatedly will overwrite the old one.
* It is necessary to set BT_A2DP_USE_EXTERNAL_CODEC to y.
*
* @note The SEID determines the priority of negotiating the configuration with the peer for initiator.
* @note After A2DP sink init, every SEID is pre-registered with the mandatory default SBC SEP.
* Calling this API overwrites that SEID. A2DP requires at least one SBC SEP; registering a
* non-SBC codec that would overwrite the last SBC SEP fails with ESP_A2D_SEP_REG_SBC_REQUIRED.
* Therefore using AAC (or other non-SBC codecs) requires ESP_A2D_MAX_SEPS >= 2.
* The SEID determines the priority of negotiating the configuration with the peer for initiator.
* The lower the SEID, the higher the priority of the codec capability.
*
* @param[in] seid: local SEP identifier, start from 0, less than ESP_A2D_MAX_SEPS
@@ -667,7 +672,11 @@ esp_err_t esp_a2d_source_set_pref_mcc(esp_a2d_conn_hdl_t conn_hdl, const esp_a2d
* SEP index repeatedly will overwrite the old one.
* It is necessary to set BT_A2DP_USE_EXTERNAL_CODEC to y.
*
* @note The SEID determines the priority of negotiating the configuration with the peer for initiator.
* @note After A2DP source init, every SEID is pre-registered with the mandatory default SBC SEP.
* Calling this API overwrites that SEID. A2DP requires at least one SBC SEP; registering a
* non-SBC codec that would overwrite the last SBC SEP fails with ESP_A2D_SEP_REG_SBC_REQUIRED.
* Therefore using AAC (or other non-SBC codecs) requires ESP_A2D_MAX_SEPS >= 2.
* The SEID determines the priority of negotiating the configuration with the peer for initiator.
* The lower the SEID, the higher the priority of the codec capability.
*
* @param[in] seid: local SEP identifier, start from 0, less than ESP_A2D_MAX_SEPS
@@ -542,10 +542,8 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
tAVDT_CS cs;
char *p_service_name;
tBTA_UTL_COD cod;
#if (BTA_AV_EXT_CODEC == FALSE)
tBTA_AV_CODEC codec_type;
UINT8 index = 0;
#endif
char p_avk_service_name[BTA_SERVICE_NAME_LEN + 1];
BCM_STRLCPY_S(p_avk_service_name, BTIF_AVK_SERVICE_NAME, BTA_SERVICE_NAME_LEN + 1);
@@ -667,10 +665,25 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
/* keep the configuration in the stream control block */
memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
#if (BTA_AV_EXT_CODEC == FALSE)
while (index < BTA_AV_MAX_SEPS &&
(p_scb->p_cos->init)(index, &codec_type, cs.cfg.codec_info,
&cs.cfg.num_protect, cs.cfg.protect_info, p_data->api_reg.tsep) == TRUE) {
/*
* Create local SEPs:
* - Internal codec: init() supplies SBC (typically one SEP).
* - External codec: A2DP mandates SBC, so pre-fill every SEID with
* the default SBC SEP; app register_stream_endpoint() may overwrite.
*/
while (index < BTA_AV_MAX_SEPS) {
#if (BTA_AV_EXT_CODEC == TRUE)
if (bta_av_co_audio_build_sbc_default(p_data->api_reg.tsep, &codec_type,
cs.cfg.codec_info) != TRUE) {
APPL_TRACE_ERROR("failed to build default SBC SEP for seid %d", index);
break;
}
#endif
if ((p_scb->p_cos->init)(index, &codec_type, cs.cfg.codec_info,
&cs.cfg.num_protect, cs.cfg.protect_info,
p_data->api_reg.tsep) != TRUE) {
break;
}
#if (BTA_AV_SINK_INCLUDED == TRUE)
if (p_data->api_reg.tsep == AVDT_TSEP_SNK) {
@@ -698,7 +711,6 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
break;
}
}
#endif
if (!bta_av_cb.reg_audio) {
if (p_data->api_reg.tsep == AVDT_TSEP_SRC) {
@@ -87,6 +87,19 @@ typedef struct {
extern BOOLEAN bta_av_co_audio_init(UINT8 seid, UINT8 *p_codec_type, UINT8 *p_codec_info,
UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 tsep);
/*******************************************************************************
**
** Function bta_av_co_audio_build_sbc_default
**
** Description Build the mandatory default SBC codec capability for the
** given SEP type (source or sink).
**
** Returns TRUE if built successfully, FALSE otherwise.
**
*******************************************************************************/
extern BOOLEAN bta_av_co_audio_build_sbc_default(UINT8 tsep, UINT8 *p_codec_type,
UINT8 *p_codec_info);
/*******************************************************************************
**
** Function bta_av_co_audio_disc_res
@@ -298,6 +298,37 @@ static void bta_av_co_report_peer_all_snk_codec_caps(tBTA_AV_HNDL hndl)
}
#endif /* BTC_AV_SRC_INCLUDED */
/*******************************************************************************
**
** Function bta_av_co_audio_build_sbc_default
**
** Description Build the mandatory default SBC codec capability for the
** given SEP type (source or sink).
**
** Returns TRUE if built successfully, FALSE otherwise.
**
*******************************************************************************/
BOOLEAN bta_av_co_audio_build_sbc_default(UINT8 tsep, UINT8 *p_codec_type, UINT8 *p_codec_info)
{
FUNC_TRACE();
if (p_codec_type == NULL || p_codec_info == NULL) {
return FALSE;
}
*p_codec_type = BTA_AV_CODEC_SBC;
if (tsep == AVDT_TSEP_SRC) {
return (A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *)&bta_av_co_sbc_caps,
p_codec_info) == A2D_SUCCESS);
} else if (tsep == AVDT_TSEP_SNK) {
return (A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps,
p_codec_info) == A2D_SUCCESS);
}
APPL_TRACE_WARNING("bta_av_co_audio_build_sbc_default invalid SEP type %d", tsep);
return FALSE;
}
/*******************************************************************************
**
** Function bta_av_co_audio_init
@@ -1242,9 +1242,15 @@ static bt_status_t btc_av_init(int service_id)
#if (BTC_AV_EXT_CODEC == TRUE)
UINT8 index;
UINT8 tsep = (service_id == BTA_A2DP_SINK_SERVICE_ID) ? AVDT_TSEP_SNK : AVDT_TSEP_SRC;
for (index = 0; index < BTA_AV_MAX_SEPS; index++) {
btc_av_cb.codec_caps[index].id = BTC_AV_CODEC_NONE;
memset(btc_av_cb.codec_caps[index].info, 0, AVDT_CODEC_SIZE);
/* A2DP mandates SBC: fill every SEID with the default SBC capability */
if (bta_av_co_audio_build_sbc_default(tsep, &btc_av_cb.codec_caps[index].id,
btc_av_cb.codec_caps[index].info) != TRUE) {
BTC_TRACE_ERROR("%s: failed to build default SBC for seid %d", __func__, index);
btc_av_cb.codec_caps[index].id = BTC_AV_CODEC_NONE;
memset(btc_av_cb.codec_caps[index].info, 0, AVDT_CODEC_SIZE);
}
}
#endif
@@ -1629,6 +1635,7 @@ static void btc_av_reg_sep(uint8_t tsep, uint8_t seid, esp_a2d_mcc_t *mcc)
tBTA_AV_DATA_CBACK *p_data_cback = NULL;
esp_a2d_cb_param_t param;
tBTA_AV_CODEC codec_type = ESP_A2D_MCT_NON_A2DP;
UINT8 index;
param.a2d_sep_reg_stat.seid = seid;
if (btc_av_cb.sm_handle == NULL || btc_sm_get_state(btc_av_cb.sm_handle) != BTC_AV_STATE_IDLE) {
@@ -1638,6 +1645,27 @@ static void btc_av_reg_sep(uint8_t tsep, uint8_t seid, esp_a2d_mcc_t *mcc)
return;
}
/*
* A2DP requires at least one SBC SEP. Reject a non-SBC registration that
* would overwrite the last remaining SBC capability.
*/
if (mcc->type != ESP_A2D_MCT_SBC) {
BOOLEAN has_other_sbc = FALSE;
for (index = 0; index < BTA_AV_MAX_SEPS; index++) {
if (index != seid && btc_av_cb.codec_caps[index].id == BTC_AV_CODEC_SBC) {
has_other_sbc = TRUE;
break;
}
}
if (!has_other_sbc) {
param.a2d_sep_reg_stat.reg_state = ESP_A2D_SEP_REG_SBC_REQUIRED;
btc_a2d_cb_to_app(ESP_A2D_SEP_REG_STATE_EVT, &param);
BTC_TRACE_WARNING("%s: refuse seid %d codec 0x%02x, at least one SBC SEP is required",
__func__, seid, mcc->type);
return;
}
}
if (tsep == AVDT_TSEP_SNK) {
p_data_cback = bte_av_media_sink_callback;
}