component/bt: add AVRC controller example with simple PASSTHROUGH cmd
This commit is contained in:
parent
fa72a98635
commit
44914c17bc
|
@ -95,7 +95,7 @@ typedef struct {
|
||||||
static esp_profile_cb_t bt_av_sink_callback = NULL;
|
static esp_profile_cb_t bt_av_sink_callback = NULL;
|
||||||
|
|
||||||
static btif_av_cb_t btif_av_cb = {0};
|
static btif_av_cb_t btif_av_cb = {0};
|
||||||
// static TIMER_LIST_ENT tle_av_open_on_rc;
|
static TIMER_LIST_ENT tle_av_open_on_rc;
|
||||||
|
|
||||||
// TODO: need protection against race
|
// TODO: need protection against race
|
||||||
#define BTIF_A2D_CB_TO_APP(_event, _param) do { \
|
#define BTIF_A2D_CB_TO_APP(_event, _param) do { \
|
||||||
|
@ -125,6 +125,7 @@ else\
|
||||||
case BTA_AV_RC_FEAT_EVT: \
|
case BTA_AV_RC_FEAT_EVT: \
|
||||||
case BTA_AV_REMOTE_RSP_EVT: \
|
case BTA_AV_REMOTE_RSP_EVT: \
|
||||||
{ \
|
{ \
|
||||||
|
btif_rc_handler(e, d);\
|
||||||
}break; \
|
}break; \
|
||||||
|
|
||||||
static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data);
|
static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data);
|
||||||
|
@ -146,6 +147,9 @@ static void btif_av_event_free_data(btif_sm_event_t event, void *p_data);
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
** Extern functions
|
** Extern functions
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data);
|
||||||
|
extern BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr);
|
||||||
|
extern void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp);
|
||||||
|
|
||||||
extern tBTA_AV_CO_FUNCTS bta_av_a2d_cos;
|
extern tBTA_AV_CO_FUNCTS bta_av_a2d_cos;
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
@ -202,6 +206,34 @@ const char *dump_av_sm_event_name(btif_av_sm_event_t event)
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
** Local helper functions
|
** Local helper functions
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
** Function btif_initiate_av_open_tmr_hdlr
|
||||||
|
**
|
||||||
|
** Description Timer to trigger AV open if the remote headset establishes
|
||||||
|
** RC connection w/o AV connection. The timer is needed to IOP
|
||||||
|
** with headsets that do establish AV after RC connection.
|
||||||
|
**
|
||||||
|
** Returns void
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
static void btif_initiate_av_open_tmr_hdlr(TIMER_LIST_ENT *tle)
|
||||||
|
{
|
||||||
|
BD_ADDR peer_addr;
|
||||||
|
UNUSED(tle);
|
||||||
|
btif_av_connect_req_t connect_req;
|
||||||
|
UNUSED(tle);
|
||||||
|
/* is there at least one RC connection - There should be */
|
||||||
|
if (btif_rc_get_connected_peer(peer_addr)) {
|
||||||
|
BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
|
||||||
|
/* In case of AVRCP connection request, we will initiate SRC connection */
|
||||||
|
connect_req.target_bda = (bt_bdaddr_t *)&peer_addr;
|
||||||
|
connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
|
||||||
|
btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char *)&connect_req);
|
||||||
|
} else {
|
||||||
|
BTIF_TRACE_ERROR("%s No connected RC peers", __FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
** Static functions
|
** Static functions
|
||||||
|
@ -280,15 +312,40 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case BTA_AV_RC_OPEN_EVT:
|
case BTA_AV_RC_OPEN_EVT:
|
||||||
|
/* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So
|
||||||
|
* as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore,
|
||||||
|
* we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state.
|
||||||
|
* We initiate the AV connection after a small 3s timeout to avoid any collisions from the
|
||||||
|
* headsets, as some headsets initiate the AVRC connection first and then
|
||||||
|
* immediately initiate the AV connection
|
||||||
|
*
|
||||||
|
* TODO: We may need to do this only on an AVRCP Play. FixMe
|
||||||
|
*/
|
||||||
|
|
||||||
|
BTIF_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
|
||||||
|
memset(&tle_av_open_on_rc, 0, sizeof(tle_av_open_on_rc));
|
||||||
|
tle_av_open_on_rc.param = (UINT32)btif_initiate_av_open_tmr_hdlr;
|
||||||
|
btu_start_timer(&tle_av_open_on_rc, BTU_TTYPE_USER_FUNC,
|
||||||
|
BTIF_TIMEOUT_AV_OPEN_ON_RC_SECS);
|
||||||
|
btif_rc_handler(event, p_data);
|
||||||
|
break;
|
||||||
|
|
||||||
case BTA_AV_REMOTE_CMD_EVT:
|
case BTA_AV_REMOTE_CMD_EVT:
|
||||||
case BTA_AV_VENDOR_CMD_EVT:
|
case BTA_AV_VENDOR_CMD_EVT:
|
||||||
case BTA_AV_META_MSG_EVT:
|
case BTA_AV_META_MSG_EVT:
|
||||||
case BTA_AV_RC_FEAT_EVT:
|
case BTA_AV_RC_FEAT_EVT:
|
||||||
case BTA_AV_REMOTE_RSP_EVT:
|
case BTA_AV_REMOTE_RSP_EVT:
|
||||||
case BTA_AV_RC_CLOSE_EVT:
|
btif_rc_handler(event, (tBTA_AV *)p_data);
|
||||||
BTIF_TRACE_WARNING("%s : unhandled RC event:%s\n", __FUNCTION__,
|
|
||||||
dump_av_sm_event_name(event));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BTA_AV_RC_CLOSE_EVT:
|
||||||
|
if (tle_av_open_on_rc.in_use) {
|
||||||
|
BTIF_TRACE_DEBUG("BTA_AV_RC_CLOSE_EVT: Stopping AV timer.");
|
||||||
|
btu_stop_timer(&tle_av_open_on_rc);
|
||||||
|
}
|
||||||
|
btif_rc_handler(event, p_data);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BTIF_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__,
|
BTIF_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__,
|
||||||
dump_av_sm_event_name(event));
|
dump_av_sm_event_name(event));
|
||||||
|
@ -354,7 +411,6 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data
|
||||||
btif_report_connection_state(state, &(btif_av_cb.peer_bda));
|
btif_report_connection_state(state, &(btif_av_cb.peer_bda));
|
||||||
/* change state to open/idle based on the status */
|
/* change state to open/idle based on the status */
|
||||||
btif_sm_change_state(btif_av_cb.sm_handle, av_state);
|
btif_sm_change_state(btif_av_cb.sm_handle, av_state);
|
||||||
#if (BTIF_AV_SRC_INCLUDED == TRUE)
|
|
||||||
if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
|
if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
|
||||||
/* if queued PLAY command, send it now */
|
/* if queued PLAY command, send it now */
|
||||||
btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
|
btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
|
||||||
|
@ -365,7 +421,6 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data
|
||||||
/* Bring up AVRCP connection too */
|
/* Bring up AVRCP connection too */
|
||||||
BTA_AvOpenRc(btif_av_cb.bta_handle);
|
BTA_AvOpenRc(btif_av_cb.bta_handle);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
btif_queue_advance();
|
btif_queue_advance();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -461,8 +516,7 @@ static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data
|
||||||
|
|
||||||
/* Handle the RC_CLOSE event for the cleanup */
|
/* Handle the RC_CLOSE event for the cleanup */
|
||||||
case BTA_AV_RC_CLOSE_EVT:
|
case BTA_AV_RC_CLOSE_EVT:
|
||||||
BTIF_TRACE_WARNING("%s : unhandled RC event:%s\n", __FUNCTION__,
|
btif_rc_handler(event, (tBTA_AV *)p_data);
|
||||||
dump_av_sm_event_name(event));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -540,6 +594,9 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data)
|
||||||
|
|
||||||
case BTIF_AV_DISCONNECT_REQ_EVT:
|
case BTIF_AV_DISCONNECT_REQ_EVT:
|
||||||
BTA_AvClose(btif_av_cb.bta_handle);
|
BTA_AvClose(btif_av_cb.bta_handle);
|
||||||
|
if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
|
||||||
|
BTA_AvCloseRc(btif_av_cb.bta_handle);
|
||||||
|
}
|
||||||
|
|
||||||
/* inform the application that we are disconnecting */
|
/* inform the application that we are disconnecting */
|
||||||
btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
|
btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
|
||||||
|
@ -656,6 +713,9 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data
|
||||||
|
|
||||||
/* request avdtp to close */
|
/* request avdtp to close */
|
||||||
BTA_AvClose(btif_av_cb.bta_handle);
|
BTA_AvClose(btif_av_cb.bta_handle);
|
||||||
|
if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
|
||||||
|
BTA_AvCloseRc(btif_av_cb.bta_handle);
|
||||||
|
}
|
||||||
|
|
||||||
/* inform the application that we are disconnecting */
|
/* inform the application that we are disconnecting */
|
||||||
btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
|
btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
|
||||||
|
@ -1108,7 +1168,9 @@ bt_status_t btif_av_execute_service(BOOLEAN b_enable)
|
||||||
/* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
|
/* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
|
||||||
* auto-suspend av streaming on AG events(SCO or Call). The suspend shall
|
* auto-suspend av streaming on AG events(SCO or Call). The suspend shall
|
||||||
* be initiated by the app/audioflinger layers */
|
* be initiated by the app/audioflinger layers */
|
||||||
BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_NO_SCO_SSPD),
|
BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_NO_SCO_SSPD)
|
||||||
|
// | BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR
|
||||||
|
| BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL,
|
||||||
bte_av_callback);
|
bte_av_callback);
|
||||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos);
|
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos);
|
||||||
} else {
|
} else {
|
||||||
|
|
1906
components/bt/bluedroid/btif/btif_rc.c
Executable file
1906
components/bt/bluedroid/btif/btif_rc.c
Executable file
File diff suppressed because it is too large
Load diff
309
components/bt/bluedroid/btif/include/bt_rc.h
Executable file
309
components/bt/bluedroid/btif/include/bt_rc.h
Executable file
|
@ -0,0 +1,309 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BT_RC_H__
|
||||||
|
#define __BT_RC_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "bt_defs.h"
|
||||||
|
|
||||||
|
/* Macros */
|
||||||
|
#define BTRC_MAX_ATTR_STR_LEN 255
|
||||||
|
#define BTRC_UID_SIZE 8
|
||||||
|
#define BTRC_MAX_APP_SETTINGS 8
|
||||||
|
#define BTRC_MAX_FOLDER_DEPTH 4
|
||||||
|
#define BTRC_MAX_APP_ATTR_SIZE 16
|
||||||
|
#define BTRC_MAX_ELEM_ATTR_SIZE 7
|
||||||
|
|
||||||
|
typedef uint8_t btrc_uid_t[BTRC_UID_SIZE];
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_FEAT_NONE = 0x00, /* AVRCP 1.0 */
|
||||||
|
BTRC_FEAT_METADATA = 0x01, /* AVRCP 1.3 */
|
||||||
|
BTRC_FEAT_ABSOLUTE_VOLUME = 0x02, /* Supports TG role and volume sync */
|
||||||
|
BTRC_FEAT_BROWSE = 0x04, /* AVRCP 1.4 and up, with Browsing support */
|
||||||
|
} btrc_remote_features_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_PLAYSTATE_STOPPED = 0x00, /* Stopped */
|
||||||
|
BTRC_PLAYSTATE_PLAYING = 0x01, /* Playing */
|
||||||
|
BTRC_PLAYSTATE_PAUSED = 0x02, /* Paused */
|
||||||
|
BTRC_PLAYSTATE_FWD_SEEK = 0x03, /* Fwd Seek*/
|
||||||
|
BTRC_PLAYSTATE_REV_SEEK = 0x04, /* Rev Seek*/
|
||||||
|
BTRC_PLAYSTATE_ERROR = 0xFF, /* Error */
|
||||||
|
} btrc_play_status_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_EVT_PLAY_STATUS_CHANGED = 0x01,
|
||||||
|
BTRC_EVT_TRACK_CHANGE = 0x02,
|
||||||
|
BTRC_EVT_TRACK_REACHED_END = 0x03,
|
||||||
|
BTRC_EVT_TRACK_REACHED_START = 0x04,
|
||||||
|
BTRC_EVT_PLAY_POS_CHANGED = 0x05,
|
||||||
|
BTRC_EVT_APP_SETTINGS_CHANGED = 0x08,
|
||||||
|
} btrc_event_id_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_NOTIFICATION_TYPE_INTERIM = 0,
|
||||||
|
BTRC_NOTIFICATION_TYPE_CHANGED = 1,
|
||||||
|
} btrc_notification_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_PLAYER_ATTR_EQUALIZER = 0x01,
|
||||||
|
BTRC_PLAYER_ATTR_REPEAT = 0x02,
|
||||||
|
BTRC_PLAYER_ATTR_SHUFFLE = 0x03,
|
||||||
|
BTRC_PLAYER_ATTR_SCAN = 0x04,
|
||||||
|
} btrc_player_attr_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_MEDIA_ATTR_TITLE = 0x01,
|
||||||
|
BTRC_MEDIA_ATTR_ARTIST = 0x02,
|
||||||
|
BTRC_MEDIA_ATTR_ALBUM = 0x03,
|
||||||
|
BTRC_MEDIA_ATTR_TRACK_NUM = 0x04,
|
||||||
|
BTRC_MEDIA_ATTR_NUM_TRACKS = 0x05,
|
||||||
|
BTRC_MEDIA_ATTR_GENRE = 0x06,
|
||||||
|
BTRC_MEDIA_ATTR_PLAYING_TIME = 0x07,
|
||||||
|
} btrc_media_attr_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_PLAYER_VAL_OFF_REPEAT = 0x01,
|
||||||
|
BTRC_PLAYER_VAL_SINGLE_REPEAT = 0x02,
|
||||||
|
BTRC_PLAYER_VAL_ALL_REPEAT = 0x03,
|
||||||
|
BTRC_PLAYER_VAL_GROUP_REPEAT = 0x04
|
||||||
|
} btrc_player_repeat_val_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_PLAYER_VAL_OFF_SHUFFLE = 0x01,
|
||||||
|
BTRC_PLAYER_VAL_ALL_SHUFFLE = 0x02,
|
||||||
|
BTRC_PLAYER_VAL_GROUP_SHUFFLE = 0x03
|
||||||
|
} btrc_player_shuffle_val_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BTRC_STS_BAD_CMD = 0x00, /* Invalid command */
|
||||||
|
BTRC_STS_BAD_PARAM = 0x01, /* Invalid parameter */
|
||||||
|
BTRC_STS_NOT_FOUND = 0x02, /* Specified parameter is wrong or not found */
|
||||||
|
BTRC_STS_INTERNAL_ERR = 0x03, /* Internal Error */
|
||||||
|
BTRC_STS_NO_ERROR = 0x04 /* Operation Success */
|
||||||
|
} btrc_status_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t num_attr;
|
||||||
|
uint8_t attr_ids[BTRC_MAX_APP_SETTINGS];
|
||||||
|
uint8_t attr_values[BTRC_MAX_APP_SETTINGS];
|
||||||
|
} btrc_player_settings_t;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
btrc_play_status_t play_status;
|
||||||
|
btrc_uid_t track; /* queue position in NowPlaying */
|
||||||
|
uint32_t song_pos;
|
||||||
|
btrc_player_settings_t player_setting;
|
||||||
|
} btrc_register_notification_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t id; /* can be attr_id or value_id */
|
||||||
|
uint8_t text[BTRC_MAX_ATTR_STR_LEN];
|
||||||
|
} btrc_player_setting_text_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t attr_id;
|
||||||
|
uint8_t text[BTRC_MAX_ATTR_STR_LEN];
|
||||||
|
} btrc_element_attr_val_t;
|
||||||
|
|
||||||
|
/** Callback for the controller's supported feautres */
|
||||||
|
typedef void (* btrc_remote_features_callback)(bt_bdaddr_t *bd_addr,
|
||||||
|
btrc_remote_features_t features);
|
||||||
|
|
||||||
|
/** Callback for play status request */
|
||||||
|
typedef void (* btrc_get_play_status_callback)();
|
||||||
|
|
||||||
|
/** Callback for list player application attributes (Shuffle, Repeat,...) */
|
||||||
|
typedef void (* btrc_list_player_app_attr_callback)();
|
||||||
|
|
||||||
|
/** Callback for list player application attributes (Shuffle, Repeat,...) */
|
||||||
|
typedef void (* btrc_list_player_app_values_callback)(btrc_player_attr_t attr_id);
|
||||||
|
|
||||||
|
/** Callback for getting the current player application settings value
|
||||||
|
** num_attr: specifies the number of attribute ids contained in p_attrs
|
||||||
|
*/
|
||||||
|
typedef void (* btrc_get_player_app_value_callback) (uint8_t num_attr, btrc_player_attr_t *p_attrs);
|
||||||
|
|
||||||
|
/** Callback for getting the player application settings attributes' text
|
||||||
|
** num_attr: specifies the number of attribute ids contained in p_attrs
|
||||||
|
*/
|
||||||
|
typedef void (* btrc_get_player_app_attrs_text_callback) (uint8_t num_attr, btrc_player_attr_t *p_attrs);
|
||||||
|
|
||||||
|
/** Callback for getting the player application settings values' text
|
||||||
|
** num_attr: specifies the number of value ids contained in p_vals
|
||||||
|
*/
|
||||||
|
typedef void (* btrc_get_player_app_values_text_callback) (uint8_t attr_id, uint8_t num_val, uint8_t *p_vals);
|
||||||
|
|
||||||
|
/** Callback for setting the player application settings values */
|
||||||
|
typedef void (* btrc_set_player_app_value_callback) (btrc_player_settings_t *p_vals);
|
||||||
|
|
||||||
|
/** Callback to fetch the get element attributes of the current song
|
||||||
|
** num_attr: specifies the number of attributes requested in p_attrs
|
||||||
|
*/
|
||||||
|
typedef void (* btrc_get_element_attr_callback) (uint8_t num_attr, btrc_media_attr_t *p_attrs);
|
||||||
|
|
||||||
|
/** Callback for register notification (Play state change/track change/...)
|
||||||
|
** param: Is only valid if event_id is BTRC_EVT_PLAY_POS_CHANGED
|
||||||
|
*/
|
||||||
|
typedef void (* btrc_register_notification_callback) (btrc_event_id_t event_id, uint32_t param);
|
||||||
|
|
||||||
|
/* AVRCP 1.4 Enhancements */
|
||||||
|
/** Callback for volume change on CT
|
||||||
|
** volume: Current volume setting on the CT (0-127)
|
||||||
|
*/
|
||||||
|
typedef void (* btrc_volume_change_callback) (uint8_t volume, uint8_t ctype);
|
||||||
|
|
||||||
|
/** Callback for passthrough commands */
|
||||||
|
typedef void (* btrc_passthrough_cmd_callback) (int id, int key_state);
|
||||||
|
|
||||||
|
/** BT-RC Target callback structure. */
|
||||||
|
typedef struct {
|
||||||
|
/** set to sizeof(BtRcCallbacks) */
|
||||||
|
size_t size;
|
||||||
|
btrc_remote_features_callback remote_features_cb;
|
||||||
|
btrc_get_play_status_callback get_play_status_cb;
|
||||||
|
btrc_list_player_app_attr_callback list_player_app_attr_cb;
|
||||||
|
btrc_list_player_app_values_callback list_player_app_values_cb;
|
||||||
|
btrc_get_player_app_value_callback get_player_app_value_cb;
|
||||||
|
btrc_get_player_app_attrs_text_callback get_player_app_attrs_text_cb;
|
||||||
|
btrc_get_player_app_values_text_callback get_player_app_values_text_cb;
|
||||||
|
btrc_set_player_app_value_callback set_player_app_value_cb;
|
||||||
|
btrc_get_element_attr_callback get_element_attr_cb;
|
||||||
|
btrc_register_notification_callback register_notification_cb;
|
||||||
|
btrc_volume_change_callback volume_change_cb;
|
||||||
|
btrc_passthrough_cmd_callback passthrough_cmd_cb;
|
||||||
|
} btrc_callbacks_t;
|
||||||
|
|
||||||
|
/** Represents the standard BT-RC AVRCP Target interface. */
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
/** set to sizeof(BtRcInterface) */
|
||||||
|
size_t size;
|
||||||
|
/**
|
||||||
|
* Register the BtRc callbacks
|
||||||
|
*/
|
||||||
|
bt_status_t (*init)( btrc_callbacks_t* callbacks );
|
||||||
|
|
||||||
|
/** Respose to GetPlayStatus request. Contains the current
|
||||||
|
** 1. Play status
|
||||||
|
** 2. Song duration/length
|
||||||
|
** 3. Song position
|
||||||
|
*/
|
||||||
|
bt_status_t (*get_play_status_rsp)( btrc_play_status_t play_status, uint32_t song_len, uint32_t song_pos);
|
||||||
|
|
||||||
|
/** Lists the support player application attributes (Shuffle/Repeat/...)
|
||||||
|
** num_attr: Specifies the number of attributes contained in the pointer p_attrs
|
||||||
|
*/
|
||||||
|
bt_status_t (*list_player_app_attr_rsp)( int num_attr, btrc_player_attr_t *p_attrs);
|
||||||
|
|
||||||
|
/** Lists the support player application attributes (Shuffle Off/On/Group)
|
||||||
|
** num_val: Specifies the number of values contained in the pointer p_vals
|
||||||
|
*/
|
||||||
|
bt_status_t (*list_player_app_value_rsp)( int num_val, uint8_t *p_vals);
|
||||||
|
|
||||||
|
/** Returns the current application attribute values for each of the specified attr_id */
|
||||||
|
bt_status_t (*get_player_app_value_rsp)( btrc_player_settings_t *p_vals);
|
||||||
|
|
||||||
|
/** Returns the application attributes text ("Shuffle"/"Repeat"/...)
|
||||||
|
** num_attr: Specifies the number of attributes' text contained in the pointer p_attrs
|
||||||
|
*/
|
||||||
|
bt_status_t (*get_player_app_attr_text_rsp)( int num_attr, btrc_player_setting_text_t *p_attrs);
|
||||||
|
|
||||||
|
/** Returns the application attributes text ("Shuffle"/"Repeat"/...)
|
||||||
|
** num_attr: Specifies the number of attribute values' text contained in the pointer p_vals
|
||||||
|
*/
|
||||||
|
bt_status_t (*get_player_app_value_text_rsp)( int num_val, btrc_player_setting_text_t *p_vals);
|
||||||
|
|
||||||
|
/** Returns the current songs' element attributes text ("Title"/"Album"/"Artist")
|
||||||
|
** num_attr: Specifies the number of attributes' text contained in the pointer p_attrs
|
||||||
|
*/
|
||||||
|
bt_status_t (*get_element_attr_rsp)( uint8_t num_attr, btrc_element_attr_val_t *p_attrs);
|
||||||
|
|
||||||
|
/** Response to set player attribute request ("Shuffle"/"Repeat")
|
||||||
|
** rsp_status: Status of setting the player attributes for the current media player
|
||||||
|
*/
|
||||||
|
bt_status_t (*set_player_app_value_rsp)(btrc_status_t rsp_status);
|
||||||
|
|
||||||
|
/* Response to the register notification request (Play state change/track change/...).
|
||||||
|
** event_id: Refers to the event_id this notification change corresponds too
|
||||||
|
** type: Response type - interim/changed
|
||||||
|
** p_params: Based on the event_id, this parameter should be populated
|
||||||
|
*/
|
||||||
|
bt_status_t (*register_notification_rsp)(btrc_event_id_t event_id,
|
||||||
|
btrc_notification_type_t type,
|
||||||
|
btrc_register_notification_t *p_param);
|
||||||
|
|
||||||
|
/* AVRCP 1.4 enhancements */
|
||||||
|
|
||||||
|
/**Send current volume setting to remote side. Support limited to SetAbsoluteVolume
|
||||||
|
** This can be enhanced to support Relative Volume (AVRCP 1.0).
|
||||||
|
** With RelateVolume, we will send VOLUME_UP/VOLUME_DOWN opposed to absolute volume level
|
||||||
|
** volume: Should be in the range 0-127. bit7 is reseved and cannot be set
|
||||||
|
*/
|
||||||
|
bt_status_t (*set_volume)(uint8_t volume);
|
||||||
|
|
||||||
|
/** Closes the interface. */
|
||||||
|
void (*cleanup)( void );
|
||||||
|
} btrc_interface_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (* btrc_passthrough_rsp_callback) (int id, int key_state);
|
||||||
|
|
||||||
|
typedef void (* btrc_connection_state_callback) (bool state, bt_bdaddr_t *bd_addr);
|
||||||
|
|
||||||
|
/** BT-RC Controller callback structure. */
|
||||||
|
typedef struct {
|
||||||
|
/** set to sizeof(BtRcCallbacks) */
|
||||||
|
size_t size;
|
||||||
|
btrc_passthrough_rsp_callback passthrough_rsp_cb;
|
||||||
|
btrc_connection_state_callback connection_state_cb;
|
||||||
|
} btrc_ctrl_callbacks_t;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/** Represents the standard BT-RC AVRCP Controller interface. */
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
/** set to sizeof(BtRcInterface) */
|
||||||
|
size_t size;
|
||||||
|
/**
|
||||||
|
* Register the BtRc callbacks
|
||||||
|
*/
|
||||||
|
bt_status_t (*init)( btrc_ctrl_callbacks_t* callbacks );
|
||||||
|
|
||||||
|
/** send pass through command to target */
|
||||||
|
bt_status_t (*send_pass_through_cmd) ( bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state );
|
||||||
|
|
||||||
|
/** Closes the interface. */
|
||||||
|
void (*cleanup)( void );
|
||||||
|
} btrc_ctrl_interface_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the BtRc callbacks
|
||||||
|
*/
|
||||||
|
bt_status_t btrc_ctrl_init(btrc_ctrl_callbacks_t *callbacks);
|
||||||
|
|
||||||
|
/** send pass through command to target */
|
||||||
|
bt_status_t btrc_ctrl_send_passthrough_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state);
|
||||||
|
|
||||||
|
/** Closes the interface. */
|
||||||
|
void btrc_ctrl_cleanup(void);
|
||||||
|
|
||||||
|
#endif /* __BT_RC_H__ */
|
|
@ -532,9 +532,7 @@ extern "C" {
|
||||||
#define BUS_GSC 0x1A
|
#define BUS_GSC 0x1A
|
||||||
|
|
||||||
/* User input interface */
|
/* User input interface */
|
||||||
#define _IO(a, b) (0) // temporary hack
|
#if UINPUT_INCLUDED
|
||||||
#define _IOW(a, b, c) (1) // temporary hack
|
|
||||||
|
|
||||||
#define UINPUT_IOCTL_BASE 'U'
|
#define UINPUT_IOCTL_BASE 'U'
|
||||||
|
|
||||||
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
|
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
|
||||||
|
@ -551,6 +549,8 @@ extern "C" {
|
||||||
#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
|
#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
|
||||||
#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
|
#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
|
||||||
|
|
||||||
|
#endif /* UINPUT_INCLUDED */
|
||||||
|
|
||||||
#ifndef NBITS
|
#ifndef NBITS
|
||||||
#define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1)
|
#define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1013,7 +1013,7 @@
|
||||||
|
|
||||||
/* The maximum number of SDP records the server can support. */
|
/* The maximum number of SDP records the server can support. */
|
||||||
#ifndef SDP_MAX_RECORDS
|
#ifndef SDP_MAX_RECORDS
|
||||||
#define SDP_MAX_RECORDS 4 /*max is 30*/
|
#define SDP_MAX_RECORDS 6 /*max is 30*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The maximum number of attributes in each record. */
|
/* The maximum number of attributes in each record. */
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
|
|
||||||
#include "esp_system.h"
|
|
||||||
// #include "EspAudio.h"
|
|
||||||
// #include "EspAudioCom.h"
|
|
||||||
|
|
||||||
#include "bt_app_common.h"
|
|
||||||
#include "esp_bt_stack_manager.h"
|
|
||||||
#include "esp_gap_bt_api.h"
|
|
||||||
// #include "bta_api.h"
|
|
||||||
#include "esp_a2dp_api.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BT_APP_EVT_STACK_ON = 0xa0,
|
|
||||||
BT_APP_EVT_MAX
|
|
||||||
} bt_app_evt_t;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
esp_a2d_cb_param_t a2d;
|
|
||||||
} bt_app_evt_arg;
|
|
||||||
|
|
||||||
static void bt_app_handle_evt(uint16_t event, void *p_param);
|
|
||||||
|
|
||||||
static void bt_app_a2d_cb(uint32_t event, void *param)
|
|
||||||
{
|
|
||||||
switch (event) {
|
|
||||||
case ESP_A2D_CONNECTION_STATE_EVT:
|
|
||||||
case ESP_A2D_AUDIO_STATE_EVT:
|
|
||||||
case ESP_A2D_AUDIO_CFG_EVT:
|
|
||||||
{
|
|
||||||
bt_app_transfer_context(bt_app_handle_evt, event, param, sizeof(bt_app_evt_arg), NULL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
BT_APP_TRACE_ERROR("===a2dp invalid cb event: %d\n", event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
|
|
||||||
{
|
|
||||||
// EspAudioPlayerStreamWrite((uint8_t *)data, len, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bt_app_handle_evt(uint16_t event, void *p_param)
|
|
||||||
{
|
|
||||||
BT_APP_TRACE_DEBUG("bt_app_handle_evt 0x%x\n", event);
|
|
||||||
esp_a2d_cb_param_t *a2d = NULL;
|
|
||||||
switch (event) {
|
|
||||||
case BT_APP_EVT_STACK_ON: {
|
|
||||||
char *dev_name = "ESP_SPEAKER";
|
|
||||||
esp_bt_gap_set_device_name(dev_name);
|
|
||||||
|
|
||||||
esp_a2d_register_callback(bt_app_a2d_cb);
|
|
||||||
esp_a2d_register_data_callback(bt_app_a2d_data_cb);
|
|
||||||
|
|
||||||
esp_a2d_sink_init();
|
|
||||||
esp_bt_gap_set_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ESP_A2D_CONNECTION_STATE_EVT: {
|
|
||||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
|
||||||
BT_APP_TRACE_EVENT("===a2dp conn_state_cb %d ===\n", a2d->conn_stat.state);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ESP_A2D_AUDIO_STATE_EVT: {
|
|
||||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
|
||||||
BT_APP_TRACE_EVENT("===a2dp audio_state_cb %d ===\n", a2d->audio_stat.state);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ESP_A2D_AUDIO_CFG_EVT: {
|
|
||||||
a2d = (esp_a2d_cb_param_t *)(p_param);
|
|
||||||
BT_APP_TRACE_EVENT("===a2dp audio_cfg_cb type %d ===\n", a2d->audio_cfg.mcc.type);
|
|
||||||
if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC) {
|
|
||||||
// temporarily hardcoded the PCM configuaration
|
|
||||||
BT_APP_TRACE_EVENT("configure audio player\n");
|
|
||||||
// EspAudioPlayerStreamCfg(StreamSampleRate_44k, 2, StreamBitLen_16BIT);
|
|
||||||
// EspAudio_SetupStream("stream.pcm", InputSrcType_Stream);
|
|
||||||
// EspAudio_SetVolume(99);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
BT_APP_TRACE_ERROR("===application invalid event: %d\n", event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_main_entry(void)
|
|
||||||
{
|
|
||||||
esp_err_t init, enable;
|
|
||||||
init = esp_bt_init_stack();
|
|
||||||
if (init != ESP_OK) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
enable = esp_bt_enable_stack();
|
|
||||||
if (enable != ESP_OK) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_app_transfer_context(bt_app_handle_evt, BT_APP_EVT_STACK_ON, NULL, 0, NULL);
|
|
||||||
}
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/timers.h"
|
||||||
|
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "EspAudio.h"
|
||||||
|
#include "EspAudioCom.h"
|
||||||
|
|
||||||
|
#include "bt_app_common.h"
|
||||||
|
#include "esp_bt_stack_manager.h"
|
||||||
|
#include "esp_gap_bt_api.h"
|
||||||
|
#include "esp_a2dp_api.h"
|
||||||
|
|
||||||
|
#include "bt_rc.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BT_APP_EVT_STACK_ON = 0xa0,
|
||||||
|
BT_APP_EVT_MAX
|
||||||
|
} bt_app_evt_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool state;
|
||||||
|
bt_bdaddr_t bd_addr;
|
||||||
|
} esp_avrc_conn_state_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int id;
|
||||||
|
int key_state;
|
||||||
|
} esp_avrc_passthrough_rsp_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int id;
|
||||||
|
int key_state;
|
||||||
|
} esp_avrc_key_state_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
esp_a2d_cb_param_t a2d;
|
||||||
|
esp_avrc_conn_state_t avrc_state;
|
||||||
|
esp_avrc_passthrough_rsp_t avrc_passthrough_rsp;
|
||||||
|
esp_avrc_key_state_t avrc_key;
|
||||||
|
} bt_app_evt_arg;
|
||||||
|
|
||||||
|
/// AVRC callback events
|
||||||
|
typedef enum {
|
||||||
|
ESP_AVRC_CONNECTION_STATE_EVT = 5, /*!< connection state changed event */
|
||||||
|
ESP_AVRC_PASSTHROUGH_RSP_EVT, /*!< AVRC PASSTHROUGH commands */
|
||||||
|
ESP_AVRC_KEY_STATE_TO
|
||||||
|
} esp_avrc_cb_event_t;
|
||||||
|
|
||||||
|
static esp_a2d_audio_state_t m_audio_state = ESP_A2D_AUDIO_STATE_STOPPED;
|
||||||
|
static TimerHandle_t m_key_tmr = 0;
|
||||||
|
static int m_key_state = 1; // 0 for pressed, 1 for released
|
||||||
|
static xTaskHandle xKeyTaskHandle = 0;
|
||||||
|
|
||||||
|
static void bt_app_handle_evt(uint16_t event, void *p_param);
|
||||||
|
|
||||||
|
static void key_press_task_handler(void *arg)
|
||||||
|
{
|
||||||
|
int key_id = 0x48; // rewind
|
||||||
|
for(;;) {
|
||||||
|
if (m_audio_state != ESP_A2D_AUDIO_STATE_STARTED) {
|
||||||
|
BT_APP_TRACE_EVENT("-----key_tmr_hdlr, return, audio state: %d\n", m_audio_state);
|
||||||
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_app_evt_arg param;
|
||||||
|
memset(¶m, 0, sizeof(bt_app_evt_arg));
|
||||||
|
if (m_key_state == 1) {
|
||||||
|
param.avrc_key.key_state = 1;
|
||||||
|
m_key_state = 0;
|
||||||
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||||
|
} else {
|
||||||
|
param.avrc_key.key_state = 0;
|
||||||
|
m_key_state = 1;
|
||||||
|
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
param.avrc_key.id = key_id; // 0x41 volume up, 0x4b FORWARD
|
||||||
|
|
||||||
|
BT_APP_TRACE_EVENT("-----key_task_hdlr: %d, key_id %d---\n", m_key_state, param.avrc_key.id);
|
||||||
|
bt_app_transfer_context(bt_app_handle_evt, ESP_AVRC_KEY_STATE_TO, ¶m, sizeof(bt_app_evt_arg), NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void key_tmr_handler(TimerHandle_t xTimer)
|
||||||
|
{
|
||||||
|
if (m_audio_state != ESP_A2D_AUDIO_STATE_STARTED) {
|
||||||
|
BT_APP_TRACE_EVENT("-----key_tmr_hdlr, return, audio state: %d\n", m_audio_state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_app_evt_arg param;
|
||||||
|
memset(¶m, 0, sizeof(bt_app_evt_arg));
|
||||||
|
if (m_key_state == 1) {
|
||||||
|
param.avrc_key.key_state = 1;
|
||||||
|
m_key_state = 0;
|
||||||
|
} else {
|
||||||
|
param.avrc_key.key_state = 0;
|
||||||
|
m_key_state = 1;
|
||||||
|
}
|
||||||
|
param.avrc_key.id = 0x41; // volume up
|
||||||
|
BT_APP_TRACE_EVENT("-----key_tmr_hdlr: %d, key_id %d---\n", m_key_state, param.avrc_key.id);
|
||||||
|
bt_app_transfer_context(bt_app_handle_evt, ESP_AVRC_KEY_STATE_TO, ¶m, sizeof(bt_app_evt_arg), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bt_app_a2d_cb(uint32_t event, void *param)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case ESP_A2D_CONNECTION_STATE_EVT:
|
||||||
|
case ESP_A2D_AUDIO_STATE_EVT:
|
||||||
|
case ESP_A2D_AUDIO_CFG_EVT:
|
||||||
|
{
|
||||||
|
bt_app_transfer_context(bt_app_handle_evt, event, param, sizeof(bt_app_evt_arg), NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
BT_APP_TRACE_ERROR("===a2dp invalid cb event: %d\n", event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void btrc_passthrough_rsp_cb(int id, int key_state)
|
||||||
|
{
|
||||||
|
bt_app_evt_arg param;
|
||||||
|
memset(¶m, 0, sizeof(bt_app_evt_arg));
|
||||||
|
param.avrc_passthrough_rsp.id = id;
|
||||||
|
param.avrc_passthrough_rsp.key_state = key_state;
|
||||||
|
bt_app_transfer_context(bt_app_handle_evt, ESP_AVRC_PASSTHROUGH_RSP_EVT, ¶m, sizeof(bt_app_evt_arg), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void btrc_conn_state_cb(bool state, bt_bdaddr_t *bd_addr)
|
||||||
|
{
|
||||||
|
bt_app_evt_arg param;
|
||||||
|
memset(¶m, 0, sizeof(bt_app_evt_arg));
|
||||||
|
param.avrc_state.state = state;
|
||||||
|
memcpy(¶m.avrc_state.bd_addr, bd_addr, sizeof(bt_bdaddr_t));
|
||||||
|
bt_app_transfer_context(bt_app_handle_evt, ESP_AVRC_CONNECTION_STATE_EVT, ¶m, sizeof(bt_app_evt_arg), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static btrc_ctrl_callbacks_t btrc_ctrl_cb = {
|
||||||
|
sizeof(btrc_ctrl_callbacks_t),
|
||||||
|
btrc_passthrough_rsp_cb,
|
||||||
|
btrc_conn_state_cb
|
||||||
|
};
|
||||||
|
|
||||||
|
static void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
|
||||||
|
{
|
||||||
|
EspAudioPlayerStreamWrite((uint8_t *)data, len, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bt_app_handle_evt(uint16_t event, void *p_param)
|
||||||
|
{
|
||||||
|
BT_APP_TRACE_DEBUG("bt_app_handle_evt 0x%x\n", event);
|
||||||
|
esp_a2d_cb_param_t *a2d = NULL;
|
||||||
|
switch (event) {
|
||||||
|
case BT_APP_EVT_STACK_ON: {
|
||||||
|
char *dev_name = "ESP_SPEAKER";
|
||||||
|
esp_bt_gap_set_device_name(dev_name);
|
||||||
|
|
||||||
|
esp_a2d_register_callback(bt_app_a2d_cb);
|
||||||
|
esp_a2d_register_data_callback(bt_app_a2d_data_cb);
|
||||||
|
|
||||||
|
esp_a2d_sink_init();
|
||||||
|
|
||||||
|
btrc_ctrl_init(&btrc_ctrl_cb);
|
||||||
|
esp_bt_gap_set_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_A2D_CONNECTION_STATE_EVT: {
|
||||||
|
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||||
|
BT_APP_TRACE_EVENT("===a2dp conn_state_cb %d ===\n", a2d->conn_stat.state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_A2D_AUDIO_STATE_EVT: {
|
||||||
|
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||||
|
BT_APP_TRACE_EVENT("===a2dp audio_state_cb %d, %d===\n", a2d->audio_stat.state, (int)m_key_tmr);
|
||||||
|
m_audio_state = a2d->audio_stat.state;
|
||||||
|
if (m_audio_state == ESP_A2D_AUDIO_STATE_STARTED &&
|
||||||
|
m_key_tmr == 0) {
|
||||||
|
BT_APP_TRACE_EVENT("mm1\n");
|
||||||
|
xTaskCreate(key_press_task_handler, "keyT", 2048, NULL, 10, &xKeyTaskHandle);
|
||||||
|
#if 0
|
||||||
|
int32_t key_tmr_id = 10;
|
||||||
|
m_key_tmr = xTimerCreate("appKeyTmr", 3000 / portTICK_PERIOD_MS, pdTRUE, (void *) key_tmr_id, key_tmr_handler);
|
||||||
|
if (xTimerStart(m_key_tmr, 10 / portTICK_PERIOD_MS) != pdTRUE) {
|
||||||
|
BT_APP_TRACE_EVENT(" timer start failed\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_A2D_AUDIO_CFG_EVT: {
|
||||||
|
a2d = (esp_a2d_cb_param_t *)(p_param);
|
||||||
|
BT_APP_TRACE_EVENT("===a2dp audio_cfg_cb type %d ===\n", a2d->audio_cfg.mcc.type);
|
||||||
|
if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC) {
|
||||||
|
// temporarily hardcoded the PCM configuaration
|
||||||
|
BT_APP_TRACE_EVENT("configure audio player\n");
|
||||||
|
EspAudioPlayerStreamCfg(StreamSampleRate_44k, 2, StreamBitLen_16BIT);
|
||||||
|
EspAudio_SetupStream("stream.pcm", InputSrcType_Stream);
|
||||||
|
EspAudio_SetVolume(99);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_AVRC_CONNECTION_STATE_EVT: {
|
||||||
|
esp_avrc_conn_state_t *conn_state = (esp_avrc_conn_state_t *)(p_param);
|
||||||
|
BT_APP_TRACE_EVENT("===avrc conn_state evt %d ===\n", conn_state->state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_AVRC_PASSTHROUGH_RSP_EVT: {
|
||||||
|
esp_avrc_passthrough_rsp_t *passthrough_rsp = (esp_avrc_passthrough_rsp_t *)(p_param);
|
||||||
|
BT_APP_TRACE_EVENT("===avrc passthrough evt id 0x%x, key_state %d===\n", passthrough_rsp->id, passthrough_rsp->key_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_AVRC_KEY_STATE_TO: {
|
||||||
|
esp_avrc_key_state_t *key_s = (esp_avrc_key_state_t *)(p_param);
|
||||||
|
BT_APP_TRACE_EVENT("===avrc send key id 0x%x, state %d\n", key_s->id, key_s->key_state);
|
||||||
|
btrc_ctrl_send_passthrough_cmd(NULL, key_s->id, key_s->key_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
BT_APP_TRACE_ERROR("===application invalid event: %d\n", event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main_entry(void)
|
||||||
|
{
|
||||||
|
esp_err_t init, enable;
|
||||||
|
init = esp_bt_init_stack();
|
||||||
|
if (init != ESP_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
enable = esp_bt_enable_stack();
|
||||||
|
if (enable != ESP_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_app_transfer_context(bt_app_handle_evt, BT_APP_EVT_STACK_ON, NULL, 0, NULL);
|
||||||
|
}
|
Loading…
Reference in a new issue