mirror of
https://github.com/espressif/esp-idf.git
synced 2024-09-20 00:36:01 -04:00
Merge branch 'feature/btdm_AVRCP_TG' into 'master'
component/bt: implement AVRCP Target APIs See merge request idf/esp-idf!3899
This commit is contained in:
commit
603d293365
@ -123,6 +123,7 @@ if(CONFIG_BT_ENABLED)
|
||||
"bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c"
|
||||
"bluedroid/btc/profile/std/a2dp/btc_av.c"
|
||||
"bluedroid/btc/profile/std/avrc/btc_avrc.c"
|
||||
"bluedroid/btc/profile/std/avrc/bta_avrc_co.c"
|
||||
"bluedroid/btc/profile/std/gap/btc_gap_ble.c"
|
||||
"bluedroid/btc/profile/std/gap/btc_gap_bt.c"
|
||||
"bluedroid/btc/profile/std/gatt/btc_gatt_common.c"
|
||||
|
@ -32,7 +32,7 @@ esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
btc_profile_cb_set(BTC_PID_AVRC, callback);
|
||||
btc_profile_cb_set(BTC_PID_AVRC_CT, callback);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -45,8 +45,8 @@ esp_err_t esp_avrc_ct_init(void)
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC;
|
||||
msg.act = BTC_AVRC_CTRL_API_INIT_EVT;
|
||||
msg.pid = BTC_PID_AVRC_CT;
|
||||
msg.act = BTC_AVRC_CT_API_INIT_EVT;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
|
||||
@ -62,8 +62,8 @@ esp_err_t esp_avrc_ct_deinit(void)
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC;
|
||||
msg.act = BTC_AVRC_CTRL_API_DEINIT_EVT;
|
||||
msg.pid = BTC_PID_AVRC_CT;
|
||||
msg.act = BTC_AVRC_CT_API_DEINIT_EVT;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
|
||||
@ -82,8 +82,8 @@ esp_err_t esp_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uin
|
||||
|
||||
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;
|
||||
msg.pid = BTC_PID_AVRC_CT;
|
||||
msg.act = BTC_AVRC_CTRL_API_SND_SET_PLAYER_SETTING_EVT;
|
||||
|
||||
btc_avrc_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_avrc_args_t));
|
||||
@ -97,6 +97,30 @@ esp_err_t esp_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uin
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_ct_send_get_rn_capabilities_cmd(uint8_t tl)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tl >= 16) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC_CT;
|
||||
msg.act = BTC_AVRC_STATUS_API_SND_GET_RN_CAPS_EVT;
|
||||
|
||||
btc_avrc_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_avrc_args_t));
|
||||
|
||||
arg.get_caps_cmd.tl = tl;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@ -108,9 +132,13 @@ esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_i
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (!btc_avrc_ct_rn_evt_supported(event_id)) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC;
|
||||
msg.pid = BTC_PID_AVRC_CT;
|
||||
msg.act = BTC_AVRC_NOTIFY_API_SND_REG_NOTIFY_EVT;
|
||||
|
||||
btc_avrc_args_t arg;
|
||||
@ -137,7 +165,7 @@ esp_err_t esp_avrc_ct_send_metadata_cmd(uint8_t tl, uint8_t attr_mask)
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC;
|
||||
msg.pid = BTC_PID_AVRC_CT;
|
||||
msg.act = BTC_AVRC_STATUS_API_SND_META_EVT;
|
||||
|
||||
btc_avrc_args_t arg;
|
||||
@ -163,7 +191,7 @@ esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC;
|
||||
msg.pid = BTC_PID_AVRC_CT;
|
||||
msg.act = BTC_AVRC_CTRL_API_SND_PTCMD_EVT;
|
||||
|
||||
btc_avrc_args_t arg;
|
||||
@ -178,4 +206,246 @@ esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/** following is the API of AVRCP target role **/
|
||||
/*********************************************************************************************/
|
||||
|
||||
esp_err_t esp_avrc_tg_register_callback(esp_avrc_tg_cb_t callback)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (callback == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
btc_profile_cb_set(BTC_PID_AVRC_TG, callback);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_tg_init(void)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC_TG;
|
||||
msg.act = BTC_AVRC_TG_API_INIT_EVT;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_tg_deinit(void)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC_TG;
|
||||
msg.act = BTC_AVRC_TG_API_DEINIT_EVT;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
bool esp_avrc_psth_bit_mask_operation(esp_avrc_bit_mask_op_t op, esp_avrc_psth_bit_mask_t *psth,
|
||||
esp_avrc_pt_cmd_t cmd)
|
||||
{
|
||||
if (!psth ||
|
||||
cmd > ESP_AVRC_PT_CMD_VENDOR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t *p = &psth->bits[(uint8_t)cmd >> 4];
|
||||
uint16_t mask = (uint16_t)1 << ((uint8_t)cmd & 0x0F);
|
||||
switch (op) {
|
||||
case ESP_AVRC_BIT_MASK_OP_SET:
|
||||
*p |= mask;
|
||||
break;
|
||||
case ESP_AVRC_BIT_MASK_OP_CLEAR:
|
||||
*p &= ~mask;
|
||||
break;
|
||||
case ESP_AVRC_BIT_MASK_OP_TEST:
|
||||
return (*p & mask);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_tg_get_psth_cmd_filter(esp_avrc_psth_filter_t filter, esp_avrc_psth_bit_mask_t *cmd_set)
|
||||
{
|
||||
if ((esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) ||
|
||||
(! btc_avrc_tg_init_p())) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (filter >= ESP_AVRC_PSTH_FILTER_SUPPORT_MAX ||
|
||||
cmd_set == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (filter == ESP_AVRC_PSTH_FILTER_ALLOWED_CMD) {
|
||||
const uint16_t *allowed_cmd_set = btc_avrc_tg_get_allowed_command();
|
||||
memcpy(cmd_set, allowed_cmd_set, sizeof(esp_avrc_psth_bit_mask_t));
|
||||
} else if (filter == ESP_AVRC_PSTH_FILTER_SUPPORTED_CMD) {
|
||||
const uint16_t *supported_cmd_set = btc_avrc_tg_get_supported_command();
|
||||
memcpy(cmd_set, supported_cmd_set, sizeof(esp_avrc_psth_bit_mask_t));
|
||||
} else {
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_tg_set_psth_cmd_filter(esp_avrc_psth_filter_t filter, const esp_avrc_psth_bit_mask_t *cmd_set)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (filter >= ESP_AVRC_PSTH_FILTER_SUPPORT_MAX ||
|
||||
cmd_set == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (filter == ESP_AVRC_PSTH_FILTER_ALLOWED_CMD) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (filter == ESP_AVRC_PSTH_FILTER_SUPPORTED_CMD) {
|
||||
bool allowed = btc_avrc_tg_check_supported_command(cmd_set->bits);
|
||||
if (!allowed) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC_TG;
|
||||
msg.act = BTC_AVRC_TG_API_SET_PSTH_SUPPORTED_CMD_EVT;
|
||||
|
||||
btc_avrc_tg_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_avrc_tg_args_t));
|
||||
arg.set_psth_cmd = (uint16_t *)cmd_set->bits;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_tg_args_t),
|
||||
btc_avrc_tg_arg_deep_copy);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
} else {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_tg_get_rn_evt_cap(esp_avrc_rn_evt_cap_t cap, esp_avrc_rn_evt_cap_mask_t *evt_set)
|
||||
{
|
||||
if ((esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) ||
|
||||
(! btc_avrc_tg_init_p())) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (cap >= ESP_AVRC_RN_CAP_MAX ||
|
||||
evt_set == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (cap == ESP_AVRC_RN_CAP_ALLOWED_EVT) {
|
||||
evt_set->bits = btc_avrc_tg_get_rn_allowed_evt();
|
||||
} else if (cap == ESP_AVRC_RN_CAP_SUPPORTED_EVT) {
|
||||
evt_set->bits = btc_avrc_tg_get_rn_supported_evt();
|
||||
} else {
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_tg_set_rn_evt_cap(const esp_avrc_rn_evt_cap_mask_t *evt_set)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (evt_set == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
bool allowed = btc_avrc_tg_check_rn_supported_evt(evt_set->bits);
|
||||
if (!allowed) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC_TG;
|
||||
msg.act = BTC_AVRC_TG_API_SET_RN_SUPPORTED_EVT;
|
||||
|
||||
btc_avrc_tg_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_avrc_tg_args_t));
|
||||
|
||||
arg.set_rn_evt = evt_set->bits;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_tg_args_t), NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
bool esp_avrc_rn_evt_bit_mask_operation(esp_avrc_bit_mask_op_t op, esp_avrc_rn_evt_cap_mask_t *events,
|
||||
esp_avrc_rn_event_ids_t event_id)
|
||||
{
|
||||
if (!events ||
|
||||
event_id >= ESP_AVRC_RN_MAX_EVT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t *p = &events->bits;
|
||||
uint16_t mask = (uint16_t)1 << ((uint8_t)event_id & 0x0F);
|
||||
switch (op) {
|
||||
case ESP_AVRC_BIT_MASK_OP_SET:
|
||||
*p |= mask;
|
||||
break;
|
||||
case ESP_AVRC_BIT_MASK_OP_CLEAR:
|
||||
*p &= ~mask;
|
||||
break;
|
||||
case ESP_AVRC_BIT_MASK_OP_TEST:
|
||||
return (*p & mask);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_tg_send_rn_rsp(esp_avrc_rn_event_ids_t event_id, esp_avrc_rn_rsp_t rsp,
|
||||
esp_avrc_rn_param_t *param)
|
||||
{
|
||||
if ((esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) ||
|
||||
(! btc_avrc_tg_connected_p())) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if ( ! btc_avrc_tg_rn_evt_supported((uint8_t)event_id)) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC_TG;
|
||||
msg.act = BTC_AVRC_TG_API_SEND_RN_RSP_EVT;
|
||||
|
||||
btc_avrc_tg_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_avrc_tg_args_t));
|
||||
|
||||
arg.rn_rsp.event_id = event_id;
|
||||
arg.rn_rsp.rsp = rsp;
|
||||
memcpy(&arg.rn_rsp.param, param, sizeof(esp_avrc_rn_param_t));
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_tg_args_t), NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
|
||||
}
|
||||
|
||||
#endif /* #if BTC_AV_INCLUDED */
|
||||
|
@ -34,17 +34,97 @@ typedef enum {
|
||||
ESP_AVRC_FEAT_ADV_CTRL = 0x0200, /*!< remote control advanced control commmand/response */
|
||||
} esp_avrc_features_t;
|
||||
|
||||
/// AVRC supported features flag retrieved in SDP record
|
||||
typedef enum {
|
||||
ESP_AVRC_FEAT_FLAG_CAT1 = 0x0001, /*!< category 1 */
|
||||
ESP_AVRC_FEAT_FLAG_CAT2 = 0x0002, /*!< category 2 */
|
||||
ESP_AVRC_FEAT_FLAG_CAT3 = 0x0004, /*!< category 3 */
|
||||
ESP_AVRC_FEAT_FLAG_CAT4 = 0x0008, /*!< category 4 */
|
||||
ESP_AVRC_FEAT_FLAG_BROWSING = 0x0040, /*!< browsing */
|
||||
ESP_AVRC_FEAT_FLAG_COVER_ART_GET_IMAGE_PROP = 0x0080, /*!< Cover Art GetImageProperties */
|
||||
ESP_AVRC_FEAT_FLAG_COVER_ART_GET_IMAGE = 0x0100, /*!< Cover Art GetImage */
|
||||
ESP_AVRC_FEAT_FLAG_COVER_ART_GET_LINKED_THUMBNAIL = 0x0200, /*!< Cover Art GetLinkedThumbnail */
|
||||
} esp_avrc_feature_flag_t;
|
||||
|
||||
/// AVRC passthrough command code
|
||||
typedef enum {
|
||||
ESP_AVRC_PT_CMD_PLAY = 0x44, /*!< play */
|
||||
ESP_AVRC_PT_CMD_STOP = 0x45, /*!< stop */
|
||||
ESP_AVRC_PT_CMD_PAUSE = 0x46, /*!< pause */
|
||||
ESP_AVRC_PT_CMD_FORWARD = 0x4B, /*!< forward */
|
||||
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_SELECT = 0x00, /*!< select */
|
||||
ESP_AVRC_PT_CMD_UP = 0x01, /*!< up */
|
||||
ESP_AVRC_PT_CMD_DOWN = 0x02, /*!< down */
|
||||
ESP_AVRC_PT_CMD_LEFT = 0x03, /*!< left */
|
||||
ESP_AVRC_PT_CMD_RIGHT = 0x04, /*!< right */
|
||||
ESP_AVRC_PT_CMD_RIGHT_UP = 0x05, /*!< right-up */
|
||||
ESP_AVRC_PT_CMD_RIGHT_DOWN = 0x06, /*!< right-down */
|
||||
ESP_AVRC_PT_CMD_LEFT_UP = 0x07, /*!< left-up */
|
||||
ESP_AVRC_PT_CMD_LEFT_DOWN = 0x08, /*!< left-down */
|
||||
ESP_AVRC_PT_CMD_ROOT_MENU = 0x09, /*!< root menu */
|
||||
ESP_AVRC_PT_CMD_SETUP_MENU = 0x0A, /*!< setup menu */
|
||||
ESP_AVRC_PT_CMD_CONT_MENU = 0x0B, /*!< contents menu */
|
||||
ESP_AVRC_PT_CMD_FAV_MENU = 0x0C, /*!< favorite menu */
|
||||
ESP_AVRC_PT_CMD_EXIT = 0x0D, /*!< exit */
|
||||
ESP_AVRC_PT_CMD_0 = 0x20, /*!< 0 */
|
||||
ESP_AVRC_PT_CMD_1 = 0x21, /*!< 1 */
|
||||
ESP_AVRC_PT_CMD_2 = 0x22, /*!< 2 */
|
||||
ESP_AVRC_PT_CMD_3 = 0x23, /*!< 3 */
|
||||
ESP_AVRC_PT_CMD_4 = 0x24, /*!< 4 */
|
||||
ESP_AVRC_PT_CMD_5 = 0x25, /*!< 5 */
|
||||
ESP_AVRC_PT_CMD_6 = 0x26, /*!< 6 */
|
||||
ESP_AVRC_PT_CMD_7 = 0x27, /*!< 7 */
|
||||
ESP_AVRC_PT_CMD_8 = 0x28, /*!< 8 */
|
||||
ESP_AVRC_PT_CMD_9 = 0x29, /*!< 9 */
|
||||
ESP_AVRC_PT_CMD_DOT = 0x2A, /*!< dot */
|
||||
ESP_AVRC_PT_CMD_ENTER = 0x2B, /*!< enter */
|
||||
ESP_AVRC_PT_CMD_CLEAR = 0x2C, /*!< clear */
|
||||
ESP_AVRC_PT_CMD_CHAN_UP = 0x30, /*!< channel up */
|
||||
ESP_AVRC_PT_CMD_CHAN_DOWN = 0x31, /*!< channel down */
|
||||
ESP_AVRC_PT_CMD_PREV_CHAN = 0x32, /*!< previous channel */
|
||||
ESP_AVRC_PT_CMD_SOUND_SEL = 0x33, /*!< sound select */
|
||||
ESP_AVRC_PT_CMD_INPUT_SEL = 0x34, /*!< input select */
|
||||
ESP_AVRC_PT_CMD_DISP_INFO = 0x35, /*!< display information */
|
||||
ESP_AVRC_PT_CMD_HELP = 0x36, /*!< help */
|
||||
ESP_AVRC_PT_CMD_PAGE_UP = 0x37, /*!< page up */
|
||||
ESP_AVRC_PT_CMD_PAGE_DOWN = 0x38, /*!< page down */
|
||||
ESP_AVRC_PT_CMD_POWER = 0x40, /*!< power */
|
||||
ESP_AVRC_PT_CMD_VOL_UP = 0x41, /*!< volume up */
|
||||
ESP_AVRC_PT_CMD_VOL_DOWN = 0x42, /*!< volume down */
|
||||
ESP_AVRC_PT_CMD_MUTE = 0x43, /*!< mute */
|
||||
ESP_AVRC_PT_CMD_PLAY = 0x44, /*!< play */
|
||||
ESP_AVRC_PT_CMD_STOP = 0x45, /*!< stop */
|
||||
ESP_AVRC_PT_CMD_PAUSE = 0x46, /*!< pause */
|
||||
ESP_AVRC_PT_CMD_RECORD = 0x47, /*!< record */
|
||||
ESP_AVRC_PT_CMD_REWIND = 0x48, /*!< rewind */
|
||||
ESP_AVRC_PT_CMD_FAST_FORWARD = 0x49, /*!< fast forward */
|
||||
ESP_AVRC_PT_CMD_EJECT = 0x4A, /*!< eject */
|
||||
ESP_AVRC_PT_CMD_FORWARD = 0x4B, /*!< forward */
|
||||
ESP_AVRC_PT_CMD_BACKWARD = 0x4C, /*!< backward */
|
||||
ESP_AVRC_PT_CMD_ANGLE = 0x50, /*!< angle */
|
||||
ESP_AVRC_PT_CMD_SUBPICT = 0x51, /*!< subpicture */
|
||||
ESP_AVRC_PT_CMD_F1 = 0x71, /*!< F1 */
|
||||
ESP_AVRC_PT_CMD_F2 = 0x72, /*!< F2 */
|
||||
ESP_AVRC_PT_CMD_F3 = 0x73, /*!< F3 */
|
||||
ESP_AVRC_PT_CMD_F4 = 0x74, /*!< F4 */
|
||||
ESP_AVRC_PT_CMD_F5 = 0x75, /*!< F5 */
|
||||
ESP_AVRC_PT_CMD_VENDOR = 0x7E, /*!< vendor unique */
|
||||
} esp_avrc_pt_cmd_t;
|
||||
|
||||
/// AVRC passthrough command filter
|
||||
typedef enum {
|
||||
ESP_AVRC_PSTH_FILTER_ALLOWED_CMD = 0, /*!< all of the PASSTHROUGH commands that can possibly be used, immuateble */
|
||||
ESP_AVRC_PSTH_FILTER_SUPPORTED_CMD = 1, /*!< PASSTHROUGH commands selectively supported according to the current configuration */
|
||||
ESP_AVRC_PSTH_FILTER_SUPPORT_MAX,
|
||||
} esp_avrc_psth_filter_t;
|
||||
|
||||
/// AVRC passthrough command bit mask
|
||||
typedef struct {
|
||||
uint16_t bits[8]; /*!< bit mask representation of PASSTHROUGH commands */
|
||||
} esp_avrc_psth_bit_mask_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_AVRC_BIT_MASK_OP_TEST = 0, /*!< operation code to test a specific bit */
|
||||
ESP_AVRC_BIT_MASK_OP_SET = 1, /*!< operation code to set a specific bit */
|
||||
ESP_AVRC_BIT_MASK_OP_CLEAR = 2, /*!< operation code to clear a specific bit */
|
||||
} esp_avrc_bit_mask_op_t;
|
||||
|
||||
/// AVRC passthrough command state
|
||||
typedef enum {
|
||||
ESP_AVRC_PT_CMD_STATE_PRESSED = 0, /*!< key pressed */
|
||||
@ -59,8 +139,18 @@ typedef enum {
|
||||
ESP_AVRC_CT_PLAY_STATUS_RSP_EVT = 3, /*!< play status response event */
|
||||
ESP_AVRC_CT_CHANGE_NOTIFY_EVT = 4, /*!< notification event */
|
||||
ESP_AVRC_CT_REMOTE_FEATURES_EVT = 5, /*!< feature of remote device indication event */
|
||||
ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT = 6, /*!< supported notification events capability of peer device */
|
||||
} esp_avrc_ct_cb_event_t;
|
||||
|
||||
/// AVRC Target callback events
|
||||
typedef enum {
|
||||
ESP_AVRC_TG_CONNECTION_STATE_EVT = 0, /*!< connection state changed event */
|
||||
ESP_AVRC_TG_REMOTE_FEATURES_EVT = 1, /*!< feature of remote device indication event */
|
||||
ESP_AVRC_TG_PASSTHROUGH_CMD_EVT = 2, /*!< passthrough command event */
|
||||
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_cb_event_t;
|
||||
|
||||
/// AVRC metadata attribute mask
|
||||
typedef enum {
|
||||
ESP_AVRC_MD_ATTR_TITLE = 0x1, /*!< title of the playing track */
|
||||
@ -82,9 +172,32 @@ typedef enum {
|
||||
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_NOW_PLAYING_CHANGE = 0x09, /*!< now playing content changed */
|
||||
ESP_AVRC_RN_AVAILABLE_PLAYERS_CHANGE = 0x0a, /*!< available players changed */
|
||||
ESP_AVRC_RN_ADDRESSED_PLAYER_CHANGE = 0x0b, /*!< the addressed player changed */
|
||||
ESP_AVRC_RN_UIDS_CHANGE = 0x0c, /*!< UIDs changed */
|
||||
ESP_AVRC_RN_VOLUME_CHANGE = 0x0d, /*!< volume changed locally on TG */
|
||||
ESP_AVRC_RN_MAX_EVT
|
||||
} esp_avrc_rn_event_ids_t;
|
||||
|
||||
/// AVRC target notification event notification capability
|
||||
typedef enum {
|
||||
ESP_AVRC_RN_CAP_ALLOWED_EVT = 0, /*!< all of the notification events that can possibly be supported, immutable */
|
||||
ESP_AVRC_RN_CAP_SUPPORTED_EVT = 1, /*!< notification events selectively supported according to the current configuration */
|
||||
ESP_AVRC_RN_CAP_MAX,
|
||||
} esp_avrc_rn_evt_cap_t;
|
||||
|
||||
/// AVRC target notification event capability bit mask
|
||||
typedef struct {
|
||||
uint16_t bits; /*!< bit mask representation of PASSTHROUGH commands */
|
||||
} esp_avrc_rn_evt_cap_mask_t;
|
||||
|
||||
/// AVRC notification response type
|
||||
typedef enum {
|
||||
ESP_AVRC_RN_RSP_INTERIM = 13, /*!< initial response to RegisterNotification, should be sent T_mtp(1000ms) from receiving the command */
|
||||
ESP_AVRC_RN_RSP_CHANGED = 15, /*!< final response to RegisterNotification command */
|
||||
} esp_avrc_rn_rsp_t;
|
||||
|
||||
/// AVRC player setting ids
|
||||
typedef enum {
|
||||
ESP_AVRC_PS_EQUALIZER = 0x01, /*!< equalizer, on or off */
|
||||
@ -122,6 +235,46 @@ typedef enum {
|
||||
ESP_AVRC_PS_SCAN_GROUP = 0x3 /*!< group scan */
|
||||
} esp_avrc_ps_scn_value_ids_t;
|
||||
|
||||
/// AVCTP response codes
|
||||
typedef enum {
|
||||
ESP_AVRC_RSP_NOT_IMPL = 8, /*!< not implemented */
|
||||
ESP_AVRC_RSP_ACCEPT = 9, /*!< accept */
|
||||
ESP_AVRC_RSP_REJECT = 10, /*!< reject */
|
||||
ESP_AVRC_RSP_IN_TRANS = 11, /*!< in transition */
|
||||
ESP_AVRC_RSP_IMPL_STBL = 12, /*!< implemented/stable */
|
||||
ESP_AVRC_RSP_CHANGED = 13, /*!< changed */
|
||||
ESP_AVRC_RSP_INTERIM = 15, /*!< interim */
|
||||
} esp_avrc_rsp_t;
|
||||
|
||||
/// AVRCP battery status
|
||||
typedef enum {
|
||||
ESP_AVRC_BATT_NORMAL = 0, /*!< normal state */
|
||||
ESP_AVRC_BATT_WARNING = 1, /*!< unable to operate soon */
|
||||
ESP_AVRC_BATT_CRITICAL = 2, /*!< cannot operate any more */
|
||||
ESP_AVRC_BATT_EXTERNAL = 3, /*!< plugged to external power supply */
|
||||
ESP_AVRC_BATT_FULL_CHARGE = 4, /*!< when completely charged from external power supply */
|
||||
} esp_avrc_batt_stat_t;
|
||||
|
||||
/// AVRCP current status of playback
|
||||
typedef enum {
|
||||
ESP_AVRC_PLAYBACK_STOPPED = 0, /*!< stopped */
|
||||
ESP_AVRC_PLAYBACK_PLAYING = 1, /*!< playing */
|
||||
ESP_AVRC_PLAYBACK_PAUSED = 2, /*!< paused */
|
||||
ESP_AVRC_PLAYBACK_FWD_SEEK = 3, /*!< forward seek */
|
||||
ESP_AVRC_PLAYBACK_REV_SEEK = 4, /*!< reverse seek */
|
||||
ESP_AVRC_PLAYBACK_ERROR = 0xFF, /*!< error */
|
||||
} esp_avrc_playback_stat_t;
|
||||
|
||||
/// AVRCP notification parameters
|
||||
typedef union
|
||||
{
|
||||
uint8_t volume; /*!< response data for ESP_AVRC_RN_VOLUME_CHANGE, ranges 0..127 */
|
||||
esp_avrc_playback_stat_t playback; /*!< response data for ESP_AVRC_RN_PLAY_STATUS_CHANGE */
|
||||
uint8_t elm_id[8]; /*!< response data for ESP_AVRC_RN_TRACK_CHANGE */
|
||||
uint32_t play_pos; /*!< response data for ESP_AVRC_RN_PLAY_POS_CHANGED, in millisecond */
|
||||
esp_avrc_batt_stat_t batt; /*!< response data for ESP_AVRC_RN_BATTERY_STATUS_CHANGE */
|
||||
} esp_avrc_rn_param_t;
|
||||
|
||||
/// AVRC controller callback parameters
|
||||
typedef union {
|
||||
/**
|
||||
@ -155,7 +308,7 @@ typedef union {
|
||||
*/
|
||||
struct avrc_ct_change_notify_param {
|
||||
uint8_t event_id; /*!< id of AVRC event notification */
|
||||
uint32_t event_parameter; /*!< event notification parameter */
|
||||
esp_avrc_rn_param_t event_parameter; /*!< event notification parameter */
|
||||
} change_ntf; /*!< notifications */
|
||||
|
||||
/**
|
||||
@ -163,11 +316,61 @@ typedef union {
|
||||
*/
|
||||
struct avrc_ct_rmt_feats_param {
|
||||
uint32_t feat_mask; /*!< AVRC feature mask of remote device */
|
||||
uint16_t tg_feat_flag; /*!< feature flag of remote device as TG */
|
||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
||||
} rmt_feats; /*!< AVRC features discovered from remote SDP server */
|
||||
|
||||
|
||||
/**
|
||||
* @brief ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT
|
||||
*/
|
||||
struct avrc_ct_get_rn_caps_rsp_param {
|
||||
uint8_t cap_count; /*!< number of items provided in event or company_id according to cap_id used */
|
||||
esp_avrc_rn_evt_cap_mask_t evt_set; /*!< supported event_ids represented in bit-mask */
|
||||
} get_rn_caps_rsp; /*!< get supported event capabilities response from AVRCP target */
|
||||
} esp_avrc_ct_cb_param_t;
|
||||
|
||||
/// AVRC target callback parameters
|
||||
typedef union {
|
||||
/**
|
||||
* @brief ESP_AVRC_TG_CONNECTION_STATE_EVT
|
||||
*/
|
||||
struct avrc_tg_conn_stat_param {
|
||||
bool connected; /*!< whether AVRC connection is set up */
|
||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
||||
} conn_stat; /*!< AVRC connection status */
|
||||
|
||||
/**
|
||||
* @brief ESP_AVRC_TG_REMOTE_FEATURES_EVT
|
||||
*/
|
||||
struct avrc_tg_rmt_feats_param {
|
||||
uint32_t feat_mask; /*!< AVRC feature mask of remote device */
|
||||
uint16_t ct_feat_flag; /*!< feature flag of remote device as CT */
|
||||
esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
|
||||
} rmt_feats; /*!< AVRC features discovered through SDP */
|
||||
|
||||
/**
|
||||
* @brief ESP_AVRC_TG_PASSTHROUGH_CMD_EVT
|
||||
*/
|
||||
struct avrc_tg_psth_cmd_param {
|
||||
uint8_t key_code; /*!< passthrough command code */
|
||||
uint8_t key_state; /*!< 0 for PRESSED, 1 for RELEASED */
|
||||
} psth_cmd; /*!< passthrough command */
|
||||
|
||||
/**
|
||||
* @brief ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT
|
||||
*/
|
||||
struct avrc_tg_set_abs_vol_param {
|
||||
uint8_t volume; /*!< volume ranges from 0 to 127 */
|
||||
} set_abs_vol; /*!< set absolute volume command targeted on audio sink */
|
||||
|
||||
/**
|
||||
* @brief ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT
|
||||
*/
|
||||
struct avrc_tg_reg_ntf_param {
|
||||
uint8_t event_id; /*!< event id of AVRC RegisterNotification */
|
||||
uint32_t event_parameter; /*!< event notification parameter */
|
||||
} reg_ntf; /*!< register notification */
|
||||
} esp_avrc_tg_cb_param_t;
|
||||
|
||||
/**
|
||||
* @brief AVRCP controller callback function type
|
||||
@ -176,23 +379,28 @@ typedef union {
|
||||
*/
|
||||
typedef void (* esp_avrc_ct_cb_t)(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param);
|
||||
|
||||
/**
|
||||
* @brief AVRCP target callback function type
|
||||
* @param event : Event type
|
||||
* @param param : Pointer to callback parameter union
|
||||
*/
|
||||
typedef void (* esp_avrc_tg_cb_t)(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t *param);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register application callbacks to AVRCP module; for now only AVRCP Controller
|
||||
* role is supported. This function should be called after esp_bluedroid_enable()
|
||||
* completes successfully
|
||||
* @brief Register application callbacks to AVRCP module. This function should be
|
||||
* called after esp_bluedroid_enable() completes successfully
|
||||
*
|
||||
* @param[in] callback: AVRCP controller callback function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
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
|
||||
@ -200,13 +408,12 @@ esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback);
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_avrc_ct_init(void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief De-initialize AVRCP controller module. This function should be called after
|
||||
@ -214,7 +421,7 @@ esp_err_t esp_avrc_ct_init(void);
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*/
|
||||
esp_err_t esp_avrc_ct_deinit(void);
|
||||
@ -229,11 +436,24 @@ esp_err_t esp_avrc_ct_deinit(void);
|
||||
* @param[in] value_id : attribute value defined for the specific player application setting attribute
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*/
|
||||
esp_err_t esp_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uint8_t value_id);
|
||||
|
||||
/**
|
||||
* @brief Send GetCapabilities PDU to AVRCP target to retrieve remote device's supported
|
||||
* notification event_ids. 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.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*/
|
||||
esp_err_t esp_avrc_ct_send_get_rn_capabilities_cmd(uint8_t tl);
|
||||
|
||||
/**
|
||||
* @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
|
||||
@ -243,7 +463,8 @@ esp_err_t esp_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uin
|
||||
* @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_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_NOT_SUPPORTED: if the event_id is not supported in current implementation
|
||||
* - ESP_FAIL: others
|
||||
*/
|
||||
esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_id, uint32_t event_parameter);
|
||||
@ -258,7 +479,7 @@ esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_i
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_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);
|
||||
@ -275,12 +496,176 @@ esp_err_t esp_avrc_ct_send_metadata_cmd(uint8_t tl, uint8_t attr_mask);
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*/
|
||||
esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register application callbacks to AVRCP target module; This function should be
|
||||
* called after esp_bluedroid_enable() completes successfully
|
||||
*
|
||||
* @param[in] callback: AVRCP target callback function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
* - ESP_FAIL: others
|
||||
*/
|
||||
esp_err_t esp_avrc_tg_deinit(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Get the current filter of remote passthrough commands on AVRC target. Filter is given by
|
||||
* filter type and bit mask for the passthrough commands. This function should be called
|
||||
* after esp_avrc_tg_init().
|
||||
* For filter type ESP_AVRC_PSTH_FILTER_ALLOWED_CMD, the retrieved command set is constant and
|
||||
* it covers all of the passthrough commands that can possibly be supported.
|
||||
* For filter type ESP_AVRC_PSTH_FILTER_SUPPORT_COMMANDS, the retrieved command set covers the
|
||||
* passthrough commands selected to be supported according to current configuration. The
|
||||
* configuration can be changed using esp_avrc_tg_set_psth_cmd_filter()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not enabled or AVRC TG is not initialized
|
||||
* - ESP_ERR_INVALID_ARG: if filter type is invalid or cmd_set is NULL
|
||||
* - ESP_FAIL: otherwise
|
||||
*/
|
||||
esp_err_t esp_avrc_tg_get_psth_cmd_filter(esp_avrc_psth_filter_t filter, esp_avrc_psth_bit_mask_t *cmd_set);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Set the filter of remote passthrough commands on AVRC target. Filter is given by
|
||||
* filter type and bit mask for the passthrough commands. This function should be called
|
||||
* after esp_avrc_tg_init().
|
||||
* If filter type is ESP_AVRC_PSTH_FILTER_SUPPORT_CMD, the passthrough commands which
|
||||
* are set "1" as given in cmd_set will generate ESP_AVRC_CT_PASSTHROUGH_RSP_EVT callback
|
||||
* event and are auto-accepted in the protocol stack, other commands are replied with response
|
||||
* type "NOT IMPLEMENTED" (8). The set of supported commands should be a subset of allowed
|
||||
* command set. The allowed command set can be retrieved using esp_avrc_tg_get_psth_cmd_filter()
|
||||
* with filter type "ESP_AVRC_PSTH_FILTER_ALLOWED_CMD".
|
||||
*
|
||||
* Filter type "ESP_AVRC_PSTH_FILTER_ALLOWED_CMD" does not apply to this function
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not enabled
|
||||
* - ESP_ERR_INVALID_ARG: if filter type is invalid or cmd_set is NULL
|
||||
* - ESP_ERR_NOT_SUPPORTED:: if filter type is ESP_AVRC_PSTH_FILTER_ALLOWED_CMD, or cmd_set
|
||||
* includes unallowed commands
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_avrc_tg_set_psth_cmd_filter(esp_avrc_psth_filter_t filter, const esp_avrc_psth_bit_mask_t *cmd_set);
|
||||
|
||||
/**
|
||||
* @brief Operate on the type esp_avrc_psth_bit_mask_t with regard to a specific PASSTHROUGH command
|
||||
* @param[in] op: operation requested on the bit mask field
|
||||
* @param[in] psth: pointer to passthrough command bit mask structure
|
||||
* @param[in] cmd: passthrough command code
|
||||
*
|
||||
* @return For operation ESP_AVRC_BIT_MASK_OP_SET or ESP_AVRC_BIT_MASK_OP_CLEAR, return
|
||||
* true for a successful operation, otherwise return false
|
||||
* For operation ESP_AVRC_BIT_MASK_OP_TEST, return true if the corresponding bit
|
||||
* is set, otherwise false
|
||||
*
|
||||
*/
|
||||
bool esp_avrc_psth_bit_mask_operation(esp_avrc_bit_mask_op_t op, esp_avrc_psth_bit_mask_t *psth,
|
||||
esp_avrc_pt_cmd_t cmd);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Get the requested event notification capabilies on local AVRC target. The capability is returned
|
||||
* in a bit mask representation in evt_set. This function should be called after
|
||||
* esp_avrc_tg_init().
|
||||
* For capability type "ESP_AVRC_RN_CAP_ALLOWED_EVT, the retrieved event set is constant and
|
||||
* it covers all of the notifcation events that can possibly be supported with current
|
||||
* implementation.
|
||||
* For capability type ESP_AVRC_RN_CAP_SUPPORTED_EVT, the event set covers the notification
|
||||
* events selected to be supported under current configuration, The configuration can be
|
||||
* changed using esp_avrc_tg_set_rn_evt_cap()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not enabled or AVRC TG is not initialized
|
||||
* - ESP_ERR_INVALID_ARG: if cap is invalid or evt_set is NULL
|
||||
* - ESP_FAIL: otherwise
|
||||
*/
|
||||
esp_err_t esp_avrc_tg_get_rn_evt_cap(esp_avrc_rn_evt_cap_t cap, esp_avrc_rn_evt_cap_mask_t *evt_set);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Set the event notification capabilities on local AVRCP target. The capability is given in a
|
||||
* bit mask representation in evt_set and must be a subset of allowed event IDs with current
|
||||
* implementation. This function should be called after esp_avrc_tg_init().
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not enabled
|
||||
* - ESP_ERR_INVALID_ARG: if evt_set is NULL
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_avrc_tg_set_rn_evt_cap(const esp_avrc_rn_evt_cap_mask_t *evt_set);
|
||||
|
||||
/**
|
||||
* @brief Operate on the type esp_avrc_rn_evt_cap_mask_t with regard to a specific event
|
||||
* @param[in] op: operation requested on the bit mask field
|
||||
* @param[in] events: pointer to event notification capability bit mask structure
|
||||
* @param[in] event_id: notification event code
|
||||
*
|
||||
* @return For operation ESP_AVRC_BIT_MASK_OP_SET or ESP_AVRC_BIT_MASK_OP_CLEAR, return
|
||||
* true for a successful operation, otherwise return false
|
||||
* For operation ESP_AVRC_BIT_MASK_OP_TEST, return true if the corresponding bit
|
||||
* is set, otherwise false
|
||||
*
|
||||
*/
|
||||
bool esp_avrc_rn_evt_bit_mask_operation(esp_avrc_bit_mask_op_t op, esp_avrc_rn_evt_cap_mask_t *events,
|
||||
esp_avrc_rn_event_ids_t event_id);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Send RegisterNotification Response to remote AVRCP controller. Local event notification
|
||||
* capability can be set using esp_avrc_tg_set_rn_evt_cap(),
|
||||
* in a bit mask representation in evt_set. This function should be called after
|
||||
* esp_avrc_tg_init()
|
||||
* @param[in] event_id: notification event ID that remote AVRCP CT registers
|
||||
* @param[in] rsp: notification response code
|
||||
* @param[in] param: parameters included in the specific notification
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not enabled or AVRC TG is not initialized
|
||||
* - ESP_ERR_INVALID_ARG: if evt_set is NULL
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_avrc_tg_send_rn_rsp(esp_avrc_rn_event_ids_t event_id, esp_avrc_rn_rsp_t rsp,
|
||||
esp_avrc_rn_param_t *param);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -73,26 +73,6 @@ enum {
|
||||
BTA_AV_CLOSING_SST
|
||||
};
|
||||
|
||||
|
||||
/* the call out functions for audio stream */
|
||||
/* const tBTA_AV_CO_FUNCTS bta_av_a2d_cos =
|
||||
{
|
||||
bta_av_co_audio_init,
|
||||
bta_av_co_audio_disc_res,
|
||||
bta_av_co_audio_getconfig,
|
||||
bta_av_co_audio_setconfig,
|
||||
bta_av_co_audio_open,
|
||||
bta_av_co_audio_close,
|
||||
bta_av_co_audio_start,
|
||||
bta_av_co_audio_stop,
|
||||
bta_av_co_audio_src_data_path,
|
||||
bta_av_co_audio_delay
|
||||
};
|
||||
*/
|
||||
tBTA_AV_CO_FUNCTS *p_bta_av_a2d_cos = NULL;
|
||||
|
||||
|
||||
|
||||
/* ssm action functions for audio stream */
|
||||
const tBTA_AV_SACT bta_av_a2d_action[] = {
|
||||
bta_av_do_disc_a2d, /* BTA_AV_DO_DISC */
|
||||
|
@ -335,6 +335,8 @@ UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx)
|
||||
p_rcb->shdl = shdl;
|
||||
p_rcb->lidx = lidx;
|
||||
p_rcb->peer_features = 0;
|
||||
p_rcb->peer_ct_features = 0;
|
||||
p_rcb->peer_tg_features = 0;
|
||||
if (lidx == (BTA_AV_NUM_LINKS + 1)) {
|
||||
/* this LIDX is reserved for the AVRCP ACP connection */
|
||||
p_cb->rc_acp_handle = p_rcb->handle;
|
||||
@ -397,22 +399,13 @@ static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data, BOOLEA
|
||||
static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id, BOOLEAN is_inquiry)
|
||||
{
|
||||
tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL;
|
||||
BOOLEAN rc_id_allowed = FALSE;
|
||||
if (bta_av_cb.p_rc_cos && bta_av_cb.p_rc_cos->rc_cmd) {
|
||||
rc_id_allowed = bta_av_cb.p_rc_cos->rc_cmd(rc_id);
|
||||
}
|
||||
|
||||
if (p_bta_av_rc_id) {
|
||||
if (is_inquiry) {
|
||||
if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
|
||||
ret_code = BTA_AV_RSP_IMPL_STBL;
|
||||
}
|
||||
} else {
|
||||
if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
|
||||
ret_code = BTA_AV_RSP_ACCEPT;
|
||||
} else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) && p_bta_av_rc_id_ac) {
|
||||
if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
|
||||
ret_code = BTA_AV_RSP_INTERIM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rc_id_allowed == TRUE) {
|
||||
ret_code = is_inquiry ? BTA_AV_RSP_IMPL_STBL : BTA_AV_RSP_ACCEPT;
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
@ -529,6 +522,8 @@ void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
|
||||
|
||||
bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr);
|
||||
rc_open.peer_features = p_cb->rcb[i].peer_features;
|
||||
rc_open.peer_ct_features = p_cb->rcb[i].peer_ct_features;
|
||||
rc_open.peer_tg_features = p_cb->rcb[i].peer_tg_features;
|
||||
rc_open.sdp_disc_done = TRUE;
|
||||
rc_open.status = BTA_AV_SUCCESS;
|
||||
APPL_TRACE_DEBUG("local features:x%x peer_features:x%x", p_cb->features,
|
||||
@ -687,7 +682,6 @@ void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
|
||||
static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR *p_vendor)
|
||||
{
|
||||
tAVRC_STS status = BTA_AV_STS_NO_RSP;
|
||||
UINT8 xx;
|
||||
UINT16 u16;
|
||||
UINT8 *p = p_vendor->p_vendor_data + 2;
|
||||
|
||||
@ -696,15 +690,13 @@ static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR *p_vendor)
|
||||
if ((u16 != 5) || (p_vendor->vendor_len != 9)) {
|
||||
status = AVRC_STS_INTERNAL_ERR;
|
||||
} else {
|
||||
/* make sure the player_id is valid */
|
||||
for (xx = 0; xx < p_bta_av_cfg->num_evt_ids; xx++) {
|
||||
if (*p == p_bta_av_cfg->p_meta_evt_ids[xx]) {
|
||||
break;
|
||||
/* make sure the event_id is valid */
|
||||
status = AVRC_STS_BAD_PARAM;
|
||||
if (bta_av_cb.p_rc_cos && bta_av_cb.p_rc_cos->rn_evt_supported) {
|
||||
if (bta_av_cb.p_rc_cos->rn_evt_supported(*p) == TRUE) {
|
||||
status = BTA_AV_STS_NO_RSP;
|
||||
}
|
||||
}
|
||||
if (xx == p_bta_av_cfg->num_evt_ids) {
|
||||
status = AVRC_STS_BAD_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
@ -763,9 +755,12 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
|
||||
(p_bta_av_cfg->num_co_ids << 2));
|
||||
} else if (u8 == AVRC_CAP_EVENTS_SUPPORTED) {
|
||||
*p_ctype = AVRC_RSP_IMPL_STBL;
|
||||
p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
|
||||
memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids,
|
||||
p_bta_av_cfg->num_evt_ids);
|
||||
if (bta_av_cb.p_rc_cos && bta_av_cb.p_rc_cos->rn_evt_cap) {
|
||||
p_rc_rsp->get_caps.count = bta_av_cb.p_rc_cos->rn_evt_cap(
|
||||
p_rc_rsp->get_caps.param.event_id);
|
||||
} else {
|
||||
p_rc_rsp->get_caps.count = 0;
|
||||
}
|
||||
} else {
|
||||
APPL_TRACE_DEBUG("Invalid capability ID: 0x%x", u8);
|
||||
/* reject - unknown capability ID */
|
||||
@ -774,7 +769,6 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case AVRC_PDU_REGISTER_NOTIFICATION:
|
||||
/* make sure the event_id is implemented */
|
||||
p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id (p_vendor);
|
||||
@ -783,6 +777,12 @@ tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_ms
|
||||
}
|
||||
break;
|
||||
|
||||
case AVRC_PDU_SET_ABSOLUTE_VOLUME:
|
||||
p_rc_rsp->rsp.status = BTA_AV_STS_NO_RSP;
|
||||
break;
|
||||
default:
|
||||
APPL_TRACE_WARNING("%s unhandled RC vendor PDU: 0x%x", __FUNCTION__, pdu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@ -857,6 +857,10 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data)
|
||||
av.remote_cmd.label = p_data->rc_msg.label;
|
||||
}
|
||||
}
|
||||
/* else if this is a pass thru respone that TG doesn't implement thie command */
|
||||
else if (p_data->rc_msg.msg.hdr.ctype == AVRC_RSP_NOT_IMPL) {
|
||||
/* do nothing, no need to setup for callback */
|
||||
}
|
||||
/* else if this is a pass thru response */
|
||||
else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT) {
|
||||
/* set up for callback */
|
||||
@ -1484,15 +1488,15 @@ static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_av_check_peer_features
|
||||
** Function bta_av_check_peer_rc_features
|
||||
**
|
||||
** Description check supported features on the peer device from the SDP record
|
||||
** and return the feature mask
|
||||
** Description check supported AVRC features on the peer device from the SDP
|
||||
** record and return the feature mask
|
||||
**
|
||||
** Returns tBTA_AV_FEAT peer device feature mask
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid)
|
||||
tBTA_AV_FEAT bta_av_check_peer_rc_features (UINT16 service_uuid, UINT16 *rc_features)
|
||||
{
|
||||
tBTA_AV_FEAT peer_features = 0;
|
||||
tBTA_AV_CB *p_cb = &bta_av_cb;
|
||||
@ -1501,7 +1505,7 @@ tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid)
|
||||
UINT16 peer_rc_version = 0;
|
||||
UINT16 categories = 0;
|
||||
|
||||
APPL_TRACE_DEBUG("bta_av_check_peer_features service_uuid:x%x", service_uuid);
|
||||
APPL_TRACE_DEBUG("bta_av_check_peer_rc features service_uuid:x%x", service_uuid);
|
||||
/* loop through all records we found */
|
||||
while (TRUE) {
|
||||
/* get next record; if none found, we're done */
|
||||
@ -1541,7 +1545,12 @@ tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
APPL_TRACE_DEBUG("peer_features:x%x", peer_features);
|
||||
|
||||
if (rc_features) {
|
||||
*rc_features = categories;
|
||||
}
|
||||
|
||||
APPL_TRACE_DEBUG("peer_features:x%x, rc:x%x", peer_features, categories);
|
||||
return peer_features;
|
||||
}
|
||||
|
||||
@ -1564,6 +1573,8 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
|
||||
tBTA_AV_RC_FEAT rc_feat;
|
||||
UINT8 rc_handle;
|
||||
tBTA_AV_FEAT peer_features; /* peer features mask */
|
||||
UINT16 peer_ct_features; /* peer features mask as controller */
|
||||
UINT16 peer_tg_features; /* peer features mask as target */
|
||||
UNUSED(p_data);
|
||||
|
||||
APPL_TRACE_DEBUG("bta_av_rc_disc_done disc:x%x", p_cb->disc);
|
||||
@ -1589,17 +1600,13 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
|
||||
|
||||
APPL_TRACE_DEBUG("rc_handle %d", rc_handle);
|
||||
/* check peer version and whether support CT and TG role */
|
||||
peer_features = bta_av_check_peer_features (UUID_SERVCLASS_AV_REMOTE_CONTROL);
|
||||
if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && ((peer_features & BTA_AV_FEAT_ADV_CTRL) == 0)) {
|
||||
/* if we support advance control and peer does not, check their support on TG role
|
||||
* some implementation uses 1.3 on CT ans 1.4 on TG */
|
||||
peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET);
|
||||
}
|
||||
peer_features = bta_av_check_peer_rc_features (UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_ct_features);
|
||||
peer_features |= bta_av_check_peer_rc_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET, &peer_tg_features);
|
||||
|
||||
p_cb->disc = 0;
|
||||
utl_freebuf((void **) &p_cb->p_disc_db);
|
||||
|
||||
APPL_TRACE_DEBUG("peer_features 0x%x, features 0x%x", peer_features, p_cb->features);
|
||||
APPL_TRACE_DEBUG("peer_features 0x%x, local features 0x%x", peer_features, p_cb->features);
|
||||
|
||||
/* if we have no rc connection */
|
||||
if (rc_handle == BTA_AV_RC_HANDLE_NONE) {
|
||||
@ -1611,6 +1618,8 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
|
||||
if (p_lcb) {
|
||||
rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx);
|
||||
p_cb->rcb[rc_handle].peer_features = peer_features;
|
||||
p_cb->rcb[rc_handle].peer_ct_features = peer_ct_features;
|
||||
p_cb->rcb[rc_handle].peer_tg_features = peer_tg_features;
|
||||
}
|
||||
#if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE)
|
||||
else {
|
||||
@ -1631,6 +1640,8 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data)
|
||||
p_cb->rcb[rc_handle].peer_features = peer_features;
|
||||
rc_feat.rc_handle = rc_handle;
|
||||
rc_feat.peer_features = peer_features;
|
||||
rc_feat.peer_ct_features = peer_ct_features;
|
||||
rc_feat.peer_tg_features = peer_tg_features;
|
||||
(*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV *) &rc_feat);
|
||||
}
|
||||
}
|
||||
@ -1665,6 +1676,8 @@ void bta_av_rc_closed(tBTA_AV_DATA *p_data)
|
||||
rc_close.rc_handle = i;
|
||||
p_rcb->status &= ~BTA_AV_RC_CONN_MASK;
|
||||
p_rcb->peer_features = 0;
|
||||
p_rcb->peer_ct_features = 0;
|
||||
p_rcb->peer_tg_features = 0;
|
||||
APPL_TRACE_DEBUG(" shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx);
|
||||
if (p_rcb->shdl) {
|
||||
if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) {
|
||||
|
@ -105,7 +105,9 @@ void BTA_AvDisable(void)
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback, tBTA_AV_CO_FUNCTS *bta_av_cos, UINT8 tsep)
|
||||
void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id,
|
||||
tBTA_AV_DATA_CBACK *p_data_cback, tBTA_AV_CO_FUNCTS *bta_av_cos,
|
||||
tBTA_AVRC_CO_FUNCTS *bta_avrc_cos, UINT8 tsep)
|
||||
{
|
||||
tBTA_AV_API_REG *p_buf;
|
||||
|
||||
@ -122,6 +124,7 @@ void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id,
|
||||
p_buf->app_id = app_id;
|
||||
p_buf->p_app_data_cback = p_data_cback;
|
||||
p_buf->bta_av_cos = bta_av_cos;
|
||||
p_buf->bta_avrc_cos = bta_avrc_cos;
|
||||
p_buf->tsep = tsep;
|
||||
bta_sys_sendmsg(p_buf);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ const UINT32 bta_av_meta_caps_co_ids[] = {
|
||||
};
|
||||
|
||||
/* AVRCP cupported categories */
|
||||
#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2)
|
||||
#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT1)
|
||||
|
||||
/* Added to modify
|
||||
** 1. flush timeout
|
||||
@ -62,26 +62,11 @@ const UINT16 bta_av_audio_flush_to[] = {
|
||||
/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI */
|
||||
/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */
|
||||
#if AVRC_METADATA_INCLUDED == TRUE
|
||||
#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
|
||||
#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT2) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
|
||||
#else
|
||||
#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1)
|
||||
#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT2)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed.
|
||||
*/
|
||||
const UINT8 bta_av_meta_caps_evt_ids[] = {
|
||||
AVRC_EVT_PLAY_STATUS_CHANGE,
|
||||
AVRC_EVT_TRACK_CHANGE,
|
||||
AVRC_EVT_PLAY_POS_CHANGED,
|
||||
/* TODO: Add support for these events
|
||||
AVRC_EVT_APP_SETTING_CHANGE,
|
||||
*/
|
||||
};
|
||||
#ifndef BTA_AV_NUM_RC_EVT_IDS
|
||||
#define BTA_AV_NUM_RC_EVT_IDS (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
|
||||
#endif /* BTA_AV_NUM_RC_EVT_IDS */
|
||||
|
||||
/* the MTU for the AVRCP browsing channel */
|
||||
#ifndef BTA_AV_MAX_RC_BR_MTU
|
||||
#define BTA_AV_MAX_RC_BR_MTU 1008
|
||||
@ -105,10 +90,8 @@ const tBTA_AV_CFG bta_av_cfg = {
|
||||
600, /* AVDTP video transport channel flush timeout */
|
||||
FALSE, /* TRUE, to accept AVRC 1.3 group nevigation command */
|
||||
2, /* company id count in p_meta_co_ids */
|
||||
BTA_AV_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */
|
||||
BTA_AV_RC_PASS_RSP_CODE,/* the default response code for pass through commands */
|
||||
bta_av_meta_caps_co_ids,/* the metadata Get Capabilities response for company id */
|
||||
bta_av_meta_caps_evt_ids,/* the the metadata Get Capabilities response for event id */
|
||||
NULL, /* the action function table for VDP stream */
|
||||
NULL, /* action function to register VDP */
|
||||
{0}, /* Default AVRCP controller name */
|
||||
@ -117,91 +100,4 @@ const tBTA_AV_CFG bta_av_cfg = {
|
||||
|
||||
tBTA_AV_CFG *p_bta_av_cfg = (tBTA_AV_CFG *) &bta_av_cfg;
|
||||
|
||||
const UINT16 bta_av_rc_id[] = {
|
||||
0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
|
||||
4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP,
|
||||
8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU,
|
||||
12=FAV_MENU, 13=EXIT */
|
||||
|
||||
0, /* not used */
|
||||
|
||||
0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
|
||||
4=4, 5=5, 6=6, 7=7,
|
||||
8=8, 9=9, 10=DOT, 11=ENTER,
|
||||
12=CLEAR */
|
||||
|
||||
0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL,
|
||||
4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP,
|
||||
8=PAGE_DOWN */
|
||||
|
||||
#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
|
||||
/* btui_app provides an example of how to leave the decision of rejecting a command or not
|
||||
* based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later)
|
||||
* If the decision is per player for a particular rc_id, the related bit is clear (not set) */
|
||||
0x0070, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
|
||||
4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
|
||||
8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
|
||||
12=BACKWARD */
|
||||
#else
|
||||
#if (defined BTA_AVRCP_FF_RW_SUPPORT) && (BTA_AVRCP_FF_RW_SUPPORT == TRUE)
|
||||
0x1b70, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
|
||||
4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
|
||||
8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
|
||||
12=BACKWARD */
|
||||
#else
|
||||
0x1870, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
|
||||
4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
|
||||
8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
|
||||
12=BACKWARD */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
|
||||
|
||||
0, /* not used */
|
||||
|
||||
0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
|
||||
4=F4, 5=F5 */
|
||||
};
|
||||
|
||||
#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
|
||||
const UINT16 bta_av_rc_id_ac[] = {
|
||||
0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
|
||||
4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP,
|
||||
8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU,
|
||||
12=FAV_MENU, 13=EXIT */
|
||||
|
||||
0, /* not used */
|
||||
|
||||
0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
|
||||
4=4, 5=5, 6=6, 7=7,
|
||||
8=8, 9=9, 10=DOT, 11=ENTER,
|
||||
12=CLEAR */
|
||||
|
||||
0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL,
|
||||
4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP,
|
||||
8=PAGE_DOWN */
|
||||
|
||||
/* btui_app provides an example of how to leave the decision of rejecting a command or not
|
||||
* based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later)
|
||||
* If the decision is per player for a particular rc_id, the related bit is set */
|
||||
0x1800, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
|
||||
4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
|
||||
8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
|
||||
12=BACKWARD */
|
||||
|
||||
0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
|
||||
|
||||
0, /* not used */
|
||||
|
||||
0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
|
||||
4=F4, 5=F5 */
|
||||
};
|
||||
UINT16 *p_bta_av_rc_id_ac = (UINT16 *) bta_av_rc_id_ac;
|
||||
#else
|
||||
UINT16 *p_bta_av_rc_id_ac = NULL;
|
||||
#endif
|
||||
|
||||
UINT16 *p_bta_av_rc_id = (UINT16 *) bta_av_rc_id;
|
||||
|
||||
#endif /* if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) */
|
||||
|
@ -534,6 +534,11 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
registr.app_id = p_data->api_reg.app_id;
|
||||
registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
|
||||
registr.p_bta_av_cos = p_data->api_reg.bta_av_cos;
|
||||
registr.p_bta_avrc_cos = p_data->api_reg.bta_avrc_cos;
|
||||
|
||||
// set the avrc call-out functions
|
||||
bta_av_cb.p_rc_cos = p_data->api_reg.bta_avrc_cos;
|
||||
|
||||
do {
|
||||
p_scb = bta_av_alloc_scb(registr.chnl);
|
||||
if (p_scb == NULL) {
|
||||
@ -619,7 +624,6 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
if (registr.chnl == BTA_AV_CHNL_AUDIO) {
|
||||
/* set up the audio stream control block */
|
||||
p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action;
|
||||
// p_scb->p_cos = &bta_av_a2d_cos;
|
||||
p_scb->p_cos = registr.p_bta_av_cos;
|
||||
p_scb->media_type = AVDT_MEDIA_AUDIO;
|
||||
cs.cfg.psc_mask = AVDT_PSC_TRANS;
|
||||
|
@ -174,6 +174,7 @@ typedef struct {
|
||||
UINT8 tsep; // local SEP type
|
||||
tBTA_AV_DATA_CBACK *p_app_data_cback;
|
||||
tBTA_AV_CO_FUNCTS *bta_av_cos;
|
||||
tBTA_AVRC_CO_FUNCTS *bta_avrc_cos;
|
||||
} tBTA_AV_API_REG;
|
||||
|
||||
|
||||
@ -473,6 +474,8 @@ typedef struct {
|
||||
UINT8 shdl; /* stream handle (hdi + 1) */
|
||||
UINT8 lidx; /* (index+1) to LCB */
|
||||
tBTA_AV_FEAT peer_features; /* peer features mask */
|
||||
UINT16 peer_ct_features;
|
||||
UINT16 peer_tg_features;
|
||||
} tBTA_AV_RCB;
|
||||
#define BTA_AV_NUM_RCB (BTA_AV_NUM_STRS + 2)
|
||||
|
||||
@ -509,6 +512,7 @@ typedef struct {
|
||||
tBTA_AV_FEAT features; /* features mask */
|
||||
tBTA_SEC sec_mask; /* security mask */
|
||||
tBTA_AV_HNDL handle; /* the handle for SDP activity */
|
||||
tBTA_AVRC_CO_FUNCTS *p_rc_cos; /* AVRCP call-out functions */
|
||||
BOOLEAN disabling; /* TRUE if api disabled called */
|
||||
UINT8 disc; /* (hdi+1) or (rc_handle|BTA_AV_CHNL_MSK) if p_disc_db is in use */
|
||||
UINT8 state; /* state machine state */
|
||||
@ -544,12 +548,7 @@ extern tBTA_AV_CB *bta_av_cb_ptr;
|
||||
/* config struct */
|
||||
extern tBTA_AV_CFG *p_bta_av_cfg;
|
||||
|
||||
/* rc id config struct */
|
||||
extern UINT16 *p_bta_av_rc_id;
|
||||
extern UINT16 *p_bta_av_rc_id_ac;
|
||||
|
||||
extern const tBTA_AV_SACT bta_av_a2d_action[];
|
||||
// extern const tBTA_AV_CO_FUNCTS bta_av_a2d_cos;
|
||||
extern const tBTA_AV_SACT bta_av_vdp_action[];
|
||||
extern tAVDT_CTRL_CBACK *const bta_av_dt_cback[];
|
||||
extern void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt);
|
||||
|
@ -279,20 +279,35 @@ typedef void *(*tBTA_AV_CO_DATAPATH) (tBTA_AV_CODEC codec_type,
|
||||
UINT32 *p_len, UINT32 *p_timestamp);
|
||||
typedef void (*tBTA_AV_CO_DELAY) (tBTA_AV_HNDL hndl, UINT16 delay);
|
||||
|
||||
/// AVRCP call-out function
|
||||
// check whether PASSTHROUGH command is supported
|
||||
typedef BOOLEAN (*tBTA_AVRC_CO_CMD_ALLOWED) (tBTA_AV_RC rc_id);
|
||||
// get the event notification capabilities
|
||||
typedef UINT8 (*tBTA_AVRC_CO_RN_EVT_CAP) (UINT8 *event_ids);
|
||||
// check whether the event_id is supported
|
||||
typedef BOOLEAN (*tBTA_AVRC_CO_RN_EVT_SUPPORTED) (UINT8 event_id);
|
||||
|
||||
/* the call-out functions for one stream */
|
||||
typedef struct {
|
||||
tBTA_AV_CO_INIT init;
|
||||
tBTA_AV_CO_DISC_RES disc_res;
|
||||
tBTA_AV_CO_GETCFG getcfg;
|
||||
tBTA_AV_CO_SETCFG setcfg;
|
||||
tBTA_AV_CO_OPEN open;
|
||||
tBTA_AV_CO_CLOSE close;
|
||||
tBTA_AV_CO_START start;
|
||||
tBTA_AV_CO_STOP stop;
|
||||
tBTA_AV_CO_DATAPATH data;
|
||||
tBTA_AV_CO_DELAY delay;
|
||||
tBTA_AV_CO_INIT init;
|
||||
tBTA_AV_CO_DISC_RES disc_res;
|
||||
tBTA_AV_CO_GETCFG getcfg;
|
||||
tBTA_AV_CO_SETCFG setcfg;
|
||||
tBTA_AV_CO_OPEN open;
|
||||
tBTA_AV_CO_CLOSE close;
|
||||
tBTA_AV_CO_START start;
|
||||
tBTA_AV_CO_STOP stop;
|
||||
tBTA_AV_CO_DATAPATH data;
|
||||
tBTA_AV_CO_DELAY delay;
|
||||
} tBTA_AV_CO_FUNCTS;
|
||||
|
||||
/* the call-out functions for AVRCP */
|
||||
typedef struct {
|
||||
tBTA_AVRC_CO_CMD_ALLOWED rc_cmd;
|
||||
tBTA_AVRC_CO_RN_EVT_CAP rn_evt_cap;
|
||||
tBTA_AVRC_CO_RN_EVT_SUPPORTED rn_evt_supported;
|
||||
} tBTA_AVRC_CO_FUNCTS;
|
||||
|
||||
typedef UINT8 tBTA_AV_EVT;
|
||||
|
||||
/* Event associated with BTA_AV_ENABLE_EVT */
|
||||
@ -307,6 +322,7 @@ typedef struct {
|
||||
UINT8 app_id; /* ID associated with call to BTA_AvRegister() */
|
||||
tBTA_AV_STATUS status;
|
||||
tBTA_AV_CO_FUNCTS *p_bta_av_cos;
|
||||
tBTA_AVRC_CO_FUNCTS *p_bta_avrc_cos;
|
||||
} tBTA_AV_REGISTER;
|
||||
|
||||
/* data associated with BTA_AV_OPEN_EVT */
|
||||
@ -377,6 +393,8 @@ typedef struct {
|
||||
UINT8 rc_handle;
|
||||
BOOLEAN sdp_disc_done;
|
||||
tBTA_AV_FEAT peer_features;
|
||||
UINT16 peer_ct_features;
|
||||
UINT16 peer_tg_features;
|
||||
BD_ADDR peer_addr;
|
||||
tBTA_AV_STATUS status;
|
||||
} tBTA_AV_RC_OPEN;
|
||||
@ -391,6 +409,8 @@ typedef struct {
|
||||
typedef struct {
|
||||
UINT8 rc_handle;
|
||||
tBTA_AV_FEAT peer_features;
|
||||
UINT16 peer_ct_features;
|
||||
UINT16 peer_tg_features;
|
||||
} tBTA_AV_RC_FEAT;
|
||||
|
||||
/* data associated with BTA_AV_REMOTE_CMD_EVT */
|
||||
@ -519,10 +539,8 @@ typedef struct {
|
||||
UINT16 video_flush_to; /* AVDTP video transport channel flush timeout */
|
||||
BOOLEAN avrc_group; /* TRUE, to accept AVRC 1.3 group nevigation command */
|
||||
UINT8 num_co_ids; /* company id count in p_meta_co_ids */
|
||||
UINT8 num_evt_ids; /* event id count in p_meta_evt_ids */
|
||||
tBTA_AV_CODE rc_pass_rsp; /* the default response code for pass through commands */
|
||||
const UINT32 *p_meta_co_ids;/* the metadata Get Capabilities response for company id */
|
||||
const UINT8 *p_meta_evt_ids;/* the the metadata Get Capabilities response for event id */
|
||||
const tBTA_AV_ACT *p_act_tbl;/* the action function table for VDP stream */
|
||||
tBTA_AV_REG *p_reg; /* action function to register VDP */
|
||||
char avrc_controller_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP controller name */
|
||||
@ -580,7 +598,9 @@ void BTA_AvDisable(void);
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name,
|
||||
UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback, tBTA_AV_CO_FUNCTS *bta_av_cos, UINT8 tsep);
|
||||
UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback,
|
||||
tBTA_AV_CO_FUNCTS *bta_av_cos, tBTA_AVRC_CO_FUNCTS *bta_avrc_cos,
|
||||
UINT8 tsep);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
@ -78,7 +78,8 @@ static btc_func_t profile_tab[BTC_PID_NUM] = {
|
||||
[BTC_PID_PRF_QUE] = {btc_profile_queue_handler, NULL },
|
||||
#if BTC_AV_INCLUDED
|
||||
[BTC_PID_A2DP] = {btc_a2dp_call_handler, btc_a2dp_cb_handler },
|
||||
[BTC_PID_AVRC] = {btc_avrc_call_handler, NULL },
|
||||
[BTC_PID_AVRC_CT] = {btc_avrc_ct_call_handler, NULL },
|
||||
[BTC_PID_AVRC_TG] = {btc_avrc_tg_call_handler, NULL },
|
||||
#endif /* #if BTC_AV_INCLUDED */
|
||||
#if CONFIG_BT_SPP_ENABLED
|
||||
[BTC_PID_SPP] = {btc_spp_call_handler, btc_spp_cb_handler },
|
||||
|
@ -57,7 +57,8 @@ typedef enum {
|
||||
BTC_PID_GAP_BT,
|
||||
BTC_PID_PRF_QUE,
|
||||
BTC_PID_A2DP,
|
||||
BTC_PID_AVRC,
|
||||
BTC_PID_AVRC_CT,
|
||||
BTC_PID_AVRC_TG,
|
||||
BTC_PID_SPP,
|
||||
#if BTC_HF_CLIENT_INCLUDED
|
||||
BTC_PID_HF_CLIENT,
|
||||
|
@ -148,6 +148,7 @@ static void btc_av_event_free_data(btc_sm_event_t event, void *p_data);
|
||||
*************************************************************************/
|
||||
|
||||
extern tBTA_AV_CO_FUNCTS bta_av_a2d_cos;
|
||||
extern tBTA_AVRC_CO_FUNCTS bta_avrc_cos;
|
||||
/*****************************************************************************
|
||||
** Local helper functions
|
||||
******************************************************************************/
|
||||
@ -1233,7 +1234,7 @@ bt_status_t btc_av_execute_service(BOOLEAN b_enable, UINT8 tsep)
|
||||
| BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR
|
||||
| BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL,
|
||||
bte_av_callback);
|
||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos, tsep);
|
||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos, &bta_avrc_cos, tsep);
|
||||
} else {
|
||||
BTA_AvDeregister(btc_av_cb.bta_handle);
|
||||
BTA_AvDisable();
|
||||
|
106
components/bt/bluedroid/btc/profile/std/avrc/bta_avrc_co.c
Normal file
106
components/bt/bluedroid/btc/profile/std/avrc/bta_avrc_co.c
Normal file
@ -0,0 +1,106 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* This is the AVRC call-out function implementation for BTC.
|
||||
*
|
||||
******************************************************************************/
|
||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Filename: bta_avrc_co.c
|
||||
*
|
||||
* Description: Bluetooth AVRC implementation
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common/bt_target.h"
|
||||
#include "bta/bta_sys.h"
|
||||
#include "bta/bta_av_api.h"
|
||||
#include "btc_avrc.h"
|
||||
|
||||
#if BTC_AV_INCLUDED
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_avrc_co_cmd_allowed
|
||||
**
|
||||
** Description Check if local AVRCP TG configuration supports a specific
|
||||
** PASSTHROUGH command with the given operation_id
|
||||
**
|
||||
** Returns TRUE if operation_id is supported, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_avrc_co_cmd_allowed(tBTA_AV_RC rc_id)
|
||||
{
|
||||
if (rc_id >= BTA_AV_VENDOR) {
|
||||
return FALSE;
|
||||
}
|
||||
const uint16_t *rc_cmd = btc_avrc_tg_get_supported_command();
|
||||
if (rc_cmd[rc_id >> 4] & ((uint16_t)1 << (rc_id & 0x0F))) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_avrc_co_rn_evt_cap
|
||||
**
|
||||
** Description get the event notifcation capabilities on AVRCP target
|
||||
**
|
||||
** Returns number of event_ids supported
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT8 bta_avrc_co_rn_evt_cap(UINT8 *event_ids)
|
||||
{
|
||||
if (event_ids == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT16 event_bits = btc_avrc_tg_get_rn_supported_evt();
|
||||
UINT8 count = 0;
|
||||
for (UINT8 i = 0; i < 16; ++i, event_bits >>= 1) {
|
||||
if (event_bits & 0x01) {
|
||||
event_ids[count++] = i;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_avrc_co_evt_supported
|
||||
**
|
||||
** Description Check if local AVRCP TG configuration supports the given
|
||||
** event_id
|
||||
**
|
||||
** Returns TRUE if operation_id is supported, FALSE otherwise
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_avrc_co_rn_evt_supported(UINT8 event_id)
|
||||
{
|
||||
return btc_avrc_tg_rn_evt_supported(event_id) ?
|
||||
TRUE : FALSE;
|
||||
}
|
||||
|
||||
/* the call out functions for AVRC */
|
||||
tBTA_AVRC_CO_FUNCTS bta_avrc_cos = {
|
||||
bta_avrc_co_cmd_allowed,
|
||||
bta_avrc_co_rn_evt_cap,
|
||||
bta_avrc_co_rn_evt_supported,
|
||||
};
|
||||
|
||||
#endif /* #if BTC_AV_INCLUDED */
|
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,8 @@
|
||||
#include "common/bt_defs.h"
|
||||
#include "stack/bt_types.h"
|
||||
#include "bta/bta_av_api.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "esp_avrc_api.h"
|
||||
|
||||
#if (BTC_AV_INCLUDED == TRUE)
|
||||
#ifndef BTC_AVRC_TGT_INCLUDED
|
||||
@ -29,13 +31,14 @@
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
BTC_AVRC_CTRL_API_INIT_EVT = 0,
|
||||
BTC_AVRC_CTRL_API_DEINIT_EVT,
|
||||
BTC_AVRC_CT_API_INIT_EVT = 0,
|
||||
BTC_AVRC_CT_API_DEINIT_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_STATUS_API_SND_GET_RN_CAPS_EVT,
|
||||
BTC_AVRC_NOTIFY_API_SND_REG_NOTIFY_EVT,
|
||||
BTC_AVRC_CTRL_API_SET_PLAYER_SETTING_EVT
|
||||
BTC_AVRC_CTRL_API_SND_SET_PLAYER_SETTING_EVT
|
||||
} btc_avrc_act_t;
|
||||
|
||||
typedef struct {
|
||||
@ -61,18 +64,40 @@ typedef struct {
|
||||
uint8_t value_id;
|
||||
} ps_cmd_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t tl;
|
||||
} get_caps_cmd_t;
|
||||
|
||||
/* btc_avrc_args_t */
|
||||
typedef union {
|
||||
pt_cmd_t pt_cmd;
|
||||
md_cmd_t md_cmd;
|
||||
rn_cmd_t rn_cmd;
|
||||
ps_cmd_t ps_cmd;
|
||||
get_caps_cmd_t get_caps_cmd;
|
||||
} btc_avrc_args_t;
|
||||
|
||||
/** BT-RC Controller callback structure. */
|
||||
typedef void (* btrc_passthrough_rsp_callback) (int id, int key_state);
|
||||
/* btc_avrc_tg_act_t */
|
||||
typedef enum {
|
||||
BTC_AVRC_TG_API_INIT_EVT = 0,
|
||||
BTC_AVRC_TG_API_DEINIT_EVT,
|
||||
BTC_AVRC_TG_API_SET_RN_SUPPORTED_EVT,
|
||||
BTC_AVRC_TG_API_SET_PSTH_SUPPORTED_CMD_EVT,
|
||||
BTC_AVRC_TG_API_SEND_RN_RSP_EVT,
|
||||
} btc_avrc_tg_act_t;
|
||||
|
||||
typedef void (* btrc_connection_state_callback) (bool state, bt_bdaddr_t *bd_addr);
|
||||
typedef struct {
|
||||
esp_avrc_rn_event_ids_t event_id;
|
||||
esp_avrc_rn_rsp_t rsp;
|
||||
esp_avrc_rn_param_t param;
|
||||
} rn_rsp_t;
|
||||
|
||||
/* btc_avrc_tg_args_t */
|
||||
typedef union {
|
||||
rn_rsp_t rn_rsp; /* BTC_AVRC_TG_API_SEND_RN_RSP_EVT */
|
||||
uint16_t set_rn_evt; /* BTC_AVRC_TG_API_SET_RN_SUPPORTED_EVT */
|
||||
uint16_t *set_psth_cmd; /* BTC_AVRC_TG_API_SET_PSTH_SUPPORTED_CMD_EVT */
|
||||
} btc_avrc_tg_args_t;
|
||||
|
||||
void btc_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data);
|
||||
|
||||
@ -81,7 +106,24 @@ BOOLEAN btc_rc_get_connected_peer(BD_ADDR peer_addr);
|
||||
/*******************************************************************************
|
||||
** BTC AVRC API
|
||||
********************************************************************************/
|
||||
void btc_avrc_call_handler(btc_msg_t *msg);
|
||||
void btc_avrc_ct_call_handler(btc_msg_t *msg);
|
||||
void btc_avrc_tg_call_handler(btc_msg_t *msg);
|
||||
void btc_avrc_tg_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
|
||||
|
||||
bool btc_avrc_tg_init_p(void);
|
||||
bool btc_avrc_ct_init_p(void);
|
||||
bool btc_avrc_tg_connected_p(void);
|
||||
bool btc_avrc_ct_connected_p(void);
|
||||
|
||||
const uint16_t *btc_avrc_tg_get_supported_command(void);
|
||||
const uint16_t *btc_avrc_tg_get_allowed_command(void);
|
||||
bool btc_avrc_tg_check_supported_command(const uint16_t *cmd_set);
|
||||
|
||||
uint16_t btc_avrc_tg_get_rn_allowed_evt(void);
|
||||
uint16_t btc_avrc_tg_get_rn_supported_evt(void);
|
||||
bool btc_avrc_tg_check_rn_supported_evt(uint16_t evt_set);
|
||||
bool btc_avrc_tg_rn_evt_supported(uint8_t event_id);
|
||||
bool btc_avrc_ct_rn_evt_supported(uint8_t event_id);
|
||||
|
||||
#endif ///BTC_AV_INCLUDED == TRUE
|
||||
|
||||
|
@ -237,6 +237,22 @@ static tAVRC_STS avrc_bld_get_element_attr_cmd (tAVRC_GET_ELEM_ATTRS_CMD *p_cmd,
|
||||
return AVRC_STS_NO_ERROR;
|
||||
}
|
||||
|
||||
static tAVRC_STS avrc_bld_get_caps_cmd(tAVRC_GET_CAPS_CMD *p_cmd, BT_HDR *p_pkt)
|
||||
{
|
||||
UINT8 *p_data, *p_start;
|
||||
|
||||
AVRC_TRACE_API("avrc_bld_get_caps");
|
||||
/* get the existing length, if any, and also the num attributes */
|
||||
// Set the notify value
|
||||
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
|
||||
p_data = p_start + 2; /* pdu + rsvd */
|
||||
/* add fixed length 1 */
|
||||
UINT16_TO_BE_STREAM(p_data, 1);
|
||||
/* capability id */
|
||||
UINT8_TO_BE_STREAM(p_data, p_cmd->capability_id);
|
||||
p_pkt->len = (p_data - p_start);
|
||||
return AVRC_STS_NO_ERROR;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVRC_BldCommand
|
||||
@ -296,6 +312,9 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
|
||||
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;
|
||||
case AVRC_PDU_GET_CAPABILITIES:
|
||||
status = avrc_bld_get_caps_cmd(&p_cmd->get_caps, p_pkt);
|
||||
break;
|
||||
}
|
||||
|
||||
if (alloc && (status != AVRC_STS_NO_ERROR) ) {
|
||||
|
@ -593,6 +593,10 @@ static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
|
||||
}
|
||||
break;
|
||||
|
||||
case AVRC_EVT_VOLUME_CHANGE:
|
||||
UINT8_TO_BE_STREAM(p_data, p_rsp->param.volume);
|
||||
len = 2;
|
||||
break;
|
||||
default:
|
||||
status = AVRC_STS_BAD_PARAM;
|
||||
AVRC_TRACE_ERROR("unknown event_id");
|
||||
@ -652,6 +656,31 @@ tAVRC_STS avrc_bld_group_navigation_rsp (UINT16 navi_id, BT_HDR *p_pkt)
|
||||
return AVRC_STS_NO_ERROR;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avrc_bld_set_absolute_volume_rsp
|
||||
**
|
||||
** Description This function builds the Set Absolute Volume command
|
||||
** response
|
||||
**
|
||||
** Returns AVRC_STS_NO_ERROR, if the response is built successfully
|
||||
** Otherwise, the error code.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tAVRC_STS avrc_bld_set_absolute_volume_rsp(tAVRC_SET_VOLUME_RSP *p_rsp, BT_HDR *p_pkt)
|
||||
{
|
||||
UINT8 *p_data, *p_start;
|
||||
|
||||
p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
|
||||
p_data = p_start + 2; /* pdu + rsvd */
|
||||
UINT16_TO_BE_STREAM(p_data, 1); /* fixed length 1 */
|
||||
UINT8_TO_BE_STREAM(p_data, p_rsp->volume);
|
||||
|
||||
p_pkt->len = (p_data - p_start);
|
||||
|
||||
return AVRC_STS_NO_ERROR;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avrc_bld_rejected_rsp
|
||||
@ -842,9 +871,12 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt
|
||||
status = avrc_bld_next_rsp(&p_rsp->continu, p_pkt);
|
||||
break;
|
||||
|
||||
case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
|
||||
case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
|
||||
status = avrc_bld_next_rsp(&p_rsp->abort, p_pkt);
|
||||
break;
|
||||
case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
|
||||
status = avrc_bld_set_absolute_volume_rsp(&p_rsp->volume, p_pkt);
|
||||
break;
|
||||
}
|
||||
|
||||
if (alloc && (status != AVRC_STS_NO_ERROR) ) {
|
||||
|
@ -90,9 +90,28 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p
|
||||
p_result->reg_notif.event_id = eventid;
|
||||
BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p);
|
||||
}
|
||||
AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x", eventid,
|
||||
p_result->reg_notif.param.volume);
|
||||
// todo: parse the response for other event_ids
|
||||
AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event 0x%x", eventid);
|
||||
break;
|
||||
#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
|
||||
case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
|
||||
BE_STREAM_TO_UINT8 (p_result->get_caps.capability_id, p);
|
||||
BE_STREAM_TO_UINT8 (p_result->get_caps.count, p);
|
||||
if (p_result->get_caps.capability_id == AVRC_CAP_EVENTS_SUPPORTED) {
|
||||
if (p_result->get_caps.count > AVRC_CAP_MAX_NUM_EVT_ID) {
|
||||
status = AVRC_STS_INTERNAL_ERR;
|
||||
} else {
|
||||
BE_STREAM_TO_ARRAY(p, p_result->get_caps.param.event_id, p_result->get_caps.count);
|
||||
}
|
||||
} else if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID) {
|
||||
if (p_result->get_caps.count > AVRC_CAP_MAX_NUM_COMP_ID) {
|
||||
status = AVRC_STS_INTERNAL_ERR;
|
||||
} else {
|
||||
for (int i = 0; i < p_result->get_caps.count; ++i) {
|
||||
BE_STREAM_TO_UINT24(p_result->get_caps.param.company_id[i], p);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status = AVRC_STS_BAD_CMD;
|
||||
@ -112,12 +131,10 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p
|
||||
** Otherwise, the error code defined by AVRCP 1.4
|
||||
**
|
||||
*******************************************************************************/
|
||||
tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len)
|
||||
tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result)
|
||||
{
|
||||
tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
|
||||
UINT16 id;
|
||||
UNUSED(p_buf);
|
||||
UNUSED(buf_len);
|
||||
|
||||
if (p_msg && p_result) {
|
||||
switch (p_msg->hdr.opcode) {
|
||||
|
@ -249,6 +249,9 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_
|
||||
case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
|
||||
if (len != 1) {
|
||||
status = AVRC_STS_INTERNAL_ERR;
|
||||
} else {
|
||||
BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
|
||||
p_result->volume.volume &= 0x7F; // remove the top bit
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE)
|
||||
|
||||
#ifndef SDP_AVRCP_1_4
|
||||
#define SDP_AVRCP_1_4 FALSE
|
||||
#define SDP_AVRCP_1_4 TRUE
|
||||
#endif
|
||||
|
||||
#ifndef SDP_AVCTP_1_4
|
||||
|
@ -58,6 +58,7 @@ BOOLEAN AVRC_IsValidAvcType(UINT8 pdu_id, UINT8 avc_type)
|
||||
case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
|
||||
case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
|
||||
case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
|
||||
case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
|
||||
if (avc_type == AVRC_CMD_CTRL) {
|
||||
result = TRUE;
|
||||
}
|
||||
|
@ -590,8 +590,7 @@ extern tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result,
|
||||
** Otherwise, the error code defined by AVRCP 1.4
|
||||
**
|
||||
*******************************************************************************/
|
||||
extern tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result,
|
||||
UINT8 *p_buf, UINT16 buf_len);
|
||||
extern tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
@ -834,7 +834,7 @@ typedef union {
|
||||
#define AVRC_IS_VALID_CAP_ID(a) (((a == AVRC_CAP_COMPANY_ID) || (a == AVRC_CAP_EVENTS_SUPPORTED)) ? TRUE : FALSE)
|
||||
|
||||
#define AVRC_IS_VALID_EVENT_ID(a) (((a >= AVRC_EVT_PLAY_STATUS_CHANGE) && \
|
||||
(a <= AVRC_EVT_APP_SETTING_CHANGE)) ? TRUE : FALSE)
|
||||
(a <= AVRC_EVT_VOLUME_CHANGE)) ? TRUE : FALSE)
|
||||
|
||||
#define AVRC_IS_VALID_ATTRIBUTE(a) (((((a > 0) && a <= AVRC_PLAYER_SETTING_SCAN)) || \
|
||||
(a >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? TRUE : FALSE)
|
||||
|
@ -25,15 +25,31 @@
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s.h"
|
||||
|
||||
#include "sys/lock.h"
|
||||
|
||||
// AVRCP used transaction label
|
||||
#define APP_RC_CT_TL_GET_CAPS (0)
|
||||
#define APP_RC_CT_TL_GET_META_DATA (1)
|
||||
#define APP_RC_CT_TL_RN_TRACK_CHANGE (2)
|
||||
#define APP_RC_CT_TL_RN_PLAYBACK_CHANGE (3)
|
||||
#define APP_RC_CT_TL_RN_PLAY_POS_CHANGE (4)
|
||||
|
||||
/* a2dp event handler */
|
||||
static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param);
|
||||
/* avrc event handler */
|
||||
static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param);
|
||||
/* avrc CT event handler */
|
||||
static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param);
|
||||
/* avrc TG event handler */
|
||||
static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param);
|
||||
|
||||
static uint32_t m_pkt_cnt = 0;
|
||||
static esp_a2d_audio_state_t m_audio_state = ESP_A2D_AUDIO_STATE_STOPPED;
|
||||
static const char *m_a2d_conn_state_str[] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
|
||||
static const char *m_a2d_audio_state_str[] = {"Suspended", "Stopped", "Started"};
|
||||
static uint32_t s_pkt_cnt = 0;
|
||||
static esp_a2d_audio_state_t s_audio_state = ESP_A2D_AUDIO_STATE_STOPPED;
|
||||
static const char *s_a2d_conn_state_str[] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
|
||||
static const char *s_a2d_audio_state_str[] = {"Suspended", "Stopped", "Started"};
|
||||
static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
|
||||
static _lock_t s_volume_lock;
|
||||
static xTaskHandle s_vcs_task_hdl = NULL;
|
||||
static uint8_t s_volume = 0;
|
||||
static bool s_volume_notify;
|
||||
|
||||
/* callback for A2DP sink */
|
||||
void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||
@ -55,8 +71,8 @@ void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
size_t bytes_written;
|
||||
i2s_write(0, data, len, &bytes_written, portMAX_DELAY);
|
||||
if (++m_pkt_cnt % 100 == 0) {
|
||||
ESP_LOGI(BT_AV_TAG, "Audio packet count %u", m_pkt_cnt);
|
||||
if (++s_pkt_cnt % 100 == 0) {
|
||||
ESP_LOGI(BT_AV_TAG, "Audio packet count %u", s_pkt_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,10 +80,6 @@ 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);
|
||||
if(!attr_text) {
|
||||
ESP_LOGI(BT_AV_TAG, "malloc failed ");
|
||||
return;
|
||||
}
|
||||
memcpy(attr_text, rc->meta_rsp.attr_text, rc->meta_rsp.attr_length);
|
||||
attr_text[rc->meta_rsp.attr_length] = 0;
|
||||
|
||||
@ -83,12 +95,29 @@ void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param
|
||||
case ESP_AVRC_CT_CONNECTION_STATE_EVT:
|
||||
case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT:
|
||||
case ESP_AVRC_CT_CHANGE_NOTIFY_EVT:
|
||||
case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
|
||||
bt_app_work_dispatch(bt_av_hdl_avrc_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
|
||||
case ESP_AVRC_CT_REMOTE_FEATURES_EVT:
|
||||
case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: {
|
||||
bt_app_work_dispatch(bt_av_hdl_avrc_ct_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(BT_AV_TAG, "Invalid AVRC event: %d", event);
|
||||
ESP_LOGE(BT_RC_CT_TAG, "Invalid AVRC event: %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bt_app_rc_tg_cb(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_AVRC_TG_CONNECTION_STATE_EVT:
|
||||
case ESP_AVRC_TG_REMOTE_FEATURES_EVT:
|
||||
case ESP_AVRC_TG_PASSTHROUGH_CMD_EVT:
|
||||
case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT:
|
||||
case ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT:
|
||||
bt_app_work_dispatch(bt_av_hdl_avrc_tg_evt, event, param, sizeof(esp_avrc_tg_cb_param_t), NULL);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(BT_RC_TG_TAG, "Invalid AVRC event: %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -102,15 +131,20 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||
uint8_t *bda = a2d->conn_stat.remote_bda;
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP connection state: %s, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
m_a2d_conn_state_str[a2d->conn_stat.state], bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
s_a2d_conn_state_str[a2d->conn_stat.state], bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
||||
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED){
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_A2D_AUDIO_STATE_EVT: {
|
||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP audio state: %s", m_a2d_audio_state_str[a2d->audio_stat.state]);
|
||||
m_audio_state = a2d->audio_stat.state;
|
||||
ESP_LOGI(BT_AV_TAG, "A2DP audio state: %s", s_a2d_audio_state_str[a2d->audio_stat.state]);
|
||||
s_audio_state = a2d->audio_stat.state;
|
||||
if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state) {
|
||||
m_pkt_cnt = 0;
|
||||
s_pkt_cnt = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -130,7 +164,7 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
}
|
||||
i2s_set_clk(0, sample_rate, 16, 2);
|
||||
|
||||
ESP_LOGI(BT_AV_TAG, "Configure audio player 0x%x-0x%x-0x%x-0x%x",
|
||||
ESP_LOGI(BT_AV_TAG, "Configure audio player %x-%x-%x-%x",
|
||||
a2d->audio_cfg.mcc.cie.sbc[0],
|
||||
a2d->audio_cfg.mcc.cie.sbc[1],
|
||||
a2d->audio_cfg.mcc.cie.sbc[2],
|
||||
@ -145,57 +179,182 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_new_track()
|
||||
static void bt_av_new_track(void)
|
||||
{
|
||||
//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);
|
||||
// request metadata
|
||||
uint8_t attr_mask = ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_ARTIST | ESP_AVRC_MD_ATTR_ALBUM | ESP_AVRC_MD_ATTR_GENRE;
|
||||
esp_avrc_ct_send_metadata_cmd(APP_RC_CT_TL_GET_META_DATA, attr_mask);
|
||||
|
||||
// register notification if peer support the event_id
|
||||
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
|
||||
ESP_AVRC_RN_TRACK_CHANGE)) {
|
||||
esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_TRACK_CHANGE, ESP_AVRC_RN_TRACK_CHANGE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_av_notify_evt_handler(uint8_t event_id, uint32_t event_parameter)
|
||||
static void bt_av_playback_changed(void)
|
||||
{
|
||||
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
|
||||
ESP_AVRC_RN_PLAY_STATUS_CHANGE)) {
|
||||
esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_PLAYBACK_CHANGE, ESP_AVRC_RN_PLAY_STATUS_CHANGE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_play_pos_changed(void)
|
||||
{
|
||||
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
|
||||
ESP_AVRC_RN_PLAY_POS_CHANGED)) {
|
||||
esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_PLAY_POS_CHANGE, ESP_AVRC_RN_PLAY_POS_CHANGED, 10);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
|
||||
{
|
||||
switch (event_id) {
|
||||
case ESP_AVRC_RN_TRACK_CHANGE:
|
||||
bt_av_new_track();
|
||||
break;
|
||||
case ESP_AVRC_RN_PLAY_STATUS_CHANGE:
|
||||
ESP_LOGI(BT_AV_TAG, "Playback status changed: 0x%x", event_parameter->playback);
|
||||
bt_av_playback_changed();
|
||||
break;
|
||||
case ESP_AVRC_RN_PLAY_POS_CHANGED:
|
||||
ESP_LOGI(BT_AV_TAG, "Play position changed: %d-ms", event_parameter->play_pos);
|
||||
bt_av_play_pos_changed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param)
|
||||
static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
|
||||
{
|
||||
ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
|
||||
ESP_LOGD(BT_RC_CT_TAG, "%s evt %d", __func__, event);
|
||||
esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(p_param);
|
||||
switch (event) {
|
||||
case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
|
||||
uint8_t *bda = rc->conn_stat.remote_bda;
|
||||
ESP_LOGI(BT_AV_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
|
||||
if (rc->conn_stat.connected) {
|
||||
bt_av_new_track();
|
||||
// get remote supported event_ids of peer AVRCP Target
|
||||
esp_avrc_ct_send_get_rn_capabilities_cmd(APP_RC_CT_TL_GET_CAPS);
|
||||
} else {
|
||||
// clear peer notification capability record
|
||||
s_avrc_peer_rn_cap.bits = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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_RC_CT_TAG, "AVRC passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state);
|
||||
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);
|
||||
ESP_LOGI(BT_RC_CT_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);
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRC event notification: %d", rc->change_ntf.event_id);
|
||||
bt_av_notify_evt_handler(rc->change_ntf.event_id, &rc->change_ntf.event_parameter);
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
|
||||
ESP_LOGI(BT_AV_TAG, "AVRC remote features 0x%x", rc->rmt_feats.feat_mask);
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRC remote features %x, TG features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.tg_feat_flag);
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: {
|
||||
ESP_LOGI(BT_RC_CT_TAG, "remote rn_cap: count %d, bitmask 0x%x", rc->get_rn_caps_rsp.cap_count,
|
||||
rc->get_rn_caps_rsp.evt_set.bits);
|
||||
s_avrc_peer_rn_cap.bits = rc->get_rn_caps_rsp.evt_set.bits;
|
||||
bt_av_new_track();
|
||||
bt_av_playback_changed();
|
||||
bt_av_play_pos_changed();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
|
||||
ESP_LOGE(BT_RC_CT_TAG, "%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void volume_set_by_controller(uint8_t volume)
|
||||
{
|
||||
ESP_LOGI(BT_RC_TG_TAG, "Volume is set by remote controller %d%%\n", (uint32_t)volume * 100 / 0x7f);
|
||||
_lock_acquire(&s_volume_lock);
|
||||
s_volume = volume;
|
||||
_lock_release(&s_volume_lock);
|
||||
}
|
||||
|
||||
static void volume_set_by_local_host(uint8_t volume)
|
||||
{
|
||||
ESP_LOGI(BT_RC_TG_TAG, "Volume is set locally to: %d%%", (uint32_t)volume * 100 / 0x7f);
|
||||
_lock_acquire(&s_volume_lock);
|
||||
s_volume = volume;
|
||||
_lock_release(&s_volume_lock);
|
||||
|
||||
if (s_volume_notify) {
|
||||
esp_avrc_rn_param_t rn_param;
|
||||
rn_param.volume = s_volume;
|
||||
esp_avrc_tg_send_rn_rsp(ESP_AVRC_RN_VOLUME_CHANGE, ESP_AVRC_RN_RSP_CHANGED, &rn_param);
|
||||
s_volume_notify = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void volume_change_simulation(void *arg)
|
||||
{
|
||||
ESP_LOGI(BT_RC_TG_TAG, "start volume change simulation");
|
||||
|
||||
for (;;) {
|
||||
vTaskDelay(10000 / portTICK_RATE_MS);
|
||||
|
||||
uint8_t volume = (s_volume + 5) & 0x7f;
|
||||
volume_set_by_local_host(volume);
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param)
|
||||
{
|
||||
ESP_LOGD(BT_RC_TG_TAG, "%s evt %d", __func__, event);
|
||||
esp_avrc_tg_cb_param_t *rc = (esp_avrc_tg_cb_param_t *)(p_param);
|
||||
switch (event) {
|
||||
case ESP_AVRC_TG_CONNECTION_STATE_EVT: {
|
||||
uint8_t *bda = rc->conn_stat.remote_bda;
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
if (rc->conn_stat.connected) {
|
||||
// create task to simulate volume change
|
||||
xTaskCreate(volume_change_simulation, "vcsT", 2048, NULL, 5, &s_vcs_task_hdl);
|
||||
} else {
|
||||
vTaskDelete(s_vcs_task_hdl);
|
||||
ESP_LOGI(BT_RC_TG_TAG, "Stop volume change simulation");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_TG_PASSTHROUGH_CMD_EVT: {
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC passthrough cmd: key_code 0x%x, key_state %d", rc->psth_cmd.key_code, rc->psth_cmd.key_state);
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT: {
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC set absolute volume: %d%%", (int)rc->set_abs_vol.volume * 100/ 0x7f);
|
||||
volume_set_by_controller(rc->set_abs_vol.volume);
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT: {
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC register event notification: %d, param: 0x%x", rc->reg_ntf.event_id, rc->reg_ntf.event_parameter);
|
||||
if (rc->reg_ntf.event_id == ESP_AVRC_RN_VOLUME_CHANGE) {
|
||||
s_volume_notify = true;
|
||||
esp_avrc_rn_param_t rn_param;
|
||||
rn_param.volume = s_volume;
|
||||
esp_avrc_tg_send_rn_rsp(ESP_AVRC_RN_VOLUME_CHANGE, ESP_AVRC_RN_RSP_INTERIM, &rn_param);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_TG_REMOTE_FEATURES_EVT: {
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC remote features %x, CT features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.ct_feat_flag);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(BT_RC_TG_TAG, "%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "esp_avrc_api.h"
|
||||
|
||||
#define BT_AV_TAG "BT_AV"
|
||||
#define BT_RC_TG_TAG "RCTG"
|
||||
#define BT_RC_CT_TAG "RCCT"
|
||||
|
||||
/**
|
||||
* @brief callback function for A2DP sink
|
||||
@ -30,4 +32,9 @@ void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len);
|
||||
*/
|
||||
void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param);
|
||||
|
||||
/**
|
||||
* @brief callback function for AVRCP target
|
||||
*/
|
||||
void bt_app_rc_tg_cb(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t *param);
|
||||
|
||||
#endif /* __BT_APP_AV_H__*/
|
||||
|
@ -21,14 +21,15 @@ static void bt_app_task_handler(void *arg);
|
||||
static bool bt_app_send_msg(bt_app_msg_t *msg);
|
||||
static void bt_app_work_dispatched(bt_app_msg_t *msg);
|
||||
|
||||
static xQueueHandle bt_app_task_queue = NULL;
|
||||
static xTaskHandle bt_app_task_handle = NULL;
|
||||
static xQueueHandle s_bt_app_task_queue = NULL;
|
||||
static xTaskHandle s_bt_app_task_handle = NULL;
|
||||
|
||||
bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback)
|
||||
{
|
||||
ESP_LOGD(BT_APP_CORE_TAG, "%s event 0x%x, param len %d", __func__, event, param_len);
|
||||
|
||||
bt_app_msg_t msg = { };
|
||||
bt_app_msg_t msg;
|
||||
memset(&msg, 0, sizeof(bt_app_msg_t));
|
||||
|
||||
msg.sig = BT_APP_SIG_WORK_DISPATCH;
|
||||
msg.event = event;
|
||||
@ -56,7 +57,7 @@ static bool bt_app_send_msg(bt_app_msg_t *msg)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xQueueSend(bt_app_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
|
||||
if (xQueueSend(s_bt_app_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
|
||||
ESP_LOGE(BT_APP_CORE_TAG, "%s xQueue send failed", __func__);
|
||||
return false;
|
||||
}
|
||||
@ -74,14 +75,14 @@ static void bt_app_task_handler(void *arg)
|
||||
{
|
||||
bt_app_msg_t msg;
|
||||
for (;;) {
|
||||
if (pdTRUE == xQueueReceive(bt_app_task_queue, &msg, (portTickType)portMAX_DELAY)) {
|
||||
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (portTickType)portMAX_DELAY)) {
|
||||
ESP_LOGD(BT_APP_CORE_TAG, "%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
|
||||
switch (msg.sig) {
|
||||
case BT_APP_SIG_WORK_DISPATCH:
|
||||
bt_app_work_dispatched(&msg);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(BT_APP_CORE_TAG, "%s, unhandled sig: 0x%x", __func__, msg.sig);
|
||||
ESP_LOGW(BT_APP_CORE_TAG, "%s, unhandled sig: %d", __func__, msg.sig);
|
||||
break;
|
||||
} // switch (msg.sig)
|
||||
|
||||
@ -94,19 +95,19 @@ static void bt_app_task_handler(void *arg)
|
||||
|
||||
void bt_app_task_start_up(void)
|
||||
{
|
||||
bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
||||
xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, bt_app_task_handle);
|
||||
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
||||
xTaskCreate(bt_app_task_handler, "BtAppT", 3072, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
void bt_app_task_shut_down(void)
|
||||
{
|
||||
if (bt_app_task_handle) {
|
||||
vTaskDelete(bt_app_task_handle);
|
||||
bt_app_task_handle = NULL;
|
||||
if (s_bt_app_task_handle) {
|
||||
vTaskDelete(s_bt_app_task_handle);
|
||||
s_bt_app_task_handle = NULL;
|
||||
}
|
||||
if (bt_app_task_queue) {
|
||||
vQueueDelete(bt_app_task_queue);
|
||||
bt_app_task_queue = NULL;
|
||||
if (s_bt_app_task_queue) {
|
||||
vQueueDelete(s_bt_app_task_queue);
|
||||
s_bt_app_task_queue = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -599,6 +599,39 @@ static void ble_gatts_init(void)
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "set local MTU failed, error code = 0x%x", local_mtu_ret);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_BT_GAP_AUTH_CMPL_EVT: {
|
||||
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGI(BT_BLE_COEX_TAG, "authentication success: %s", param->auth_cmpl.device_name);
|
||||
esp_log_buffer_hex(BT_BLE_COEX_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
|
||||
} else {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if (CONFIG_BT_SSP_ENABLED == true)
|
||||
case ESP_BT_GAP_CFM_REQ_EVT:
|
||||
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
|
||||
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
|
||||
break;
|
||||
case ESP_BT_GAP_KEY_NOTIF_EVT:
|
||||
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
|
||||
break;
|
||||
case ESP_BT_GAP_KEY_REQ_EVT:
|
||||
ESP_LOGI(BT_BLE_COEX_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
|
||||
break;
|
||||
#endif
|
||||
default: {
|
||||
ESP_LOGI(BT_BLE_COEX_TAG, "event: %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* handler for bluetooth stack enabled events */
|
||||
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
{
|
||||
@ -608,14 +641,23 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
/* set up bt device name */
|
||||
esp_bt_dev_set_device_name(BT_DEVICE_NAME);
|
||||
|
||||
/* initialize A2DP sink */
|
||||
esp_a2d_register_callback(&bt_app_a2d_cb);
|
||||
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
|
||||
esp_a2d_sink_init();
|
||||
esp_bt_gap_register_callback(bt_app_gap_cb);
|
||||
|
||||
/* initialize AVRCP controller */
|
||||
esp_avrc_ct_init();
|
||||
esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
|
||||
/* initialize AVRCP target */
|
||||
assert (esp_avrc_tg_init() == ESP_OK);
|
||||
esp_avrc_tg_register_callback(bt_app_rc_tg_cb);
|
||||
|
||||
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);
|
||||
|
||||
/* initialize A2DP sink */
|
||||
esp_a2d_register_callback(&bt_app_a2d_cb);
|
||||
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
|
||||
esp_a2d_sink_init();
|
||||
|
||||
/* set discoverable and connectable mode, wait to be connected */
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
||||
@ -629,26 +671,24 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
// Initialize NVS.
|
||||
ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
/* Initialize NVS — it is used to store PHY calibration data */
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( ret );
|
||||
ESP_ERROR_CHECK(err);
|
||||
|
||||
i2s_config_t i2s_config = {
|
||||
#ifdef CONFIG_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
.mode = I2S_MODE_DAC_BUILT_IN,
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
|
||||
#else
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
|
||||
#endif
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = 16,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 60,
|
||||
.intr_alloc_flags = 0, //Default interrupt priority
|
||||
@ -658,6 +698,7 @@ void app_main()
|
||||
|
||||
i2s_driver_install(0, &i2s_config, 0, NULL);
|
||||
#ifdef CONFIG_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
|
||||
i2s_set_pin(0, NULL);
|
||||
#else
|
||||
i2s_pin_config_t pin_config = {
|
||||
@ -671,34 +712,51 @@ void app_main()
|
||||
#endif
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "%s initialize controller failed\n", __func__);
|
||||
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
if (ret) {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "%s enable controller failed\n", __func__);
|
||||
if ((err = esp_bt_controller_enable(ESP_BT_MODE_BTDM)) != ESP_OK) {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "%s init bluetooth failed\n", __func__);
|
||||
if ((err = esp_bluedroid_init()) != ESP_OK) {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "%s enable bluetooth failed\n", __func__);
|
||||
|
||||
if ((err = esp_bluedroid_enable()) != ESP_OK) {
|
||||
ESP_LOGE(BT_BLE_COEX_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* create application task */
|
||||
bt_app_task_start_up();
|
||||
|
||||
/* Bluetooth device name, connection mode and profile set up */
|
||||
bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
|
||||
|
||||
#if (CONFIG_BT_SSP_ENABLED == true)
|
||||
/* Set default parameters for Secure Simple Pairing */
|
||||
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
|
||||
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
|
||||
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set default parameters for Legacy Pairing
|
||||
* Use fixed pin code
|
||||
*/
|
||||
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
|
||||
esp_bt_pin_code_t pin_code;
|
||||
pin_code[0] = '1';
|
||||
pin_code[1] = '2';
|
||||
pin_code[2] = '3';
|
||||
pin_code[3] = '4';
|
||||
esp_bt_gap_set_pin(pin_type, 4, pin_code);
|
||||
|
||||
//gatt server init
|
||||
ble_gatts_init();
|
||||
}
|
||||
|
@ -25,15 +25,31 @@
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s.h"
|
||||
|
||||
#include "sys/lock.h"
|
||||
|
||||
// AVRCP used transaction label
|
||||
#define APP_RC_CT_TL_GET_CAPS (0)
|
||||
#define APP_RC_CT_TL_GET_META_DATA (1)
|
||||
#define APP_RC_CT_TL_RN_TRACK_CHANGE (2)
|
||||
#define APP_RC_CT_TL_RN_PLAYBACK_CHANGE (3)
|
||||
#define APP_RC_CT_TL_RN_PLAY_POS_CHANGE (4)
|
||||
|
||||
/* a2dp event handler */
|
||||
static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param);
|
||||
/* avrc event handler */
|
||||
static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param);
|
||||
/* avrc CT event handler */
|
||||
static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param);
|
||||
/* avrc TG event handler */
|
||||
static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param);
|
||||
|
||||
static uint32_t s_pkt_cnt = 0;
|
||||
static esp_a2d_audio_state_t s_audio_state = ESP_A2D_AUDIO_STATE_STOPPED;
|
||||
static const char *s_a2d_conn_state_str[] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
|
||||
static const char *s_a2d_audio_state_str[] = {"Suspended", "Stopped", "Started"};
|
||||
static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
|
||||
static _lock_t s_volume_lock;
|
||||
static xTaskHandle s_vcs_task_hdl = NULL;
|
||||
static uint8_t s_volume = 0;
|
||||
static bool s_volume_notify;
|
||||
|
||||
/* callback for A2DP sink */
|
||||
void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||
@ -79,12 +95,29 @@ void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param
|
||||
case ESP_AVRC_CT_CONNECTION_STATE_EVT:
|
||||
case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT:
|
||||
case ESP_AVRC_CT_CHANGE_NOTIFY_EVT:
|
||||
case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
|
||||
bt_app_work_dispatch(bt_av_hdl_avrc_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
|
||||
case ESP_AVRC_CT_REMOTE_FEATURES_EVT:
|
||||
case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: {
|
||||
bt_app_work_dispatch(bt_av_hdl_avrc_ct_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(BT_AV_TAG, "Invalid AVRC event: %d", event);
|
||||
ESP_LOGE(BT_RC_CT_TAG, "Invalid AVRC event: %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bt_app_rc_tg_cb(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_AVRC_TG_CONNECTION_STATE_EVT:
|
||||
case ESP_AVRC_TG_REMOTE_FEATURES_EVT:
|
||||
case ESP_AVRC_TG_PASSTHROUGH_CMD_EVT:
|
||||
case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT:
|
||||
case ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT:
|
||||
bt_app_work_dispatch(bt_av_hdl_avrc_tg_evt, event, param, sizeof(esp_avrc_tg_cb_param_t), NULL);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(BT_RC_TG_TAG, "Invalid AVRC event: %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -146,57 +179,182 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_new_track()
|
||||
static void bt_av_new_track(void)
|
||||
{
|
||||
//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);
|
||||
// request metadata
|
||||
uint8_t attr_mask = ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_ARTIST | ESP_AVRC_MD_ATTR_ALBUM | ESP_AVRC_MD_ATTR_GENRE;
|
||||
esp_avrc_ct_send_metadata_cmd(APP_RC_CT_TL_GET_META_DATA, attr_mask);
|
||||
|
||||
// register notification if peer support the event_id
|
||||
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
|
||||
ESP_AVRC_RN_TRACK_CHANGE)) {
|
||||
esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_TRACK_CHANGE, ESP_AVRC_RN_TRACK_CHANGE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_av_notify_evt_handler(uint8_t event_id, uint32_t event_parameter)
|
||||
static void bt_av_playback_changed(void)
|
||||
{
|
||||
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
|
||||
ESP_AVRC_RN_PLAY_STATUS_CHANGE)) {
|
||||
esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_PLAYBACK_CHANGE, ESP_AVRC_RN_PLAY_STATUS_CHANGE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_play_pos_changed(void)
|
||||
{
|
||||
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
|
||||
ESP_AVRC_RN_PLAY_POS_CHANGED)) {
|
||||
esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_PLAY_POS_CHANGE, ESP_AVRC_RN_PLAY_POS_CHANGED, 10);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
|
||||
{
|
||||
switch (event_id) {
|
||||
case ESP_AVRC_RN_TRACK_CHANGE:
|
||||
bt_av_new_track();
|
||||
break;
|
||||
case ESP_AVRC_RN_PLAY_STATUS_CHANGE:
|
||||
ESP_LOGI(BT_AV_TAG, "Playback status changed: 0x%x", event_parameter->playback);
|
||||
bt_av_playback_changed();
|
||||
break;
|
||||
case ESP_AVRC_RN_PLAY_POS_CHANGED:
|
||||
ESP_LOGI(BT_AV_TAG, "Play position changed: %d-ms", event_parameter->play_pos);
|
||||
bt_av_play_pos_changed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param)
|
||||
static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
|
||||
{
|
||||
ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
|
||||
ESP_LOGD(BT_RC_CT_TAG, "%s evt %d", __func__, event);
|
||||
esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(p_param);
|
||||
switch (event) {
|
||||
case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
|
||||
uint8_t *bda = rc->conn_stat.remote_bda;
|
||||
ESP_LOGI(BT_AV_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
|
||||
if (rc->conn_stat.connected) {
|
||||
bt_av_new_track();
|
||||
// get remote supported event_ids of peer AVRCP Target
|
||||
esp_avrc_ct_send_get_rn_capabilities_cmd(APP_RC_CT_TL_GET_CAPS);
|
||||
} else {
|
||||
// clear peer notification capability record
|
||||
s_avrc_peer_rn_cap.bits = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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_RC_CT_TAG, "AVRC passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state);
|
||||
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);
|
||||
ESP_LOGI(BT_RC_CT_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);
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRC event notification: %d", rc->change_ntf.event_id);
|
||||
bt_av_notify_evt_handler(rc->change_ntf.event_id, &rc->change_ntf.event_parameter);
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
|
||||
ESP_LOGI(BT_AV_TAG, "AVRC remote features %x", rc->rmt_feats.feat_mask);
|
||||
ESP_LOGI(BT_RC_CT_TAG, "AVRC remote features %x, TG features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.tg_feat_flag);
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT: {
|
||||
ESP_LOGI(BT_RC_CT_TAG, "remote rn_cap: count %d, bitmask 0x%x", rc->get_rn_caps_rsp.cap_count,
|
||||
rc->get_rn_caps_rsp.evt_set.bits);
|
||||
s_avrc_peer_rn_cap.bits = rc->get_rn_caps_rsp.evt_set.bits;
|
||||
bt_av_new_track();
|
||||
bt_av_playback_changed();
|
||||
bt_av_play_pos_changed();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
|
||||
ESP_LOGE(BT_RC_CT_TAG, "%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void volume_set_by_controller(uint8_t volume)
|
||||
{
|
||||
ESP_LOGI(BT_RC_TG_TAG, "Volume is set by remote controller %d%%\n", (uint32_t)volume * 100 / 0x7f);
|
||||
_lock_acquire(&s_volume_lock);
|
||||
s_volume = volume;
|
||||
_lock_release(&s_volume_lock);
|
||||
}
|
||||
|
||||
static void volume_set_by_local_host(uint8_t volume)
|
||||
{
|
||||
ESP_LOGI(BT_RC_TG_TAG, "Volume is set locally to: %d%%", (uint32_t)volume * 100 / 0x7f);
|
||||
_lock_acquire(&s_volume_lock);
|
||||
s_volume = volume;
|
||||
_lock_release(&s_volume_lock);
|
||||
|
||||
if (s_volume_notify) {
|
||||
esp_avrc_rn_param_t rn_param;
|
||||
rn_param.volume = s_volume;
|
||||
esp_avrc_tg_send_rn_rsp(ESP_AVRC_RN_VOLUME_CHANGE, ESP_AVRC_RN_RSP_CHANGED, &rn_param);
|
||||
s_volume_notify = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void volume_change_simulation(void *arg)
|
||||
{
|
||||
ESP_LOGI(BT_RC_TG_TAG, "start volume change simulation");
|
||||
|
||||
for (;;) {
|
||||
vTaskDelay(10000 / portTICK_RATE_MS);
|
||||
|
||||
uint8_t volume = (s_volume + 5) & 0x7f;
|
||||
volume_set_by_local_host(volume);
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_hdl_avrc_tg_evt(uint16_t event, void *p_param)
|
||||
{
|
||||
ESP_LOGD(BT_RC_TG_TAG, "%s evt %d", __func__, event);
|
||||
esp_avrc_tg_cb_param_t *rc = (esp_avrc_tg_cb_param_t *)(p_param);
|
||||
switch (event) {
|
||||
case ESP_AVRC_TG_CONNECTION_STATE_EVT: {
|
||||
uint8_t *bda = rc->conn_stat.remote_bda;
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
if (rc->conn_stat.connected) {
|
||||
// create task to simulate volume change
|
||||
xTaskCreate(volume_change_simulation, "vcsT", 2048, NULL, 5, &s_vcs_task_hdl);
|
||||
} else {
|
||||
vTaskDelete(s_vcs_task_hdl);
|
||||
ESP_LOGI(BT_RC_TG_TAG, "Stop volume change simulation");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_TG_PASSTHROUGH_CMD_EVT: {
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC passthrough cmd: key_code 0x%x, key_state %d", rc->psth_cmd.key_code, rc->psth_cmd.key_state);
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT: {
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC set absolute volume: %d%%", (int)rc->set_abs_vol.volume * 100/ 0x7f);
|
||||
volume_set_by_controller(rc->set_abs_vol.volume);
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT: {
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC register event notification: %d, param: 0x%x", rc->reg_ntf.event_id, rc->reg_ntf.event_parameter);
|
||||
if (rc->reg_ntf.event_id == ESP_AVRC_RN_VOLUME_CHANGE) {
|
||||
s_volume_notify = true;
|
||||
esp_avrc_rn_param_t rn_param;
|
||||
rn_param.volume = s_volume;
|
||||
esp_avrc_tg_send_rn_rsp(ESP_AVRC_RN_VOLUME_CHANGE, ESP_AVRC_RN_RSP_INTERIM, &rn_param);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_TG_REMOTE_FEATURES_EVT: {
|
||||
ESP_LOGI(BT_RC_TG_TAG, "AVRC remote features %x, CT features %x", rc->rmt_feats.feat_mask, rc->rmt_feats.ct_feat_flag);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(BT_RC_TG_TAG, "%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "esp_avrc_api.h"
|
||||
|
||||
#define BT_AV_TAG "BT_AV"
|
||||
#define BT_RC_TG_TAG "RCTG"
|
||||
#define BT_RC_CT_TAG "RCCT"
|
||||
|
||||
/**
|
||||
* @brief callback function for A2DP sink
|
||||
@ -30,4 +32,9 @@ void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len);
|
||||
*/
|
||||
void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param);
|
||||
|
||||
/**
|
||||
* @brief callback function for AVRCP target
|
||||
*/
|
||||
void bt_app_rc_tg_cb(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t *param);
|
||||
|
||||
#endif /* __BT_APP_AV_H__*/
|
||||
|
@ -96,7 +96,7 @@ static void bt_app_task_handler(void *arg)
|
||||
void bt_app_task_start_up(void)
|
||||
{
|
||||
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
||||
xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle);
|
||||
xTaskCreate(bt_app_task_handler, "BtAppT", 3072, NULL, configMAX_PRIORITIES - 3, &s_bt_app_task_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,7 @@ void app_main()
|
||||
pin_code[2] = '3';
|
||||
pin_code[3] = '4';
|
||||
esp_bt_gap_set_pin(pin_type, 4, pin_code);
|
||||
|
||||
}
|
||||
|
||||
void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||
@ -177,14 +178,22 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
esp_bt_dev_set_device_name(dev_name);
|
||||
|
||||
esp_bt_gap_register_callback(bt_app_gap_cb);
|
||||
/* initialize A2DP sink */
|
||||
esp_a2d_register_callback(&bt_app_a2d_cb);
|
||||
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
|
||||
esp_a2d_sink_init();
|
||||
|
||||
/* initialize AVRCP controller */
|
||||
esp_avrc_ct_init();
|
||||
esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
|
||||
/* initialize AVRCP target */
|
||||
assert (esp_avrc_tg_init() == ESP_OK);
|
||||
esp_avrc_tg_register_callback(bt_app_rc_tg_cb);
|
||||
|
||||
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);
|
||||
|
||||
/* initialize A2DP sink */
|
||||
esp_a2d_register_callback(&bt_app_a2d_cb);
|
||||
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
|
||||
esp_a2d_sink_init();
|
||||
|
||||
/* set discoverable and connectable mode, wait to be connected */
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
||||
|
Loading…
Reference in New Issue
Block a user