fix(bt): Add invalid codec capability verification when registering SEP

This commit is contained in:
yangfeng
2026-08-20 14:17:00 +08:00
parent 998bd59e3f
commit d1d1f91b12
3 changed files with 137 additions and 0 deletions

View File

@@ -85,6 +85,24 @@ typedef enum {
#define BTC_AV_M24_CIE_OFFSET 3 #define BTC_AV_M24_CIE_OFFSET 3
#define BTC_AV_M24_CIE_LEN 6 #define BTC_AV_M24_CIE_LEN 6
#define BTC_AV_SBC_SNK_HQ_BITPOOL 53
#define BTC_AV_SBC_CH_MODE_ALL (ESP_A2D_SBC_CIE_CH_MODE_MONO | \
ESP_A2D_SBC_CIE_CH_MODE_DUAL_CHANNEL | \
ESP_A2D_SBC_CIE_CH_MODE_STEREO | \
ESP_A2D_SBC_CIE_CH_MODE_JOINT_STEREO)
#define BTC_AV_SBC_CH_MODE_SRC_C1 (ESP_A2D_SBC_CIE_CH_MODE_DUAL_CHANNEL | \
ESP_A2D_SBC_CIE_CH_MODE_STEREO | \
ESP_A2D_SBC_CIE_CH_MODE_JOINT_STEREO)
#define BTC_AV_SBC_BLOCK_LEN_ALL (ESP_A2D_SBC_CIE_BLOCK_LEN_4 | \
ESP_A2D_SBC_CIE_BLOCK_LEN_8 | \
ESP_A2D_SBC_CIE_BLOCK_LEN_12 | \
ESP_A2D_SBC_CIE_BLOCK_LEN_16)
#define BTC_AV_SBC_NUM_SUBBANDS_ALL (ESP_A2D_SBC_CIE_NUM_SUBBANDS_4 | \
ESP_A2D_SBC_CIE_NUM_SUBBANDS_8)
#define BTC_AV_SBC_ALLOC_MTHD_ALL (ESP_A2D_SBC_CIE_ALLOC_MTHD_SNR | \
ESP_A2D_SBC_CIE_ALLOC_MTHD_LOUDNESS)
#define BTC_AV_M24_CH_1_2 (ESP_A2D_M24_CIE_CH_1 | ESP_A2D_M24_CIE_CH_2)
/***************************************************************************** /*****************************************************************************
** Local type definitions ** Local type definitions
******************************************************************************/ ******************************************************************************/
@@ -1630,6 +1648,67 @@ tBTC_AV_CODEC_INFO *btc_av_codec_cap_get(void)
return btc_av_cb.codec_caps; return btc_av_cb.codec_caps;
} }
static BOOLEAN btc_av_sep_mcc_caps_valid(BOOLEAN is_sink, const esp_a2d_mcc_t *mcc)
{
/* Mandatory bits per A2DP v1.4.1 Get All Capabilities (Tables 4.24.7, 4.144.20). */
if (mcc->type == ESP_A2D_MCT_SBC) {
const esp_a2d_cie_sbc_t *sbc = &mcc->cie.sbc_info;
if (!sbc->samp_freq || !sbc->ch_mode || !sbc->block_len ||
!sbc->num_subbands || !sbc->alloc_mthd ||
sbc->min_bitpool < A2D_SBC_IE_MIN_BITPOOL || sbc->max_bitpool > A2D_SBC_IE_MAX_BITPOOL ||
sbc->max_bitpool < sbc->min_bitpool) {
return FALSE;
}
/* Table 4.4: block length 4/8/12/16 mandatory for SRC and SNK. */
if ((sbc->block_len & BTC_AV_SBC_BLOCK_LEN_ALL) != BTC_AV_SBC_BLOCK_LEN_ALL) {
return FALSE;
}
if (is_sink) {
/* Tables 4.2, 4.3, 4.5, 4.6, 4.7: 44.1+48, all channel modes,
* both subbands, SNR+Loudness, min bitpool 2, max >= HQ JS 44.1. */
return ((sbc->samp_freq & (ESP_A2D_SBC_CIE_SF_44K | ESP_A2D_SBC_CIE_SF_48K)) ==
(ESP_A2D_SBC_CIE_SF_44K | ESP_A2D_SBC_CIE_SF_48K)) &&
((sbc->ch_mode & BTC_AV_SBC_CH_MODE_ALL) == BTC_AV_SBC_CH_MODE_ALL) &&
((sbc->num_subbands & BTC_AV_SBC_NUM_SUBBANDS_ALL) == BTC_AV_SBC_NUM_SUBBANDS_ALL) &&
((sbc->alloc_mthd & BTC_AV_SBC_ALLOC_MTHD_ALL) == BTC_AV_SBC_ALLOC_MTHD_ALL) &&
(sbc->min_bitpool == A2D_SBC_IE_MIN_BITPOOL) &&
(sbc->max_bitpool >= BTC_AV_SBC_SNK_HQ_BITPOOL);
}
/* SRC: Table 4.2 C1 (44.1 or 48), Table 4.3 Mono + C1 stereo family,
* Table 4.5 subbands 8, Table 4.6 Loudness. */
return ((sbc->samp_freq & (ESP_A2D_SBC_CIE_SF_44K | ESP_A2D_SBC_CIE_SF_48K)) != 0) &&
(sbc->ch_mode & ESP_A2D_SBC_CIE_CH_MODE_MONO) &&
(sbc->ch_mode & BTC_AV_SBC_CH_MODE_SRC_C1) &&
(sbc->num_subbands & ESP_A2D_SBC_CIE_NUM_SUBBANDS_8) &&
(sbc->alloc_mthd & ESP_A2D_SBC_CIE_ALLOC_MTHD_LOUDNESS);
}
#if (BTC_AV_CODEC_AAC_INCLUDED == TRUE)
if (mcc->type == ESP_A2D_MCT_M24) {
const esp_a2d_cie_m24_t *m24 = &mcc->cie.m24_info;
/* Table 4.14: MPEG-2 AAC LC mandatory. Table 4.16: DRC not with MPEG-2 AAC LC only. */
if (!(m24->obj_type & ESP_A2D_M24_CIE_OBJ_TYPE_2_AAC_LC) ||
!(m24->samp_freq1 | m24->samp_freq2) || !m24->ch) {
return FALSE;
}
if (m24->obj_type == ESP_A2D_M24_CIE_OBJ_TYPE_2_AAC_LC && m24->drc) {
return FALSE;
}
if (is_sink) {
/* Tables 4.17, 4.18, 4.20: 44.1+48, ch 1+2, VBR. */
return (m24->samp_freq1 & ESP_A2D_M24_CIE_SF1_44K) &&
(m24->samp_freq2 & ESP_A2D_M24_CIE_SF2_48K) &&
((m24->ch & BTC_AV_M24_CH_1_2) == BTC_AV_M24_CH_1_2) &&
m24->vbr;
}
/* SRC: Table 4.17 C1 (44.1 or 48), Table 4.18 C1 (1 or 2 ch). */
return ((m24->samp_freq1 & ESP_A2D_M24_CIE_SF1_44K) ||
(m24->samp_freq2 & ESP_A2D_M24_CIE_SF2_48K)) &&
(m24->ch & BTC_AV_M24_CH_1_2);
}
#endif
return FALSE;
}
static void btc_av_reg_sep(uint8_t tsep, uint8_t seid, esp_a2d_mcc_t *mcc) 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; tBTA_AV_DATA_CBACK *p_data_cback = NULL;
@@ -1645,6 +1724,14 @@ static void btc_av_reg_sep(uint8_t tsep, uint8_t seid, esp_a2d_mcc_t *mcc)
return; return;
} }
if (!btc_av_sep_mcc_caps_valid((tsep == AVDT_TSEP_SNK), mcc)) {
param.a2d_sep_reg_stat.reg_state = ESP_A2D_SEP_REG_UNSUPPORTED;
btc_a2d_cb_to_app(ESP_A2D_SEP_REG_STATE_EVT, &param);
BTC_TRACE_WARNING("%s: refuse seid %d codec 0x%02x, A2DP capability check failed",
__func__, seid, mcc->type);
return;
}
/* /*
* A2DP requires at least one SBC SEP. Reject a non-SBC registration that * A2DP requires at least one SBC SEP. Reject a non-SBC registration that
* would overwrite the last remaining SBC capability. * would overwrite the last remaining SBC capability.

View File

@@ -57,6 +57,31 @@ idf.py menuconfig
* Choose external I2S codec or internal DAC for audio output, and configure the output PINs under A2DP Sink Internal Codec Example Configuration. * Choose external I2S codec or internal DAC for audio output, and configure the output PINs under A2DP Sink Internal Codec Example Configuration.
### Stream Endpoint (SEP) registration
This example registers codec capabilities with `esp_a2d_sink_register_stream_endpoint()` after A2DP sink init and before connecting. A2DP requires **at least one SBC SEP**; using AAC therefore needs `ESP_A2D_MAX_SEPS >= 2`. Capabilities that do not meet A2DP Profile (SNK) fail with `ESP_A2D_SEP_REG_UNSUPPORTED` in `ESP_A2D_SEP_REG_STATE_EVT`. Overwriting the last SBC SEP fails with `ESP_A2D_SEP_REG_SBC_REQUIRED`.
**SBC (SNK)**
| Field | Mandatory |
| :---- | :-------- |
| Sampling frequency | 44.1 kHz and 48 kHz |
| Channel mode | Mono, Dual Channel, Stereo, and Joint Stereo |
| Block length | 4, 8, 12, and 16 |
| Subbands | 4 and 8 |
| Allocation method | SNR and Loudness |
| Bitpool | min = 2; max ≥ 53 (High Quality Joint Stereo 44.1 kHz, A2DP Table 4.7); max ≤ 250 |
**AAC (SNK)**
| Field | Mandatory |
| :---- | :-------- |
| Object type | MPEG-2 AAC LC |
| MPEG-D DRC | Must be 0 if only MPEG-2 AAC LC is advertised |
| Sampling frequency | 44.1 kHz and 48 kHz |
| Channels | 1 and 2 |
| VBR | Supported |
### Build and Flash ### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output. Build the project and flash it to the board, then run monitor tool to view serial output.

View File

@@ -28,6 +28,31 @@ idf.py menuconfig
* Enable Classic Bluetooth and A2DP under Component config --> Bluetooth --> Bluedroid Enable * Enable Classic Bluetooth and A2DP under Component config --> Bluetooth --> Bluedroid Enable
### Stream Endpoint (SEP) registration
This example registers codec capabilities with `esp_a2d_source_register_stream_endpoint()` after A2DP source init and before connecting. A2DP requires **at least one SBC SEP**; using AAC therefore needs `ESP_A2D_MAX_SEPS >= 2`. Capabilities that do not meet A2DP Profile (SRC) fail with `ESP_A2D_SEP_REG_UNSUPPORTED` in `ESP_A2D_SEP_REG_STATE_EVT`. Overwriting the last SBC SEP fails with `ESP_A2D_SEP_REG_SBC_REQUIRED`.
**SBC (SRC)**
| Field | Mandatory |
| :---- | :-------- |
| Sampling frequency | At least one of 44.1 kHz and 48 kHz |
| Channel mode | Mono, and at least one of Dual Channel / Stereo / Joint Stereo |
| Block length | 4, 8, 12, and 16 |
| Subbands | 8 |
| Allocation method | Loudness |
| Bitpool | min 2250, max 2250, min ≤ max |
**AAC (SRC)**
| Field | Mandatory |
| :---- | :-------- |
| Object type | MPEG-2 AAC LC |
| MPEG-D DRC | Must be 0 if only MPEG-2 AAC LC is advertised |
| Sampling frequency | At least one of 44.1 kHz and 48 kHz |
| Channels | At least one of 1 and 2 |
| VBR | Optional |
### Build and Flash ### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output. Build the project and flash it to the board, then run monitor tool to view serial output.