mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
feat(bt/bluedroid): Add API to set encoder parameters for A2DP source
- Add API to set encoder parameters for A2DP source - Add the use of the API for setting encoding parameters in the a2dp_source example
This commit is contained in:
@@ -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
|
||||
*/
|
||||
@@ -349,6 +349,35 @@ esp_err_t esp_a2d_source_init(void)
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_source_set_pref_mcc(esp_a2d_conn_hdl_t conn_hdl, const esp_a2d_mcc_t *pref_mcc)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_source_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (conn_hdl == 0 || pref_mcc == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_A2DP;
|
||||
msg.act = BTC_AV_SRC_API_SET_PREF_MCC_EVT;
|
||||
|
||||
btc_av_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_av_args_t));
|
||||
arg.set_pref_mcc.conn_hdl = conn_hdl;
|
||||
memcpy(&arg.set_pref_mcc.pref_mcc, pref_mcc, sizeof(esp_a2d_mcc_t));
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_a2d_source_register_stream_endpoint(uint8_t seid, const esp_a2d_mcc_t *mcc)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -243,6 +243,7 @@ typedef enum {
|
||||
ESP_A2D_SNK_GET_DELAY_VALUE_EVT, /*!< indicate a2dp sink get delay report value complete, only used for A2DP SINK */
|
||||
ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT, /*!< report delay value, only used for A2DP SRC */
|
||||
ESP_A2D_REPORT_SNK_CODEC_CAPS_EVT, /*!< report sink codec capabilities, only used for A2DP SRC */
|
||||
ESP_A2D_SRC_SET_PREF_MCC_EVT, /*!< indicate a2dp source set preferred media codec configuration status, only used for A2DP SRC */
|
||||
} esp_a2d_cb_event_t;
|
||||
|
||||
/**
|
||||
@@ -349,6 +350,16 @@ typedef union {
|
||||
esp_a2d_mcc_t mcc; /*!< A2DP sink media codec capability information */
|
||||
} a2d_report_snk_codec_caps_stat; /*!< A2DP source received sink codec capabilities */
|
||||
|
||||
/**
|
||||
* @brief ESP_A2D_SRC_SET_PREF_MCC_EVT
|
||||
*/
|
||||
struct a2d_set_pref_mcc_param {
|
||||
esp_bt_status_t set_status; /*!< set status.
|
||||
@note Possible values: ESP_BT_STATUS_SUCCESS, ESP_BT_STATUS_FAIL,
|
||||
ESP_BT_STATUS_NOT_READY, ESP_BT_STATUS_BUSY, ESP_BT_STATUS_UNSUPPORTED. */
|
||||
esp_a2d_conn_hdl_t conn_hdl; /*!< connection handle */
|
||||
} a2d_set_pref_mcc_stat; /*!< A2DP source set preferred media codec configuration */
|
||||
|
||||
} esp_a2d_cb_param_t;
|
||||
|
||||
/**
|
||||
@@ -570,6 +581,23 @@ esp_err_t esp_a2d_get_profile_status(esp_a2d_profile_status_t *profile_status);
|
||||
*/
|
||||
esp_err_t esp_a2d_source_init(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Set the preferred A2DP source media codec configuration after establishing A2DP connection
|
||||
* and before starting A2DP stream.
|
||||
*
|
||||
* @param[in] conn_hdl : connection handle
|
||||
* @param[in] pref_mcc : preferred media codec configuration
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_ARG: invalid parameter
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_a2d_source_set_pref_mcc(esp_a2d_conn_hdl_t conn_hdl, const esp_a2d_mcc_t *pref_mcc);
|
||||
|
||||
/**
|
||||
* @brief Register a a2dp source Stream Endpoint (SEP) with specific codec capability, shall register
|
||||
* SEP after a2dp source initializing and before a2dp connection establishing. Register the same
|
||||
|
||||
@@ -121,6 +121,7 @@ static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT
|
||||
static UINT8 bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg);
|
||||
static UINT8 bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg);
|
||||
static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index);
|
||||
static BOOLEAN bta_av_co_audio_src_supports_pref_cfg(void);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -1409,6 +1410,28 @@ static UINT8 bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8
|
||||
return status;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_src_supports_pref_cfg
|
||||
**
|
||||
** Description Check if the media source codec capability supports the preferred configuration
|
||||
**
|
||||
** Returns TRUE if the media source supports preferred config, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
static BOOLEAN bta_av_co_audio_src_supports_pref_cfg(void)
|
||||
{
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
return (bta_av_co_cb.codec_pref_cfg.id == bta_av_co_cb.codec_caps.id &&
|
||||
bta_av_sbc_cfg_in_external_codec_cap((UINT8 *)&bta_av_co_cb.codec_pref_cfg.info,
|
||||
(UINT8 *)&bta_av_co_cb.codec_caps.info) == A2D_SUCCESS);
|
||||
#else
|
||||
return (bta_av_co_cb.codec_pref_cfg.id == BTC_AV_CODEC_SBC &&
|
||||
bta_av_sbc_cfg_in_cap((UINT8 *)&bta_av_co_cb.codec_pref_cfg.info,
|
||||
(tA2D_SBC_CIE *)&bta_av_co_sbc_caps) == A2D_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_codec_supported
|
||||
@@ -1493,6 +1516,219 @@ BOOLEAN bta_av_co_audio_codec_supported(tBTC_AV_STATUS *p_status)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_set_pref_mcc
|
||||
**
|
||||
** Description Set preferred codec configuration for a specific connection
|
||||
** and initiate reconfiguration if the connection is open.
|
||||
**
|
||||
** Note: This function returns TRUE if the preferred config is
|
||||
** supported. The actual success
|
||||
** or failure of reconfiguration will be reported asynchronously
|
||||
** via BTA_AV_RECONFIG_EVT.
|
||||
**
|
||||
** Returns TRUE if the preferred config is supported, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_av_co_audio_set_pref_mcc(tBTA_AV_HNDL hndl, tBTC_AV_CODEC_INFO *pref_mcc)
|
||||
{
|
||||
#if (BTC_AV_SRC_INCLUDED == TRUE)
|
||||
tBTA_AV_CO_PEER *p_peer;
|
||||
tBTA_AV_CO_SINK *p_sink;
|
||||
UINT8 codec_cfg[AVDT_CODEC_SIZE];
|
||||
UINT8 num_protect = 0;
|
||||
UINT8 snk_index;
|
||||
BOOLEAN pref_cfg_supported = FALSE;
|
||||
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
|
||||
BOOLEAN cp_active;
|
||||
#endif
|
||||
|
||||
if (pref_mcc) {
|
||||
bta_av_co_cb.codec_pref_cfg.id = pref_mcc->id;
|
||||
memcpy(bta_av_co_cb.codec_pref_cfg.info, pref_mcc->info, AVDT_CODEC_SIZE);
|
||||
pref_cfg_supported = bta_av_co_audio_src_supports_pref_cfg();
|
||||
|
||||
if (pref_cfg_supported) {
|
||||
/* Retrieve the peer info for the specified handle */
|
||||
p_peer = bta_av_co_get_peer(hndl);
|
||||
if (p_peer == NULL) {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_set_pref_mcc could not find peer entry for handle 0x%x", hndl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!p_peer->opened) {
|
||||
APPL_TRACE_WARNING("bta_av_co_audio_set_pref_mcc connection 0x%x is not opened", hndl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Update the current codec configuration */
|
||||
bta_av_co_audio_codec_reset();
|
||||
|
||||
/* Protect access to bta_av_co_cb.codec_cfg */
|
||||
osi_mutex_global_lock();
|
||||
|
||||
/* Try to use the currently selected sink first. */
|
||||
if (p_peer->p_snk != NULL &&
|
||||
p_peer->p_snk->codec_type == bta_av_co_cb.codec_cfg.id &&
|
||||
bta_av_co_audio_codec_match(p_peer->p_snk->codec_caps)) {
|
||||
/* Current sink supports the new preferred config, use it */
|
||||
p_sink = p_peer->p_snk;
|
||||
} else if (bta_av_co_audio_peer_supports_codec(p_peer, &snk_index)) {
|
||||
/* Current sink doesn't support, find another one that does */
|
||||
p_sink = &p_peer->snks[snk_index];
|
||||
/* Check that this sink is compatible with the CP */
|
||||
if (!bta_av_co_audio_sink_supports_cp(p_sink)) {
|
||||
APPL_TRACE_DEBUG("bta_av_co_audio_set_pref_mcc connection 0x%x sink %d doesn't support cp", hndl, snk_index);
|
||||
osi_mutex_global_unlock();
|
||||
bta_av_co_audio_clear_pref_mcc(hndl);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
/* No sink supports the new preferred config */
|
||||
APPL_TRACE_DEBUG("bta_av_co_audio_set_pref_mcc connection 0x%x has no sink supporting preferred config", hndl);
|
||||
osi_mutex_global_unlock();
|
||||
bta_av_co_audio_clear_pref_mcc(hndl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Build the codec configuration for this sink */
|
||||
if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg)) {
|
||||
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
|
||||
cp_active = bta_av_co_audio_sink_has_scmst(p_sink);
|
||||
#endif
|
||||
/* Check if configuration actually changed:
|
||||
* 1. Sink changed
|
||||
* 2. Codec configuration changed
|
||||
* 3. CP state changed (if applicable)
|
||||
*/
|
||||
if (p_sink != p_peer->p_snk || memcmp(codec_cfg, p_peer->codec_cfg, AVDT_CODEC_SIZE)
|
||||
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
|
||||
|| (p_peer->cp_active != cp_active)
|
||||
#endif
|
||||
) {
|
||||
/* Update peer configuration with the new codec config based on preferred config. */
|
||||
p_peer->p_snk = p_sink;
|
||||
memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE);
|
||||
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
|
||||
p_peer->cp_active = cp_active;
|
||||
bta_av_co_cb.cp.active = cp_active;
|
||||
if (cp_active) {
|
||||
num_protect = BTA_AV_CP_INFO_LEN;
|
||||
}
|
||||
#endif
|
||||
/* Reconfigure the connection to apply preferred codec configuration.
|
||||
* This is an asynchronous operation. Success/failure will be reported
|
||||
* via BTA_AV_RECONFIG_EVT. */
|
||||
APPL_TRACE_DEBUG("bta_av_co_audio_set_pref_mcc call BTA_AvReconfig(0x%x) to apply preferred config", hndl);
|
||||
p_peer->pref_mcc_reconfig_initiated = TRUE;
|
||||
BTA_AvReconfig(hndl, TRUE, p_sink->sep_info_idx, p_peer->codec_cfg, num_protect, (UINT8 *)bta_av_co_cp_scmst);
|
||||
} else {
|
||||
/* Configuration hasn't changed, no need to reconfigure. */
|
||||
APPL_TRACE_DEBUG("bta_av_co_audio_set_pref_mcc no change, hndl:0x%x", hndl);
|
||||
p_peer->pref_mcc_reconfig_initiated = FALSE;
|
||||
osi_mutex_global_unlock();
|
||||
/* Return TRUE to indicate preferred config is set. */
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_set_pref_mcc build cfg failed, hndl:0x%x", hndl);
|
||||
osi_mutex_global_unlock();
|
||||
bta_av_co_audio_clear_pref_mcc(hndl);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
osi_mutex_global_unlock();
|
||||
}
|
||||
|
||||
return pref_cfg_supported;
|
||||
} else {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_set_pref_mcc pref_mcc NULL");
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
UNUSED(hndl);
|
||||
UNUSED(pref_mcc);
|
||||
return FALSE;
|
||||
#endif /* BTC_AV_SRC_INCLUDED == TRUE */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_clear_pref_mcc
|
||||
**
|
||||
** Description Clear the preferred codec configuration
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_av_co_audio_clear_pref_mcc(tBTA_AV_HNDL hndl)
|
||||
{
|
||||
UNUSED(hndl);
|
||||
#if (BTC_AV_SRC_INCLUDED == TRUE)
|
||||
bta_av_co_cb.codec_pref_cfg.id = BTC_AV_CODEC_NONE;
|
||||
memset(bta_av_co_cb.codec_pref_cfg.info, 0, AVDT_CODEC_SIZE);
|
||||
/* reset codec configuration */
|
||||
bta_av_co_audio_codec_reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_pref_mcc_reconfig_initiated
|
||||
**
|
||||
** Description Check if a reconfig was actually initiated by the last call
|
||||
** to bta_av_co_audio_set_pref_mcc(). This is used to determine
|
||||
** if we need to wait for BTA_AV_RECONFIG_EVT or can notify
|
||||
** immediately (when config unchanged).
|
||||
**
|
||||
** Returns TRUE if reconfig was initiated, FALSE if config unchanged
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_av_co_audio_pref_mcc_reconfig_initiated(tBTA_AV_HNDL hndl)
|
||||
{
|
||||
#if (BTC_AV_SRC_INCLUDED == TRUE)
|
||||
tBTA_AV_CO_PEER *p_peer;
|
||||
|
||||
/* Retrieve the peer info for the specified handle */
|
||||
p_peer = bta_av_co_get_peer(hndl);
|
||||
if (p_peer == NULL || !p_peer->opened) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return p_peer->pref_mcc_reconfig_initiated;
|
||||
#else
|
||||
UNUSED(hndl);
|
||||
return FALSE;
|
||||
#endif /* BTC_AV_SRC_INCLUDED == TRUE */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_pref_mcc_reconfig_clear
|
||||
**
|
||||
** Description Clear the pref_mcc_reconfig_initiated flag. This should be
|
||||
** called after processing a BTA_AV_RECONFIG_EVT for preferred
|
||||
** codec config change.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_av_co_audio_pref_mcc_reconfig_clear(tBTA_AV_HNDL hndl)
|
||||
{
|
||||
#if (BTC_AV_SRC_INCLUDED == TRUE)
|
||||
tBTA_AV_CO_PEER *p_peer;
|
||||
|
||||
/* Retrieve the peer info for the specified handle */
|
||||
p_peer = bta_av_co_get_peer(hndl);
|
||||
if (p_peer != NULL) {
|
||||
p_peer->pref_mcc_reconfig_initiated = FALSE;
|
||||
}
|
||||
#else
|
||||
UNUSED(hndl);
|
||||
#endif /* BTC_AV_SRC_INCLUDED == TRUE */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_codec_reset
|
||||
@@ -1504,20 +1740,48 @@ BOOLEAN bta_av_co_audio_codec_supported(tBTC_AV_STATUS *p_status)
|
||||
*******************************************************************************/
|
||||
void bta_av_co_audio_codec_reset(void)
|
||||
{
|
||||
BOOLEAN pref_cfg_supported;
|
||||
|
||||
osi_mutex_global_lock();
|
||||
FUNC_TRACE();
|
||||
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
bta_av_co_cb.codec_cfg.id = bta_av_co_cb.codec_caps.id;
|
||||
bta_av_build_src_cfg(bta_av_co_cb.codec_cfg.info, bta_av_co_cb.codec_caps.info);
|
||||
#else
|
||||
/* Reset the current configuration to SBC */
|
||||
bta_av_co_cb.codec_cfg.id = BTC_AV_CODEC_SBC;
|
||||
if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btc_av_sbc_default_config, bta_av_co_cb.codec_cfg.info) != A2D_SUCCESS) {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed");
|
||||
pref_cfg_supported = FALSE;
|
||||
#if (BTC_AV_SRC_INCLUDED == TRUE)
|
||||
switch (bta_av_co_cb.codec_pref_cfg.id) {
|
||||
case BTC_AV_CODEC_NONE: {
|
||||
APPL_TRACE_DEBUG("bta_av_co_audio_codec_reset preferred codec configuration is not set");
|
||||
break;
|
||||
}
|
||||
case BTC_AV_CODEC_SBC: {
|
||||
if (bta_av_co_audio_src_supports_pref_cfg()) {
|
||||
pref_cfg_supported = TRUE;
|
||||
} else {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_codec_reset unsupported pref cfg");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_codec_reset bad pref cfg id %d", bta_av_co_cb.codec_pref_cfg.id);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pref_cfg_supported) {
|
||||
bta_av_co_cb.codec_cfg = bta_av_co_cb.codec_pref_cfg;
|
||||
} else {
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
bta_av_co_cb.codec_cfg.id = bta_av_co_cb.codec_caps.id;
|
||||
bta_av_build_src_cfg(bta_av_co_cb.codec_cfg.info, bta_av_co_cb.codec_caps.info);
|
||||
#else
|
||||
/* Reset the current configuration to SBC */
|
||||
bta_av_co_cb.codec_cfg.id = BTC_AV_CODEC_SBC;
|
||||
if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btc_av_sbc_default_config, bta_av_co_cb.codec_cfg.info) != A2D_SUCCESS) {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
osi_mutex_global_unlock();
|
||||
}
|
||||
|
||||
@@ -1549,7 +1813,15 @@ BOOLEAN bta_av_co_audio_set_codec(const tBTC_AV_MEDIA_FEEDINGS *p_feeding, tBTC_
|
||||
case BTC_AV_CODEC_PCM:
|
||||
new_cfg.id = BTC_AV_CODEC_SBC;
|
||||
|
||||
sbc_config = btc_av_sbc_default_config;
|
||||
if (bta_av_co_audio_src_supports_pref_cfg()) {
|
||||
if (A2D_ParsSbcInfo((tA2D_SBC_CIE *)&sbc_config, bta_av_co_cb.codec_pref_cfg.info, FALSE) != A2D_SUCCESS) {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_set_codec A2D_ParsSbcInfo failed");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
sbc_config = btc_av_sbc_default_config;
|
||||
}
|
||||
|
||||
if ((p_feeding->cfg.pcm.num_channel != 1) &&
|
||||
(p_feeding->cfg.pcm.num_channel != 2)) {
|
||||
APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM channel number unsupported");
|
||||
@@ -1561,11 +1833,16 @@ BOOLEAN bta_av_co_audio_set_codec(const tBTC_AV_MEDIA_FEEDINGS *p_feeding, tBTC_
|
||||
return FALSE;
|
||||
}
|
||||
switch (p_feeding->cfg.pcm.sampling_freq) {
|
||||
/* SBC supports 16/32/44.1/48kHz */
|
||||
case 16000:
|
||||
sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_16;
|
||||
break;
|
||||
case 32000:
|
||||
sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_32;
|
||||
break;
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 48000:
|
||||
sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_48;
|
||||
break;
|
||||
@@ -1708,6 +1985,7 @@ void bta_av_co_init(tBTC_AV_CODEC_INFO *codec_caps)
|
||||
if (codec_caps) {
|
||||
memcpy(&bta_av_co_cb.codec_caps, codec_caps, sizeof(tBTC_AV_CODEC_INFO));
|
||||
}
|
||||
bta_av_co_cb.codec_pref_cfg.id = BTC_AV_CODEC_NONE;
|
||||
bta_av_co_cb.codec_cfg_setconfig.id = BTC_AV_CODEC_NONE;
|
||||
|
||||
#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -430,17 +430,44 @@ void btc_a2dp_source_setup_codec(void)
|
||||
{
|
||||
tBTC_AV_MEDIA_FEEDINGS media_feeding;
|
||||
tBTC_AV_STATUS status;
|
||||
UINT16 minmtu;
|
||||
tA2D_SBC_CIE sbc_config;
|
||||
|
||||
APPL_TRACE_EVENT("## A2DP SETUP CODEC ##\n");
|
||||
|
||||
osi_mutex_global_lock();
|
||||
|
||||
/* for now hardcode 44.1 khz 16 bit stereo PCM format */
|
||||
media_feeding.cfg.pcm.sampling_freq = 44100;
|
||||
bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
|
||||
|
||||
/* derive PCM feeding from SBC configuration */
|
||||
switch (sbc_config.samp_freq) {
|
||||
case A2D_SBC_IE_SAMP_FREQ_48:
|
||||
media_feeding.cfg.pcm.sampling_freq = 48000;
|
||||
break;
|
||||
case A2D_SBC_IE_SAMP_FREQ_32:
|
||||
media_feeding.cfg.pcm.sampling_freq = 32000;
|
||||
break;
|
||||
case A2D_SBC_IE_SAMP_FREQ_16:
|
||||
media_feeding.cfg.pcm.sampling_freq = 16000;
|
||||
break;
|
||||
case A2D_SBC_IE_SAMP_FREQ_44:
|
||||
media_feeding.cfg.pcm.sampling_freq = 44100;
|
||||
break;
|
||||
default:
|
||||
media_feeding.cfg.pcm.sampling_freq = 44100;
|
||||
APPL_TRACE_WARNING("btc_a2dp_source_setup_codec unsupported SBC sampling frequency: %d", sbc_config.samp_freq);
|
||||
break;
|
||||
}
|
||||
|
||||
media_feeding.cfg.pcm.num_channel = (sbc_config.ch_mode == A2D_SBC_IE_CH_MD_MONO) ? 1 : 2;
|
||||
media_feeding.cfg.pcm.bit_per_sample = 16;
|
||||
media_feeding.cfg.pcm.num_channel = 2;
|
||||
media_feeding.format = BTC_AV_CODEC_PCM;
|
||||
|
||||
APPL_TRACE_DEBUG("btc_a2dp_source_setup_codec PCM feeding derived from SBC: freq=%d, bits=%d, ch=%d",
|
||||
media_feeding.cfg.pcm.sampling_freq,
|
||||
media_feeding.cfg.pcm.bit_per_sample,
|
||||
media_feeding.cfg.pcm.num_channel);
|
||||
|
||||
if (bta_av_co_audio_set_codec(&media_feeding, &status)) {
|
||||
tBTC_MEDIA_INIT_AUDIO_FEEDING mfeed;
|
||||
|
||||
@@ -970,11 +997,29 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin
|
||||
|
||||
/* Check the PCM feeding sampling_freq */
|
||||
switch (p_feeding->feeding.cfg.pcm.sampling_freq) {
|
||||
case 16000:
|
||||
/* For this sampling_freq the AV connection must be 16000 */
|
||||
if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf16000) {
|
||||
/* Reconfiguration needed at 16000 */
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed at 16000");
|
||||
a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf16000;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 32000:
|
||||
/* For this sampling_freq the AV connection must be 32000 */
|
||||
if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf32000) {
|
||||
/* Reconfiguration needed at 32000 */
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed at 32000");
|
||||
a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf32000;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 48000:
|
||||
/* For these sampling_freq the AV connection must be 48000 */
|
||||
if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf48000) {
|
||||
@@ -1001,13 +1046,6 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin
|
||||
break;
|
||||
}
|
||||
|
||||
/* Some AV Headsets do not support Mono => always ask for Stereo */
|
||||
if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode == SBC_MONO) {
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed in Stereo");
|
||||
a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode = SBC_JOINT_STEREO;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
|
||||
if (reconfig_needed != FALSE) {
|
||||
APPL_TRACE_DEBUG("%s :: mtu %d", __FUNCTION__, a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize);
|
||||
APPL_TRACE_DEBUG("ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d",
|
||||
@@ -1642,4 +1680,18 @@ static void btc_a2dp_source_thread_cleanup(UNUSED_ATTR void *context)
|
||||
a2dp_source_local_param.btc_aa_src_cb.poll_data = NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_set_pref_mcc
|
||||
**
|
||||
** Description
|
||||
**
|
||||
** Returns TRUE if the preferred config is supported, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_set_pref_mcc(tBTA_AV_HNDL hndl, tBTC_AV_CODEC_INFO *pref_mcc)
|
||||
{
|
||||
return bta_av_co_audio_set_pref_mcc(hndl, pref_mcc);
|
||||
}
|
||||
|
||||
#endif /* (BTC_AV_SRC_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == FALSE) */
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -232,4 +232,18 @@ void btc_a2dp_source_shutdown(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_set_pref_mcc
|
||||
**
|
||||
** Description
|
||||
**
|
||||
** Returns TRUE if the preferred config is supported, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_set_pref_mcc(tBTA_AV_HNDL hndl, tBTC_AV_CODEC_INFO *pref_mcc)
|
||||
{
|
||||
return bta_av_co_audio_set_pref_mcc(hndl, pref_mcc);
|
||||
}
|
||||
|
||||
#endif /* (BTC_AV_SRC_INCLUDED == TRUE) && (BTC_AV_EXT_CODEC == TRUE) */
|
||||
|
||||
@@ -96,6 +96,7 @@ typedef struct {
|
||||
UINT8 peer_sep; /* sep type of peer device */
|
||||
tBTC_AV_CODEC_INFO codec_caps;
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
tBTC_AV_CODEC_INFO pref_mcc; /* preferred media codec configuration */
|
||||
osi_alarm_t *tle_av_open_on_rc;
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
} btc_av_cb_t;
|
||||
@@ -152,6 +153,7 @@ static BOOLEAN btc_a2d_deinit_if_ongoing(void);
|
||||
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
static bt_status_t btc_a2d_src_init(void);
|
||||
static void btc_a2d_src_set_pref_mcc(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_mcc_t *pref_mcc);
|
||||
static bt_status_t btc_a2d_src_connect(bt_bdaddr_t *remote_bda);
|
||||
static void btc_a2d_src_deinit(void);
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
@@ -837,6 +839,15 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
|
||||
/* pending start flag will be cleared when exit current state */
|
||||
}
|
||||
|
||||
/* Check if this connection has a pending preferred config change */
|
||||
if (bta_av_co_audio_pref_mcc_reconfig_initiated(btc_av_cb.bta_handle)) {
|
||||
bta_av_co_audio_pref_mcc_reconfig_clear(btc_av_cb.bta_handle);
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_FAIL;
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
BTC_TRACE_DEBUG("pref cfg pending, closed, h:0x%x", btc_av_cb.bta_handle);
|
||||
}
|
||||
|
||||
/* change state to idle, send acknowledgement if start is pending */
|
||||
btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
|
||||
break;
|
||||
@@ -851,6 +862,24 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
|
||||
btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_START;
|
||||
btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
|
||||
}
|
||||
|
||||
/* Handle user-initiated preferred codec config change.
|
||||
* Check if this reconfig was triggered by preferred codec config change */
|
||||
if (bta_av_co_audio_pref_mcc_reconfig_initiated(p_av->reconfig.hndl)) {
|
||||
bta_av_co_audio_pref_mcc_reconfig_clear(p_av->reconfig.hndl);
|
||||
|
||||
if (p_av->reconfig.status == BTA_AV_SUCCESS) {
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_SUCCESS;
|
||||
BTC_TRACE_DEBUG("pref cfg reconfig ok, h:0x%x", p_av->reconfig.hndl);
|
||||
} else {
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("pref cfg reconfig fail, h:0x%x st:%d",
|
||||
p_av->reconfig.hndl, p_av->reconfig.status);
|
||||
bta_av_co_audio_clear_pref_mcc(p_av->reconfig.hndl);
|
||||
}
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = p_av->reconfig.hndl;
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
}
|
||||
break;
|
||||
|
||||
case BTC_AV_CONNECT_REQ_EVT:
|
||||
@@ -1745,6 +1774,10 @@ void btc_a2dp_call_handler(btc_msg_t *msg)
|
||||
btc_a2d_src_init();
|
||||
break;
|
||||
}
|
||||
case BTC_AV_SRC_API_SET_PREF_MCC_EVT: {
|
||||
btc_a2d_src_set_pref_mcc(arg->set_pref_mcc.conn_hdl, &arg->set_pref_mcc.pref_mcc);
|
||||
break;
|
||||
}
|
||||
#if (BTC_AV_EXT_CODEC == TRUE)
|
||||
case BTC_AV_SRC_API_REG_SEP_EVT: {
|
||||
btc_av_reg_sep(AVDT_TSEP_SRC, arg->reg_sep.seid, &arg->reg_sep.mcc);
|
||||
@@ -1923,6 +1956,86 @@ static void btc_a2d_src_deinit(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_a2d_src_set_pref_mcc(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_mcc_t *pref_mcc)
|
||||
{
|
||||
UNUSED(conn_hdl);
|
||||
UNUSED(pref_mcc);
|
||||
#if A2D_DYNAMIC_MEMORY == TRUE
|
||||
if (btc_av_cb_ptr)
|
||||
#endif
|
||||
{
|
||||
esp_a2d_cb_param_t param;
|
||||
|
||||
if (btc_av_cb.sm_handle == NULL || btc_sm_get_state(btc_av_cb.sm_handle) != BTC_AV_STATE_OPENED) {
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_NOT_READY;
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
BTC_TRACE_DEBUG("btc_a2d_src_set_pref_mcc not ready");
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn_hdl != btc_av_cb.bta_handle) {
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_UNSUPPORTED;
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
BTC_TRACE_DEBUG("btc_a2d_src_set_pref_mcc bad hndl %d", conn_hdl);
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bta_av_co_audio_pref_mcc_reconfig_initiated(conn_hdl)) {
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_BUSY;
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
BTC_TRACE_DEBUG("btc_a2d_src_set_pref_mcc reconfig busy");
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pref_mcc->type) {
|
||||
case ESP_A2D_MCT_SBC: {
|
||||
btc_av_cb.pref_mcc.id = BTC_AV_CODEC_SBC;
|
||||
if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btc_av_sbc_default_config, btc_av_cb.pref_mcc.info) == A2D_SUCCESS) {
|
||||
/* overwrite sbc cie */
|
||||
memcpy(btc_av_cb.pref_mcc.info + A2D_SBC_CIE_OFF, &pref_mcc->cie, A2D_SBC_CIE_LEN);
|
||||
|
||||
/* Note: Return value only indicates if the config is supported and reconfig is initiated.
|
||||
* Actual success/failure will be reported via ESP_A2D_SRC_SET_PREF_MCC_EVT
|
||||
* when BTA_AV_RECONFIG_EVT is received. */
|
||||
if (!btc_a2dp_source_set_pref_mcc(conn_hdl, &btc_av_cb.pref_mcc)) {
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_UNSUPPORTED;
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
BTC_TRACE_DEBUG("btc_a2d_src_set_pref_mcc bad params");
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
} else {
|
||||
/* Check if reconfig was actually initiated */
|
||||
if (!bta_av_co_audio_pref_mcc_reconfig_initiated(conn_hdl)) {
|
||||
/* Configuration unchanged, no reconfig needed.
|
||||
* Preferred config is already in use, notify success immediately. */
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_SUCCESS;
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
BTC_TRACE_DEBUG("btc_a2d_src_set_pref_mcc already active");
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_FAIL;
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
BTC_TRACE_DEBUG("btc_a2d_src_set_pref_mcc build SBC info failed");
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
param.a2d_set_pref_mcc_stat.set_status = ESP_BT_STATUS_UNSUPPORTED;
|
||||
param.a2d_set_pref_mcc_stat.conn_hdl = btc_av_cb.bta_handle;
|
||||
BTC_TRACE_DEBUG("btc_a2d_src_set_pref_mcc bad codec type %d", pref_mcc->type);
|
||||
btc_a2d_cb_to_app(ESP_A2D_SRC_SET_PREF_MCC_EVT, ¶m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bt_status_t btc_a2d_src_connect(bt_bdaddr_t *remote_bda)
|
||||
{
|
||||
BTC_TRACE_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -54,6 +54,7 @@ typedef struct {
|
||||
UINT16 mtu; /* maximum transmit unit size */
|
||||
UINT16 uuid_to_connect; /* uuid of peer device */
|
||||
BOOLEAN got_disc_res; /* got the results of initiating discovery */
|
||||
BOOLEAN pref_mcc_reconfig_initiated; /* TRUE if last bta_av_co_audio_set_pref_mcc() initiated reconfig for this peer */
|
||||
} tBTA_AV_CO_PEER;
|
||||
|
||||
typedef struct {
|
||||
@@ -67,6 +68,7 @@ typedef struct {
|
||||
tBTC_AV_CODEC_INFO codec_caps;
|
||||
/* Current codec configuration - access to this variable must be protected */
|
||||
tBTC_AV_CODEC_INFO codec_cfg;
|
||||
tBTC_AV_CODEC_INFO codec_pref_cfg; /* preferred media codec configuration for source */
|
||||
tBTC_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */
|
||||
|
||||
tBTA_AV_CO_CP cp;
|
||||
@@ -122,6 +124,61 @@ UINT8 bta_av_co_cp_get_flag(void);
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_set_pref_mcc
|
||||
**
|
||||
** Description Set preferred codec configuration for a specific connection
|
||||
** and initiate reconfiguration if the connection is open.
|
||||
**
|
||||
** Note: This function returns TRUE if the preferred config is
|
||||
** supported. The actual success
|
||||
** or failure of reconfiguration will be reported asynchronously
|
||||
** via BTA_AV_RECONFIG_EVT.
|
||||
**
|
||||
** Returns TRUE if the preferred config is supported, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_av_co_audio_set_pref_mcc(tBTA_AV_HNDL hndl, tBTC_AV_CODEC_INFO *pref_mcc);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_clear_pref_mcc
|
||||
**
|
||||
** Description Clear the preferred codec configuration
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_av_co_audio_clear_pref_mcc(tBTA_AV_HNDL hndl);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_pref_mcc_reconfig_initiated
|
||||
**
|
||||
** Description Check if a reconfig was actually initiated by the last call
|
||||
** to bta_av_co_audio_set_pref_mcc(). This is used to determine
|
||||
** if we need to wait for BTA_AV_RECONFIG_EVT or can notify
|
||||
** immediately (when config unchanged).
|
||||
**
|
||||
** Returns TRUE if reconfig was initiated, FALSE if config unchanged
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_av_co_audio_pref_mcc_reconfig_initiated(tBTA_AV_HNDL hndl);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_pref_mcc_reconfig_clear
|
||||
**
|
||||
** Description Clear the pref_mcc_reconfig_initiated flag for a specific
|
||||
** connection. This should be called after processing a
|
||||
** BTA_AV_RECONFIG_EVT for preferred codec config change.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_av_co_audio_pref_mcc_reconfig_clear(tBTA_AV_HNDL hndl);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_co_audio_codec_reset
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -150,6 +150,17 @@ void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av);
|
||||
*******************************************************************************/
|
||||
void btc_a2dp_source_set_tx_flush(BOOLEAN enable);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function btc_a2dp_source_set_pref_mcc
|
||||
**
|
||||
** Description set preferred codec configuration
|
||||
**
|
||||
** Returns TRUE if the preferred config is supported, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN btc_a2dp_source_set_pref_mcc(tBTA_AV_HNDL hndl, tBTC_AV_CODEC_INFO *pref_mcc);
|
||||
|
||||
#if (BTC_AV_EXT_CODEC == FALSE)
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -78,6 +78,7 @@ typedef enum {
|
||||
#endif /* BTC_AV_SINK_INCLUDED */
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
BTC_AV_SRC_API_INIT_EVT,
|
||||
BTC_AV_SRC_API_SET_PREF_MCC_EVT,
|
||||
BTC_AV_SRC_API_REG_SEP_EVT,
|
||||
BTC_AV_SRC_API_DEINIT_EVT,
|
||||
BTC_AV_SRC_API_CONNECT_EVT,
|
||||
@@ -108,6 +109,11 @@ typedef union {
|
||||
bt_bdaddr_t src_connect;
|
||||
// BTC_AV_SRC_API_DISCONNECT_EVT
|
||||
bt_bdaddr_t src_disconn;
|
||||
// BTC_AV_SRC_API_SET_PREF_MCC_EVT
|
||||
struct {
|
||||
esp_a2d_conn_hdl_t conn_hdl;
|
||||
esp_a2d_mcc_t pref_mcc;
|
||||
} set_pref_mcc;
|
||||
#endif /* BTC_AV_SRC_INCLUDED */
|
||||
// BTC_AV_CONFIG_EVT
|
||||
esp_a2d_mcc_t mcc;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -91,6 +91,12 @@ static void bt_app_av_sm_hdlr(uint16_t event, void *param);
|
||||
/* utils for transfer BLuetooth Deveice Address into string form */
|
||||
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size);
|
||||
|
||||
/* check preferred codec configuration against sink capabilities */
|
||||
static bool check_pref_mcc_against_sink_caps(const esp_a2d_mcc_t *sink_caps, const esp_a2d_mcc_t *pref_mcc);
|
||||
|
||||
/* set preferred codec configuration */
|
||||
static void bt_app_a2d_set_pref_mcc(esp_a2d_conn_hdl_t conn_hdl, const esp_a2d_mcc_t *sink_caps);
|
||||
|
||||
/* A2DP application state machine handler for each state */
|
||||
static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param);
|
||||
static void bt_app_av_state_connecting_hdlr(uint16_t event, void *param);
|
||||
@@ -404,6 +410,77 @@ static void bt_app_av_sm_hdlr(uint16_t event, void *param)
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_one_bit_set_u8(uint8_t v)
|
||||
{
|
||||
return (v != 0) && ((v & (uint8_t)(v - 1)) == 0);
|
||||
}
|
||||
|
||||
static bool check_pref_mcc_against_sink_caps(const esp_a2d_mcc_t *sink_caps, const esp_a2d_mcc_t *pref_mcc)
|
||||
{
|
||||
const esp_a2d_cie_sbc_t *caps;
|
||||
const esp_a2d_cie_sbc_t *cfg;
|
||||
|
||||
if (sink_caps == NULL || pref_mcc == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (sink_caps->type != pref_mcc->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pref_mcc->type != ESP_A2D_MCT_SBC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
caps = &sink_caps->cie.sbc_info;
|
||||
cfg = &pref_mcc->cie.sbc_info;
|
||||
|
||||
/* For preferred configuration, each field should select a single value (one bit) */
|
||||
if (!is_one_bit_set_u8(cfg->samp_freq) || ((cfg->samp_freq & caps->samp_freq) != cfg->samp_freq)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_one_bit_set_u8(cfg->ch_mode) || ((cfg->ch_mode & caps->ch_mode) != cfg->ch_mode)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_one_bit_set_u8(cfg->block_len) || ((cfg->block_len & caps->block_len) != cfg->block_len)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_one_bit_set_u8(cfg->num_subbands) || ((cfg->num_subbands & caps->num_subbands) != cfg->num_subbands)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_one_bit_set_u8(cfg->alloc_mthd) || ((cfg->alloc_mthd & caps->alloc_mthd) != cfg->alloc_mthd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cfg->min_bitpool < caps->min_bitpool || cfg->max_bitpool > caps->max_bitpool || cfg->min_bitpool > cfg->max_bitpool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bt_app_a2d_set_pref_mcc(esp_a2d_conn_hdl_t conn_hdl, const esp_a2d_mcc_t *sink_caps)
|
||||
{
|
||||
esp_a2d_mcc_t pref_mcc;
|
||||
|
||||
memset(&pref_mcc, 0, sizeof(pref_mcc));
|
||||
pref_mcc.type = ESP_A2D_MCT_SBC;
|
||||
pref_mcc.cie.sbc_info.samp_freq = ESP_A2D_SBC_CIE_SF_44K;
|
||||
pref_mcc.cie.sbc_info.ch_mode = ESP_A2D_SBC_CIE_CH_MODE_MONO; // Joint Stereo --> Mono
|
||||
pref_mcc.cie.sbc_info.block_len = ESP_A2D_SBC_CIE_BLOCK_LEN_16;
|
||||
pref_mcc.cie.sbc_info.num_subbands = ESP_A2D_SBC_CIE_NUM_SUBBANDS_8;
|
||||
pref_mcc.cie.sbc_info.alloc_mthd = ESP_A2D_SBC_CIE_ALLOC_MTHD_LOUDNESS;
|
||||
pref_mcc.cie.sbc_info.min_bitpool = 2;
|
||||
pref_mcc.cie.sbc_info.max_bitpool = 35; // 53 --> 35
|
||||
|
||||
if (!check_pref_mcc_against_sink_caps(sink_caps, &pref_mcc)) {
|
||||
ESP_LOGW(BT_AV_TAG, "pref_mcc not supported by sink");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t ret = esp_a2d_source_set_pref_mcc(conn_hdl, &pref_mcc);
|
||||
ESP_LOGD(BT_AV_TAG, "Set pref_mcc result: %s", esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param)
|
||||
{
|
||||
esp_a2d_cb_param_t *a2d = NULL;
|
||||
@@ -581,6 +658,30 @@ static void bt_app_av_state_connected_hdlr(uint16_t event, void *param)
|
||||
ESP_LOGI(BT_AV_TAG, "%s, delay value: %u * 1/10 ms", __func__, a2d->a2d_report_delay_value_stat.delay_value);
|
||||
break;
|
||||
}
|
||||
case ESP_A2D_REPORT_SNK_CODEC_CAPS_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
esp_a2d_mcc_t *sink_mcc = &a2d->a2d_report_snk_codec_caps_stat.mcc;
|
||||
ESP_LOGI(BT_AV_TAG, "sink codec type: %d", sink_mcc->type);
|
||||
/* for now only SBC stream is supported */
|
||||
if (sink_mcc->type == ESP_A2D_MCT_SBC) {
|
||||
ESP_LOGI(BT_AV_TAG, "sink codec capabilities: 0x%x-0x%x-0x%x-0x%x-0x%x-%d-%d",
|
||||
sink_mcc->cie.sbc_info.samp_freq,
|
||||
sink_mcc->cie.sbc_info.ch_mode,
|
||||
sink_mcc->cie.sbc_info.block_len,
|
||||
sink_mcc->cie.sbc_info.num_subbands,
|
||||
sink_mcc->cie.sbc_info.alloc_mthd,
|
||||
sink_mcc->cie.sbc_info.min_bitpool,
|
||||
sink_mcc->cie.sbc_info.max_bitpool);
|
||||
}
|
||||
bt_app_a2d_set_pref_mcc(a2d->a2d_report_snk_codec_caps_stat.conn_hdl, sink_mcc);
|
||||
break;
|
||||
}
|
||||
case ESP_A2D_SRC_SET_PREF_MCC_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(param);
|
||||
ESP_LOGI(BT_AV_TAG, "Set preferred media codec config result: conn_hdl: %d, set_status: %d",
|
||||
a2d->a2d_set_pref_mcc_stat.conn_hdl, a2d->a2d_set_pref_mcc_stat.set_status);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
|
||||
break;
|
||||
@@ -629,7 +730,8 @@ static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t
|
||||
case ESP_AVRC_CT_CHANGE_NOTIFY_EVT:
|
||||
case ESP_AVRC_CT_REMOTE_FEATURES_EVT:
|
||||
case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT:
|
||||
case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
|
||||
case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT:
|
||||
case ESP_AVRC_CT_PROF_STATE_EVT: {
|
||||
bt_app_work_dispatch(bt_av_hdl_avrc_ct_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
@@ -722,6 +824,17 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
|
||||
ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume response: volume %d", rc->set_volume_rsp.volume);
|
||||
break;
|
||||
}
|
||||
/* when avrcp controller init or deinit completed, this event comes */
|
||||
case ESP_AVRC_CT_PROF_STATE_EVT: {
|
||||
if (ESP_AVRC_INIT_SUCCESS == rc->avrc_ct_init_stat.state) {
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRCP CT STATE: Init Complete");
|
||||
} else if (ESP_AVRC_DEINIT_SUCCESS == rc->avrc_ct_init_stat.state) {
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRCP CT STATE: Deinit Complete");
|
||||
} else {
|
||||
ESP_LOGE(BT_RC_CT_TAG, "AVRCP CT STATE error: %d", rc->avrc_ct_init_stat.state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* other */
|
||||
default: {
|
||||
ESP_LOGE(BT_RC_CT_TAG, "%s unhandled event: %d", __func__, event);
|
||||
|
||||
Reference in New Issue
Block a user