diff --git a/components/bt/host/bluedroid/api/include/api/esp_avrc_api.h b/components/bt/host/bluedroid/api/include/api/esp_avrc_api.h index 52dba0c6f1..6fae9c1b29 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_avrc_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_avrc_api.h @@ -145,6 +145,7 @@ typedef enum { ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT = 7, /*!< set absolute volume response event */ ESP_AVRC_CT_COVER_ART_STATE_EVT = 8, /*!< cover art client connection state changed event */ ESP_AVRC_CT_COVER_ART_DATA_EVT = 9, /*!< cover art client data event */ + ESP_AVRC_CT_PROF_STATE_EVT = 10, /*!< Indicate AVRCP controller init or deinit complete */ } esp_avrc_ct_cb_event_t; /// AVRC Target callback events @@ -155,6 +156,7 @@ typedef enum { ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT = 3, /*!< set absolute volume command from remote device */ ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT = 4, /*!< register notification event */ ESP_AVRC_TG_SET_PLAYER_APP_VALUE_EVT = 5, /*!< set application attribute value, attribute refer to esp_avrc_ps_attr_ids_t */ + ESP_AVRC_TG_PROF_STATE_EVT = 6, /*!< Indicate AVRCP target init or deinit complete */ } esp_avrc_tg_cb_event_t; /// AVRC metadata attribute mask @@ -303,6 +305,18 @@ typedef struct { uint8_t ct_cover_art_conn_num; /*!< Number of cover art client connections */ } esp_avrc_profile_status_t; +/** + * @brief Bluetooth AVRCP Initiation states + */ +typedef enum { + ESP_AVRC_INIT_SUCCESS = 0, /*!< Indicate init successful */ + ESP_AVRC_INIT_ALREADY, /*!< Indicate init repeated */ + ESP_AVRC_INIT_FAIL, /*!< Indicate init fail */ + ESP_AVRC_DEINIT_SUCCESS, /*!< Indicate deinit successful */ + ESP_AVRC_DEINIT_ALREADY, /*!< Indicate deinit repeated */ + ESP_AVRC_DEINIT_FAIL, /*!< Indicate deinit fail */ +} esp_avrc_init_state_t; + /// AVRC controller callback parameters typedef union { /** @@ -390,6 +404,14 @@ typedef union { uint16_t data_len; /*!< the data length of this data event, in bytes */ uint8_t *p_data; /*!< pointer to data, should copy to other buff before event callback return */ } cover_art_data; /*!< AVRC Cover Art data event */ + + /** + * @brief ESP_AVRC_CT_PROF_STATE_EVT + */ + struct avrc_ct_init_stat_param { + esp_avrc_init_state_t state; /*!< avrc ct initialization param */ + } avrc_ct_init_stat; /*!< status to indicate avrcp ct init or deinit */ + } esp_avrc_ct_cb_param_t; /// AVRC target callback parameters @@ -442,6 +464,13 @@ typedef union { esp_avrc_set_app_value_param_t *p_vals; /*!< point to the id and value of player application attribute */ } set_app_value; /*!< set player application value */ + /** + * @brief ESP_AVRC_TG_PROF_STATE_EVT + */ + struct avrc_tg_init_stat_param { + esp_avrc_init_state_t state; /*!< avrc tg initialization param */ + } avrc_tg_init_stat; /*!< status to indicate avrcp tg init or deinit */ + } esp_avrc_tg_cb_param_t; /** @@ -482,6 +511,7 @@ esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback); * @brief Initialize the bluetooth AVRCP controller module, This function should be called * after esp_bluedroid_enable() completes successfully. Note: AVRC cannot work independently, * AVRC should be used along with A2DP and AVRC should be initialized before A2DP. + * ESP_AVRC_CT_PROF_STATE_EVT with ESP_AVRC_INIT_SUCCESS will reported to the APP layer. * * @return * - ESP_OK: success @@ -496,6 +526,7 @@ esp_err_t esp_avrc_ct_init(void); * @brief De-initialize AVRCP controller module. This function should be called after * after esp_bluedroid_enable() completes successfully. Note: AVRC cannot work independently, * AVRC should be used along with A2DP and AVRC should be deinitialized before A2DP. + * ESP_AVRC_CT_PROF_STATE_EVT with ESP_AVRC_DEINIT_SUCCESS will reported to the APP layer. * * @return * - ESP_OK: success @@ -636,6 +667,7 @@ esp_err_t esp_avrc_tg_register_callback(esp_avrc_tg_cb_t callback); * @brief Initialize the bluetooth AVRCP target module, This function should be called * after esp_bluedroid_enable() completes successfully. Note: AVRC cannot work independently, * AVRC should be used along with A2DP and AVRC should be initialized before A2DP. + * ESP_AVRC_TG_PROF_STATE_EVT with ESP_AVRC_INIT_SUCCESS will reported to the APP layer. * * @return * - ESP_OK: success @@ -650,6 +682,7 @@ esp_err_t esp_avrc_tg_init(void); * @brief De-initialize AVRCP target module. This function should be called after * after esp_bluedroid_enable() completes successfully. Note: AVRC cannot work independently, * AVRC should be used along with A2DP and AVRC should be deinitialized before A2DP. + * ESP_AVRC_TG_PROF_STATE_EVT with ESP_AVRC_DEINIT_SUCCESS will reported to the APP layer. * * @return * - ESP_OK: success diff --git a/components/bt/host/bluedroid/btc/profile/std/avrc/btc_avrc.c b/components/bt/host/bluedroid/btc/profile/std/avrc/btc_avrc.c index e682729895..3ed8a02ad7 100644 --- a/components/bt/host/bluedroid/btc/profile/std/avrc/btc_avrc.c +++ b/components/bt/host/bluedroid/btc/profile/std/avrc/btc_avrc.c @@ -303,10 +303,6 @@ static bool btc_avrc_tg_set_rn_supported_evt(uint16_t evt_set) static inline void btc_avrc_ct_cb_to_app(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param) { - if (s_rc_ct_init != BTC_RC_CT_INIT_MAGIC) { - return; - } - esp_avrc_ct_cb_t btc_avrc_ct_cb = (esp_avrc_ct_cb_t)btc_profile_cb_get(BTC_PID_AVRC_CT); if (btc_avrc_ct_cb) { btc_avrc_ct_cb(event, param); @@ -315,10 +311,6 @@ static inline void btc_avrc_ct_cb_to_app(esp_avrc_ct_cb_event_t event, esp_avrc_ static inline void btc_avrc_tg_cb_to_app(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t *param) { - if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { - return; - } - esp_avrc_tg_cb_t btc_avrc_tg_cb = (esp_avrc_tg_cb_t)btc_profile_cb_get(BTC_PID_AVRC_TG); if (btc_avrc_tg_cb) { btc_avrc_tg_cb(event, param); @@ -1108,27 +1100,39 @@ BOOLEAN btc_rc_get_connected_peer(BD_ADDR peer_addr) *******************************************************************************/ static void btc_avrc_ct_init(void) { + esp_avrc_init_state_t state = ESP_AVRC_INIT_SUCCESS; + BTC_TRACE_DEBUG("## %s ##", __FUNCTION__); - if (s_rc_ct_init == BTC_RC_CT_INIT_MAGIC) { - BTC_TRACE_WARNING("%s already initialized", __FUNCTION__); - return; - } - /// initialize CT-specific resources - s_rc_ct_init = BTC_RC_CT_INIT_MAGIC; + do { - /// initialize CT-TG shared resources - if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { - memset (&btc_rc_cb, 0, sizeof(btc_rc_cb_t)); - - if (!g_av_with_rc) { - g_av_with_rc = true; + if (s_rc_ct_init == BTC_RC_CT_INIT_MAGIC) { + BTC_TRACE_WARNING("%s already initialized", __FUNCTION__); + state = ESP_AVRC_INIT_ALREADY; + break; } - if (g_a2dp_on_init) { - BTC_TRACE_WARNING("AVRC Controller is expected to be initialized in advance of A2DP !!!"); + /// initialize CT-TG shared resources + if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { + if (g_a2dp_on_init) { + BTC_TRACE_WARNING("AVRC Controller is expected to be initialized in advance of A2DP !!!"); + state = ESP_AVRC_INIT_FAIL; + break; + } + memset (&btc_rc_cb, 0, sizeof(btc_rc_cb_t)); + + if (!g_av_with_rc) { + g_av_with_rc = true; + } } - } + + /// initialize CT-specific resources + s_rc_ct_init = BTC_RC_CT_INIT_MAGIC; + } while (0); + + esp_avrc_ct_cb_param_t param = {0}; + param.avrc_ct_init_stat.state = state; + btc_avrc_ct_cb_to_app(ESP_AVRC_CT_PROF_STATE_EVT, ¶m); } @@ -1143,29 +1147,37 @@ static void btc_avrc_ct_init(void) ***************************************************************************/ static void btc_avrc_ct_deinit(void) { + esp_avrc_init_state_t state = ESP_AVRC_DEINIT_SUCCESS; + BTC_TRACE_API("## %s ##", __FUNCTION__); - if (g_a2dp_on_deinit) { - BTC_TRACE_WARNING("A2DP already deinit, AVRC CT should deinit in advance of A2DP !!!"); - } - - if (s_rc_ct_init != BTC_RC_CT_INIT_MAGIC) { - BTC_TRACE_WARNING("%s not initialized", __FUNCTION__); - return; - } - - /// deinit CT-specific resources - s_rc_ct_init = 0; - - /// deinit CT-TG shared resources - if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { - memset (&btc_rc_cb, 0, sizeof(btc_rc_cb_t)); - if (g_av_with_rc) { - g_av_with_rc = false; + do { + if (g_a2dp_on_deinit) { + BTC_TRACE_WARNING("A2DP already deinit, AVRC CT should deinit in advance of A2DP !!!"); } - } - BTC_TRACE_API("## %s ## completed", __FUNCTION__); + if (s_rc_ct_init != BTC_RC_CT_INIT_MAGIC) { + BTC_TRACE_WARNING("%s not initialized", __FUNCTION__); + state = ESP_AVRC_DEINIT_ALREADY; + break; + } + + /// deinit CT-specific resources + s_rc_ct_init = 0; + + /// deinit CT-TG shared resources + if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { + memset (&btc_rc_cb, 0, sizeof(btc_rc_cb_t)); + if (g_av_with_rc) { + g_av_with_rc = false; + } + } + BTC_TRACE_API("## %s ## completed", __FUNCTION__); + } while (0); + + esp_avrc_ct_cb_param_t param = {0}; + param.avrc_ct_init_stat.state = state; + btc_avrc_ct_cb_to_app(ESP_AVRC_CT_PROF_STATE_EVT, ¶m); } static bt_status_t btc_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uint8_t value_id) @@ -1474,30 +1486,42 @@ static void btc_avrc_ct_cover_art_get_linked_thumbnail(UINT8 *image_handle) *******************************************************************************/ static void btc_avrc_tg_init(void) { + esp_avrc_init_state_t state = ESP_AVRC_INIT_SUCCESS; + BTC_TRACE_DEBUG("## %s ##", __FUNCTION__); - if (s_rc_tg_init == BTC_RC_TG_INIT_MAGIC) { - BTC_TRACE_WARNING("%s already initialized", __FUNCTION__); - return; - } - /// initialize TG-specific resources - memcpy(s_psth_supported_cmd, cs_psth_dft_supported_cmd, sizeof(s_psth_supported_cmd)); - s_rn_supported_evt = cs_rn_dft_supported_evt; - - /// initialize CT-TG shared resources - if (s_rc_ct_init != BTC_RC_CT_INIT_MAGIC) { - memset (&btc_rc_cb, 0, sizeof(btc_rc_cb)); - - if (!g_av_with_rc) { - g_av_with_rc = true; + do { + if (s_rc_tg_init == BTC_RC_TG_INIT_MAGIC) { + BTC_TRACE_WARNING("%s already initialized", __FUNCTION__); + state = ESP_AVRC_INIT_ALREADY; + break; } - if (g_a2dp_on_init) { - BTC_TRACE_WARNING("AVRC Target is expected to be initialized in advance of A2DP !!!"); - } - } + /// initialize CT-TG shared resources + if (s_rc_ct_init != BTC_RC_CT_INIT_MAGIC) { + if (g_a2dp_on_init) { + BTC_TRACE_WARNING("AVRC Target is expected to be initialized in advance of A2DP !!!"); + state = ESP_AVRC_INIT_FAIL; + break; + } - s_rc_tg_init = BTC_RC_TG_INIT_MAGIC; + memset (&btc_rc_cb, 0, sizeof(btc_rc_cb)); + + if (!g_av_with_rc) { + g_av_with_rc = true; + } + } + + /// initialize TG-specific resources + memcpy(s_psth_supported_cmd, cs_psth_dft_supported_cmd, sizeof(s_psth_supported_cmd)); + s_rn_supported_evt = cs_rn_dft_supported_evt; + + s_rc_tg_init = BTC_RC_TG_INIT_MAGIC; + } while (0); + + esp_avrc_tg_cb_param_t param = {0}; + param.avrc_tg_init_stat.state = state; + btc_avrc_tg_cb_to_app(ESP_AVRC_TG_PROF_STATE_EVT, ¶m); } @@ -1512,31 +1536,40 @@ static void btc_avrc_tg_init(void) ***************************************************************************/ static void btc_avrc_tg_deinit(void) { + esp_avrc_init_state_t state = ESP_AVRC_DEINIT_SUCCESS; + BTC_TRACE_API("## %s ##", __FUNCTION__); - if (g_a2dp_on_deinit) { - BTC_TRACE_WARNING("A2DP already deinit, AVRC TG should deinit in advance of A2DP !!!"); - } - - if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { - BTC_TRACE_WARNING("%s not initialized", __FUNCTION__); - return; - } - - /// deinit TG-specific resources - memset(s_psth_supported_cmd, 0, sizeof(s_psth_supported_cmd)); - s_rn_supported_evt = 0; - s_rc_tg_init = 0; - - /// deinit CT-TG shared resources - if (s_rc_ct_init != BTC_RC_CT_INIT_MAGIC) { - memset (&btc_rc_cb, 0, sizeof(btc_rc_cb)); - if (g_av_with_rc) { - g_av_with_rc = false; + do { + if (g_a2dp_on_deinit) { + BTC_TRACE_WARNING("A2DP already deinit, AVRC TG should deinit in advance of A2DP !!!"); } - } - BTC_TRACE_API("## %s ## completed", __FUNCTION__); + if (s_rc_tg_init != BTC_RC_TG_INIT_MAGIC) { + BTC_TRACE_WARNING("%s not initialized", __FUNCTION__); + state = ESP_AVRC_DEINIT_ALREADY; + break; + } + + /// deinit TG-specific resources + memset(s_psth_supported_cmd, 0, sizeof(s_psth_supported_cmd)); + s_rn_supported_evt = 0; + s_rc_tg_init = 0; + + /// deinit CT-TG shared resources + if (s_rc_ct_init != BTC_RC_CT_INIT_MAGIC) { + memset (&btc_rc_cb, 0, sizeof(btc_rc_cb)); + if (g_av_with_rc) { + g_av_with_rc = false; + } + } + + BTC_TRACE_API("## %s ## completed", __FUNCTION__); + } while (0); + + esp_avrc_tg_cb_param_t param = {0}; + param.avrc_tg_init_stat.state = state; + btc_avrc_tg_cb_to_app(ESP_AVRC_TG_PROF_STATE_EVT, ¶m); } static void btc_avrc_tg_send_rn_rsp(esp_avrc_rn_event_ids_t event_id, esp_avrc_rn_rsp_t rsp, const esp_avrc_rn_param_t *param) diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c index a95e640def..a6601f624c 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c @@ -532,6 +532,17 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param) #endif 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; + } /* others */ default: ESP_LOGE(BT_RC_CT_TAG, "%s unhandled event: %d", __func__, event); @@ -587,6 +598,17 @@ static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param) ESP_LOGI(BT_RC_TG_TAG, "AVRC remote features: %"PRIx32", CT features: %x", rc->rmt_feats.feat_mask, rc->rmt_feats.ct_feat_flag); break; } + /* when avrcp target init or deinit completed, this event comes */ + case ESP_AVRC_TG_PROF_STATE_EVT: { + if (ESP_AVRC_INIT_SUCCESS == rc->avrc_tg_init_stat.state) { + ESP_LOGI(BT_RC_CT_TAG, "AVRCP TG STATE: Init Complete"); + } else if (ESP_AVRC_DEINIT_SUCCESS == rc->avrc_tg_init_stat.state) { + ESP_LOGI(BT_RC_CT_TAG, "AVRCP TG STATE: Deinit Complete"); + } else { + ESP_LOGE(BT_RC_CT_TAG, "AVRCP TG STATE error: %d", rc->avrc_tg_init_stat.state); + } + break; + } /* others */ default: ESP_LOGE(BT_RC_TG_TAG, "%s unhandled event: %d", __func__, event); @@ -665,7 +687,8 @@ void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param case ESP_AVRC_CT_REMOTE_FEATURES_EVT: case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: case ESP_AVRC_CT_COVER_ART_STATE_EVT: - case ESP_AVRC_CT_COVER_ART_DATA_EVT: { + case ESP_AVRC_CT_COVER_ART_DATA_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; } @@ -684,6 +707,7 @@ void bt_app_rc_tg_cb(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t *param case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT: case ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT: case ESP_AVRC_TG_SET_PLAYER_APP_VALUE_EVT: + case ESP_AVRC_TG_PROF_STATE_EVT: bt_app_work_dispatch(bt_av_hdl_avrc_tg_evt, event, param, sizeof(esp_avrc_tg_cb_param_t), NULL); break; default: diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c index d4da955d2f..8393b3e40f 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c @@ -153,17 +153,17 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) esp_bt_dev_register_callback(bt_app_dev_cb); esp_bt_gap_register_callback(bt_app_gap_cb); - assert(esp_avrc_ct_init() == ESP_OK); esp_avrc_ct_register_callback(bt_app_rc_ct_cb); - assert(esp_avrc_tg_init() == ESP_OK); + assert(esp_avrc_ct_init() == ESP_OK); esp_avrc_tg_register_callback(bt_app_rc_tg_cb); + assert(esp_avrc_tg_init() == ESP_OK); esp_avrc_rn_evt_cap_mask_t evt_set = {0}; esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE); assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK); - assert(esp_a2d_sink_init() == ESP_OK); esp_a2d_register_callback(&bt_app_a2d_cb); + assert(esp_a2d_sink_init() == ESP_OK); #if CONFIG_EXAMPLE_A2DP_SINK_USE_EXTERNAL_CODEC == FALSE esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);