mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
component/bt: Add AVRCP medadata attribute support so A2DP can show track title, album, etc.
Merges https://github.com/espressif/esp-idf/pull/1078
This commit is contained in:
parent
582b731c23
commit
86fa1820b7
@ -27,7 +27,7 @@ esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback)
|
|||||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback == NULL) {
|
if (callback == NULL) {
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ esp_err_t esp_avrc_ct_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
btc_msg_t msg;
|
btc_msg_t msg;
|
||||||
|
|
||||||
msg.sig = BTC_SIG_API_CALL;
|
msg.sig = BTC_SIG_API_CALL;
|
||||||
msg.pid = BTC_PID_AVRC;
|
msg.pid = BTC_PID_AVRC;
|
||||||
msg.act = BTC_AVRC_CTRL_API_INIT_EVT;
|
msg.act = BTC_AVRC_CTRL_API_INIT_EVT;
|
||||||
@ -60,7 +60,7 @@ esp_err_t esp_avrc_ct_deinit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
btc_msg_t msg;
|
btc_msg_t msg;
|
||||||
|
|
||||||
msg.sig = BTC_SIG_API_CALL;
|
msg.sig = BTC_SIG_API_CALL;
|
||||||
msg.pid = BTC_PID_AVRC;
|
msg.pid = BTC_PID_AVRC;
|
||||||
msg.act = BTC_AVRC_CTRL_API_DEINIT_EVT;
|
msg.act = BTC_AVRC_CTRL_API_DEINIT_EVT;
|
||||||
@ -70,12 +70,97 @@ esp_err_t esp_avrc_ct_deinit(void)
|
|||||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uint8_t value_id)
|
||||||
|
{
|
||||||
|
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tl >= 16 || attr_id > ESP_AVRC_PS_MAX_ATTR - 1) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
btc_msg_t msg;
|
||||||
|
msg.sig = BTC_SIG_API_CALL;
|
||||||
|
msg.pid = BTC_PID_AVRC;
|
||||||
|
msg.act = BTC_AVRC_CTRL_API_SET_PLAYER_SETTING_EVT;
|
||||||
|
|
||||||
|
btc_avrc_args_t arg;
|
||||||
|
memset(&arg, 0, sizeof(btc_avrc_args_t));
|
||||||
|
|
||||||
|
arg.ps_cmd.tl = tl;
|
||||||
|
arg.ps_cmd.attr_id = attr_id;
|
||||||
|
arg.ps_cmd.value_id = value_id;
|
||||||
|
|
||||||
|
/* Switch to BTC context */
|
||||||
|
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_args_t), NULL);
|
||||||
|
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_id, uint32_t event_parameter)
|
||||||
|
{
|
||||||
|
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tl >= 16 || event_id > ESP_AVRC_RN_MAX_EVT - 1) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
btc_msg_t msg;
|
||||||
|
msg.sig = BTC_SIG_API_CALL;
|
||||||
|
msg.pid = BTC_PID_AVRC;
|
||||||
|
msg.act = BTC_AVRC_NOTIFY_API_SND_REG_NOTIFY_EVT;
|
||||||
|
|
||||||
|
btc_avrc_args_t arg;
|
||||||
|
memset(&arg, 0, sizeof(btc_avrc_args_t));
|
||||||
|
|
||||||
|
arg.rn_cmd.tl = tl;
|
||||||
|
arg.rn_cmd.event_id = event_id;
|
||||||
|
arg.rn_cmd.event_parameter = event_parameter;
|
||||||
|
|
||||||
|
/* Switch to BTC context */
|
||||||
|
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_args_t), NULL);
|
||||||
|
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_avrc_ct_send_metadata_cmd(uint8_t tl, uint8_t attr_mask)
|
||||||
|
{
|
||||||
|
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tl >= 16) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
btc_msg_t msg;
|
||||||
|
msg.sig = BTC_SIG_API_CALL;
|
||||||
|
msg.pid = BTC_PID_AVRC;
|
||||||
|
msg.act = BTC_AVRC_STATUS_API_SND_META_EVT;
|
||||||
|
|
||||||
|
btc_avrc_args_t arg;
|
||||||
|
memset(&arg, 0, sizeof(btc_avrc_args_t));
|
||||||
|
|
||||||
|
arg.md_cmd.tl = tl;
|
||||||
|
arg.md_cmd.attr_mask = attr_mask;
|
||||||
|
|
||||||
|
/* Switch to BTC context */
|
||||||
|
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_args_t), NULL);
|
||||||
|
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state)
|
esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state)
|
||||||
{
|
{
|
||||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tl >= 16 || key_state > ESP_AVRC_PT_CMD_STATE_RELEASED) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
btc_msg_t msg;
|
btc_msg_t msg;
|
||||||
msg.sig = BTC_SIG_API_CALL;
|
msg.sig = BTC_SIG_API_CALL;
|
||||||
msg.pid = BTC_PID_AVRC;
|
msg.pid = BTC_PID_AVRC;
|
||||||
@ -87,7 +172,7 @@ esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t
|
|||||||
arg.pt_cmd.tl = tl;
|
arg.pt_cmd.tl = tl;
|
||||||
arg.pt_cmd.key_code = key_code;
|
arg.pt_cmd.key_code = key_code;
|
||||||
arg.pt_cmd.key_state = key_state;
|
arg.pt_cmd.key_state = key_state;
|
||||||
|
|
||||||
/* Switch to BTC context */
|
/* Switch to BTC context */
|
||||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_args_t), NULL);
|
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_args_t), NULL);
|
||||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||||
|
@ -40,7 +40,9 @@ typedef enum {
|
|||||||
ESP_AVRC_PT_CMD_STOP = 0x45, /*!< stop */
|
ESP_AVRC_PT_CMD_STOP = 0x45, /*!< stop */
|
||||||
ESP_AVRC_PT_CMD_PAUSE = 0x46, /*!< pause */
|
ESP_AVRC_PT_CMD_PAUSE = 0x46, /*!< pause */
|
||||||
ESP_AVRC_PT_CMD_FORWARD = 0x4B, /*!< forward */
|
ESP_AVRC_PT_CMD_FORWARD = 0x4B, /*!< forward */
|
||||||
ESP_AVRC_PT_CMD_BACKWARD = 0x4C /*!< backward */
|
ESP_AVRC_PT_CMD_BACKWARD = 0x4C, /*!< backward */
|
||||||
|
ESP_AVRC_PT_CMD_REWIND = 0x48, /*!< rewind */
|
||||||
|
ESP_AVRC_PT_CMD_FAST_FORWARD = 0x49 /*!< fast forward */
|
||||||
} esp_avrc_pt_cmd_t;
|
} esp_avrc_pt_cmd_t;
|
||||||
|
|
||||||
/// AVRC passthrough command state
|
/// AVRC passthrough command state
|
||||||
@ -53,9 +55,73 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
ESP_AVRC_CT_CONNECTION_STATE_EVT = 0, /*!< connection state changed event */
|
ESP_AVRC_CT_CONNECTION_STATE_EVT = 0, /*!< connection state changed event */
|
||||||
ESP_AVRC_CT_PASSTHROUGH_RSP_EVT = 1, /*!< passthrough response event */
|
ESP_AVRC_CT_PASSTHROUGH_RSP_EVT = 1, /*!< passthrough response event */
|
||||||
|
ESP_AVRC_CT_METADATA_RSP_EVT = 2, /*!< metadata response event */
|
||||||
|
ESP_AVRC_CT_PLAY_STATUS_RSP_EVT = 3, /*!< play status response event */
|
||||||
|
ESP_AVRC_CT_CHANGE_NOTIFY_EVT = 4, /*!< notification event */
|
||||||
ESP_AVRC_CT_MAX_EVT
|
ESP_AVRC_CT_MAX_EVT
|
||||||
} esp_avrc_ct_cb_event_t;
|
} esp_avrc_ct_cb_event_t;
|
||||||
|
|
||||||
|
//AVRC metadata attribute mask
|
||||||
|
typedef enum {
|
||||||
|
ESP_AVRC_MD_ATTR_TITLE = 0x1, /*!< title of the playing track */
|
||||||
|
ESP_AVRC_MD_ATTR_ARTIST = 0x2, /*!< track artist */
|
||||||
|
ESP_AVRC_MD_ATTR_ALBUM = 0x4, /*!< album name */
|
||||||
|
ESP_AVRC_MD_ATTR_TRACK_NUM = 0x8, /*!< track position on the album */
|
||||||
|
ESP_AVRC_MD_ATTR_NUM_TRACKS = 0x10, /*!< number of tracks on the album */
|
||||||
|
ESP_AVRC_MD_ATTR_GENRE = 0x20, /*!< track genre */
|
||||||
|
ESP_AVRC_MD_ATTR_PLAYING_TIME = 0x40 /*!< total album playing time in miliseconds */
|
||||||
|
} esp_avrc_md_attr_mask_t;
|
||||||
|
|
||||||
|
//AVRC event notification ids
|
||||||
|
typedef enum {
|
||||||
|
ESP_AVRC_RN_PLAY_STATUS_CHANGE = 0x01, /*!< track status change, eg. from playing to paused */
|
||||||
|
ESP_AVRC_RN_TRACK_CHANGE = 0x02, /*!< new track is loaded */
|
||||||
|
ESP_AVRC_RN_TRACK_REACHED_END = 0x03, /*!< current track reached end */
|
||||||
|
ESP_AVRC_RN_TRACK_REACHED_START = 0x04, /*!< current track reached start position */
|
||||||
|
ESP_AVRC_RN_PLAY_POS_CHANGED = 0x05, /*!< track playing position changed */
|
||||||
|
ESP_AVRC_RN_BATTERY_STATUS_CHANGE = 0x06, /*!< battery status changed */
|
||||||
|
ESP_AVRC_RN_SYSTEM_STATUS_CHANGE = 0x07, /*!< system status changed */
|
||||||
|
ESP_AVRC_RN_APP_SETTING_CHANGE = 0x08, /*!< application settings changed */
|
||||||
|
ESP_AVRC_RN_MAX_EVT
|
||||||
|
} esp_avrc_rn_event_ids_t;
|
||||||
|
|
||||||
|
//AVRC player setting ids
|
||||||
|
typedef enum {
|
||||||
|
ESP_AVRC_PS_EQUALIZER = 0x01, /*!< equalizer, on or off */
|
||||||
|
ESP_AVRC_PS_REPEAT_MODE = 0x02, /*!< repeat mode */
|
||||||
|
ESP_AVRC_PS_SHUFFLE_MODE = 0x03, /*!< shuffle mode */
|
||||||
|
ESP_AVRC_PS_SCAN_MODE = 0x04, /*!< scan mode on or off */
|
||||||
|
ESP_AVRC_PS_MAX_ATTR
|
||||||
|
} esp_avrc_ps_attr_ids_t;
|
||||||
|
|
||||||
|
//AVRC equalizer modes
|
||||||
|
typedef enum {
|
||||||
|
ESP_AVRC_PS_EQUALIZER_OFF = 0x1,
|
||||||
|
ESP_AVRC_PS_EQUALIZER_ON = 0x2
|
||||||
|
} esp_avrc_ps_eq_value_ids_t;
|
||||||
|
|
||||||
|
//AVRC repeat modes
|
||||||
|
typedef enum {
|
||||||
|
ESP_AVRC_PS_REPEAT_OFF = 0x1,
|
||||||
|
ESP_AVRC_PS_REPEAT_SINGLE = 0x2,
|
||||||
|
ESP_AVRC_PS_REPEAT_GROUP = 0x3
|
||||||
|
} esp_avrc_ps_rpt_value_ids_t;
|
||||||
|
|
||||||
|
|
||||||
|
//AVRC shuffle modes
|
||||||
|
typedef enum {
|
||||||
|
ESP_AVRC_PS_SHUFFLE_OFF = 0x1,
|
||||||
|
ESP_AVRC_PS_SHUFFLE_ALL = 0x2,
|
||||||
|
ESP_AVRC_PS_SHUFFLE_GROUP = 0x3
|
||||||
|
} esp_avrc_ps_shf_value_ids_t;
|
||||||
|
|
||||||
|
//AVRC scan modes
|
||||||
|
typedef enum {
|
||||||
|
ESP_AVRC_PS_SCAN_OFF = 0x1,
|
||||||
|
ESP_AVRC_PS_SCAN_ALL = 0x2,
|
||||||
|
ESP_AVRC_PS_SCAN_GROUP = 0x3
|
||||||
|
} esp_avrc_ps_scn_value_ids_t;
|
||||||
|
|
||||||
/// AVRC controller callback parameters
|
/// AVRC controller callback parameters
|
||||||
typedef union {
|
typedef union {
|
||||||
/**
|
/**
|
||||||
@ -63,10 +129,10 @@ typedef union {
|
|||||||
*/
|
*/
|
||||||
struct avrc_ct_conn_stat_param {
|
struct avrc_ct_conn_stat_param {
|
||||||
bool connected; /*!< whether AVRC connection is set up */
|
bool connected; /*!< whether AVRC connection is set up */
|
||||||
uint32_t feat_mask; /*!< AVRC feature mask of remote device */
|
uint32_t feat_mask; /*!< AVRC feature mask of remote device */
|
||||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
||||||
} conn_stat; /*!< AVRC connection status */
|
} conn_stat; /*!< AVRC connection status */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ESP_AVRC_CT_PASSTHROUGH_RSP_EVT
|
* @brief ESP_AVRC_CT_PASSTHROUGH_RSP_EVT
|
||||||
*/
|
*/
|
||||||
@ -75,6 +141,24 @@ typedef union {
|
|||||||
uint8_t key_code; /*!< passthrough command code */
|
uint8_t key_code; /*!< passthrough command code */
|
||||||
uint8_t key_state; /*!< 0 for PRESSED, 1 for RELEASED */
|
uint8_t key_state; /*!< 0 for PRESSED, 1 for RELEASED */
|
||||||
} psth_rsp; /*!< passthrough command response */
|
} psth_rsp; /*!< passthrough command response */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ESP_AVRC_CT_METADATA_RSP_EVT
|
||||||
|
*/
|
||||||
|
struct avrc_ct_meta_rsp_param {
|
||||||
|
uint8_t attr_id; /*!< id of metadata attribute */
|
||||||
|
uint8_t *attr_text; /*!< attribute itself */
|
||||||
|
int attr_length; /*!< attribute character length */
|
||||||
|
} meta_rsp; /*!< metadata attributes response */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ESP_AVRC_CT_CHANGE_NOTIFY_EVT
|
||||||
|
*/
|
||||||
|
struct avrc_ct_change_notify_param {
|
||||||
|
uint8_t event_id; /*!< id of AVRC event notification */
|
||||||
|
uint32_t event_parameter; /*!< event notification parameter */
|
||||||
|
} change_ntf; /*!< notifications */
|
||||||
|
|
||||||
} esp_avrc_ct_cb_param_t;
|
} esp_avrc_ct_cb_param_t;
|
||||||
|
|
||||||
|
|
||||||
@ -88,9 +172,9 @@ typedef void (* esp_avrc_ct_cb_t)(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_p
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register application callbacks to AVRCP module; for now only AVRCP Controller
|
* @brief Register application callbacks to AVRCP module; for now only AVRCP Controller
|
||||||
* role is supported. This function should be called after esp_bluedroid_enable()
|
* role is supported. This function should be called after esp_bluedroid_enable()
|
||||||
* completes successfully
|
* completes successfully
|
||||||
*
|
*
|
||||||
* @param[in] callback: AVRCP controller callback function
|
* @param[in] callback: AVRCP controller callback function
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
@ -107,7 +191,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
|
* @brief Initialize the bluetooth AVRCP controller module, This function should be called
|
||||||
* after esp_bluedroid_enable() completes successfully
|
* after esp_bluedroid_enable() completes successfully
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: success
|
* - ESP_OK: success
|
||||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||||
* - ESP_FAIL: others
|
* - ESP_FAIL: others
|
||||||
@ -121,13 +205,45 @@ esp_err_t esp_avrc_ct_init(void);
|
|||||||
* @brief De-initialize AVRCP controller module. This function should be called after
|
* @brief De-initialize AVRCP controller module. This function should be called after
|
||||||
* after esp_bluedroid_enable() completes successfully
|
* after esp_bluedroid_enable() completes successfully
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: success
|
* - ESP_OK: success
|
||||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||||
* - ESP_FAIL: others
|
* - ESP_FAIL: others
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_avrc_ct_deinit(void);
|
esp_err_t esp_avrc_ct_deinit(void);
|
||||||
|
|
||||||
|
/* add description */
|
||||||
|
esp_err_t esp_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uint8_t value_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send register notification command to AVRCP target, This function should be called after
|
||||||
|
* ESP_AVRC_CT_CONNECTION_STATE_EVT is received and AVRCP connection is established
|
||||||
|
*
|
||||||
|
* @param[in] tl : transaction label, 0 to 15, consecutive commands should use different values.
|
||||||
|
* @param[in] event_id : id of events, e.g. ESP_AVRC_RN_PLAY_STATUS_CHANGE, ESP_AVRC_RN_TRACK_CHANGE, etc.
|
||||||
|
* @param[in] event_parameter : special parameters, eg. playback interval for ESP_AVRC_RN_PLAY_POS_CHANGED
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: success
|
||||||
|
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||||
|
* - ESP_FAIL: others
|
||||||
|
*/
|
||||||
|
esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_id, uint32_t event_parameter);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send metadata command to AVRCP target, This function should be called after
|
||||||
|
* ESP_AVRC_CT_CONNECTION_STATE_EVT is received and AVRCP connection is established
|
||||||
|
*
|
||||||
|
* @param[in] tl : transaction label, 0 to 15, consecutive commands should use different values.
|
||||||
|
* @param[in] attr_mask : mask of attributes, e.g. ESP_AVRC_MD_ATTR_ID_TITLE | ESP_AVRC_MD_ATTR_ID_ARTIST.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: success
|
||||||
|
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||||
|
* - ESP_FAIL: others
|
||||||
|
*/
|
||||||
|
esp_err_t esp_avrc_ct_send_metadata_cmd(uint8_t tl, uint8_t attr_mask);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send passthrough command to AVRCP target, This function should be called after
|
* @brief Send passthrough command to AVRCP target, This function should be called after
|
||||||
@ -138,7 +254,7 @@ esp_err_t esp_avrc_ct_deinit(void);
|
|||||||
* @param[in] key_state : passthrough command key state, ESP_AVRC_PT_CMD_STATE_PRESSED or
|
* @param[in] key_state : passthrough command key state, ESP_AVRC_PT_CMD_STATE_PRESSED or
|
||||||
* ESP_AVRC_PT_CMD_STATE_RELEASED
|
* ESP_AVRC_PT_CMD_STATE_RELEASED
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: success
|
* - ESP_OK: success
|
||||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||||
* - ESP_FAIL: others
|
* - ESP_FAIL: others
|
||||||
|
@ -1120,7 +1120,7 @@ bt_status_t btc_av_execute_service(BOOLEAN b_enable)
|
|||||||
* auto-suspend av streaming on AG events(SCO or Call). The suspend shall
|
* auto-suspend av streaming on AG events(SCO or Call). The suspend shall
|
||||||
* be initiated by the app/audioflinger layers */
|
* be initiated by the app/audioflinger layers */
|
||||||
BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_NO_SCO_SSPD)
|
BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_NO_SCO_SSPD)
|
||||||
// | BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR
|
| BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR
|
||||||
| BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL,
|
| BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL,
|
||||||
bte_av_callback);
|
bte_av_callback);
|
||||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos);
|
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos);
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "btc_manage.h"
|
#include "btc_manage.h"
|
||||||
#include "esp_avrc_api.h"
|
#include "esp_avrc_api.h"
|
||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
|
#include "allocator.h"
|
||||||
|
|
||||||
#if BTC_AV_INCLUDED
|
#if BTC_AV_INCLUDED
|
||||||
|
|
||||||
@ -96,6 +97,7 @@ rc_device_t device;
|
|||||||
static void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open);
|
static void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open);
|
||||||
static void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close);
|
static void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close);
|
||||||
static void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp);
|
static void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp);
|
||||||
|
static void handle_rc_metadata_rsp ( tBTA_AV_META_MSG *p_remote_rsp);
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
** Static variables
|
** Static variables
|
||||||
@ -250,6 +252,86 @@ static void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_rc_attributes_rsp ( tAVRC_MSG_VENDOR *vendor_msg)
|
||||||
|
{
|
||||||
|
uint8_t attr_count = vendor_msg->p_vendor_data[4];
|
||||||
|
int attr_index = 5;
|
||||||
|
int attr_length = 0;
|
||||||
|
uint32_t attr_id = 0;
|
||||||
|
|
||||||
|
//Check if there are any attributes
|
||||||
|
if (attr_count < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_avrc_ct_cb_param_t param[attr_count];
|
||||||
|
memset(¶m[0], 0, sizeof(esp_avrc_ct_cb_param_t) * attr_count);
|
||||||
|
|
||||||
|
for (int i = 0; i < attr_count; i++) {
|
||||||
|
attr_length = (int) vendor_msg->p_vendor_data[7 + attr_index] | vendor_msg->p_vendor_data[6 + attr_index] << 8;
|
||||||
|
|
||||||
|
//Received attribute text is not null terminated, so it's useful to know it's length
|
||||||
|
param[i].meta_rsp.attr_length = attr_length;
|
||||||
|
param[i].meta_rsp.attr_text = &vendor_msg->p_vendor_data[8 + attr_index];
|
||||||
|
|
||||||
|
attr_id = vendor_msg->p_vendor_data[3 + attr_index] |
|
||||||
|
vendor_msg->p_vendor_data[2 + attr_index] << 8 | vendor_msg->p_vendor_data[1 + attr_index] << 16 |
|
||||||
|
vendor_msg->p_vendor_data[attr_index] << 24;
|
||||||
|
|
||||||
|
//Convert to mask id
|
||||||
|
param[i].meta_rsp.attr_id = (1 << (attr_id - 1));
|
||||||
|
|
||||||
|
btc_avrc_ct_cb_to_app(ESP_AVRC_CT_METADATA_RSP_EVT, ¶m[i]);
|
||||||
|
|
||||||
|
attr_index += (int) vendor_msg->p_vendor_data[7 + attr_index] + 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_rc_notification_rsp ( tAVRC_MSG_VENDOR *vendor_msg)
|
||||||
|
{
|
||||||
|
esp_avrc_ct_cb_param_t param;
|
||||||
|
|
||||||
|
param.change_ntf.event_id = vendor_msg->p_vendor_data[4];
|
||||||
|
|
||||||
|
param.change_ntf.event_parameter = vendor_msg->p_vendor_data[5] << 24 | vendor_msg->p_vendor_data[6] << 16 |
|
||||||
|
vendor_msg->p_vendor_data[7] << 8 | vendor_msg->p_vendor_data[8];
|
||||||
|
|
||||||
|
btc_avrc_ct_cb_to_app(ESP_AVRC_CT_CHANGE_NOTIFY_EVT, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Function handle_rc_metadata_rsp
|
||||||
|
*
|
||||||
|
* - Argument: tBTA_AV_META_MSG metadata command response
|
||||||
|
*
|
||||||
|
* - Description: Vendor metadata response handler
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
static void handle_rc_metadata_rsp ( tBTA_AV_META_MSG *p_remote_rsp)
|
||||||
|
{
|
||||||
|
#if (AVRC_METADATA_INCLUDED == TRUE)
|
||||||
|
tAVRC_MSG *avrc_msg = p_remote_rsp->p_msg;
|
||||||
|
tAVRC_MSG_VENDOR *vendor_msg = &avrc_msg->vendor;
|
||||||
|
|
||||||
|
//Check what type of metadata was received
|
||||||
|
switch (vendor_msg->hdr.ctype) {
|
||||||
|
case AVRC_RSP_CHANGED:
|
||||||
|
if (vendor_msg->p_vendor_data[0] == AVRC_PDU_REGISTER_NOTIFICATION) {
|
||||||
|
handle_rc_notification_rsp(vendor_msg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVRC_RSP_IMPL_STBL:
|
||||||
|
if (vendor_msg->p_vendor_data[0] == AVRC_PDU_GET_ELEMENT_ATTR) {
|
||||||
|
handle_rc_attributes_rsp(vendor_msg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
LOG_ERROR("%s AVRCP metadata is not enabled", __FUNCTION__);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Function handle_rc_passthrough_rsp
|
* Function handle_rc_passthrough_rsp
|
||||||
*
|
*
|
||||||
@ -326,8 +408,12 @@ void btc_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BTA_AV_META_MSG_EVT: {
|
||||||
|
handle_rc_metadata_rsp(&(p_data->meta_msg));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// below events are not handled for now
|
// below events are not handled for now
|
||||||
case BTA_AV_META_MSG_EVT:
|
|
||||||
case BTA_AV_REMOTE_CMD_EVT:
|
case BTA_AV_REMOTE_CMD_EVT:
|
||||||
default:
|
default:
|
||||||
LOG_DEBUG("Unhandled RC event : 0x%x", event);
|
LOG_DEBUG("Unhandled RC event : 0x%x", event);
|
||||||
@ -390,13 +476,124 @@ static void btc_avrc_ct_deinit(void)
|
|||||||
LOG_INFO("## %s ## completed", __FUNCTION__);
|
LOG_INFO("## %s ## completed", __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bt_status_t btc_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uint8_t value_id)
|
||||||
|
{
|
||||||
|
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
#if (AVRC_METADATA_INCLUDED == TRUE)
|
||||||
|
CHECK_ESP_RC_CONNECTED;
|
||||||
|
|
||||||
|
tAVRC_COMMAND avrc_cmd = {0};
|
||||||
|
BT_HDR *p_msg = NULL;
|
||||||
|
tAVRC_APP_SETTING values = {0};
|
||||||
|
|
||||||
|
values.attr_id = attr_id;
|
||||||
|
values.attr_val = value_id;
|
||||||
|
|
||||||
|
avrc_cmd.set_app_val.opcode = AVRC_OP_VENDOR;
|
||||||
|
avrc_cmd.set_app_val.status = AVRC_STS_NO_ERROR;
|
||||||
|
avrc_cmd.set_app_val.num_val = 1;
|
||||||
|
avrc_cmd.set_app_val.p_vals = &values;
|
||||||
|
avrc_cmd.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE;
|
||||||
|
|
||||||
|
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||||
|
if (status == AVRC_STS_NO_ERROR) {
|
||||||
|
if (btc_rc_vb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||||
|
BTA_AvMetaCmd(btc_rc_vb.rc_handle, tl, BTA_AV_CMD_CTRL, p_msg);
|
||||||
|
status = BT_STATUS_SUCCESS;
|
||||||
|
} else {
|
||||||
|
status = BT_STATUS_FAIL;
|
||||||
|
LOG_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
LOG_DEBUG("%s: feature not enabled", __FUNCTION__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bt_status_t btc_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_id, uint32_t event_parameter)
|
||||||
|
{
|
||||||
|
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
#if (AVRC_METADATA_INCLUDED == TRUE)
|
||||||
|
CHECK_ESP_RC_CONNECTED;
|
||||||
|
|
||||||
|
tAVRC_COMMAND avrc_cmd = {0};
|
||||||
|
BT_HDR *p_msg = NULL;
|
||||||
|
|
||||||
|
avrc_cmd.reg_notif.opcode = AVRC_OP_VENDOR;
|
||||||
|
avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
|
||||||
|
avrc_cmd.reg_notif.event_id = event_id;
|
||||||
|
avrc_cmd.reg_notif.param = event_parameter;
|
||||||
|
avrc_cmd.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
|
||||||
|
|
||||||
|
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||||
|
if (status == AVRC_STS_NO_ERROR) {
|
||||||
|
if (btc_rc_vb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||||
|
BTA_AvMetaCmd(btc_rc_vb.rc_handle, tl, AVRC_CMD_NOTIF, p_msg);
|
||||||
|
status = BT_STATUS_SUCCESS;
|
||||||
|
} else {
|
||||||
|
status = BT_STATUS_FAIL;
|
||||||
|
LOG_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
LOG_DEBUG("%s: feature not enabled", __FUNCTION__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bt_status_t btc_avrc_ct_send_metadata_cmd (uint8_t tl, uint8_t attr_mask)
|
||||||
|
{
|
||||||
|
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
#if (AVRC_METADATA_INCLUDED == TRUE)
|
||||||
|
CHECK_ESP_RC_CONNECTED;
|
||||||
|
uint32_t index = 0;
|
||||||
|
|
||||||
|
tAVRC_COMMAND avrc_cmd = {0};
|
||||||
|
BT_HDR *p_msg = NULL;
|
||||||
|
|
||||||
|
avrc_cmd.get_elem_attrs.opcode = AVRC_OP_VENDOR;
|
||||||
|
avrc_cmd.get_elem_attrs.status = AVRC_STS_NO_ERROR;
|
||||||
|
avrc_cmd.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
|
||||||
|
|
||||||
|
for (int count = 0; count < AVRC_MAX_ELEM_ATTR_SIZE; count++) {
|
||||||
|
if ((attr_mask & (1 << count)) > 0) {
|
||||||
|
avrc_cmd.get_elem_attrs.attrs[index] = count + 1;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
avrc_cmd.get_elem_attrs.num_attr = index;
|
||||||
|
|
||||||
|
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||||
|
if (status == AVRC_STS_NO_ERROR) {
|
||||||
|
if (btc_rc_vb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||||
|
BTA_AvMetaCmd(btc_rc_vb.rc_handle, tl, AVRC_CMD_STATUS, p_msg);
|
||||||
|
status = BT_STATUS_SUCCESS;
|
||||||
|
} else {
|
||||||
|
status = BT_STATUS_FAIL;
|
||||||
|
LOG_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
LOG_DEBUG("%s: feature not enabled", __FUNCTION__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static bt_status_t btc_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state)
|
static bt_status_t btc_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state)
|
||||||
{
|
{
|
||||||
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
|
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
|
||||||
if (tl >= 16 ||
|
|
||||||
key_state > ESP_AVRC_PT_CMD_STATE_RELEASED) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
#if (AVRC_CTLR_INCLUDED == TRUE)
|
#if (AVRC_CTLR_INCLUDED == TRUE)
|
||||||
CHECK_ESP_RC_CONNECTED;
|
CHECK_ESP_RC_CONNECTED;
|
||||||
LOG_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
|
LOG_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__,
|
||||||
@ -436,6 +633,18 @@ void btc_avrc_call_handler(btc_msg_t *msg)
|
|||||||
// todo: callback to application
|
// todo: callback to application
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case BTC_AVRC_STATUS_API_SND_META_EVT: {
|
||||||
|
btc_avrc_ct_send_metadata_cmd(arg->md_cmd.tl, arg->md_cmd.attr_mask);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BTC_AVRC_NOTIFY_API_SND_REG_NOTIFY_EVT: {
|
||||||
|
btc_avrc_ct_send_register_notification_cmd(arg->rn_cmd.tl, arg->rn_cmd.event_id, arg->rn_cmd.event_parameter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BTC_AVRC_CTRL_API_SET_PLAYER_SETTING_EVT: {
|
||||||
|
btc_avrc_ct_send_set_player_value_cmd(arg->ps_cmd.tl, arg->ps_cmd.attr_id, arg->ps_cmd.value_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LOG_WARN("%s : unhandled event: %d\n", __FUNCTION__, msg->act);
|
LOG_WARN("%s : unhandled event: %d\n", __FUNCTION__, msg->act);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,11 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
BTC_AVRC_CTRL_API_INIT_EVT = 0,
|
BTC_AVRC_CTRL_API_INIT_EVT = 0,
|
||||||
BTC_AVRC_CTRL_API_DEINIT_EVT,
|
BTC_AVRC_CTRL_API_DEINIT_EVT,
|
||||||
BTC_AVRC_CTRL_API_SND_PTCMD_EVT
|
BTC_AVRC_CTRL_API_SND_PTCMD_EVT,
|
||||||
|
BTC_AVRC_STATUS_API_SND_META_EVT,
|
||||||
|
BTC_AVRC_STATUS_API_SND_PLAY_STATUS_EVT,
|
||||||
|
BTC_AVRC_NOTIFY_API_SND_REG_NOTIFY_EVT,
|
||||||
|
BTC_AVRC_CTRL_API_SET_PLAYER_SETTING_EVT
|
||||||
} btc_avrc_act_t;
|
} btc_avrc_act_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -48,14 +52,29 @@ typedef struct {
|
|||||||
uint8_t key_state;
|
uint8_t key_state;
|
||||||
} pt_cmd_t;
|
} pt_cmd_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t tl;
|
||||||
|
uint8_t attr_mask;
|
||||||
|
} md_cmd_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t tl;
|
||||||
|
uint8_t event_id;
|
||||||
|
uint32_t event_parameter;
|
||||||
|
} rn_cmd_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t tl;
|
||||||
|
uint8_t attr_id;
|
||||||
|
uint8_t value_id;
|
||||||
|
} ps_cmd_t;
|
||||||
|
|
||||||
/* btc_avrc_args_t */
|
/* btc_avrc_args_t */
|
||||||
typedef union {
|
typedef union {
|
||||||
// BTC_AVRC_CTRL_API_SND_PT_CMD_EVT
|
pt_cmd_t pt_cmd;
|
||||||
struct {
|
md_cmd_t md_cmd;
|
||||||
uint8_t tl;
|
rn_cmd_t rn_cmd;
|
||||||
uint8_t key_code;
|
ps_cmd_t ps_cmd;
|
||||||
uint8_t key_state;
|
|
||||||
} pt_cmd;
|
|
||||||
} btc_avrc_args_t;
|
} btc_avrc_args_t;
|
||||||
|
|
||||||
/** BT-RC Controller callback structure. */
|
/** BT-RC Controller callback structure. */
|
||||||
|
@ -98,7 +98,7 @@ static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HD
|
|||||||
** Otherwise, the error code.
|
** Otherwise, the error code.
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
static tAVRC_STS avrc_bld_vol_change_notfn(BT_HDR *p_pkt)
|
static tAVRC_STS avrc_bld_register_change_notfn(UINT8 event_id, UINT32 event_parameter, BT_HDR *p_pkt)
|
||||||
{
|
{
|
||||||
UINT8 *p_data, *p_start;
|
UINT8 *p_data, *p_start;
|
||||||
|
|
||||||
@ -109,8 +109,8 @@ static tAVRC_STS avrc_bld_vol_change_notfn(BT_HDR *p_pkt)
|
|||||||
p_data = p_start + 2; /* pdu + rsvd */
|
p_data = p_start + 2; /* pdu + rsvd */
|
||||||
/* add fixed length 5 -*/
|
/* add fixed length 5 -*/
|
||||||
UINT16_TO_BE_STREAM(p_data, 5);
|
UINT16_TO_BE_STREAM(p_data, 5);
|
||||||
UINT8_TO_BE_STREAM(p_data, AVRC_EVT_VOLUME_CHANGE);
|
UINT8_TO_BE_STREAM(p_data, event_id);
|
||||||
UINT32_TO_BE_STREAM(p_data, 0);
|
UINT32_TO_BE_STREAM(p_data, event_parameter);
|
||||||
p_pkt->len = (p_data - p_start);
|
p_pkt->len = (p_data - p_start);
|
||||||
return AVRC_STS_NO_ERROR;
|
return AVRC_STS_NO_ERROR;
|
||||||
}
|
}
|
||||||
@ -132,8 +132,7 @@ static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
|
|||||||
AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode);
|
AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode);
|
||||||
|
|
||||||
UINT16 offset = 0;
|
UINT16 offset = 0;
|
||||||
switch (opcode)
|
switch (opcode) {
|
||||||
{
|
|
||||||
case AVRC_OP_PASS_THRU:
|
case AVRC_OP_PASS_THRU:
|
||||||
offset = AVRC_MSG_PASS_THRU_OFFSET;
|
offset = AVRC_MSG_PASS_THRU_OFFSET;
|
||||||
break;
|
break;
|
||||||
@ -148,7 +147,7 @@ static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
|
|||||||
if (p_pkt) {
|
if (p_pkt) {
|
||||||
UINT8 *p_data, *p_start;
|
UINT8 *p_data, *p_start;
|
||||||
|
|
||||||
p_pkt->layer_specific = AVCT_DATA_CTRL;
|
p_pkt->layer_specific = AVCT_DATA_CTRL;
|
||||||
p_pkt->event = opcode;
|
p_pkt->event = opcode;
|
||||||
p_pkt->offset = offset;
|
p_pkt->offset = offset;
|
||||||
p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
|
p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
|
||||||
@ -175,6 +174,69 @@ static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
|
|||||||
return p_pkt;
|
return p_pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function avrc_bld_set_player_value_cmd
|
||||||
|
**
|
||||||
|
** Description This function builds the Set Player Application Value command.
|
||||||
|
**
|
||||||
|
** Returns AVRC_STS_NO_ERROR, if the command is built successfully
|
||||||
|
** Otherwise, the error code.
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
static tAVRC_STS avrc_bld_set_player_value_cmd(tAVRC_SET_APP_VALUE_CMD *p_cmd, BT_HDR *p_pkt)
|
||||||
|
{
|
||||||
|
UINT8 *p_data, *p_start;
|
||||||
|
|
||||||
|
/* get the existing length, if any, and also the num attributes */
|
||||||
|
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
|
||||||
|
p_data = p_start + 2; /* pdu + rsvd */
|
||||||
|
/* add length */
|
||||||
|
UINT16_TO_BE_STREAM(p_data, 3);
|
||||||
|
/* Number of attributes */
|
||||||
|
UINT8_TO_BE_STREAM(p_data, 1);
|
||||||
|
UINT8_TO_BE_STREAM(p_data, p_cmd->p_vals->attr_id);
|
||||||
|
UINT8_TO_BE_STREAM(p_data, p_cmd->p_vals->attr_val);
|
||||||
|
|
||||||
|
p_pkt->len = (p_data - p_start);
|
||||||
|
return AVRC_STS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function avrc_bld_get_element_attr_cmd
|
||||||
|
**
|
||||||
|
** Description This function builds the Get Element Attribute command.
|
||||||
|
**
|
||||||
|
** Returns AVRC_STS_NO_ERROR, if the command is built successfully
|
||||||
|
** Otherwise, the error code.
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
static tAVRC_STS avrc_bld_get_element_attr_cmd (tAVRC_GET_ELEM_ATTRS_CMD *p_cmd, BT_HDR *p_pkt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
UINT8 *p_data, *p_start;
|
||||||
|
|
||||||
|
AVRC_TRACE_API("avrc_bld_get_element_attr_cmd num_attr: %d", p_cmd->num_attr);
|
||||||
|
/* get the existing length, if any, and also the num attributes */
|
||||||
|
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
|
||||||
|
p_data = p_start + 2; /* pdu + rsvd */
|
||||||
|
/* add length */
|
||||||
|
UINT16_TO_BE_STREAM(p_data, 8 + 1 /* id + attr count */ + p_cmd->num_attr * sizeof(UINT32));
|
||||||
|
/* Identifier 0x0 (PLAYING) */
|
||||||
|
UINT64_TO_BE_STREAM(p_data, (UINT64)(0));
|
||||||
|
/* Attribute count */
|
||||||
|
UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr);
|
||||||
|
|
||||||
|
for (i = 0; i < p_cmd->num_attr; i++) {
|
||||||
|
AVRC_TRACE_API("avrc_bld_get_element_attr_cmd attr_id: %d", p_cmd->attrs[i]);
|
||||||
|
UINT32_TO_BE_STREAM(p_data, p_cmd->attrs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_pkt->len = (p_data - p_start);
|
||||||
|
return AVRC_STS_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
** Function AVRC_BldCommand
|
** Function AVRC_BldCommand
|
||||||
@ -223,14 +285,17 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
|
case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
|
||||||
#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
|
status = avrc_bld_set_player_value_cmd(&p_cmd->set_app_val, p_pkt);
|
||||||
if (AVRC_EVT_VOLUME_CHANGE == p_cmd->reg_notif.event_id) {
|
|
||||||
status = avrc_bld_vol_change_notfn(p_pkt);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
|
||||||
|
status = avrc_bld_get_element_attr_cmd(&p_cmd->get_elem_attrs, p_pkt);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
|
||||||
|
status = avrc_bld_register_change_notfn(p_cmd->reg_notif.event_id, p_cmd->reg_notif.param, p_pkt);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alloc && (status != AVRC_STS_NO_ERROR) ) {
|
if (alloc && (status != AVRC_STS_NO_ERROR) ) {
|
||||||
|
@ -276,6 +276,7 @@ typedef struct {
|
|||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
** Macros to get and put bytes to and from a stream (Big Endian format)
|
** Macros to get and put bytes to and from a stream (Big Endian format)
|
||||||
*/
|
*/
|
||||||
|
#define UINT64_TO_BE_STREAM(p, u64) {*(p)++ = (UINT8)((u64) >> 56); *(p)++ = (UINT8)((u64) >> 48); *(p)++ = (UINT8)((u64) >> 40); *(p)++ = (UINT8)((u64) >> 32); *(p)++ = (UINT8)((u64) >> 24); *(p)++ = (UINT8)((u64) >> 16); *(p)++ = (UINT8)((u64) >> 8); *(p)++ = (UINT8)(u64); }
|
||||||
#define UINT32_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 24); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
|
#define UINT32_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 24); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
|
||||||
#define UINT24_TO_BE_STREAM(p, u24) {*(p)++ = (UINT8)((u24) >> 16); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)(u24);}
|
#define UINT24_TO_BE_STREAM(p, u24) {*(p)++ = (UINT8)((u24) >> 16); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)(u24);}
|
||||||
#define UINT16_TO_BE_STREAM(p, u16) {*(p)++ = (UINT8)((u16) >> 8); *(p)++ = (UINT8)(u16);}
|
#define UINT16_TO_BE_STREAM(p, u16) {*(p)++ = (UINT8)((u16) >> 8); *(p)++ = (UINT8)(u16);}
|
||||||
|
@ -31,7 +31,6 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param);
|
|||||||
/* avrc event handler */
|
/* avrc event handler */
|
||||||
static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param);
|
static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param);
|
||||||
|
|
||||||
|
|
||||||
static uint32_t m_pkt_cnt = 0;
|
static uint32_t m_pkt_cnt = 0;
|
||||||
static esp_a2d_audio_state_t m_audio_state = ESP_A2D_AUDIO_STATE_STOPPED;
|
static esp_a2d_audio_state_t m_audio_state = ESP_A2D_AUDIO_STATE_STOPPED;
|
||||||
|
|
||||||
@ -58,11 +57,24 @@ void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bt_app_alloc_meta_buffer(esp_avrc_ct_cb_param_t *param)
|
||||||
|
{
|
||||||
|
esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(param);
|
||||||
|
uint8_t *attr_text = (uint8_t *) malloc (rc->meta_rsp.attr_length + 1);
|
||||||
|
memcpy(attr_text, rc->meta_rsp.attr_text, rc->meta_rsp.attr_length);
|
||||||
|
attr_text[rc->meta_rsp.attr_length] = 0;
|
||||||
|
|
||||||
|
rc->meta_rsp.attr_text = attr_text;
|
||||||
|
}
|
||||||
|
|
||||||
void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)
|
void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)
|
||||||
{
|
{
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
case ESP_AVRC_CT_METADATA_RSP_EVT:
|
||||||
|
bt_app_alloc_meta_buffer(param);
|
||||||
case ESP_AVRC_CT_CONNECTION_STATE_EVT:
|
case ESP_AVRC_CT_CONNECTION_STATE_EVT:
|
||||||
case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: {
|
case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT:
|
||||||
|
case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: {
|
||||||
bt_app_work_dispatch(bt_av_hdl_avrc_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
|
bt_app_work_dispatch(bt_av_hdl_avrc_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -106,6 +118,22 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bt_av_new_track()
|
||||||
|
{
|
||||||
|
//Register notifications and request metadata
|
||||||
|
esp_avrc_ct_send_metadata_cmd(0, ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_ARTIST | ESP_AVRC_MD_ATTR_ALBUM | ESP_AVRC_MD_ATTR_GENRE);
|
||||||
|
esp_avrc_ct_send_register_notification_cmd(1, ESP_AVRC_RN_TRACK_CHANGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_av_notify_evt_handler(uint8_t event_id, uint32_t event_parameter)
|
||||||
|
{
|
||||||
|
switch (event_id) {
|
||||||
|
case ESP_AVRC_RN_TRACK_CHANGE:
|
||||||
|
bt_av_new_track();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param)
|
static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param)
|
||||||
{
|
{
|
||||||
ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
|
ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
|
||||||
@ -114,13 +142,27 @@ static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param)
|
|||||||
case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
|
case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
|
||||||
uint8_t *bda = rc->conn_stat.remote_bda;
|
uint8_t *bda = rc->conn_stat.remote_bda;
|
||||||
ESP_LOGI(BT_AV_TAG, "avrc conn_state evt: state %d, feature 0x%x, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
ESP_LOGI(BT_AV_TAG, "avrc conn_state evt: state %d, feature 0x%x, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||||
rc->conn_stat.connected, rc->conn_stat.feat_mask, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
rc->conn_stat.connected, rc->conn_stat.feat_mask, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||||
|
|
||||||
|
if (rc->conn_stat.connected) {
|
||||||
|
bt_av_new_track();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: {
|
case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: {
|
||||||
ESP_LOGI(BT_AV_TAG, "avrc passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state);
|
ESP_LOGI(BT_AV_TAG, "avrc passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ESP_AVRC_CT_METADATA_RSP_EVT: {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "avrc metadata rsp: attribute id 0x%x, %s", rc->meta_rsp.attr_id, rc->meta_rsp.attr_text);
|
||||||
|
free(rc->meta_rsp.attr_text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "avrc event notification: %d, param: %d", rc->change_ntf.event_id, rc->change_ntf.event_parameter);
|
||||||
|
bt_av_notify_evt_handler(rc->change_ntf.event_id, rc->change_ntf.event_parameter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
|
ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user