From: wangmengyang Date: Fri, 4 Nov 2016 14:08:12 +0000 (+0800) Subject: component/bt: port btif_rc.c X-Git-Tag: v2.1-rc1~196^2~83 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=32cbf523105673c92e4d6836f11437fc595a0291;p=esp-idf component/bt: port btif_rc.c --- diff --git a/examples/09_a2dp/components/bluedroid_demos/btif/btif_rc.c b/examples/09_a2dp/components/bluedroid_demos/btif/btif_rc.c new file mode 100755 index 0000000000..ccb2cfeb58 --- /dev/null +++ b/examples/09_a2dp/components/bluedroid_demos/btif/btif_rc.c @@ -0,0 +1,1880 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +/***************************************************************************** + * + * Filename: btif_rc.c + * + * Description: Bluetooth AVRC implementation + * + *****************************************************************************/ +// #include +#include "bt_defs.h" +// #include +#include +#include "bta_api.h" +#include "bta_av_api.h" +#include "avrc_defs.h" +#include "gki.h" + +#define LOG_TAG "bt_btif_avrc" +#include "btif_common.h" +#include "btif_util.h" +#include "btif_av.h" +#include "bt_rc.h" +#include "uinput.h" + +/***************************************************************************** +** Constants & Macros +******************************************************************************/ + +/* cod value for Headsets */ +#define COD_AV_HEADSETS 0x0404 +/* for AVRC 1.4 need to change this */ +#define MAX_RC_NOTIFICATIONS AVRC_EVT_APP_SETTING_CHANGE + +#define IDX_GET_PLAY_STATUS_RSP 0 +#define IDX_LIST_APP_ATTR_RSP 1 +#define IDX_LIST_APP_VALUE_RSP 2 +#define IDX_GET_CURR_APP_VAL_RSP 3 +#define IDX_SET_APP_VAL_RSP 4 +#define IDX_GET_APP_ATTR_TXT_RSP 5 +#define IDX_GET_APP_VAL_TXT_RSP 6 +#define IDX_GET_ELEMENT_ATTR_RSP 7 +#define MAX_VOLUME 128 +#define MAX_LABEL 16 +#define MAX_TRANSACTIONS_PER_SESSION 16 +#define MAX_CMD_QUEUE_LEN 8 +#define PLAY_STATUS_PLAYING 1 + +/*******************************************************/ +/* temporary hack of symbols in "fcntl.h", */ +#define O_RDWR (0) +#define open(a, b) (0) +#define write(a, b, c) (0) +#define access(a, b) (0) +#define close(a) ((void)0) +#define ioctl(a, b, c) ((void)0) +/*******************************************************/ + +#define CHECK_RC_CONNECTED \ + BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__); \ + if(btif_rc_cb.rc_connected == FALSE) \ + { \ + BTIF_TRACE_WARNING("Function %s() called when RC is not connected", __FUNCTION__); \ + return BT_STATUS_NOT_READY; \ + } + +#define FILL_PDU_QUEUE(index, ctype, label, pending) \ +{ \ + btif_rc_cb.rc_pdu_info[index].ctype = ctype; \ + btif_rc_cb.rc_pdu_info[index].label = label; \ + btif_rc_cb.rc_pdu_info[index].is_rsp_pending = pending; \ +} + +#define SEND_METAMSG_RSP(index, avrc_rsp) \ +{ \ + if(btif_rc_cb.rc_pdu_info[index].is_rsp_pending == FALSE) \ + { \ + BTIF_TRACE_WARNING("%s Not sending response as no PDU was registered", __FUNCTION__); \ + return BT_STATUS_UNHANDLED; \ + } \ + send_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_pdu_info[index].label, \ + btif_rc_cb.rc_pdu_info[index].ctype, avrc_rsp); \ + btif_rc_cb.rc_pdu_info[index].ctype = 0; \ + btif_rc_cb.rc_pdu_info[index].label = 0; \ + btif_rc_cb.rc_pdu_info[index].is_rsp_pending = FALSE; \ +} + +/***************************************************************************** +** Local type definitions +******************************************************************************/ +typedef struct { + UINT8 bNotify; + UINT8 label; +} btif_rc_reg_notifications_t; + +typedef struct +{ + UINT8 label; + UINT8 ctype; + BOOLEAN is_rsp_pending; +} btif_rc_cmd_ctxt_t; + +/* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single struct */ +typedef struct { + BOOLEAN rc_connected; + UINT8 rc_handle; + tBTA_AV_FEAT rc_features; + BD_ADDR rc_addr; + UINT16 rc_pending_play; + btif_rc_cmd_ctxt_t rc_pdu_info[MAX_CMD_QUEUE_LEN]; + btif_rc_reg_notifications_t rc_notif[MAX_RC_NOTIFICATIONS]; + unsigned int rc_volume; + uint8_t rc_vol_label; +} btif_rc_cb_t; + +typedef struct { + BOOLEAN in_use; + UINT8 lbl; + UINT8 handle; +} rc_transaction_t; + +typedef struct +{ + pthread_mutex_t lbllock; + rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION]; +} rc_device_t; + + +rc_device_t device; + +#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 const 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_FAST_FORWARD, 0 }, + { NULL, 0, 0, 0 } +}; + +static void send_reject_response (UINT8 rc_handle, UINT8 label, + UINT8 pdu, UINT8 status); +static UINT8 opcode_from_pdu(UINT8 pdu); +static void send_metamsg_rsp (UINT8 rc_handle, UINT8 label, + tBTA_AV_CODE code, tAVRC_RESPONSE *pmetamsg_resp); +static void register_volumechange(UINT8 label); +static void lbl_init(); +static void lbl_destroy(); +static void init_all_transactions(); +static bt_status_t get_transaction(rc_transaction_t **ptransaction); +static void release_transaction(UINT8 label); +static rc_transaction_t* get_transaction_by_lbl(UINT8 label); +static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg); +static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND* p_param, UINT8 ctype, UINT8 label); +static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label); + +/***************************************************************************** +** Static variables +******************************************************************************/ +static btif_rc_cb_t btif_rc_cb; +static btrc_callbacks_t *bt_rc_callbacks = NULL; +static btrc_ctrl_callbacks_t *bt_rc_ctrl_callbacks = NULL; + +/***************************************************************************** +** Static functions +******************************************************************************/ + +/***************************************************************************** +** Externs +******************************************************************************/ +extern BOOLEAN btif_hf_call_terminated_recently(); +extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod); + + +/***************************************************************************** +** Functions +******************************************************************************/ + +/***************************************************************************** +** Local uinput helper functions +******************************************************************************/ +int send_event (int fd, uint16_t type, uint16_t code, int32_t value) +{ + struct uinput_event event; + BTIF_TRACE_DEBUG("%s type:%u code:%u value:%d", __FUNCTION__, + type, code, value); + 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) +{ + BTIF_TRACE_DEBUG("%s fd:%d key:%u pressed:%d", __FUNCTION__, + fd, key, pressed); + + if (fd < 0) + { + return; + } + + BTIF_TRACE_DEBUG("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_ERROR("%s ERROR: uinput device is not in the system", __FUNCTION__); + return -1; +} + +int uinput_create(char *name) +{ + struct uinput_dev dev; + int fd, 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_ERROR("%s ERROR: uinput device open failed", __FUNCTION__); + return -1; + } + memset(&dev, 0, sizeof(dev)); + if (name) + strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE-1); + + 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_ERROR("%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); +#if 0 // hack + if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) { + BTIF_TRACE_ERROR("%s Unable to create uinput device", __FUNCTION__); + close(fd); + return -1; + } +#endif + return fd; +} + +int init_uinput (void) +{ + char *name = "AVRCP"; + + BTIF_TRACE_DEBUG("%s", __FUNCTION__); + uinput_fd = uinput_create(name); + if (uinput_fd < 0) { + BTIF_TRACE_ERROR("%s AVRCP: Failed to initialize uinput for %s (%d)", + __FUNCTION__, name, uinput_fd); + } else { + BTIF_TRACE_DEBUG("%s AVRCP: Initialized uinput for %s (fd=%d)", + __FUNCTION__, name, uinput_fd); + } + return uinput_fd; +} + +void close_uinput (void) +{ + BTIF_TRACE_DEBUG("%s", __FUNCTION__); + if (uinput_fd > 0) { + ioctl(uinput_fd, UI_DEV_DESTROY, 0); // ?? + + close(uinput_fd); + uinput_fd = -1; + } +} + +void handle_rc_features() +{ + btrc_remote_features_t rc_features = BTRC_FEAT_NONE; + bt_bdaddr_t rc_addr; + bdcpy(rc_addr.address, btif_rc_cb.rc_addr); + + // TODO(eisenbach): If devices need to be blacklisted for absolute + // volume, it should be added to device/include/interop_database.h + // For now, everything goes... If blacklisting is necessary, exclude + // the following bit here: + // btif_rc_cb.rc_features &= ~BTA_AV_FEAT_ADV_CTRL; + + if (btif_rc_cb.rc_features & BTA_AV_FEAT_BROWSE) + { + rc_features |= BTRC_FEAT_BROWSE; + } + + if ( (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL) && + (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG)) + { + rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME; + } + + if (btif_rc_cb.rc_features & BTA_AV_FEAT_METADATA) + { + rc_features |= BTRC_FEAT_METADATA; + } + + BTIF_TRACE_DEBUG("%s: rc_features=0x%x", __FUNCTION__, rc_features); + HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features) + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + BTIF_TRACE_DEBUG("Checking for feature flags in btif_rc_handler with label %d", + btif_rc_cb.rc_vol_label); + // Register for volume change on connect + if(btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL && + btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) + { + rc_transaction_t *p_transaction=NULL; + bt_status_t status = BT_STATUS_NOT_READY; + if(MAX_LABEL==btif_rc_cb.rc_vol_label) + { + status=get_transaction(&p_transaction); + } + else + { + p_transaction=get_transaction_by_lbl(btif_rc_cb.rc_vol_label); + if(NULL!=p_transaction) + { + BTIF_TRACE_DEBUG("register_volumechange already in progress for label %d", + btif_rc_cb.rc_vol_label); + return; + } + else + status=get_transaction(&p_transaction); + } + + if(BT_STATUS_SUCCESS == status && NULL!=p_transaction) + { + btif_rc_cb.rc_vol_label=p_transaction->lbl; + register_volumechange(btif_rc_cb.rc_vol_label); + } + } +#endif +} + + +/*************************************************************************** + * 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_DEBUG("%s: rc_handle: %d", __FUNCTION__, p_rc_open->rc_handle); + bt_status_t result = BT_STATUS_SUCCESS; +#if (AVRC_CTLR_INCLUDED == TRUE) + bt_bdaddr_t rc_addr; +#endif + + if(p_rc_open->status == BTA_AV_SUCCESS) + { + //check if already some RC is connected + if (btif_rc_cb.rc_connected) + { + BTIF_TRACE_ERROR("Got RC OPEN in connected state, Connected RC: %d \ + and Current RC: %d", btif_rc_cb.rc_handle,p_rc_open->rc_handle ); + if ((btif_rc_cb.rc_handle != p_rc_open->rc_handle) + && (bdcmp(btif_rc_cb.rc_addr, p_rc_open->peer_addr))) + { + BTIF_TRACE_DEBUG("Got RC connected for some other handle"); + BTA_AvCloseRc(p_rc_open->rc_handle); + return; + } + } + memcpy(btif_rc_cb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR)); + btif_rc_cb.rc_features = p_rc_open->peer_features; + btif_rc_cb.rc_vol_label=MAX_LABEL; + btif_rc_cb.rc_volume=MAX_VOLUME; + + btif_rc_cb.rc_connected = TRUE; + btif_rc_cb.rc_handle = p_rc_open->rc_handle; + + /* on locally initiated connection we will get remote features as part of connect */ + if (btif_rc_cb.rc_features != 0) + handle_rc_features(); + + result = uinput_driver_check(); + if(result == BT_STATUS_SUCCESS) + { + init_uinput(); + } +#if (AVRC_CTLR_INCLUDED == TRUE) + bdcpy(rc_addr.address, btif_rc_cb.rc_addr); + /* report connection state if device is AVRCP target */ + if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) { + if (bt_rc_ctrl_callbacks != NULL) { + HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, TRUE, &rc_addr); + } + } +#endif + } + else + { + BTIF_TRACE_ERROR("%s Connect failed with error code: %d", + __FUNCTION__, p_rc_open->status); + btif_rc_cb.rc_connected = FALSE; + } +} + +/*************************************************************************** + * 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) +{ +#if (AVRC_CTLR_INCLUDED == TRUE) + bt_bdaddr_t rc_addr; + tBTA_AV_FEAT features; +#endif + BTIF_TRACE_DEBUG("%s: rc_handle: %d", __FUNCTION__, p_rc_close->rc_handle); + if ((p_rc_close->rc_handle != btif_rc_cb.rc_handle) + && (bdcmp(btif_rc_cb.rc_addr, p_rc_close->peer_addr))) + { + BTIF_TRACE_ERROR("Got disconnect of unknown device"); + return; + } + + btif_rc_cb.rc_handle = 0; + btif_rc_cb.rc_connected = FALSE; + memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR)); + memset(btif_rc_cb.rc_notif, 0, sizeof(btif_rc_cb.rc_notif)); +#if (AVRC_CTLR_INCLUDED == TRUE) + features = btif_rc_cb.rc_features; +#endif + btif_rc_cb.rc_features = 0; + btif_rc_cb.rc_vol_label=MAX_LABEL; + btif_rc_cb.rc_volume=MAX_VOLUME; + init_all_transactions(); + close_uinput(); +#if (AVRC_CTLR_INCLUDED == TRUE) + bdcpy(rc_addr.address, btif_rc_cb.rc_addr); +#endif + memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR)); +#if (AVRC_CTLR_INCLUDED == TRUE) + /* report connection state if device is AVRCP target */ + if (features & BTA_AV_FEAT_RCTG) { + if (bt_rc_ctrl_callbacks != NULL) { + HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, FALSE, &rc_addr); + } + } +#endif +} + +/*************************************************************************** + * 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; + + BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id=%d", __FUNCTION__, p_remote_cmd->rc_id); + + /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up this PLAY */ + if (p_remote_cmd) + { + /* queue AVRC PLAY if GAVDTP Open notification to app is pending (2 second timer) */ + if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) && (!btif_av_is_connected())) + { + if (p_remote_cmd->key_state == AVRC_STATE_PRESS) + { + APPL_TRACE_WARNING("%s: AVDT not open, queuing the PLAY command", __FUNCTION__); + btif_rc_cb.rc_pending_play = TRUE; + } + return; + } + + if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb.rc_pending_play)) + { + APPL_TRACE_WARNING("%s: Clear the pending PLAY on PAUSE received", __FUNCTION__); + btif_rc_cb.rc_pending_play = FALSE; + return; + } + } + + if ((p_remote_cmd->rc_id == BTA_AV_RC_STOP) && (!btif_av_stream_started_ready())) + { + APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd",__FUNCTION__); + return; + } + + if (p_remote_cmd->key_state == AVRC_STATE_RELEASE) { + status = "released"; + pressed = 0; + } else { + status = "pressed"; + pressed = 1; + } + + /* If this is Play/Pause command (press or release) before processing, check the following + * a voice call has ended recently + * the remote device is not of type headset + * If the above conditions meet, drop the Play/Pause command + * This fix is to interop with certain carkits which sends an automatic PLAY or PAUSE + * commands right after call ends + */ + if((p_remote_cmd->rc_id == BTA_AV_RC_PLAY || p_remote_cmd->rc_id == BTA_AV_RC_PAUSE)&& + (btif_hf_call_terminated_recently() == TRUE) && + (check_cod( (const bt_bdaddr_t*)&(btif_rc_cb.rc_addr), COD_AV_HEADSETS) != TRUE)) + { + BTIF_TRACE_DEBUG("%s:Dropping the play/Pause command received right after call end cmd:%d", + __FUNCTION__,p_remote_cmd->rc_id); + return; + } + + if (p_remote_cmd->rc_id == BTA_AV_RC_FAST_FOR || p_remote_cmd->rc_id == BTA_AV_RC_REWIND) { + HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed); + return; + } + + for (i = 0; key_map[i].name != NULL; i++) { + if (p_remote_cmd->rc_id == key_map[i].avrcp) { + BTIF_TRACE_DEBUG("%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_DEBUG("%s: AVRC %s Release Faked earlier, drowned now", + __FUNCTION__, key_map[i].name); + return; + } + send_key(uinput_fd, key_map[i].mapped_id, pressed); + if ((key_map[i].release_quirk == 1) && (pressed == 1)) + { + GKI_delay(30); // 30ms + BTIF_TRACE_DEBUG("%s: AVRC %s Release quirk enabled, send release now", + __FUNCTION__, key_map[i].name); + send_key(uinput_fd, key_map[i].mapped_id, 0); + } + break; + } + } + + if (key_map[i].name == NULL) + BTIF_TRACE_ERROR("%s AVRCP: unknown button 0x%02X %s", __FUNCTION__, + p_remote_cmd->rc_id, status); +} + +/*************************************************************************** + * Function handle_rc_passthrough_rsp + * + * - Argument: tBTA_AV_REMOTE_RSP passthrough command response + * + * - Description: Remote control passthrough response handler + * + ***************************************************************************/ +void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp) +{ +#if (AVRC_CTLR_INCLUDED == TRUE) + const char *status; + if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) + { + int key_state; + if (p_remote_rsp->key_state == AVRC_STATE_RELEASE) + { + status = "released"; + key_state = 1; + } + else + { + status = "pressed"; + key_state = 0; + } + + BTIF_TRACE_DEBUG("%s: rc_id=%d status=%s", __FUNCTION__, p_remote_rsp->rc_id, status); + + release_transaction(p_remote_rsp->label); + if (bt_rc_ctrl_callbacks != NULL) { + HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, p_remote_rsp->rc_id, key_state); + } + } + else + { + BTIF_TRACE_ERROR("%s DUT does not support AVRCP controller role", __FUNCTION__); + } +#else + BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __FUNCTION__); +#endif +} + +void handle_uid_changed_notification(tBTA_AV_META_MSG *pmeta_msg, tAVRC_COMMAND *pavrc_command) +{ + tAVRC_RESPONSE avrc_rsp = {0}; + avrc_rsp.rsp.pdu = pavrc_command->pdu; + avrc_rsp.rsp.status = AVRC_STS_NO_ERROR; + avrc_rsp.rsp.opcode = pavrc_command->cmd.opcode; + + avrc_rsp.reg_notif.event_id = pavrc_command->reg_notif.event_id; + avrc_rsp.reg_notif.param.uid_counter = 0; + + send_metamsg_rsp(pmeta_msg->rc_handle, pmeta_msg->label, AVRC_RSP_INTERIM, &avrc_rsp); + send_metamsg_rsp(pmeta_msg->rc_handle, pmeta_msg->label, AVRC_RSP_CHANGED, &avrc_rsp); + +} + + +/*************************************************************************** + * Function handle_rc_metamsg_cmd + * + * - Argument: tBTA_AV_VENDOR Structure containing the received + * metamsg command + * + * - Description: Remote control metamsg command handler (AVRCP 1.3) + * + ***************************************************************************/ +void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg) +{ + /* Parse the metamsg command and pass it on to BTL-IFS */ + UINT8 scratch_buf[512] = {0}; + tAVRC_COMMAND avrc_command = {0}; + tAVRC_STS status; + + BTIF_TRACE_EVENT("+ %s", __FUNCTION__); + + if (pmeta_msg->p_msg->hdr.opcode != AVRC_OP_VENDOR) + { + BTIF_TRACE_WARNING("Invalid opcode: %x", pmeta_msg->p_msg->hdr.opcode); + return; + } + if (pmeta_msg->len < 3) + { + BTIF_TRACE_WARNING("Invalid length.Opcode: 0x%x, len: 0x%x", pmeta_msg->p_msg->hdr.opcode, + pmeta_msg->len); + return; + } + + if (pmeta_msg->code >= AVRC_RSP_NOT_IMPL) + { +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) +{ + rc_transaction_t *transaction=NULL; + transaction=get_transaction_by_lbl(pmeta_msg->label); + if(NULL!=transaction) + { + handle_rc_metamsg_rsp(pmeta_msg); + } + else + { + BTIF_TRACE_DEBUG("%s:Discard vendor dependent rsp. code: %d label:%d.", + __FUNCTION__, pmeta_msg->code, pmeta_msg->label); + } + return; +} +#else +{ + BTIF_TRACE_DEBUG("%s:Received vendor dependent rsp. code: %d len: %d. Not processing it.", + __FUNCTION__, pmeta_msg->code, pmeta_msg->len); + return; +} +#endif + } + + status=AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf, sizeof(scratch_buf)); + BTIF_TRACE_DEBUG("Received vendor command.code,PDU and label: %d, %d,%d",pmeta_msg->code, + avrc_command.cmd.pdu, pmeta_msg->label); + + if (status != AVRC_STS_NO_ERROR) + { + /* return error */ + BTIF_TRACE_WARNING("%s: Error in parsing received metamsg command. status: 0x%02x", + __FUNCTION__, status); + send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_command.pdu, status); + } + else + { + /* if RegisterNotification, add it to our registered queue */ + + if (avrc_command.cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION) + { + UINT8 event_id = avrc_command.reg_notif.event_id; + BTIF_TRACE_EVENT("%s:New register notification received.event_id:%s,label:0x%x,code:%x", + __FUNCTION__,dump_rc_notification_event_id(event_id), pmeta_msg->label,pmeta_msg->code); + btif_rc_cb.rc_notif[event_id-1].bNotify = TRUE; + btif_rc_cb.rc_notif[event_id-1].label = pmeta_msg->label; + + if(event_id == AVRC_EVT_UIDS_CHANGE) + { + handle_uid_changed_notification(pmeta_msg, &avrc_command); + return; + } + + } + + BTIF_TRACE_EVENT("%s: Passing received metamsg command to app. pdu: %s", + __FUNCTION__, dump_rc_pdu(avrc_command.cmd.pdu)); + + /* Since handle_rc_metamsg_cmd() itself is called from + *btif context, no context switching is required. Invoke + * btif_rc_upstreams_evt directly from here. */ + btif_rc_upstreams_evt((uint16_t)avrc_command.cmd.pdu, &avrc_command, pmeta_msg->code, + pmeta_msg->label); + } +} + +/*************************************************************************** + ** + ** Function btif_rc_handler + ** + ** Description RC event handler + ** + ***************************************************************************/ +void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data) +{ + BTIF_TRACE_DEBUG ("%s event:%s", __FUNCTION__, dump_rc_event(event)); + switch (event) + { + case BTA_AV_RC_OPEN_EVT: + { + BTIF_TRACE_DEBUG("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_DEBUG("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; +#if (AVRC_CTLR_INCLUDED == TRUE) + case BTA_AV_REMOTE_RSP_EVT: + { + BTIF_TRACE_DEBUG("RSP: rc_id:0x%x key_state:%d", p_data->remote_rsp.rc_id, + p_data->remote_rsp.key_state); + handle_rc_passthrough_rsp( (&p_data->remote_rsp) ); + } + break; +#endif + case BTA_AV_RC_FEAT_EVT: + { + BTIF_TRACE_DEBUG("Peer_features:%x", p_data->rc_feat.peer_features); + btif_rc_cb.rc_features = p_data->rc_feat.peer_features; + handle_rc_features(); + } + break; + case BTA_AV_META_MSG_EVT: + { + BTIF_TRACE_DEBUG("BTA_AV_META_MSG_EVT code:%d label:%d", p_data->meta_msg.code, + p_data->meta_msg.label); + BTIF_TRACE_DEBUG(" company_id:0x%x len:%d handle:%d", p_data->meta_msg.company_id, + p_data->meta_msg.len, p_data->meta_msg.rc_handle); + /* handle the metamsg command */ + handle_rc_metamsg_cmd(&(p_data->meta_msg)); + } + break; + default: + BTIF_TRACE_DEBUG("Unhandled RC event : 0x%x", 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; +} + +/*************************************************************************** + ** + ** Function btif_rc_check_handle_pending_play + ** + ** Description Clears the queued PLAY command. if bSend is TRUE, forwards to app + ** + ***************************************************************************/ + +/* clear the queued PLAY command. if bSend is TRUE, forward to app */ +void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp) +{ + UNUSED(peer_addr); + + BTIF_TRACE_DEBUG("%s: bSendToApp=%d", __FUNCTION__, bSendToApp); + if (btif_rc_cb.rc_pending_play) + { + if (bSendToApp) + { + tBTA_AV_REMOTE_CMD remote_cmd; + APPL_TRACE_DEBUG("%s: Sending queued PLAYED event to app", __FUNCTION__); + + memset (&remote_cmd, 0, sizeof(tBTA_AV_REMOTE_CMD)); + remote_cmd.rc_handle = btif_rc_cb.rc_handle; + remote_cmd.rc_id = AVRC_ID_PLAY; + remote_cmd.hdr.ctype = AVRC_CMD_CTRL; + remote_cmd.hdr.opcode = AVRC_OP_PASS_THRU; + + /* delay sending to app, else there is a timing issue in the framework, + ** which causes the audio to be on th device's speaker. Delay between + ** OPEN & RC_PLAYs + */ + GKI_delay (200); + /* send to app - both PRESSED & RELEASED */ + remote_cmd.key_state = AVRC_STATE_PRESS; + handle_rc_passthrough_cmd( &remote_cmd ); + + GKI_delay (100); + + remote_cmd.key_state = AVRC_STATE_RELEASE; + handle_rc_passthrough_cmd( &remote_cmd ); + } + btif_rc_cb.rc_pending_play = FALSE; + } +} + +/* Generic reject response */ +static void send_reject_response (UINT8 rc_handle, UINT8 label, UINT8 pdu, UINT8 status) +{ + UINT8 ctype = AVRC_RSP_REJ; + tAVRC_RESPONSE avrc_rsp; + BT_HDR *p_msg = NULL; + memset (&avrc_rsp, 0, sizeof(tAVRC_RESPONSE)); + + avrc_rsp.rsp.opcode = opcode_from_pdu(pdu); + avrc_rsp.rsp.pdu = pdu; + avrc_rsp.rsp.status = status; + + if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(rc_handle, &avrc_rsp, &p_msg)) ) + { + BTIF_TRACE_DEBUG("%s:Sending error notification to handle:%d. pdu:%s,status:0x%02x", + __FUNCTION__, rc_handle, dump_rc_pdu(pdu), status); + BTA_AvMetaRsp(rc_handle, label, ctype, p_msg); + } +} + +/*************************************************************************** + * Function send_metamsg_rsp + * + * - Argument: + * rc_handle RC handle corresponding to the connected RC + * label Label of the RC response + * code Response type + * pmetamsg_resp Vendor response + * + * - Description: Remote control metamsg response handler (AVRCP 1.3) + * + ***************************************************************************/ +static void send_metamsg_rsp (UINT8 rc_handle, UINT8 label, tBTA_AV_CODE code, + tAVRC_RESPONSE *pmetamsg_resp) +{ + UINT8 ctype; + + if (!pmetamsg_resp) + { + BTIF_TRACE_WARNING("%s: Invalid response received from application", __FUNCTION__); + return; + } + + BTIF_TRACE_EVENT("+%s: rc_handle: %d, label: %d, code: 0x%02x, pdu: %s", __FUNCTION__, + rc_handle, label, code, dump_rc_pdu(pmetamsg_resp->rsp.pdu)); + + if (pmetamsg_resp->rsp.status != AVRC_STS_NO_ERROR) + { + ctype = AVRC_RSP_REJ; + } + else + { + if ( code < AVRC_RSP_NOT_IMPL) + { + if (code == AVRC_CMD_NOTIF) + { + ctype = AVRC_RSP_INTERIM; + } + else if (code == AVRC_CMD_STATUS) + { + ctype = AVRC_RSP_IMPL_STBL; + } + else + { + ctype = AVRC_RSP_ACCEPT; + } + } + else + { + ctype = code; + } + } + /* if response is for register_notification, make sure the rc has + actually registered for this */ + if((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) && (code == AVRC_RSP_CHANGED)) + { + BOOLEAN bSent = FALSE; + UINT8 event_id = pmetamsg_resp->reg_notif.event_id; + BOOLEAN bNotify = (btif_rc_cb.rc_connected) && (btif_rc_cb.rc_notif[event_id-1].bNotify); + + /* de-register this notification for a CHANGED response */ + btif_rc_cb.rc_notif[event_id-1].bNotify = FALSE; + BTIF_TRACE_DEBUG("%s rc_handle: %d. event_id: 0x%02d bNotify:%u", __FUNCTION__, + btif_rc_cb.rc_handle, event_id, bNotify); + if (bNotify) + { + BT_HDR *p_msg = NULL; + tAVRC_STS status; + + if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(btif_rc_cb.rc_handle, + pmetamsg_resp, &p_msg)) ) + { + BTIF_TRACE_DEBUG("%s Sending notification to rc_handle: %d. event_id: 0x%02d", + __FUNCTION__, btif_rc_cb.rc_handle, event_id); + bSent = TRUE; + BTA_AvMetaRsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label, + ctype, p_msg); + } + else + { + BTIF_TRACE_WARNING("%s failed to build metamsg response. status: 0x%02x", + __FUNCTION__, status); + } + + } + + if (!bSent) + { + BTIF_TRACE_DEBUG("%s: Notification not sent, as there are no RC connections or the \ + CT has not subscribed for event_id: %s", __FUNCTION__, dump_rc_notification_event_id(event_id)); + } + } + else + { + /* All other commands go here */ + + BT_HDR *p_msg = NULL; + tAVRC_STS status; + + status = AVRC_BldResponse(rc_handle, pmetamsg_resp, &p_msg); + + if (status == AVRC_STS_NO_ERROR) + { + BTA_AvMetaRsp(rc_handle, label, ctype, p_msg); + } + else + { + BTIF_TRACE_ERROR("%s: failed to build metamsg response. status: 0x%02x", + __FUNCTION__, status); + } + } +} + +static UINT8 opcode_from_pdu(UINT8 pdu) +{ + UINT8 opcode = 0; + + switch (pdu) + { + case AVRC_PDU_NEXT_GROUP: + case AVRC_PDU_PREV_GROUP: /* pass thru */ + opcode = AVRC_OP_PASS_THRU; + break; + + default: /* vendor */ + opcode = AVRC_OP_VENDOR; + break; + } + + return opcode; +} + +/******************************************************************************* +** +** Function btif_rc_upstreams_evt +** +** Description Executes AVRC UPSTREAMS events in btif context. +** +** Returns void +** +*******************************************************************************/ +static void btif_rc_upstreams_evt(UINT16 event, tAVRC_COMMAND *pavrc_cmd, UINT8 ctype, UINT8 label) +{ + BTIF_TRACE_EVENT("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__, + dump_rc_pdu(pavrc_cmd->pdu), btif_rc_cb.rc_handle, ctype, label); + + switch (event) + { + case AVRC_PDU_GET_PLAY_STATUS: + { + FILL_PDU_QUEUE(IDX_GET_PLAY_STATUS_RSP, ctype, label, TRUE) + HAL_CBACK(bt_rc_callbacks, get_play_status_cb); + } + break; + case AVRC_PDU_LIST_PLAYER_APP_ATTR: + case AVRC_PDU_LIST_PLAYER_APP_VALUES: + case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: + case AVRC_PDU_SET_PLAYER_APP_VALUE: + case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: + case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: + { + /* TODO: Add support for Application Settings */ + send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_CMD); + } + break; + case AVRC_PDU_GET_ELEMENT_ATTR: + { + btrc_media_attr_t element_attrs[BTRC_MAX_ELEM_ATTR_SIZE]; + UINT8 num_attr; + memset(&element_attrs, 0, sizeof(element_attrs)); + if (pavrc_cmd->get_elem_attrs.num_attr == 0) + { + /* CT requests for all attributes */ + int attr_cnt; + num_attr = BTRC_MAX_ELEM_ATTR_SIZE; + for (attr_cnt = 0; attr_cnt < BTRC_MAX_ELEM_ATTR_SIZE; attr_cnt++) + { + element_attrs[attr_cnt] = attr_cnt + 1; + } + } + else if (pavrc_cmd->get_elem_attrs.num_attr == 0xFF) + { + /* 0xff indicates, no attributes requested - reject */ + send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, + AVRC_STS_BAD_PARAM); + return; + } + else + { + int attr_cnt, filled_attr_count; + + num_attr = 0; + /* Attribute IDs from 1 to AVRC_MAX_NUM_MEDIA_ATTR_ID are only valid, + * hence HAL definition limits the attributes to AVRC_MAX_NUM_MEDIA_ATTR_ID. + * Fill only valid entries. + */ + for (attr_cnt = 0; (attr_cnt < pavrc_cmd->get_elem_attrs.num_attr) && + (num_attr < AVRC_MAX_NUM_MEDIA_ATTR_ID); attr_cnt++) + { + if ((pavrc_cmd->get_elem_attrs.attrs[attr_cnt] > 0) && + (pavrc_cmd->get_elem_attrs.attrs[attr_cnt] <= AVRC_MAX_NUM_MEDIA_ATTR_ID)) + { + /* Skip the duplicate entries : PTS sends duplicate entries for Fragment cases + */ + for (filled_attr_count = 0; filled_attr_count < num_attr; filled_attr_count++) + { + if (element_attrs[filled_attr_count] == pavrc_cmd->get_elem_attrs.attrs[attr_cnt]) + break; + } + if (filled_attr_count == num_attr) + { + element_attrs[num_attr] = pavrc_cmd->get_elem_attrs.attrs[attr_cnt]; + num_attr++; + } + } + } + } + FILL_PDU_QUEUE(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, TRUE); + HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs); + } + break; + case AVRC_PDU_REGISTER_NOTIFICATION: + { + if(pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED && + pavrc_cmd->reg_notif.param == 0) + { + BTIF_TRACE_WARNING("%s Device registering position changed with illegal param 0.", + __FUNCTION__); + send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, AVRC_STS_BAD_PARAM); + /* de-register this notification for a rejected response */ + btif_rc_cb.rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = FALSE; + return; + } + HAL_CBACK(bt_rc_callbacks, register_notification_cb, pavrc_cmd->reg_notif.event_id, + pavrc_cmd->reg_notif.param); + } + break; + case AVRC_PDU_INFORM_DISPLAY_CHARSET: + { + tAVRC_RESPONSE avrc_rsp; + BTIF_TRACE_EVENT("%s() AVRC_PDU_INFORM_DISPLAY_CHARSET", __FUNCTION__); + if(btif_rc_cb.rc_connected == TRUE) + { + memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP)); + avrc_rsp.inform_charset.opcode=opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET); + avrc_rsp.inform_charset.pdu=AVRC_PDU_INFORM_DISPLAY_CHARSET; + avrc_rsp.inform_charset.status=AVRC_STS_NO_ERROR; + send_metamsg_rsp(btif_rc_cb.rc_handle, label, ctype, &avrc_rsp); + } + } + break; + default: + { + send_reject_response (btif_rc_cb.rc_handle, label, pavrc_cmd->pdu, + (pavrc_cmd->pdu == AVRC_PDU_SEARCH)?AVRC_STS_SEARCH_NOT_SUP:AVRC_STS_BAD_CMD); + return; + } + break; + } + +} + + +/******************************************************************************* +** +** Function btif_rc_upstreams_rsp_evt +** +** Description Executes AVRC UPSTREAMS response events in btif context. +** +** Returns void +** +*******************************************************************************/ +static void btif_rc_upstreams_rsp_evt(UINT16 event, tAVRC_RESPONSE *pavrc_resp, UINT8 ctype, UINT8 label) +{ + BTIF_TRACE_EVENT("%s pdu: %s handle: 0x%x ctype:%x label:%x", __FUNCTION__, + dump_rc_pdu(pavrc_resp->pdu), btif_rc_cb.rc_handle, ctype, label); + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + switch (event) + { + case AVRC_PDU_REGISTER_NOTIFICATION: + { + if(AVRC_RSP_CHANGED==ctype) + btif_rc_cb.rc_volume=pavrc_resp->reg_notif.param.volume; + HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->reg_notif.param.volume,ctype) + } + break; + + case AVRC_PDU_SET_ABSOLUTE_VOLUME: + { + BTIF_TRACE_DEBUG("Set absolute volume change event received: volume %d,ctype %d", + pavrc_resp->volume.volume,ctype); + if(AVRC_RSP_ACCEPT==ctype) + btif_rc_cb.rc_volume=pavrc_resp->volume.volume; + HAL_CBACK(bt_rc_callbacks,volume_change_cb,pavrc_resp->volume.volume,ctype) + } + break; + + default: + return; + } +#endif +} + +/************************************************************************************ +** AVRCP API Functions +************************************************************************************/ + +/******************************************************************************* +** +** Function init +** +** Description Initializes the AVRC interface +** +** Returns bt_status_t +** +*******************************************************************************/ +static bt_status_t init(btrc_callbacks_t* callbacks ) +{ + BTIF_TRACE_EVENT("## %s ##", __FUNCTION__); + bt_status_t result = BT_STATUS_SUCCESS; + + if (bt_rc_callbacks) + return BT_STATUS_DONE; + + bt_rc_callbacks = callbacks; + memset (&btif_rc_cb, 0, sizeof(btif_rc_cb)); + btif_rc_cb.rc_vol_label=MAX_LABEL; + btif_rc_cb.rc_volume=MAX_VOLUME; + lbl_init(); + + return result; +} + +/******************************************************************************* +** +** Function init_ctrl +** +** Description Initializes the AVRC interface +** +** Returns bt_status_t +** +*******************************************************************************/ +static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks ) +{ + BTIF_TRACE_EVENT("## %s ##", __FUNCTION__); + bt_status_t result = BT_STATUS_SUCCESS; + + if (bt_rc_ctrl_callbacks) + return BT_STATUS_DONE; + + bt_rc_ctrl_callbacks = callbacks; + memset (&btif_rc_cb, 0, sizeof(btif_rc_cb)); + btif_rc_cb.rc_vol_label=MAX_LABEL; + btif_rc_cb.rc_volume=MAX_VOLUME; + lbl_init(); + + return result; +} + +/*************************************************************************** +** +** Function get_play_status_rsp +** +** Description Returns the current play status. +** This method is called in response to +** GetPlayStatus request. +** +** Returns bt_status_t +** +***************************************************************************/ +static bt_status_t get_play_status_rsp(btrc_play_status_t play_status, uint32_t song_len, + uint32_t song_pos) +{ + tAVRC_RESPONSE avrc_rsp; + CHECK_RC_CONNECTED + memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP)); + avrc_rsp.get_play_status.song_len = song_len; + avrc_rsp.get_play_status.song_pos = song_pos; + avrc_rsp.get_play_status.play_status = play_status; + + avrc_rsp.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS; + avrc_rsp.get_play_status.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAY_STATUS); + avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR; + /* Send the response */ + SEND_METAMSG_RSP(IDX_GET_PLAY_STATUS_RSP, &avrc_rsp); + return BT_STATUS_SUCCESS; +} + +/*************************************************************************** +** +** Function get_element_attr_rsp +** +** Description Returns the current songs' element attributes +** in text. +** +** Returns bt_status_t +** +***************************************************************************/ +static bt_status_t get_element_attr_rsp(uint8_t num_attr, btrc_element_attr_val_t *p_attrs) +{ + tAVRC_RESPONSE avrc_rsp; + UINT32 i; + tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE]; + CHECK_RC_CONNECTED + memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr); + + if (num_attr == 0) + { + avrc_rsp.get_play_status.status = AVRC_STS_BAD_PARAM; + } + else + { + for (i=0; iplay_status; + if (avrc_rsp.reg_notif.param.play_status == PLAY_STATUS_PLAYING) + btif_av_clear_remote_suspend_flag(); + break; + case BTRC_EVT_TRACK_CHANGE: + memcpy(&(avrc_rsp.reg_notif.param.track), &(p_param->track), sizeof(btrc_uid_t)); + break; + case BTRC_EVT_PLAY_POS_CHANGED: + avrc_rsp.reg_notif.param.play_pos = p_param->song_pos; + break; + default: + BTIF_TRACE_WARNING("%s : Unhandled event ID : 0x%x", __FUNCTION__, event_id); + return BT_STATUS_UNHANDLED; + } + + avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION; + avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION); + avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR; + + /* Send the response. */ + send_metamsg_rsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label, + ((type == BTRC_NOTIFICATION_TYPE_INTERIM)?AVRC_CMD_NOTIF:AVRC_RSP_CHANGED), &avrc_rsp); + return BT_STATUS_SUCCESS; +} + +/*************************************************************************** +** +** Function set_volume +** +** Description 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 +** as opposed to absolute volume level +** volume: Should be in the range 0-127. bit7 is reseved and cannot be set +** +** Returns bt_status_t +** +***************************************************************************/ +static bt_status_t set_volume(uint8_t volume) +{ + BTIF_TRACE_DEBUG("%s", __FUNCTION__); + CHECK_RC_CONNECTED + tAVRC_STS status = BT_STATUS_UNSUPPORTED; + rc_transaction_t *p_transaction=NULL; + + if(btif_rc_cb.rc_volume==volume) + { + status=BT_STATUS_DONE; + BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x",__FUNCTION__, volume); + return status; + } + + if ((btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) && + (btif_rc_cb.rc_features & BTA_AV_FEAT_ADV_CTRL)) + { + tAVRC_COMMAND avrc_cmd = {0}; + BT_HDR *p_msg = NULL; + + BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume=%d", __FUNCTION__, volume); + avrc_cmd.volume.opcode = AVRC_OP_VENDOR; + avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME; + avrc_cmd.volume.status = AVRC_STS_NO_ERROR; + avrc_cmd.volume.volume = volume; + + if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR) + { + bt_status_t tran_status=get_transaction(&p_transaction); + if(BT_STATUS_SUCCESS == tran_status && NULL!=p_transaction) + { + BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", + __FUNCTION__,p_transaction->lbl); + BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_CTRL, p_msg); + status = BT_STATUS_SUCCESS; + } + else + { + if(NULL!=p_msg) + GKI_freebuf(p_msg); + BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x", + __FUNCTION__, tran_status); + status = BT_STATUS_FAIL; + } + } + else + { + BTIF_TRACE_ERROR("%s: failed to build absolute volume command. status: 0x%02x", + __FUNCTION__, status); + status = BT_STATUS_FAIL; + } + } + else + status=BT_STATUS_NOT_READY; + return status; +} + + +/*************************************************************************** +** +** Function register_volumechange +** +** Description Register for volume change notification from remote side. +** +** Returns void +** +***************************************************************************/ + +static void register_volumechange (UINT8 lbl) +{ + tAVRC_COMMAND avrc_cmd = {0}; + BT_HDR *p_msg = NULL; + tAVRC_STS BldResp=AVRC_STS_BAD_CMD; + rc_transaction_t *p_transaction=NULL; + + BTIF_TRACE_DEBUG("%s called with label:%d",__FUNCTION__,lbl); + + avrc_cmd.cmd.opcode=0x00; + avrc_cmd.pdu = AVRC_PDU_REGISTER_NOTIFICATION; + avrc_cmd.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE; + avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR; + + BldResp=AVRC_BldCommand(&avrc_cmd, &p_msg); + if(AVRC_STS_NO_ERROR==BldResp && p_msg) + { + p_transaction=get_transaction_by_lbl(lbl); + if(NULL!=p_transaction) + { + BTA_AvMetaCmd(btif_rc_cb.rc_handle,p_transaction->lbl, AVRC_CMD_NOTIF, p_msg); + BTIF_TRACE_DEBUG("%s:BTA_AvMetaCmd called",__FUNCTION__); + } + else + { + if(NULL!=p_msg) + GKI_freebuf(p_msg); + BTIF_TRACE_ERROR("%s transaction not obtained with label: %d",__FUNCTION__,lbl); + } + } + else + BTIF_TRACE_ERROR("%s failed to build command:%d",__FUNCTION__,BldResp); +} + + +/*************************************************************************** +** +** Function handle_rc_metamsg_rsp +** +** Description Handle RC metamessage response +** +** Returns void +** +***************************************************************************/ +static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG *pmeta_msg) +{ + tAVRC_RESPONSE avrc_response = {0}; + UINT8 scratch_buf[512] = {0}; + tAVRC_STS status = BT_STATUS_UNSUPPORTED; + + if(AVRC_OP_VENDOR==pmeta_msg->p_msg->hdr.opcode &&(AVRC_RSP_CHANGED==pmeta_msg->code + || AVRC_RSP_INTERIM==pmeta_msg->code || AVRC_RSP_ACCEPT==pmeta_msg->code + || AVRC_RSP_REJ==pmeta_msg->code || AVRC_RSP_NOT_IMPL==pmeta_msg->code)) + { + status=AVRC_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf, sizeof(scratch_buf)); + BTIF_TRACE_DEBUG("%s: code %d,event ID %d,PDU %x,parsing status %d, label:%d", + __FUNCTION__,pmeta_msg->code,avrc_response.reg_notif.event_id,avrc_response.reg_notif.pdu, + status, pmeta_msg->label); + + if (status != AVRC_STS_NO_ERROR) + { + if(AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu + && AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id + && btif_rc_cb.rc_vol_label==pmeta_msg->label) + { + btif_rc_cb.rc_vol_label=MAX_LABEL; + release_transaction(btif_rc_cb.rc_vol_label); + } + else if(AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu) + { + release_transaction(pmeta_msg->label); + } + return; + } + else if(AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu + && AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id + && btif_rc_cb.rc_vol_label!=pmeta_msg->label) + { + // Just discard the message, if the device sends back with an incorrect label + BTIF_TRACE_DEBUG("%s:Discarding register notfn in rsp.code: %d and label %d", + __FUNCTION__, pmeta_msg->code, pmeta_msg->label); + return; + } + } + else + { + BTIF_TRACE_DEBUG("%s:Received vendor dependent in adv ctrl rsp. code: %d len: %d. Not processing it.", + __FUNCTION__, pmeta_msg->code, pmeta_msg->len); + return; + } + + if(AVRC_PDU_REGISTER_NOTIFICATION==avrc_response.rsp.pdu + && AVRC_EVT_VOLUME_CHANGE==avrc_response.reg_notif.event_id + && AVRC_RSP_CHANGED==pmeta_msg->code) + { + /* re-register for volume change notification */ + // Do not re-register for rejected case, as it might get into endless loop + register_volumechange(btif_rc_cb.rc_vol_label); + } + else if(AVRC_PDU_SET_ABSOLUTE_VOLUME==avrc_response.rsp.pdu) + { + /* free up the label here */ + release_transaction(pmeta_msg->label); + } + + BTIF_TRACE_EVENT("%s: Passing received metamsg response to app. pdu: %s", + __FUNCTION__, dump_rc_pdu(avrc_response.pdu)); + btif_rc_upstreams_rsp_evt((uint16_t)avrc_response.rsp.pdu, &avrc_response, pmeta_msg->code, + pmeta_msg->label); +} + + +/*************************************************************************** +** +** Function cleanup +** +** Description Closes the AVRC interface +** +** Returns void +** +***************************************************************************/ +static void cleanup() +{ + BTIF_TRACE_EVENT("## %s ##", __FUNCTION__); + close_uinput(); + if (bt_rc_callbacks) + { + bt_rc_callbacks = NULL; + } + memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t)); + lbl_destroy(); + BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__); +} + +/*************************************************************************** +** +** Function cleanup_ctrl +** +** Description Closes the AVRC Controller interface +** +** Returns void +** +***************************************************************************/ +static void cleanup_ctrl() +{ + BTIF_TRACE_EVENT("## %s ##", __FUNCTION__); + + if (bt_rc_ctrl_callbacks) + { + bt_rc_ctrl_callbacks = NULL; + } + memset(&btif_rc_cb, 0, sizeof(btif_rc_cb_t)); + lbl_destroy(); + BTIF_TRACE_EVENT("## %s ## completed", __FUNCTION__); +} + +static bt_status_t send_passthrough_cmd(bt_bdaddr_t *bd_addr, uint8_t key_code, uint8_t key_state) +{ + tAVRC_STS status = BT_STATUS_UNSUPPORTED; +#if (AVRC_CTLR_INCLUDED == TRUE) + CHECK_RC_CONNECTED + rc_transaction_t *p_transaction=NULL; + BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__, + key_code, key_state); + if (btif_rc_cb.rc_features & BTA_AV_FEAT_RCTG) + { + bt_status_t tran_status = get_transaction(&p_transaction); + if(BT_STATUS_SUCCESS == tran_status && NULL != p_transaction) + { + BTA_AvRemoteCmd(btif_rc_cb.rc_handle, p_transaction->lbl, + (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state); + status = BT_STATUS_SUCCESS; + BTIF_TRACE_DEBUG("%s: succesfully sent passthrough command to BTA", __FUNCTION__); + } + else + { + status = BT_STATUS_FAIL; + BTIF_TRACE_DEBUG("%s: error in fetching transaction", __FUNCTION__); + } + } + else + { + status = BT_STATUS_FAIL; + BTIF_TRACE_DEBUG("%s: feature not supported", __FUNCTION__); + } +#else + BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__); +#endif + return status; +} + +static const btrc_interface_t bt_rc_interface = { + sizeof(bt_rc_interface), + init, + get_play_status_rsp, + NULL, /* list_player_app_attr_rsp */ + NULL, /* list_player_app_value_rsp */ + NULL, /* get_player_app_value_rsp */ + NULL, /* get_player_app_attr_text_rsp */ + NULL, /* get_player_app_value_text_rsp */ + get_element_attr_rsp, + NULL, /* set_player_app_value_rsp */ + register_notification_rsp, + set_volume, + cleanup, +}; + +static const btrc_ctrl_interface_t bt_rc_ctrl_interface = { + sizeof(bt_rc_ctrl_interface), + init_ctrl, + send_passthrough_cmd, + cleanup_ctrl, +}; + +/******************************************************************************* +** +** Function btif_rc_get_interface +** +** Description Get the AVRCP Target callback interface +** +** Returns btav_interface_t +** +*******************************************************************************/ +const btrc_interface_t *btif_rc_get_interface(void) +{ + BTIF_TRACE_EVENT("%s", __FUNCTION__); + return &bt_rc_interface; +} + +/******************************************************************************* +** +** Function btif_rc_ctrl_get_interface +** +** Description Get the AVRCP Controller callback interface +** +** Returns btav_interface_t +** +*******************************************************************************/ +const btrc_ctrl_interface_t *btif_rc_ctrl_get_interface(void) +{ + BTIF_TRACE_EVENT("%s", __FUNCTION__); + return &bt_rc_ctrl_interface; +} + +/******************************************************************************* +** Function initialize_transaction +** +** Description Initializes fields of the transaction structure +** +** Returns void +*******************************************************************************/ +static void initialize_transaction(int lbl) +{ + pthread_mutex_lock(&device.lbllock); + if(lbl < MAX_TRANSACTIONS_PER_SESSION) + { + device.transaction[lbl].lbl = lbl; + device.transaction[lbl].in_use=FALSE; + device.transaction[lbl].handle=0; + } + pthread_mutex_unlock(&device.lbllock); +} + +/******************************************************************************* +** Function lbl_init +** +** Description Initializes label structures and mutexes. +** +** Returns void +*******************************************************************************/ +void lbl_init() +{ + memset(&device,0,sizeof(rc_device_t)); + // pthread_mutexattr_t attr; + // pthread_mutexattr_init(&attr); + pthread_mutex_init(&(device.lbllock), NULL); + // pthread_mutexattr_destroy(&attr); + init_all_transactions(); +} + +/******************************************************************************* +** +** Function init_all_transactions +** +** Description Initializes all transactions +** +** Returns void +*******************************************************************************/ +void init_all_transactions() +{ + UINT8 txn_indx=0; + for(txn_indx=0; txn_indx < MAX_TRANSACTIONS_PER_SESSION; txn_indx++) + { + initialize_transaction(txn_indx); + } +} + +/******************************************************************************* +** +** Function get_transaction_by_lbl +** +** Description Will return a transaction based on the label. If not inuse +** will return an error. +** +** Returns bt_status_t +*******************************************************************************/ +rc_transaction_t *get_transaction_by_lbl(UINT8 lbl) +{ + rc_transaction_t *transaction = NULL; + pthread_mutex_lock(&device.lbllock); + + /* Determine if this is a valid label */ + if (lbl < MAX_TRANSACTIONS_PER_SESSION) + { + if (FALSE==device.transaction[lbl].in_use) + { + transaction = NULL; + } + else + { + transaction = &(device.transaction[lbl]); + BTIF_TRACE_DEBUG("%s: Got transaction.label: %d",__FUNCTION__,lbl); + } + } + + pthread_mutex_unlock(&device.lbllock); + return transaction; +} + +/******************************************************************************* +** +** Function get_transaction +** +** Description Obtains the transaction details. +** +** Returns bt_status_t +*******************************************************************************/ + +bt_status_t get_transaction(rc_transaction_t **ptransaction) +{ + bt_status_t result = BT_STATUS_NOMEM; + UINT8 i=0; + pthread_mutex_lock(&device.lbllock); + + // Check for unused transactions + for (i=0; i + // #include + // #include + +/******************************************************************************* +** Constants & Macros +********************************************************************************/ + +/* Events */ + +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f + +/* Synchronization events */ + +#define SYN_REPORT 0 +#define SYN_CONFIG 1 + +/* Keys and buttons */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 +#define KEY_103RD 84 +#define KEY_F13 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_F14 89 +#define KEY_F15 90 +#define KEY_F16 91 +#define KEY_F17 92 +#define KEY_F18 93 +#define KEY_F19 94 +#define KEY_F20 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_F21 120 +#define KEY_F22 121 +#define KEY_F23 122 +#define KEY_F24 123 +#define KEY_KPCOMMA 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 +#define KEY_AGAIN 129 +#define KEY_PROPS 130 +#define KEY_UNDO 131 +#define KEY_FRONT 132 +#define KEY_COPY 133 +#define KEY_OPEN 134 +#define KEY_PASTE 135 +#define KEY_FIND 136 +#define KEY_CUT 137 +#define KEY_HELP 138 +#define KEY_MENU 139 +#define KEY_CALC 140 +#define KEY_SETUP 141 +#define KEY_SLEEP 142 +#define KEY_WAKEUP 143 +#define KEY_FILE 144 +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 +#define KEY_DIRECTION 153 +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 +#define KEY_COMPUTER 157 +#define KEY_BACK 158 +#define KEY_FORWARD 159 +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 +#define KEY_ISO 170 +#define KEY_CONFIG 171 +#define KEY_HOMEPAGE 172 +#define KEY_REFRESH 173 +#define KEY_EXIT 174 +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 + +#define KEY_INTL1 181 +#define KEY_INTL2 182 +#define KEY_INTL3 183 +#define KEY_INTL4 184 +#define KEY_INTL5 185 +#define KEY_INTL6 186 +#define KEY_INTL7 187 +#define KEY_INTL8 188 +#define KEY_INTL9 189 +#define KEY_LANG1 190 +#define KEY_LANG2 191 +#define KEY_LANG3 192 +#define KEY_LANG4 193 +#define KEY_LANG5 194 +#define KEY_LANG6 195 +#define KEY_LANG7 196 +#define KEY_LANG8 197 +#define KEY_LANG9 198 + +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 +#define KEY_PLAY 207 +#define KEY_FAST_FORWARD 208 + +#define KEY_UNKNOWN 220 + +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c +#define BTN_TOOL_DOUBLETAP 0x14d +#define BTN_TOOL_TRIPLETAP 0x14e + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define KEY_OK 0x160 +#define KEY_SELECT 0x161 +#define KEY_GOTO 0x162 +#define KEY_CLEAR 0x163 +#define KEY_POWER2 0x164 +#define KEY_OPTION 0x165 +#define KEY_INFO 0x166 +#define KEY_TIME 0x167 +#define KEY_VENDOR 0x168 +#define KEY_ARCHIVE 0x169 +#define KEY_PROGRAM 0x16a +#define KEY_CHANNEL 0x16b +#define KEY_FAVORITES 0x16c +#define KEY_EPG 0x16d +#define KEY_PVR 0x16e +#define KEY_MHP 0x16f +#define KEY_LANGUAGE 0x170 +#define KEY_TITLE 0x171 +#define KEY_SUBTITLE 0x172 +#define KEY_ANGLE 0x173 +#define KEY_ZOOM 0x174 +#define KEY_MODE 0x175 +#define KEY_KEYBOARD 0x176 +#define KEY_SCREEN 0x177 +#define KEY_PC 0x178 +#define KEY_TV 0x179 +#define KEY_TV2 0x17a +#define KEY_VCR 0x17b +#define KEY_VCR2 0x17c +#define KEY_SAT 0x17d +#define KEY_SAT2 0x17e +#define KEY_CD 0x17f +#define KEY_TAPE 0x180 +#define KEY_RADIO 0x181 +#define KEY_TUNER 0x182 +#define KEY_PLAYER 0x183 +#define KEY_TEXT 0x184 +#define KEY_DVD 0x185 +#define KEY_AUX 0x186 +#define KEY_MP3 0x187 +#define KEY_AUDIO 0x188 +#define KEY_VIDEO 0x189 +#define KEY_DIRECTORY 0x18a +#define KEY_LIST 0x18b +#define KEY_MEMO 0x18c +#define KEY_CALENDAR 0x18d +#define KEY_RED 0x18e +#define KEY_GREEN 0x18f +#define KEY_YELLOW 0x190 +#define KEY_BLUE 0x191 +#define KEY_CHANNELUP 0x192 +#define KEY_CHANNELDOWN 0x193 +#define KEY_FIRST 0x194 +#define KEY_LAST 0x195 +#define KEY_AB 0x196 +#define KEY_NEXT 0x197 +#define KEY_RESTART 0x198 +#define KEY_SLOW 0x199 +#define KEY_SHUFFLE 0x19a +#define KEY_BREAK 0x19b +#define KEY_PREVIOUS 0x19c +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x19f + +#define KEY_FRAMEBACK 0x1b2 +#define KEY_FRAMEFORWARD 0x1b3 +#define KEY_CONTEXT_MENU 0x1fb + +#define KEY_MAX 0x1ff + +/* Relative axes */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_RX 0x03 +#define REL_RY 0x04 +#define REL_RZ 0x05 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f + +/* Absolute axes */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c +#define ABS_VOLUME 0x20 +#define ABS_MISC 0x28 +#define ABS_MAX 0x3f + +/* Switch events */ + +#define SW_0 0x00 +#define SW_1 0x01 +#define SW_2 0x02 +#define SW_3 0x03 +#define SW_4 0x04 +#define SW_5 0x05 +#define SW_6 0x06 +#define SW_7 0x07 +#define SW_MAX 0x0f + +/* Misc events */ + +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 +#define MSC_MAX 0x07 + +/* LEDs */ + +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_SLEEP 0x05 +#define LED_SUSPEND 0x06 +#define LED_MUTE 0x07 +#define LED_MISC 0x08 +#define LED_MAIL 0x09 +#define LED_CHARGING 0x0a +#define LED_MAX 0x0f + +/* Autorepeat values */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 + +/* Sounds */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_TONE 0x02 +#define SND_MAX 0x07 + +/* Identifiers */ + +#define ID_BUS 0 +#define ID_VENDOR 1 +#define ID_PRODUCT 2 +#define ID_VERSION 3 + +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 +#define BUS_BLUETOOTH 0x05 + +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 +#define BUS_GSC 0x1A + +/* User input interface */ +#define _IO(a, b) (0) // temporary hack +#define _IOW(a, b, c) (1) // temporary hack + +#define UINPUT_IOCTL_BASE 'U' + +#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) +#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) + +#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) +#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) +#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) +#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int) +#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int) +#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int) +#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int) +#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int) +#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*) +#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int) + +#ifndef NBITS +#define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1) +#endif + +#define UINPUT_MAX_NAME_SIZE 80 + + +/******************************************************************************* +** Type definitions and return values +********************************************************************************/ + +struct uinput_id { + uint16_t bustype; + uint16_t vendor; + uint16_t product; + uint16_t version; +}; + +struct uinput_dev { + char name[UINPUT_MAX_NAME_SIZE]; + struct uinput_id id; + int ff_effects_max; + int absmax[ABS_MAX + 1]; + int absmin[ABS_MAX + 1]; + int absfuzz[ABS_MAX + 1]; + int absflat[ABS_MAX + 1]; +}; + +struct uinput_event { + // struct timeval time; // temporarily remove this part; + uint16_t type; + uint16_t code; + int32_t value; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __UINPUT_H */ + diff --git a/examples/09_a2dp/components/bluedroid_demos/include/bt_rc.h b/examples/09_a2dp/components/bluedroid_demos/include/bt_rc.h new file mode 100755 index 0000000000..c565c48755 --- /dev/null +++ b/examples/09_a2dp/components/bluedroid_demos/include/bt_rc.h @@ -0,0 +1,296 @@ +/* + * 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 ANDROID_INCLUDE_BT_RC_H +#define ANDROID_INCLUDE_BT_RC_H + +__BEGIN_DECLS + +/* 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; + +/** 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; + +__END_DECLS + +#endif /* ANDROID_INCLUDE_BT_RC_H */