mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/btdm_avrcp_volume' into 'master'
components/bt: Add AVRCP feature about volume See merge request idf/esp-idf!5209
This commit is contained in:
commit
70474ae844
@ -29,7 +29,7 @@ esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback)
|
||||
}
|
||||
|
||||
if (callback == NULL) {
|
||||
return ESP_FAIL;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_profile_cb_set(BTC_PID_AVRC_CT, callback);
|
||||
@ -76,8 +76,8 @@ esp_err_t esp_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t attr_id, uin
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tl >= 16 || attr_id > ESP_AVRC_PS_MAX_ATTR - 1) {
|
||||
return ESP_FAIL;
|
||||
if (tl > ESP_AVRC_TRANS_LABEL_MAX || attr_id > ESP_AVRC_PS_MAX_ATTR - 1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
@ -103,7 +103,7 @@ esp_err_t esp_avrc_ct_send_get_rn_capabilities_cmd(uint8_t tl)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tl >= 16) {
|
||||
if (tl > ESP_AVRC_TRANS_LABEL_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
@ -128,8 +128,8 @@ esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_i
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tl >= 16 || event_id > ESP_AVRC_RN_MAX_EVT - 1) {
|
||||
return ESP_FAIL;
|
||||
if (tl > ESP_AVRC_TRANS_LABEL_MAX || event_id > ESP_AVRC_RN_MAX_EVT - 1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!btc_avrc_ct_rn_evt_supported(event_id)) {
|
||||
@ -153,14 +153,48 @@ esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_i
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_ct_send_set_absolute_volume_cmd(uint8_t tl, uint8_t volume)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tl > ESP_AVRC_TRANS_LABEL_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (volume > BTC_AVRC_MAX_VOLUME) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!btc_avrc_ct_rn_evt_supported(ESP_AVRC_RN_VOLUME_CHANGE)) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_AVRC_CT;
|
||||
msg.act = BTC_AVRC_CTRL_API_SND_SET_ABSOLUTE_VOLUME_EVT;
|
||||
|
||||
btc_avrc_args_t arg;
|
||||
memset(&arg, 0, sizeof(btc_avrc_args_t));
|
||||
|
||||
arg.set_abs_vol_cmd.tl = tl;
|
||||
arg.set_abs_vol_cmd.volume = volume;
|
||||
|
||||
/* Switch to BTC context */
|
||||
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_args_t), NULL);
|
||||
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_avrc_ct_send_metadata_cmd(uint8_t tl, uint8_t attr_mask)
|
||||
{
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tl >= 16) {
|
||||
return ESP_FAIL;
|
||||
if (tl > ESP_AVRC_TRANS_LABEL_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
@ -185,8 +219,8 @@ esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tl >= 16 || key_state > ESP_AVRC_PT_CMD_STATE_RELEASED) {
|
||||
return ESP_FAIL;
|
||||
if (tl > ESP_AVRC_TRANS_LABEL_MAX || key_state > ESP_AVRC_PT_CMD_STATE_RELEASED) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
@ -217,7 +251,7 @@ esp_err_t esp_avrc_tg_register_callback(esp_avrc_tg_cb_t callback)
|
||||
}
|
||||
|
||||
if (callback == NULL) {
|
||||
return ESP_FAIL;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_profile_cb_set(BTC_PID_AVRC_TG, callback);
|
||||
@ -445,7 +479,7 @@ esp_err_t esp_avrc_tg_send_rn_rsp(esp_avrc_rn_event_ids_t event_id, esp_avrc_rn_
|
||||
/* 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 */
|
||||
|
@ -24,6 +24,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_AVRC_TRANS_LABEL_MAX 15 /*!< max transaction label */
|
||||
|
||||
/// AVRC feature bit mask
|
||||
typedef enum {
|
||||
ESP_AVRC_FEAT_RCTG = 0x0001, /*!< remote control target */
|
||||
@ -140,6 +142,7 @@ typedef enum {
|
||||
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_SET_ABSOLUTE_VOLUME_RSP_EVT = 7, /*!< set absolute volume response event */
|
||||
} esp_avrc_ct_cb_event_t;
|
||||
|
||||
/// AVRC Target callback events
|
||||
@ -327,6 +330,13 @@ typedef union {
|
||||
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 */
|
||||
|
||||
/**
|
||||
* @brief ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT
|
||||
*/
|
||||
struct avrc_ct_set_volume_rsp_param {
|
||||
uint8_t volume; /*!< the volume which has actually been set, range is 0 to 0x7f, means 0% to 100% */
|
||||
} set_volume_rsp; /*!< set absolute volume response event */
|
||||
} esp_avrc_ct_cb_param_t;
|
||||
|
||||
/// AVRC target callback parameters
|
||||
@ -460,7 +470,8 @@ esp_err_t esp_avrc_ct_send_get_rn_capabilities_cmd(uint8_t tl);
|
||||
*
|
||||
* @param[in] tl : transaction label, 0 to 15, consecutive commands should use different values.
|
||||
* @param[in] event_id : id of events, e.g. ESP_AVRC_RN_PLAY_STATUS_CHANGE, ESP_AVRC_RN_TRACK_CHANGE, etc.
|
||||
* @param[in] event_parameter : special parameters, eg. playback interval for ESP_AVRC_RN_PLAY_POS_CHANGED
|
||||
* @param[in] event_parameter : playback interval for ESP_AVRC_RN_PLAY_POS_CHANGED;
|
||||
* For other events , value of this parameter is ignored.
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled
|
||||
@ -469,6 +480,19 @@ esp_err_t esp_avrc_ct_send_get_rn_capabilities_cmd(uint8_t tl);
|
||||
*/
|
||||
esp_err_t esp_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_t event_id, uint32_t event_parameter);
|
||||
|
||||
/**
|
||||
* @brief Send set absolute volume command to AVRCP target, This function should be called after
|
||||
* ESP_AVRC_CT_CONNECTION_STATE_EVT is received and AVRCP connection is established
|
||||
*
|
||||
* @param[in] tl : transaction label, 0 to 15, consecutive commands should use different values.
|
||||
* @param[in] volume : volume, 0 to 0x7f, means 0% to 100%
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - 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_set_absolute_volume_cmd(uint8_t tl, uint8_t volume);
|
||||
|
||||
/**
|
||||
* @brief Send metadata command to AVRCP target, This function should be called after
|
||||
@ -562,22 +586,22 @@ esp_err_t esp_avrc_tg_get_psth_cmd_filter(esp_avrc_psth_filter_t filter, esp_avr
|
||||
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
* @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
|
||||
* 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()
|
||||
* 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
|
||||
* - ESP_ERR_NOT_SUPPORTED:: if filter type is ESP_AVRC_PSTH_FILTER_ALLOWED_CMD, or cmd_set
|
||||
* includes unallowed commands
|
||||
*
|
||||
*/
|
||||
@ -601,13 +625,13 @@ bool esp_avrc_psth_bit_mask_operation(esp_avrc_bit_mask_op_t op, esp_avrc_psth_b
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
* 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
|
||||
* 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
|
||||
* events selected to be supported under current configuration, The configuration can be
|
||||
* changed using esp_avrc_tg_set_rn_evt_cap()
|
||||
*
|
||||
* @return
|
||||
@ -652,7 +676,7 @@ bool esp_avrc_rn_evt_bit_mask_operation(esp_avrc_bit_mask_op_t op, esp_avrc_rn_e
|
||||
* @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()
|
||||
* 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
|
||||
|
@ -40,8 +40,10 @@ const UINT32 bta_av_meta_caps_co_ids[] = {
|
||||
AVRC_CO_BROADCOM
|
||||
};
|
||||
|
||||
/* AVRCP cupported categories */
|
||||
#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT1)
|
||||
/* AVRCP supported categories */
|
||||
#define BTA_AV_RC_SNK_SUPF_CT (AVRC_SUPF_CT_CAT1)
|
||||
#define BTA_AV_RC_SRC_SUPF_CT (AVRC_SUPF_CT_CAT2)
|
||||
|
||||
|
||||
/* Added to modify
|
||||
** 1. flush timeout
|
||||
@ -62,9 +64,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_CAT2) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
|
||||
#define BTA_AV_RC_SNK_SUPF_TG (AVRC_SUPF_TG_CAT2) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
|
||||
#define BTA_AV_RC_SRC_SUPF_TG (AVRC_SUPF_TG_CAT1) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
|
||||
#else
|
||||
#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT2)
|
||||
#define BTA_AV_RC_SNK_SUPF_TG (AVRC_SUPF_TG_CAT2)
|
||||
#define BTA_AV_RC_SRC_SUPF_TG (AVRC_SUPF_TG_CAT1)
|
||||
#endif
|
||||
|
||||
/* the MTU for the AVRCP browsing channel */
|
||||
@ -80,8 +84,10 @@ const tBTA_AV_CFG bta_av_cfg = {
|
||||
48, /* AVRCP MTU at L2CAP for control channel */
|
||||
#endif
|
||||
BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
|
||||
BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */
|
||||
BTA_AV_RC_SUPF_TG, /* AVRCP target categories */
|
||||
BTA_AV_RC_SNK_SUPF_CT, /* AVRCP controller categories as SNK */
|
||||
BTA_AV_RC_SNK_SUPF_TG, /* AVRCP target categories as SNK */
|
||||
BTA_AV_RC_SRC_SUPF_CT, /* AVRCP controller categories as SRC */
|
||||
BTA_AV_RC_SRC_SUPF_TG, /* AVRCP target categories as SRC */
|
||||
672, /* AVDTP signaling channel MTU at L2CAP */
|
||||
BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */
|
||||
bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */
|
||||
|
@ -576,9 +576,13 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
|
||||
(UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
|
||||
#endif
|
||||
|
||||
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target\n", NULL,
|
||||
p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV);
|
||||
if (p_data->api_reg.tsep == AVDT_TSEP_SRC) {
|
||||
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target\n", NULL,
|
||||
p_bta_av_cfg->avrc_src_tg_cat, BTA_ID_AV);
|
||||
} else {
|
||||
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target\n", NULL,
|
||||
p_bta_av_cfg->avrc_snk_tg_cat, BTA_ID_AV);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -711,8 +715,13 @@ static void bta_av_api_register(tBTA_AV_DATA *p_data)
|
||||
}
|
||||
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
|
||||
/* create an SDP record as AVRC CT. */
|
||||
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
|
||||
p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV);
|
||||
if (p_data->api_reg.tsep == AVDT_TSEP_SRC) {
|
||||
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, "AV Remote Control Controller\n", NULL,
|
||||
p_bta_av_cfg->avrc_src_ct_cat, BTA_ID_AV);
|
||||
} else {
|
||||
bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, "AV Remote Control Controller\n", NULL,
|
||||
p_bta_av_cfg->avrc_snk_ct_cat, BTA_ID_AV);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -529,8 +529,10 @@ typedef struct {
|
||||
UINT32 company_id; /* AVRCP Company ID */
|
||||
UINT16 avrc_mtu; /* AVRCP MTU at L2CAP for control channel */
|
||||
UINT16 avrc_br_mtu; /* AVRCP MTU at L2CAP for browsing channel */
|
||||
UINT16 avrc_ct_cat; /* AVRCP controller categories */
|
||||
UINT16 avrc_tg_cat; /* AVRCP target categories */
|
||||
UINT16 avrc_snk_ct_cat; /* AVRCP controller categories as SNK */
|
||||
UINT16 avrc_snk_tg_cat; /* AVRCP target categories SNK */
|
||||
UINT16 avrc_src_ct_cat; /* AVRCP controller categories as SRC */
|
||||
UINT16 avrc_src_tg_cat; /* AVRCP target categories as SRC */
|
||||
UINT16 sig_mtu; /* AVDTP signaling channel MTU at L2CAP */
|
||||
UINT16 audio_mtu; /* AVDTP audio transport channel MTU at L2CAP */
|
||||
const UINT16 *p_audio_flush_to;/* AVDTP audio transport channel flush timeout */
|
||||
|
@ -71,7 +71,7 @@ const static uint16_t cs_psth_allowed_cmd[8] = {
|
||||
0x0078, /* 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 */
|
||||
0x1b3F, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
|
||||
0x1b7F, /* 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 */
|
||||
@ -635,6 +635,16 @@ static void handle_rc_get_caps_rsp (tAVRC_GET_CAPS_RSP *rsp)
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_rc_set_absolute_volume_rsp(tAVRC_SET_VOLUME_RSP *rsp)
|
||||
{
|
||||
esp_avrc_ct_cb_param_t param;
|
||||
memset(¶m, 0, sizeof(esp_avrc_ct_cb_param_t));
|
||||
|
||||
param.set_volume_rsp.volume = rsp->volume;
|
||||
|
||||
btc_avrc_ct_cb_to_app(ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT, ¶m);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function handle_rc_metamsg_cmd
|
||||
*
|
||||
@ -822,6 +832,11 @@ static void handle_rc_metamsg_rsp (tBTA_AV_META_MSG *p_meta_msg)
|
||||
handle_rc_get_caps_rsp(&avrc_response.get_caps);
|
||||
}
|
||||
break;
|
||||
case AVRC_PDU_SET_ABSOLUTE_VOLUME:
|
||||
if (vendor_msg->hdr.ctype == AVRC_RSP_ACCEPT) {
|
||||
handle_rc_set_absolute_volume_rsp(&avrc_response.volume);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_WARNING("%s: unhandled meta rsp: pdu 0x%x", __FUNCTION__, avrc_response.rsp.pdu);
|
||||
}
|
||||
@ -1055,15 +1070,15 @@ static bt_status_t btc_avrc_ct_send_set_player_value_cmd(uint8_t tl, uint8_t att
|
||||
avrc_cmd.set_app_val.p_vals = &values;
|
||||
avrc_cmd.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE;
|
||||
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, BTA_AV_CMD_CTRL, p_msg);
|
||||
status = BT_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -1088,15 +1103,15 @@ static bt_status_t btc_avrc_ct_send_get_rn_caps_cmd(uint8_t tl)
|
||||
avrc_cmd.get_caps.pdu = AVRC_PDU_GET_CAPABILITIES;
|
||||
avrc_cmd.get_caps.capability_id = AVRC_CAP_EVENTS_SUPPORTED;
|
||||
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_STATUS, p_msg);
|
||||
status = BT_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -1122,15 +1137,48 @@ static bt_status_t btc_avrc_ct_send_register_notification_cmd(uint8_t tl, uint8_
|
||||
avrc_cmd.reg_notif.param = event_parameter;
|
||||
avrc_cmd.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
|
||||
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_NOTIF, p_msg);
|
||||
status = BT_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
|
||||
#else
|
||||
BTC_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static bt_status_t btc_avrc_ct_send_set_absolute_volume_cmd(uint8_t tl, uint8_t volume)
|
||||
{
|
||||
tAVRC_STS status = BT_STATUS_UNSUPPORTED;
|
||||
|
||||
#if (AVRC_METADATA_INCLUDED == TRUE)
|
||||
CHECK_ESP_RC_CONNECTED;
|
||||
|
||||
tAVRC_COMMAND avrc_cmd = {0};
|
||||
BT_HDR *p_msg = NULL;
|
||||
|
||||
avrc_cmd.volume.opcode = AVRC_OP_VENDOR;
|
||||
avrc_cmd.volume.status = AVRC_STS_NO_ERROR;
|
||||
avrc_cmd.volume.volume = volume;
|
||||
avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
|
||||
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_CTRL, p_msg);
|
||||
status = BT_STATUS_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -1164,15 +1212,15 @@ static bt_status_t btc_avrc_ct_send_metadata_cmd (uint8_t tl, uint8_t attr_mask)
|
||||
|
||||
avrc_cmd.get_elem_attrs.num_attr = index;
|
||||
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
if (btc_rc_cb.rc_features & BTA_AV_FEAT_METADATA) {
|
||||
status = AVRC_BldCommand(&avrc_cmd, &p_msg);
|
||||
if (status == AVRC_STS_NO_ERROR) {
|
||||
BTA_AvMetaCmd(btc_rc_cb.rc_handle, tl, AVRC_CMD_STATUS, p_msg);
|
||||
status = BT_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
} else {
|
||||
status = BT_STATUS_FAIL;
|
||||
BTC_TRACE_DEBUG("%s: feature not supported", __FUNCTION__);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -1338,6 +1386,10 @@ void btc_avrc_ct_call_handler(btc_msg_t *msg)
|
||||
btc_avrc_ct_send_set_player_value_cmd(arg->ps_cmd.tl, arg->ps_cmd.attr_id, arg->ps_cmd.value_id);
|
||||
break;
|
||||
}
|
||||
case BTC_AVRC_CTRL_API_SND_SET_ABSOLUTE_VOLUME_EVT: {
|
||||
btc_avrc_ct_send_set_absolute_volume_cmd(arg->set_abs_vol_cmd.tl, arg->set_abs_vol_cmd.volume);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BTC_TRACE_WARNING("%s : unhandled event: %d\n", __FUNCTION__, msg->act);
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ typedef enum {
|
||||
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_SND_SET_PLAYER_SETTING_EVT
|
||||
BTC_AVRC_CTRL_API_SND_SET_PLAYER_SETTING_EVT,
|
||||
BTC_AVRC_CTRL_API_SND_SET_ABSOLUTE_VOLUME_EVT
|
||||
} btc_avrc_act_t;
|
||||
|
||||
typedef struct {
|
||||
@ -68,6 +69,14 @@ typedef struct {
|
||||
uint8_t tl;
|
||||
} get_caps_cmd_t;
|
||||
|
||||
#define BTC_AVRC_MIN_VOLUME 0x00
|
||||
#define BTC_AVRC_MAX_VOLUME 0x7f
|
||||
|
||||
typedef struct {
|
||||
uint8_t tl;
|
||||
uint8_t volume;
|
||||
} set_abs_vol_cmd_t;
|
||||
|
||||
/* btc_avrc_args_t */
|
||||
typedef union {
|
||||
pt_cmd_t pt_cmd;
|
||||
@ -75,6 +84,7 @@ typedef union {
|
||||
rn_cmd_t rn_cmd;
|
||||
ps_cmd_t ps_cmd;
|
||||
get_caps_cmd_t get_caps_cmd;
|
||||
set_abs_vol_cmd_t set_abs_vol_cmd;
|
||||
} btc_avrc_args_t;
|
||||
|
||||
/* btc_avrc_tg_act_t */
|
||||
|
@ -27,6 +27,11 @@
|
||||
#include "esp_avrc_api.h"
|
||||
|
||||
#define BT_AV_TAG "BT_AV"
|
||||
#define BT_RC_CT_TAG "RCCT"
|
||||
|
||||
// AVRCP used transaction label
|
||||
#define APP_RC_CT_TL_GET_CAPS (0)
|
||||
#define APP_RC_CT_TL_RN_VOLUME_CHANGE (1)
|
||||
|
||||
/* event for handler "bt_av_hdl_stack_up */
|
||||
enum {
|
||||
@ -63,11 +68,17 @@ static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
|
||||
/// callback function for A2DP source audio data stream
|
||||
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len);
|
||||
|
||||
/// callback function for AVRCP controller
|
||||
static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param);
|
||||
|
||||
static void a2d_app_heart_beat(void *arg);
|
||||
|
||||
/// A2DP application state machine
|
||||
static void bt_app_av_sm_hdlr(uint16_t event, void *param);
|
||||
|
||||
/// avrc CT event handler
|
||||
static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param);
|
||||
|
||||
/* A2DP application state machine handler for each state */
|
||||
static void bt_app_av_state_unconnected(uint16_t event, void *param);
|
||||
static void bt_app_av_state_connecting(uint16_t event, void *param);
|
||||
@ -81,7 +92,7 @@ static int s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||
static int s_intv_cnt = 0;
|
||||
static int s_connecting_intv = 0;
|
||||
static uint32_t s_pkt_cnt = 0;
|
||||
|
||||
static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
|
||||
static TimerHandle_t s_tmr;
|
||||
|
||||
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
|
||||
@ -322,6 +333,14 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
/* register GAP callback function */
|
||||
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);
|
||||
|
||||
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 source */
|
||||
esp_a2d_register_callback(&bt_app_a2d_cb);
|
||||
esp_a2d_source_register_data_callback(bt_app_a2d_data_cb);
|
||||
@ -578,3 +597,98 @@ static void bt_app_av_state_disconnecting(uint16_t event, void *param)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_AVRC_CT_METADATA_RSP_EVT:
|
||||
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:
|
||||
case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT:
|
||||
case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_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_RC_CT_TAG, "Invalid AVRC event: %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_volume_changed(void)
|
||||
{
|
||||
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap,
|
||||
ESP_AVRC_RN_VOLUME_CHANGE)) {
|
||||
esp_avrc_ct_send_register_notification_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, ESP_AVRC_RN_VOLUME_CHANGE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter)
|
||||
{
|
||||
switch (event_id) {
|
||||
case ESP_AVRC_RN_VOLUME_CHANGE:
|
||||
ESP_LOGI(BT_RC_CT_TAG, "Volume changed: %d", event_parameter->volume);
|
||||
ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume: volume %d", event_parameter->volume + 5);
|
||||
esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, event_parameter->volume + 5);
|
||||
bt_av_volume_changed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
|
||||
{
|
||||
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_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) {
|
||||
// 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_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_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_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_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_volume_changed();
|
||||
break;
|
||||
}
|
||||
case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
|
||||
ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume rsp: volume %d", rc->set_volume_rsp.volume);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ESP_LOGE(BT_RC_CT_TAG, "%s unhandled evt %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user