From cd93bd63b9db5bb4cb3c940f8fd2522ea973124d Mon Sep 17 00:00:00 2001 From: yangfeng Date: Fri, 10 Jul 2026 11:06:47 +0800 Subject: [PATCH] fix(bt): Fix compatibility with A2DP API legacy usage methods - Modify the timing of API calls in the A2DP example - Closes https://github.com/espressif/esp-idf/issues/18786 --- .../bt/host/bluedroid/api/esp_a2dp_api.c | 21 +++++++++++-- .../classic_bt/a2dp_sink_stream/main/main.c | 30 ++++++++++++++++-- .../avrcp_absolute_volume/main/main.c | 31 +++++++++++++++++-- .../classic_bt/avrcp_ct_metadata/main/main.c | 31 +++++++++++++++++-- .../coex/a2dp_gatts_coex/main/bt_app_av.c | 29 ++++++++++++++++- .../coex/a2dp_gatts_coex/main/main.c | 3 -- 6 files changed, 129 insertions(+), 16 deletions(-) diff --git a/components/bt/host/bluedroid/api/esp_a2dp_api.c b/components/bt/host/bluedroid/api/esp_a2dp_api.c index 55c534e9caa..b725fd762bd 100644 --- a/components/bt/host/bluedroid/api/esp_a2dp_api.c +++ b/components/bt/host/bluedroid/api/esp_a2dp_api.c @@ -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 */ @@ -14,6 +14,9 @@ #if BTC_AV_INCLUDED +// indicate the first time to call the get delay value function +static bool s_a2dp_first_call_get_delay = true; + #if BTC_AV_SINK_INCLUDED esp_err_t esp_a2d_sink_init(void) { @@ -54,7 +57,12 @@ esp_err_t esp_a2d_sink_deinit(void) /* Switch to BTC context */ bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL, NULL); - return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; + if (stat == BT_STATUS_SUCCESS) { + s_a2dp_first_call_get_delay = false; + return ESP_OK; + } else { + return ESP_FAIL; + } } esp_err_t esp_a2d_sink_register_data_callback(esp_a2d_sink_data_cb_t callback) @@ -164,7 +172,14 @@ esp_err_t esp_a2d_sink_get_delay_value(void) return ESP_ERR_INVALID_STATE; } - if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit) { + /* To be compatible with the legacy usage methods, + use a flag indicating whether this is the first time the function has been called. */ + if (s_a2dp_first_call_get_delay) { + s_a2dp_first_call_get_delay = false; + if (g_a2dp_sink_ongoing_deinit) { + return ESP_ERR_INVALID_STATE; + } + } else if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit) { return ESP_ERR_INVALID_STATE; } diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink_stream/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink_stream/main/main.c index 9d05830150a..155e6ebca63 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink_stream/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink_stream/main/main.c @@ -51,10 +51,36 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa bredr_app_gap_evt_def_hdl(event, param); } +static void bt_app_a2d_evt_hdl(uint16_t event, void *param) +{ + esp_a2d_cb_param_t *a2d = (esp_a2d_cb_param_t *)(param); + + switch (event) { + /* when a2dp init or deinit completed, this event comes */ + case ESP_A2D_PROF_STATE_EVT: { + if (ESP_A2D_INIT_SUCCESS == a2d->a2d_prof_stat.init_state) { + ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Init Complete"); + /* Get the default value of the delay value */ + esp_a2d_sink_get_delay_value(); + } else { + ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Deinit Complete"); + } + break; + } + /* others */ + default: + ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event); + break; + } +} + static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) { switch (event) { - case ESP_A2D_PROF_STATE_EVT: + case ESP_A2D_PROF_STATE_EVT: { + bt_app_work_dispatch(bt_app_a2d_evt_hdl, event, param, sizeof(esp_a2d_cb_param_t), NULL, NULL); + break; + } case ESP_A2D_SNK_PSC_CFG_EVT: case ESP_A2D_SNK_SET_DELAY_VALUE_EVT: case ESP_A2D_SNK_GET_DELAY_VALUE_EVT: { @@ -93,8 +119,6 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb); - /* Get the default value of the delay value */ - esp_a2d_sink_get_delay_value(); /* Get local device name */ esp_bt_gap_get_device_name(); diff --git a/examples/bluetooth/bluedroid/classic_bt/avrcp_absolute_volume/main/main.c b/examples/bluetooth/bluedroid/classic_bt/avrcp_absolute_volume/main/main.c index e27d34f2b75..ee3fd4c8b65 100644 --- a/examples/bluetooth/bluedroid/classic_bt/avrcp_absolute_volume/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/avrcp_absolute_volume/main/main.c @@ -40,6 +40,7 @@ enum { static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param); /* callback function for A2DP sink */ +static void bt_app_a2d_evt_hdl(uint16_t event, void *param); static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param); #if CONFIG_EXAMPLE_A2DP_SINK_STREAM_ENABLE @@ -65,10 +66,36 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa bredr_app_gap_evt_def_hdl(event, param); } +static void bt_app_a2d_evt_hdl(uint16_t event, void *param) +{ + esp_a2d_cb_param_t *a2d = (esp_a2d_cb_param_t *)(param); + + switch (event) { + /* when a2dp init or deinit completed, this event comes */ + case ESP_A2D_PROF_STATE_EVT: { + if (ESP_A2D_INIT_SUCCESS == a2d->a2d_prof_stat.init_state) { + ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Init Complete"); + /* Get the default value of the delay value */ + esp_a2d_sink_get_delay_value(); + } else { + ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Deinit Complete"); + } + break; + } + /* others */ + default: + ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event); + break; + } +} + static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) { switch (event) { - case ESP_A2D_PROF_STATE_EVT: + case ESP_A2D_PROF_STATE_EVT: { + bt_app_work_dispatch(bt_app_a2d_evt_hdl, event, param, sizeof(esp_a2d_cb_param_t), NULL, NULL); + break; + } case ESP_A2D_SNK_PSC_CFG_EVT: case ESP_A2D_SNK_SET_DELAY_VALUE_EVT: case ESP_A2D_SNK_GET_DELAY_VALUE_EVT: { @@ -164,8 +191,6 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb); #endif - /* Get the default value of the delay value */ - esp_a2d_sink_get_delay_value(); /* Get local device name */ esp_bt_gap_get_device_name(); diff --git a/examples/bluetooth/bluedroid/classic_bt/avrcp_ct_metadata/main/main.c b/examples/bluetooth/bluedroid/classic_bt/avrcp_ct_metadata/main/main.c index 5ee947afd02..7d74dbddf50 100644 --- a/examples/bluetooth/bluedroid/classic_bt/avrcp_ct_metadata/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/avrcp_ct_metadata/main/main.c @@ -40,6 +40,7 @@ enum { static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param); /* callback function for A2DP sink */ +static void bt_app_a2d_evt_hdl(uint16_t event, void *param); static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param); #if CONFIG_EXAMPLE_A2DP_SINK_STREAM_ENABLE @@ -68,10 +69,36 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa bredr_app_gap_evt_def_hdl(event, param); } +static void bt_app_a2d_evt_hdl(uint16_t event, void *param) +{ + esp_a2d_cb_param_t *a2d = (esp_a2d_cb_param_t *)(param); + + switch (event) { + /* when a2dp init or deinit completed, this event comes */ + case ESP_A2D_PROF_STATE_EVT: { + if (ESP_A2D_INIT_SUCCESS == a2d->a2d_prof_stat.init_state) { + ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Init Complete"); + /* Get the default value of the delay value */ + esp_a2d_sink_get_delay_value(); + } else { + ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Deinit Complete"); + } + break; + } + /* others */ + default: + ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event); + break; + } +} + static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) { switch (event) { - case ESP_A2D_PROF_STATE_EVT: + case ESP_A2D_PROF_STATE_EVT: { + bt_app_work_dispatch(bt_app_a2d_evt_hdl, event, param, sizeof(esp_a2d_cb_param_t), NULL, NULL); + break; + } case ESP_A2D_SNK_PSC_CFG_EVT: case ESP_A2D_SNK_SET_DELAY_VALUE_EVT: case ESP_A2D_SNK_GET_DELAY_VALUE_EVT: { @@ -218,8 +245,6 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb); #endif - /* Get the default value of the delay value */ - esp_a2d_sink_get_delay_value(); /* Get local device name */ esp_bt_gap_get_device_name(); diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c index 754ea42a82b..2a7085f729e 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c @@ -82,6 +82,30 @@ static void bt_app_avrc_ct_evt_hdl(uint16_t event, void *param) } } +/* handler for A2DP callback events */ +static void bt_app_a2d_evt_hdl(uint16_t event, void *param) +{ + esp_a2d_cb_param_t *a2d = (esp_a2d_cb_param_t *)(param); + + switch (event) { + /* when a2dp init or deinit completed, this event comes */ + case ESP_A2D_PROF_STATE_EVT: { + if (ESP_A2D_INIT_SUCCESS == a2d->a2d_prof_stat.init_state) { + ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Init Complete"); + /* Get the default value of the delay value */ + esp_a2d_sink_get_delay_value(); + } else { + ESP_LOGI(BT_AV_TAG, "A2DP PROF STATE: Deinit Complete"); + } + break; + } + /* others */ + default: + ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event); + break; + } +} + /******************************** * EXTERNAL FUNCTION DEFINITIONS *******************************/ @@ -89,13 +113,16 @@ static void bt_app_avrc_ct_evt_hdl(uint16_t event, void *param) void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) { switch (event) { + case ESP_A2D_PROF_STATE_EVT: { + bt_app_work_dispatch(bt_app_a2d_evt_hdl, event, param, sizeof(esp_a2d_cb_param_t), NULL, NULL); + break; + } case ESP_A2D_CONNECTION_STATE_EVT: case ESP_A2D_AUDIO_STATE_EVT: case ESP_A2D_AUDIO_CFG_EVT: { bt_app_work_dispatch(bt_a2d_evt_int_codec_hdl, event, param, sizeof(esp_a2d_cb_param_t), NULL, NULL); break; } - case ESP_A2D_PROF_STATE_EVT: case ESP_A2D_SNK_PSC_CFG_EVT: case ESP_A2D_SNK_SET_DELAY_VALUE_EVT: case ESP_A2D_SNK_GET_DELAY_VALUE_EVT: { diff --git a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c index 98ec7adb488..3edee11b7b7 100644 --- a/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c @@ -643,9 +643,6 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) esp_a2d_register_callback(&bt_app_a2d_cb); esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb); - /* Get the default value of the delay value */ - esp_a2d_sink_get_delay_value(); - /* set discoverable and connectable mode, wait to be connected */ esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); break;