summaryrefslogtreecommitdiffstats
path: root/btif/src
diff options
context:
space:
mode:
authorKausik Sinnaswamy <kausik@broadcom.com>2012-03-09 10:54:02 -0800
committerMatthew Xie <mattx@google.com>2012-07-14 11:19:13 -0700
commit837acf40a4968449f044cfd3cd15f7f120617eb5 (patch)
treed2e71deec39c3a5e2e9651726662748fdf6440ac /btif/src
parent5140bed9a19aadca962184ebc9ed823d5d7cb745 (diff)
downloadexternal_bluetooth_bluedroid-837acf40a4968449f044cfd3cd15f7f120617eb5.zip
external_bluetooth_bluedroid-837acf40a4968449f044cfd3cd15f7f120617eb5.tar.gz
external_bluetooth_bluedroid-837acf40a4968449f044cfd3cd15f7f120617eb5.tar.bz2
Added support to handle AVRCP 1.0 and incoming A2DP connections
Change-Id: I7863920895aa9fd77eccee4083319701bcbf4300
Diffstat (limited to 'btif/src')
-rw-r--r--btif/src/btif_av.c137
-rw-r--r--btif/src/btif_rc.c435
2 files changed, 560 insertions, 12 deletions
diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c
index d383926..a822c7f 100644
--- a/btif/src/btif_av.c
+++ b/btif/src/btif_av.c
@@ -62,12 +62,16 @@
#include "bta_api.h"
#include "bta_av_api.h"
#include "gki.h"
+#include "bd.h"
+#include "btu.h"
/*****************************************************************************
** Constants & Macros
******************************************************************************/
#define BTIF_AV_SERVICE_NAME "Advanced Audio"
+#define BTIF_TIMEOUT_AV_OPEN_ON_RC 2 /* 2 seconds */
+
typedef enum {
BTIF_AV_STATE_IDLE = 0x0,
BTIF_AV_STATE_OPENING,
@@ -99,6 +103,8 @@ typedef struct
static btav_callbacks_t *bt_av_callbacks = NULL;
static btif_av_cb_t btif_av_cb;
+static TIMER_LIST_ENT tle_av_open_on_rc;
+
#define CHECK_BTAV_INIT() if (bt_av_callbacks == NULL)\
{\
BTIF_TRACE_WARNING1("%s: BTAV not initialized", __FUNCTION__);\
@@ -109,6 +115,18 @@ else\
BTIF_TRACE_EVENT1("%s", __FUNCTION__);\
}
+/* Helper macro to avoid code duplication in the state machine handlers */
+#define CHECK_RC_EVENT(e, d) \
+ case BTA_AV_RC_OPEN_EVT: \
+ case BTA_AV_RC_CLOSE_EVT: \
+ case BTA_AV_REMOTE_CMD_EVT: \
+ case BTA_AV_VENDOR_CMD_EVT: \
+ case BTA_AV_META_MSG_EVT: \
+ case BTA_AV_RC_FEAT_EVT: \
+ { \
+ btif_rc_handler(e, d);\
+ }break; \
+
static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data);
static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *data);
static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *data);
@@ -123,6 +141,13 @@ static const btif_sm_handler_t btif_av_state_handlers[] =
};
+/*************************************************************************
+** Extern functions
+*************************************************************************/
+extern void btif_rc_init(void);
+extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data);
+extern BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr);
+
/*****************************************************************************
** Local helper functions
******************************************************************************/
@@ -173,6 +198,36 @@ 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;
+
+ /* is there at least one RC connection - There should be */
+ if (btif_rc_get_connected_peer(peer_addr)) {
+ BTIF_TRACE_DEBUG1("%s Issuing connect to the remote RC peer", __FUNCTION__);
+ btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (void*)&peer_addr);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR1("%s No connected RC peers", __FUNCTION__);
+ }
+}
+
/*****************************************************************************
** Static functions
******************************************************************************/
@@ -210,16 +265,54 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
{
btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
} break;
-
+ case BTA_AV_PENDING_EVT:
case BTIF_AV_CONNECT_REQ_EVT:
{
+ if (event == BTIF_AV_CONNECT_REQ_EVT)
+ {
memcpy(&btif_av_cb.peer_bda, (bt_bdaddr_t*)p_data, sizeof(bt_bdaddr_t));
-
BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
TRUE, BTA_SEC_NONE);
-
+ }
+ else if (event == BTA_AV_PENDING_EVT)
+ {
+ bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
+ }
btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
} 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_DEBUG0("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);
+ 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:
+ {
+ 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_DEBUG0("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_WARNING2("%s Unhandled event:%s", __FUNCTION__,
@@ -228,7 +321,6 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
return TRUE;
}
-
static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data)
{
BTIF_TRACE_DEBUG2("%s event:%s", __FUNCTION__, dump_av_sm_event_name(event));
@@ -248,26 +340,30 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data
case BTA_AV_OPEN_EVT:
{
tBTA_AV *p_bta_data = (tBTA_AV*)p_data;
- btav_connection_state_t state = BTAV_CONNECTION_STATE_DISCONNECTED;
+ btav_connection_state_t state;
+ btif_sm_state_t av_state;
BTIF_TRACE_DEBUG1("status:%d", p_bta_data->open.status);
if (p_bta_data->open.status == BTA_AV_SUCCESS)
{
state = BTAV_CONNECTION_STATE_CONNECTED;
- /* change state to open */
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+ av_state = BTIF_AV_STATE_OPENED;
}
else
{
BTIF_TRACE_WARNING1("BTA_AV_OPEN_EVT::FAILED status: %d",
p_bta_data->open.status );
- /* change state to idle */
- btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ state = BTAV_CONNECTION_STATE_DISCONNECTED;
+ av_state = BTIF_AV_STATE_IDLE;
}
/* inform the application of the event */
CHECK_CALL_CBACK(bt_av_callbacks, connection_state_cb,
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);
} break;
+ CHECK_RC_EVENT(event, p_data);
+
default:
BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__,
dump_av_sm_event_name(event));
@@ -284,7 +380,15 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data)
{
case BTIF_SM_ENTER_EVT:
- BTIF_TRACE_DEBUG0("starting av");
+ BTIF_TRACE_DEBUG0("starting av...sleeping before that");
+
+ /* Auto-starting on Open could introduce race conditions. So delaying
+ * the start.
+ *
+ * This is anyway temporary and will be removed once the START/STOP stream
+ * requests are processed.
+ */
+ GKI_delay(3000);
btif_a2dp_upon_start_req();
@@ -331,6 +435,8 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data)
btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
} break;
+ CHECK_RC_EVENT(event, p_data);
+
default:
BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__,
dump_av_sm_event_name(event));
@@ -338,7 +444,7 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data)
return TRUE;
}
-static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data)
+static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data)
{
BTIF_TRACE_DEBUG2("%s event:%s", __FUNCTION__, dump_av_sm_event_name(event));
@@ -364,6 +470,8 @@ static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data)
btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
} break;
+ CHECK_RC_EVENT(event, p_data);
+
default:
BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__,
dump_av_sm_event_name(event));
@@ -414,6 +522,8 @@ static bt_status_t init(btav_callbacks_t* callbacks )
bt_av_callbacks = callbacks;
btif_enable_service(BTA_A2DP_SERVICE_ID);
+ /* Initialize the AVRC CB */
+ btif_rc_init();
/* Also initialize the AV state machine */
btif_av_cb.sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
@@ -516,7 +626,10 @@ bt_status_t btif_av_execute_service(BOOLEAN b_enable)
BTA_AV_FEAT_RCTG|BTA_AV_FEAT_METADATA|BTA_AV_FEAT_VENDOR,
bte_av_callback);
#else
- BTA_AvEnable(BTA_SEC_AUTHENTICATE|BTA_SEC_AUTHORIZE, BTA_AV_FEAT_RCTG,
+ /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
+ * handle this request in order to allow incoming connections to succeed.
+ * We need to put this back once support for this is added */
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_RCTG,
bte_av_callback);
#endif
BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0);
diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
new file mode 100644
index 0000000..04d5681
--- /dev/null
+++ b/btif/src/btif_rc.c
@@ -0,0 +1,435 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING
+ * OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM
+ * OR ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ *****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Filename: btif_rc.c
+ *
+ * Description: Bluetooth AVRC implementation
+ *
+ *****************************************************************************/
+#include <hardware/bluetooth.h>
+#include <fcntl.h>
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "avrc_defs.h"
+#include "bd.h"
+#include "gki.h"
+
+#define LOG_TAG "BTIF_RC"
+#include "btif_common.h"
+
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+#if (!defined(AVRC_METADATA_INCLUDED) || (AVRC_METADATA_INCLUDED == FALSE))
+#define BTIF_RC_USE_UINPUT TRUE
+#include "uinput.h"
+#else
+#error "AVRCP 1.3 is not supported on Bluedroid yet."
+#endif
+
+/*****************************************************************************
+** Local type definitions
+******************************************************************************/
+typedef struct {
+ BOOLEAN rc_connected;
+ UINT8 rc_handle;
+ BD_ADDR rc_addr;
+ UINT16 rc_pending_play;
+} btif_rc_cb_t;
+
+#ifdef BTIF_RC_USE_UINPUT
+#define MAX_UINPUT_PATHS 3
+static const char* uinput_dev_path[] =
+ {"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput" };
+static int uinput_fd = -1;
+
+static int send_event (int fd, uint16_t type, uint16_t code, int32_t value);
+static void send_key (int fd, uint16_t key, int pressed);
+static int uinput_driver_check();
+static int uinput_create(char *name);
+static int init_uinput (void);
+static void close_uinput (void);
+
+static struct {
+ const char *name;
+ uint8_t avrcp;
+ uint16_t mapped_id;
+ uint8_t release_quirk;
+} key_map[] = {
+ { "PLAY", AVRC_ID_PLAY, KEY_PLAYCD, 1 },
+ { "STOP", AVRC_ID_STOP, KEY_STOPCD, 0 },
+ { "PAUSE", AVRC_ID_PAUSE, KEY_PAUSECD, 1 },
+ { "FORWARD", AVRC_ID_FORWARD, KEY_NEXTSONG, 0 },
+ { "BACKWARD", AVRC_ID_BACKWARD, KEY_PREVIOUSSONG, 0 },
+ { "REWIND", AVRC_ID_REWIND, KEY_REWIND, 0 },
+ { "FAST FORWARD", AVRC_ID_FAST_FOR, KEY_FORWARD, 0 },
+ { NULL, 0, 0, 0 }
+};
+#endif /* BTIF_RC_USE_UINPUT */
+
+
+/*****************************************************************************
+** Static variables
+******************************************************************************/
+static btif_rc_cb_t btif_rc_cb;
+
+/*****************************************************************************
+** Static functions
+******************************************************************************/
+
+/*****************************************************************************
+** Externs
+******************************************************************************/
+
+/*****************************************************************************
+** Functions
+******************************************************************************/
+
+
+#ifdef BTIF_RC_USE_UINPUT
+/*****************************************************************************
+** Local uinput helper functions
+******************************************************************************/
+int send_event (int fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct uinput_event event;
+
+ memset(&event, 0, sizeof(event));
+ event.type = type;
+ event.code = code;
+ event.value = value;
+
+ return write(fd, &event, sizeof(event));
+}
+
+void send_key (int fd, uint16_t key, int pressed)
+{
+ if (fd < 0) {
+ return;
+ }
+
+ BTIF_TRACE_DEBUG3("AVRCP: Send key %d (%d) fd=%d", key, pressed, fd);
+ send_event(fd, EV_KEY, key, pressed);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+/************** uinput related functions **************/
+int uinput_driver_check()
+{
+ uint32_t i;
+ for (i=0; i < MAX_UINPUT_PATHS; i++)
+ {
+ if (access(uinput_dev_path[i], O_RDWR) == 0) {
+ return 0;
+ }
+ }
+ BTIF_TRACE_ERROR1("%s ERROR: uinput device is not in the system", __FUNCTION__);
+ return -1;
+}
+
+int uinput_create(char *name)
+{
+ struct uinput_dev dev;
+ int fd, err, x = 0;
+
+ for(x=0; x < MAX_UINPUT_PATHS; x++)
+ {
+ fd = open(uinput_dev_path[x], O_RDWR);
+ if (fd < 0)
+ continue;
+ break;
+ }
+ if (x == MAX_UINPUT_PATHS) {
+ BTIF_TRACE_ERROR1("%s ERROR: uinput device open failed", __FUNCTION__);
+ return -1;
+ }
+ memset(&dev, 0, sizeof(dev));
+ if (name)
+ strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
+
+ dev.id.bustype = BUS_BLUETOOTH;
+ dev.id.vendor = 0x0000;
+ dev.id.product = 0x0000;
+ dev.id.version = 0x0000;
+
+ if (write(fd, &dev, sizeof(dev)) < 0) {
+ BTIF_TRACE_ERROR1("%s Unable to write device information", __FUNCTION__);
+ close(fd);
+ return -1;
+ }
+
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_EVBIT, EV_REL);
+ ioctl(fd, UI_SET_EVBIT, EV_SYN);
+
+ for (x = 0; key_map[x].name != NULL; x++)
+ ioctl(fd, UI_SET_KEYBIT, key_map[x].mapped_id);
+
+ for(x = 0; x < KEY_MAX; x++)
+ ioctl(fd, UI_SET_KEYBIT, x);
+
+ if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
+ BTIF_TRACE_ERROR1("%s Unable to create uinput device", __FUNCTION__);
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+int init_uinput (void)
+{
+ char *name = "AVRCP";
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ uinput_fd = uinput_create(name);
+ if (uinput_fd < 0) {
+ BTIF_TRACE_ERROR3("%s AVRCP: Failed to initialize uinput for %s (%d)",
+ __FUNCTION__, name, uinput_fd);
+ } else {
+ BTIF_TRACE_DEBUG3("%s AVRCP: Initialized uinput for %s (fd=%d)",
+ __FUNCTION__, name, uinput_fd);
+ }
+ return uinput_fd;
+}
+
+void close_uinput (void)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ if (uinput_fd > 0) {
+ ioctl(uinput_fd, UI_DEV_DESTROY);
+
+ close(uinput_fd);
+ uinput_fd = -1;
+ }
+}
+#endif // BTA_AVRCP_FORCE_USE_UINPUT
+
+const char *dump_rc_event_name(tBTA_AV_EVT event)
+{
+ switch(event) {
+ case BTA_AV_RC_OPEN_EVT: return "BTA_AV_RC_OPEN_EVT";
+ case BTA_AV_RC_CLOSE_EVT: return "BTA_AV_RC_CLOSE_EVT";
+ case BTA_AV_REMOTE_CMD_EVT: return "BTA_AV_REMOTE_CMD_EVT";
+ case BTA_AV_REMOTE_RSP_EVT: return "BTA_AV_REMOTE_RSP_EVT";
+ case BTA_AV_VENDOR_CMD_EVT: return "BTA_AV_VENDOR_CMD_EVT";
+ case BTA_AV_VENDOR_RSP_EVT: return "BTA_AV_VENDOR_RSP_EVT";
+ default: return "UNKNOWN_EVENT";
+ }
+}
+
+/***************************************************************************
+ * Function handle_rc_connect
+ *
+ * - Argument: tBTA_AV_RC_OPEN RC open data structure
+ *
+ * - Description: RC connection event handler
+ *
+ ***************************************************************************/
+void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
+{
+ BTIF_TRACE_DEBUG2("%s: rc_handle: %d", __FUNCTION__, p_rc_open->rc_handle);
+
+#ifdef BTIF_RC_USE_UINPUT
+ init_uinput();
+#endif
+
+ memcpy(btif_rc_cb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
+ btif_rc_cb.rc_connected = TRUE;
+ btif_rc_cb.rc_handle = p_rc_open->rc_handle;
+}
+
+/***************************************************************************
+ * Function handle_rc_disconnect
+ *
+ * - Argument: tBTA_AV_RC_CLOSE RC close data structure
+ *
+ * - Description: RC disconnection event handler
+ *
+ ***************************************************************************/
+void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
+{
+ BTIF_TRACE_DEBUG2("%s: rc_handle: %d", __FUNCTION__, p_rc_close->rc_handle);
+
+ btif_rc_cb.rc_handle = 0;
+ btif_rc_cb.rc_connected = FALSE;
+ memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
+#ifdef BTIF_RC_USE_UINPUT
+ close_uinput();
+#endif /* BTIF_RC_USE_UINPUT */
+}
+
+/***************************************************************************
+ * Function handle_rc_passthrough_cmd
+ *
+ * - Argument: tBTA_AV_RC rc_id remote control command ID
+ * tBTA_AV_STATE key_state status of key press
+ *
+ * - Description: Remote control command handler
+ *
+ ***************************************************************************/
+void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
+{
+ const char *status;
+ int pressed, i;
+
+ if (p_remote_cmd->key_state == AVRC_STATE_RELEASE) {
+ status = "released";
+ pressed = 0;
+ } else {
+ status = "pressed";
+ pressed = 1;
+ }
+
+ for (i = 0; key_map[i].name != NULL; i++) {
+ if (p_remote_cmd->rc_id == key_map[i].avrcp) {
+ BTIF_TRACE_DEBUG3("%s: %s %s", __FUNCTION__, key_map[i].name, status);
+
+ /* MusicPlayer uses a long_press_timeout of 1 second for PLAYPAUSE button
+ * and maps that to autoshuffle. So if for some reason release for PLAY/PAUSE
+ * comes 1 second after the press, the MediaPlayer UI goes into a bad state.
+ * The reason for the delay could be sniff mode exit or some AVDTP procedure etc.
+ * The fix is to generate a release right after the press and drown the 'actual'
+ * release.
+ */
+ if ((key_map[i].release_quirk == 1) && (pressed == 0))
+ {
+ BTIF_TRACE_DEBUG2("%s: AVRC %s Release Faked earlier, drowned now",
+ __FUNCTION__, key_map[i].name);
+ return;
+ }
+#ifdef BTIF_RC_USE_UINPUT
+ send_key(uinput_fd, key_map[i].mapped_id, pressed);
+#endif
+ if ((key_map[i].release_quirk == 1) && (pressed == 1))
+ {
+ GKI_delay(30); // 30ms
+ BTIF_TRACE_DEBUG2("%s: AVRC %s Release quirk enabled, send release now",
+ __FUNCTION__, key_map[i].name);
+#ifdef BTIF_RC_USE_UINPUT
+ send_key(uinput_fd, key_map[i].mapped_id, 0);
+#endif
+ }
+ break;
+ }
+ }
+
+ if (key_map[i].name == NULL)
+ BTIF_TRACE_ERROR3("%s AVRCP: unknown button 0x%02X %s", __FUNCTION__,
+ p_remote_cmd->rc_id, status);
+}
+
+/*****************************************************************************
+**
+** Function btif_rc_init
+**
+** Description Initialize RC
+**
+** Returns Returns 0 on success, -1 otherwise
+**
+*******************************************************************************/
+int btif_rc_init()
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ memset (&btif_rc_cb, 0, sizeof(btif_rc_cb));
+
+#ifdef BTIF_RC_USE_UINPUT
+ return uinput_driver_check();
+#endif /* BTIF_RC_USE_UINPUT */
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_handler
+ **
+ ** Description RC event handler
+ **
+ ***************************************************************************/
+void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
+{
+ BTIF_TRACE_DEBUG2 ("%s event:%s", __FUNCTION__, dump_rc_event_name(event));
+ switch (event)
+ {
+ case BTA_AV_RC_OPEN_EVT:
+ {
+ BTIF_TRACE_DEBUG1("Peer_features:%x", p_data->rc_open.peer_features);
+ handle_rc_connect( &(p_data->rc_open) );
+ }break;
+
+ case BTA_AV_RC_CLOSE_EVT:
+ {
+ handle_rc_disconnect( &(p_data->rc_close) );
+ }break;
+
+ case BTA_AV_REMOTE_CMD_EVT:
+ {
+ BTIF_TRACE_DEBUG2("rc_id:0x%x key_state:%d", p_data->remote_cmd.rc_id,
+ p_data->remote_cmd.key_state);
+ handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
+ }break;
+ default:
+ BTIF_TRACE_DEBUG0("Unhandled RC event");
+ }
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_get_connected_peer
+ **
+ ** Description Fetches the connected headset's BD_ADDR if any
+ **
+ ***************************************************************************/
+BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr)
+{
+ if (btif_rc_cb.rc_connected == TRUE) {
+ bdcpy(peer_addr, btif_rc_cb.rc_addr);
+ return TRUE;
+ }
+ return FALSE;
+}