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 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
|
||||
#define BTIF_A2D_CB_TO_APP(_event, _param) do { \
|
||||
|
@ -125,6 +125,7 @@ else\
|
|||
case BTA_AV_RC_FEAT_EVT: \
|
||||
case BTA_AV_REMOTE_RSP_EVT: \
|
||||
{ \
|
||||
btif_rc_handler(e, d);\
|
||||
}break; \
|
||||
|
||||
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 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;
|
||||
/*****************************************************************************
|
||||
|
@ -202,6 +206,34 @@ const char *dump_av_sm_event_name(btif_av_sm_event_t event)
|
|||
/****************************************************************************
|
||||
** 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
|
||||
|
@ -280,15 +312,40 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
|
|||
} break;
|
||||
|
||||
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_VENDOR_CMD_EVT:
|
||||
case BTA_AV_META_MSG_EVT:
|
||||
case BTA_AV_RC_FEAT_EVT:
|
||||
case BTA_AV_REMOTE_RSP_EVT:
|
||||
case BTA_AV_RC_CLOSE_EVT:
|
||||
BTIF_TRACE_WARNING("%s : unhandled RC event:%s\n", __FUNCTION__,
|
||||
dump_av_sm_event_name(event));
|
||||
btif_rc_handler(event, (tBTA_AV *)p_data);
|
||||
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:
|
||||
BTIF_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__,
|
||||
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));
|
||||
/* change state to open/idle based on the status */
|
||||
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 queued PLAY command, send it now */
|
||||
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 */
|
||||
BTA_AvOpenRc(btif_av_cb.bta_handle);
|
||||
}
|
||||
#endif
|
||||
btif_queue_advance();
|
||||
} 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 */
|
||||
case BTA_AV_RC_CLOSE_EVT:
|
||||
BTIF_TRACE_WARNING("%s : unhandled RC event:%s\n", __FUNCTION__,
|
||||
dump_av_sm_event_name(event));
|
||||
btif_rc_handler(event, (tBTA_AV *)p_data);
|
||||
break;
|
||||
|
||||
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:
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
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
|
||||
* auto-suspend av streaming on AG events(SCO or Call). The suspend shall
|
||||
* 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);
|
||||
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos);
|
||||
} 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
|
||||
|
||||
/* User input interface */
|
||||
#define _IO(a, b) (0) // temporary hack
|
||||
#define _IOW(a, b, c) (1) // temporary hack
|
||||
|
||||
#if UINPUT_INCLUDED
|
||||
#define UINPUT_IOCTL_BASE 'U'
|
||||
|
||||
#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_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
|
||||
|
||||
#endif /* UINPUT_INCLUDED */
|
||||
|
||||
#ifndef NBITS
|
||||
#define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1)
|
||||
#endif
|
||||
|
|
|
@ -1013,7 +1013,7 @@
|
|||
|
||||
/* The maximum number of SDP records the server can support. */
|
||||
#ifndef SDP_MAX_RECORDS
|
||||
#define SDP_MAX_RECORDS 4 /*max is 30*/
|
||||
#define SDP_MAX_RECORDS 6 /*max is 30*/
|
||||
#endif
|
||||
|
||||
/* 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