diff --git a/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/CMakeLists.txt new file mode 100644 index 0000000000..bcd7cd6879 --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "avrcp_cover_art_utils.c" + "avrcp_cover_art_service.c" + PRIV_REQUIRES bt esp_lcd avrcp_common_utils + INCLUDE_DIRS "." "../include") diff --git a/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/Kconfig.projbuild b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/Kconfig.projbuild new file mode 100644 index 0000000000..78035b2618 --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/Kconfig.projbuild @@ -0,0 +1,8 @@ +menu "AVRCP Cover Art Example Configuration" + config EXAMPLE_LCD_FLUSH_PARALLEL_LINES + int "LCD flush parallel lines" + default 16 + help + To speed up transfers, every SPI transfer sends a bunch of lines. + +endmenu diff --git a/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_service.c b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_service.c new file mode 100644 index 0000000000..bd837329f6 --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_service.c @@ -0,0 +1,347 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include "driver/spi_master.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ops.h" +#include "jpeg_decoder.h" +#include "avrcp_common_utils.h" +#include "avrcp_cover_art_service.h" + +/* tags*/ +#define RC_CA_SRV_TAG "RC_CA_SRV" + +//Define the height and width of the jpeg file. Make sure this matches the actual jpeg +//dimensions. +#define IMAGE_W 200 +#define IMAGE_H 200 + +// Using SPI2 in the example, as it also supports octal modes on some targets +#define LCD_HOST SPI2_HOST +// To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. +// More means more memory use, but less overhead for setting up / finishing transfers. Make sure 240 +// is dividable by this. +#define PARALLEL_LINES CONFIG_EXAMPLE_LCD_FLUSH_PARALLEL_LINES + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000) +#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 0 +#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL +#define EXAMPLE_PIN_NUM_DATA0 23 /*!< for 1-line SPI, this also referred as MOSI */ +#define EXAMPLE_PIN_NUM_PCLK 19 +#define EXAMPLE_PIN_NUM_CS 22 +#define EXAMPLE_PIN_NUM_DC 21 +#define EXAMPLE_PIN_NUM_RST 18 +#define EXAMPLE_PIN_NUM_BK_LIGHT 5 + +// The pixel number in horizontal and vertical +#define EXAMPLE_LCD_H_RES 200 +#define EXAMPLE_LCD_V_RES 200 +// Bit number used to represent command and parameter +#define EXAMPLE_LCD_CMD_BITS 8 +#define EXAMPLE_LCD_PARAM_BITS 8 + +/** + * @brief AVRCP cover art service control block structure + */ +typedef struct { + bool connected; /* Connection status flag */ + bool getting; /* Flag indicating if image is being retrieved */ + /* Related to the image */ + uint8_t image_hdl_old[7]; /* Previous image handle, used to detect image changes */ + uint32_t image_size; /* Size of the image data in bytes */ + uint8_t *image_data; /* Pointer to the image data buffer */ + bool image_final; /* Indicate whether the image reception has been completed */ + uint16_t *pixels; /* Pointer to decoded pixel data */ + esp_lcd_panel_io_handle_t io_handle; /* LCD panel IO handle */ + esp_lcd_panel_handle_t panel_handle; /* LCD panel handle */ +} avrc_cover_art_srv_cb_t; + +/******************************* + * STATIC FUNCTION DECLARATIONS + ******************************/ + +/* image handle check */ +static bool avrc_cover_art_srv_image_handle_check(uint8_t *image_handle, int len); +/* free image data */ +static void avrc_cover_art_srv_free_image_data(void); +/* initialize display (currently supports LCD only) */ +static void avrc_cover_art_srv_init_display(void); +/* deinitialize display (currently supports LCD only) */ +static void avrc_cover_art_srv_deinit_display(void); +/* free pixels */ +static void avrc_cover_art_srv_free_pixels(void); +/* decode image */ +static esp_err_t avrc_cover_art_srv_decode_image(void); +/* display image */ +static void avrc_cover_art_srv_display_image(void); + +/******************************* + * STATIC VARIABLE DEFINITIONS + ******************************/ + +/* avrcp cover art service control block */ +static avrc_cover_art_srv_cb_t s_avrc_cover_art_srv_cb; + +/******************************** + * STATIC FUNCTION DEFINITIONS + *******************************/ + +static bool avrc_cover_art_srv_image_handle_check(uint8_t *image_handle, int len) +{ + /* Image handle length must be 7 */ + if (len == 7 && memcmp(s_avrc_cover_art_srv_cb.image_hdl_old, image_handle, 7) != 0) { + memcpy(s_avrc_cover_art_srv_cb.image_hdl_old, image_handle, 7); + return true; + } + return false; +} + +static void avrc_cover_art_srv_free_image_data(void) +{ + if (s_avrc_cover_art_srv_cb.image_data) { + free(s_avrc_cover_art_srv_cb.image_data); + s_avrc_cover_art_srv_cb.image_data = NULL; + } + s_avrc_cover_art_srv_cb.image_size = 0; +} + +static void avrc_cover_art_srv_init_display(void) +{ + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT + }; + /* Initialize the GPIO of backlight */ + ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); + + spi_bus_config_t buscfg = { + .sclk_io_num = EXAMPLE_PIN_NUM_PCLK, + .mosi_io_num = EXAMPLE_PIN_NUM_DATA0, + .miso_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = PARALLEL_LINES * EXAMPLE_LCD_H_RES * 2 + 8 + }; + /* Initialize the SPI bus */ + ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); + + esp_lcd_panel_io_spi_config_t io_config = { + .dc_gpio_num = EXAMPLE_PIN_NUM_DC, + .cs_gpio_num = EXAMPLE_PIN_NUM_CS, + .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ, + .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, + .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, + .spi_mode = 0, + .trans_queue_depth = 10, + }; + /* Attach the LCD to the SPI bus */ + ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &s_avrc_cover_art_srv_cb.io_handle)); + + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_PIN_NUM_RST, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = 16, + }; + /* Initialize the LCD configuration */ + ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(s_avrc_cover_art_srv_cb.io_handle, &panel_config, &s_avrc_cover_art_srv_cb.panel_handle)); + + /* Turn off backlight to avoid unpredictable display on the LCD screen while initializing + * the LCD panel driver. (Different LCD screens may need different levels) */ + ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL)); + + /* Reset the display */ + ESP_ERROR_CHECK(esp_lcd_panel_reset(s_avrc_cover_art_srv_cb.panel_handle)); + + /* Initialize LCD panel */ + ESP_ERROR_CHECK(esp_lcd_panel_init(s_avrc_cover_art_srv_cb.panel_handle)); + + /* Turn on the screen */ + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(s_avrc_cover_art_srv_cb.panel_handle, true)); + ESP_ERROR_CHECK(esp_lcd_panel_invert_color(s_avrc_cover_art_srv_cb.panel_handle, true)); + + /* Swap x and y axis (Different LCD screens may need different options) */ + ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(s_avrc_cover_art_srv_cb.panel_handle, true)); + + /* Turn on backlight (Different LCD screens may need different levels) */ + ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL)); +} + +static void avrc_cover_art_srv_deinit_display(void) +{ + /* Turn off backlight first */ + ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL)); + + /* Turn off the display */ + if (s_avrc_cover_art_srv_cb.panel_handle) { + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(s_avrc_cover_art_srv_cb.panel_handle, false)); + /* Delete the LCD panel */ + ESP_ERROR_CHECK(esp_lcd_panel_del(s_avrc_cover_art_srv_cb.panel_handle)); + s_avrc_cover_art_srv_cb.panel_handle = NULL; + } + + /* Delete the LCD panel IO */ + if (s_avrc_cover_art_srv_cb.io_handle) { + ESP_ERROR_CHECK(esp_lcd_panel_io_del(s_avrc_cover_art_srv_cb.io_handle)); + s_avrc_cover_art_srv_cb.io_handle = NULL; + } + + /* Free the SPI bus */ + ESP_ERROR_CHECK(spi_bus_free(LCD_HOST)); + + /* Reset backlight GPIO */ + ESP_ERROR_CHECK(gpio_reset_pin(EXAMPLE_PIN_NUM_BK_LIGHT)); +} + +static void avrc_cover_art_srv_free_pixels(void) +{ + if (s_avrc_cover_art_srv_cb.pixels) { + free(s_avrc_cover_art_srv_cb.pixels); + s_avrc_cover_art_srv_cb.pixels = NULL; + } +} + +static esp_err_t avrc_cover_art_srv_decode_image(void) +{ + esp_err_t ret = ESP_OK; + + avrc_cover_art_srv_free_pixels(); + + /* Allocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `s_avrc_cover_art_srv_cb.pixels` array itself contains pointers to these lines. */ + s_avrc_cover_art_srv_cb.pixels = calloc(IMAGE_H * IMAGE_W, sizeof(uint16_t)); + + ESP_GOTO_ON_FALSE(s_avrc_cover_art_srv_cb.pixels, ESP_ERR_NO_MEM, err, RC_CA_SRV_TAG, "Error allocating memory for lines"); + + /* JPEG decode config */ + esp_jpeg_image_cfg_t jpeg_cfg = { + .indata = (uint8_t *)s_avrc_cover_art_srv_cb.image_data, + .indata_size = s_avrc_cover_art_srv_cb.image_size, + .outbuf = (uint8_t*)(s_avrc_cover_art_srv_cb.pixels), + .outbuf_size = IMAGE_W * IMAGE_H * sizeof(uint16_t), + .out_format = JPEG_IMAGE_FORMAT_RGB565, + .out_scale = JPEG_IMAGE_SCALE_0, + .flags = { + .swap_color_bytes = 1, + } + }; + + /* JPEG decode */ + esp_jpeg_image_output_t outimg; + ret = esp_jpeg_decode(&jpeg_cfg, &outimg); + + ESP_LOGI(RC_CA_SRV_TAG, "JPEG image decoded! Size of the decoded image is: %dpx x %dpx.", outimg.width, outimg.height); + + return ret; +err: + /* Something went wrong! Exit cleanly, de-allocating everything we allocated. */ + avrc_cover_art_srv_free_pixels(); + return ret; +} + +static void avrc_cover_art_srv_display_image(void) +{ + if (s_avrc_cover_art_srv_cb.panel_handle && s_avrc_cover_art_srv_cb.pixels) { + esp_lcd_panel_draw_bitmap(s_avrc_cover_art_srv_cb.panel_handle, 0, 0, EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES, s_avrc_cover_art_srv_cb.pixels); + } +} + +/******************************** + * EXTERNAL FUNCTION DEFINITIONS + *******************************/ + +void avrc_cover_art_srv_open(void) +{ + memset(&s_avrc_cover_art_srv_cb, 0, sizeof(avrc_cover_art_srv_cb_t)); + /* initialize the display */ + avrc_cover_art_srv_init_display(); +} + +void avrc_cover_art_srv_close(void) +{ + /* deinitialize the display */ + avrc_cover_art_srv_deinit_display(); + + avrc_cover_art_srv_free_image_data(); + avrc_cover_art_srv_free_pixels(); + + memset(&s_avrc_cover_art_srv_cb, 0, sizeof(avrc_cover_art_srv_cb_t)); +} + +void avrc_cover_art_srv_connect(uint16_t mtu) +{ + if (!s_avrc_cover_art_srv_cb.connected) { + ESP_LOGW(RC_CA_SRV_TAG, "Start cover art connection..."); + /* start the cover art connection */ + esp_avrc_ct_cover_art_connect(mtu); + } +} + +void avrc_cover_art_srv_set_image_final(bool final) +{ + s_avrc_cover_art_srv_cb.image_final = final; + if (s_avrc_cover_art_srv_cb.image_final) { + ESP_LOGI(RC_CA_SRV_TAG, "Cover Art Client final data event, image size: %lu bytes", s_avrc_cover_art_srv_cb.image_size); + + /* decode and display the image */ + avrc_cover_art_srv_decode_image(); + /* display the image */ + avrc_cover_art_srv_display_image(); + /* set the getting state to false, we can get next image now */ + s_avrc_cover_art_srv_cb.getting = false; + } +} + +void avrc_cover_art_srv_set_connected(bool connected) +{ + s_avrc_cover_art_srv_cb.connected = connected; +} + +void avrc_cover_art_srv_ca_req(void) +{ + /* request cover art */ + if (s_avrc_cover_art_srv_cb.connected) { + uint8_t attr_mask = ESP_AVRC_MD_ATTR_COVER_ART; + + esp_avrc_ct_send_metadata_cmd(bt_avrc_common_alloc_tl(), attr_mask); + } +} + +void avrc_cover_art_srv_save_image_data(uint8_t *p_data, uint16_t data_len) +{ + s_avrc_cover_art_srv_cb.image_size += data_len; + + uint8_t *p_buf = (uint8_t *)realloc(s_avrc_cover_art_srv_cb.image_data, s_avrc_cover_art_srv_cb.image_size * sizeof(uint8_t)); + if (!p_buf) { + ESP_LOGE(RC_CA_SRV_TAG, "%s: The memory allocation of Cover art image data failed", __func__); + avrc_cover_art_srv_free_image_data(); + return; + } + s_avrc_cover_art_srv_cb.image_data = p_buf; + memcpy(s_avrc_cover_art_srv_cb.image_data + s_avrc_cover_art_srv_cb.image_size - data_len, p_data, data_len); +} + +void avrc_cover_art_srv_ct_metadata_update(uint8_t *image_handle, int len) +{ + if (s_avrc_cover_art_srv_cb.connected && !s_avrc_cover_art_srv_cb.getting) { + /* check image handle is valid and different with last one, we don't want to get an image repeatedly */ + if (avrc_cover_art_srv_image_handle_check(image_handle, len)) { + /* free the previous image data */ + avrc_cover_art_srv_free_image_data(); + /* get the linked thumbnail */ + esp_avrc_ct_cover_art_get_linked_thumbnail(image_handle); + s_avrc_cover_art_srv_cb.getting = true; + } + } +} diff --git a/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_service.h b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_service.h new file mode 100644 index 0000000000..f92ca796ce --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_service.h @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef __AVRCP_COVER_ART_SERVICE_H__ +#define __AVRCP_COVER_ART_SERVICE_H__ + +#include +#include "esp_avrc_api.h" +#include "esp_err.h" + +/** + * @brief open AVRCP cover art service + */ +void avrc_cover_art_srv_open(void); + +/** + * @brief close AVRCP cover art service + */ +void avrc_cover_art_srv_close(void); + +/** + * @brief start the cover art connection + * + * @param [in] mtu: maximum transmission unit + */ +void avrc_cover_art_srv_connect(uint16_t mtu); + +/** + * @brief set AVRCP cover art image final, and then if image final is true, display the image + * + * @param [in] final: true if image reception has been completed, false otherwise + */ +void avrc_cover_art_srv_set_image_final(bool final); + +/** + * @brief set AVRCP cover art connected + * + * @param [in] connected: true if connected, false otherwise + */ +void avrc_cover_art_srv_set_connected(bool connected); + +/** + * @brief request AVRCP cover art + */ +void avrc_cover_art_srv_ca_req(void); + +/** + * @brief save cover art data + * + * @param [in] p_data: pointer to the cover art data + * @param [in] data_len: length of the cover art data + */ +void avrc_cover_art_srv_save_image_data(uint8_t *p_data, uint16_t data_len); + +/** + * @brief handle the cover art update when metadata response + * + * @param [in] image_handle: pointer to the image handle + * @param [in] len: length of the image handle + */ +void avrc_cover_art_srv_ct_metadata_update(uint8_t *image_handle, int len); + +#endif /* __AVRCP_COVER_ART_SERVICE_H__ */ diff --git a/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_utils.c b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_utils.c new file mode 100644 index 0000000000..1d9eeefaf8 --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_utils.c @@ -0,0 +1,91 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include +#include +#include "esp_log.h" +#include "esp_avrc_api.h" +#include "avrcp_utils_tags.h" +#include "avrcp_cover_art_service.h" + +void bt_avrc_ca_ct_evt_hdl(uint16_t event, void *param) +{ + ESP_LOGD(BT_RC_CT_TAG, "%s event: %d", __func__, event); + + esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(param); + + switch (event) { + /* when connection state changed, this event comes */ + case ESP_AVRC_CT_CONNECTION_STATE_EVT: { + if (rc->conn_stat.connected) { + /* open the cover art service */ + avrc_cover_art_srv_open(); + } else { + /* close the cover art service */ + avrc_cover_art_srv_close(); + } + break; + } + /* when metadata response, this event comes */ + case ESP_AVRC_CT_METADATA_RSP_EVT: { + ESP_LOGI(BT_RC_CT_TAG, "AVRC metadata rsp: attribute id 0x%x, %s", rc->meta_rsp.attr_id, rc->meta_rsp.attr_text); + if (rc->meta_rsp.attr_id == ESP_AVRC_MD_ATTR_COVER_ART) { + avrc_cover_art_srv_ct_metadata_update(rc->meta_rsp.attr_text, rc->meta_rsp.attr_length); + } + break; + } + /* when notified, this event comes */ + case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: { + if (rc->change_ntf.event_id == ESP_AVRC_RN_TRACK_CHANGE) { + /* request the cover art */ + avrc_cover_art_srv_ca_req(); + } + break; + } + /* when feature of remote device indicated, this event comes */ + case ESP_AVRC_CT_REMOTE_FEATURES_EVT: { + ESP_LOGI(BT_RC_CT_TAG, "AVRC remote features %"PRIx32", TG features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.tg_feat_flag); + if ((rc->rmt_feats.tg_feat_flag & ESP_AVRC_FEAT_FLAG_TG_COVER_ART)) { + ESP_LOGW(BT_RC_CT_TAG, "Peer support Cover Art feature"); + /* start the cover art connection */ + avrc_cover_art_srv_connect(ESP_AVRC_CA_MTU_MAX); + } + break; + } + /* when notification capability of peer device got, this event comes */ + case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: { + /* request the cover art */ + avrc_cover_art_srv_ca_req(); + break; + } + /* when the state of cover art changes, this event comes */ + case ESP_AVRC_CT_COVER_ART_STATE_EVT: { + if (rc->cover_art_state.state == ESP_AVRC_COVER_ART_CONNECTED) { + avrc_cover_art_srv_set_connected(true); + ESP_LOGW(BT_RC_CT_TAG, "Cover Art Client connected"); + /* request the cover art */ + avrc_cover_art_srv_ca_req(); + } else { + avrc_cover_art_srv_set_connected(false); + ESP_LOGW(BT_RC_CT_TAG, "Cover Art Client disconnected, reason:%d", rc->cover_art_state.reason); + } + break; + } + /* when obtaining the cover art image data, this event comes */ + case ESP_AVRC_CT_COVER_ART_DATA_EVT: { + /* when rc->cover_art_data.final is true, it means we have received the entire image */ + avrc_cover_art_srv_set_image_final(rc->cover_art_data.final); + break; + } + /* others */ + default: + ESP_LOGE(BT_RC_CT_TAG, "%s unhandled event: %d", __func__, event); + break; + } +} diff --git a/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_utils.h b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_utils.h new file mode 100644 index 0000000000..88e9bcd747 --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/avrcp_cover_art_utils.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef __AVRCP_COVER_ART_UTILS_H__ +#define __AVRCP_COVER_ART_UTILS_H__ + +#include + +/** + * @brief handle function for AVRCP controller cover art event + * + * @param [in] event event id + * @param [in] param callback parameter + */ +void bt_avrc_ca_ct_evt_hdl(uint16_t event, void *param); + +#endif /* __AVRCP_COVER_ART_UTILS_H__*/ diff --git a/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/idf_component.yml b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/idf_component.yml new file mode 100644 index 0000000000..d5b8ca349a --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_cover_art_utils/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + idf: ">=4.4" + esp_jpeg: ">=1.0.2" + avrcp_common_utils: + path: ${IDF_PATH}/examples/bluetooth/bluedroid/classic_bt/common/avrcp_utils/avrcp_common_utils