diff options
Diffstat (limited to 'btif/src/btif_av.c')
-rw-r--r-- | btif/src/btif_av.c | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c new file mode 100644 index 0000000..d383926 --- /dev/null +++ b/btif/src/btif_av.c @@ -0,0 +1,544 @@ +/****************************************************************************** + * + * 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_av.c + * + * Description: Bluedroid AV implementation + * + *****************************************************************************/ +#include <hardware/bluetooth.h> +#include "hardware/bt_av.h" + +#define LOG_TAG "BTIF_AV" +#include "btif_common.h" +#include "btif_sm.h" +#include "bta_api.h" +#include "bta_av_api.h" +#include "gki.h" + +/***************************************************************************** +** Constants & Macros +******************************************************************************/ +#define BTIF_AV_SERVICE_NAME "Advanced Audio" + +typedef enum { + BTIF_AV_STATE_IDLE = 0x0, + BTIF_AV_STATE_OPENING, + BTIF_AV_STATE_OPENED, + BTIF_AV_STATE_STARTED +} btif_av_state_t; + +typedef enum { + /* Reuse BTA_AV_XXX_EVT - No need to redefine them here */ + BTIF_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT, + BTIF_AV_DISCONNECT_REQ_EVT, + BTIF_AV_START_STREAM_REQ_EVT, + BTIF_AV_STOP_STREAM_REQ_EVT, + BTIF_AV_SUSPEND_STREAM_REQ_EVT, + BTIF_AV_RECONFIGURE_REQ_EVT, +} btif_av_sm_event_t; +/***************************************************************************** +** Local type definitions +******************************************************************************/ +typedef struct +{ + tBTA_AV_HNDL bta_handle; + bt_bdaddr_t peer_bda; + btif_sm_handle_t sm_handle; +} btif_av_cb_t; +/***************************************************************************** +** Static variables +******************************************************************************/ +static btav_callbacks_t *bt_av_callbacks = NULL; +static btif_av_cb_t btif_av_cb; + +#define CHECK_BTAV_INIT() if (bt_av_callbacks == NULL)\ +{\ + BTIF_TRACE_WARNING1("%s: BTAV not initialized", __FUNCTION__);\ + return BT_STATUS_NOT_READY;\ +}\ +else\ +{\ + BTIF_TRACE_EVENT1("%s", __FUNCTION__);\ +} + +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); +static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data); + +static const btif_sm_handler_t btif_av_state_handlers[] = +{ + btif_av_state_idle_handler, + btif_av_state_opening_handler, + btif_av_state_opened_handler, + btif_av_state_started_handler +}; + + +/***************************************************************************** +** Local helper functions +******************************************************************************/ +const char *dump_av_sm_state_name(btif_av_state_t state) +{ + switch (state) { + case BTIF_AV_STATE_IDLE: return "BTIF_AV_STATE_IDLE"; + case BTIF_AV_STATE_OPENING: return "BTIF_AV_STATE_OPENING"; + case BTIF_AV_STATE_OPENED: return "BTIF_AV_STATE_OPENED"; + case BTIF_AV_STATE_STARTED: return "BTIF_AV_STATE_STARTED"; + default: return "UNKNOWN_STATE"; + } +} + +const char *dump_av_sm_event_name(btif_av_sm_event_t event) +{ + switch(event) { + case BTA_AV_ENABLE_EVT: return "BTA_AV_ENABLE_EVT"; + case BTA_AV_REGISTER_EVT: return "BTA_AV_REGISTER_EVT"; + case BTA_AV_OPEN_EVT: return "BTA_AV_OPEN_EVT"; + case BTA_AV_CLOSE_EVT: return "BTA_AV_CLOSE_EVT"; + case BTA_AV_START_EVT: return "BTA_AV_START_EVT"; + case BTA_AV_STOP_EVT: return "BTA_AV_STOP_EVT"; + case BTA_AV_PROTECT_REQ_EVT: return "BTA_AV_PROTECT_REQ_EVT"; + case BTA_AV_PROTECT_RSP_EVT: return "BTA_AV_PROTECT_RSP_EVT"; + 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"; + case BTA_AV_RECONFIG_EVT: return "BTA_AV_RECONFIG_EVT"; + case BTA_AV_SUSPEND_EVT: return "BTA_AV_SUSPEND_EVT"; + case BTA_AV_PENDING_EVT: return "BTA_AV_PENDING_EVT"; + case BTA_AV_META_MSG_EVT: return "BTA_AV_META_MSG_EVT"; + case BTA_AV_REJECT_EVT: return "BTA_AV_REJECT_EVT"; + case BTA_AV_RC_FEAT_EVT: return "BTA_AV_RC_FEAT_EVT"; + + case BTIF_SM_ENTER_EVT: return "BTIF_SM_ENTER_EVT"; + case BTIF_SM_EXIT_EVT: return "BTIF_SM_EXIT_EVT"; + case BTIF_AV_CONNECT_REQ_EVT: return "BTIF_AV_CONNECT_REQ_EVT"; + case BTIF_AV_DISCONNECT_REQ_EVT: return "BTIF_AV_DISCONNECT_REQ_EVT"; + case BTIF_AV_START_STREAM_REQ_EVT: return "BTIF_AV_START_STREAM_REQ_EVT"; + case BTIF_AV_STOP_STREAM_REQ_EVT: return "BTIF_AV_STOP_STREAM_REQ_EVT"; + case BTIF_AV_SUSPEND_STREAM_REQ_EVT: return "BTIF_AV_SUSPEND_STREAM_REQ_EVT"; + case BTIF_AV_RECONFIGURE_REQ_EVT: return "BTIF_AV_RECONFIGURE_REQ_EVT"; + default: return "UNKNOWN_EVENT"; + } +} + +/***************************************************************************** +** Static functions +******************************************************************************/ + +void btif_a2dp_set_busy_level(UINT8 level); +void btif_a2dp_upon_init(void); +void btif_a2dp_upon_idle(void); +void btif_a2dp_upon_start_req(void); +void btif_a2dp_upon_started(void); +int btif_a2dp_start_media_task(void); +void btif_a2dp_stop_media_task(void); + +static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) +{ + BTIF_TRACE_DEBUG2("%s event:%s", __FUNCTION__, dump_av_sm_event_name(event)); + + switch (event) + { + case BTIF_SM_ENTER_EVT: + { + /* clear the peer_bda */ + memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t)); + btif_a2dp_upon_idle(); + } break; + + case BTIF_SM_EXIT_EVT: + break; + + case BTA_AV_ENABLE_EVT: + { + BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0); + } break; + + case BTA_AV_REGISTER_EVT: + { + btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl; + } break; + + case 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); + + btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING); + } break; + + default: + BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__, + dump_av_sm_event_name(event)); + } + 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)); + + switch (event) + { + case BTIF_SM_ENTER_EVT: + { + /* inform the application that we are entering connecting state */ + CHECK_CALL_CBACK(bt_av_callbacks, connection_state_cb, + BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb.peer_bda)); + } break; + + case BTIF_SM_EXIT_EVT: + break; + + case BTA_AV_OPEN_EVT: + { + tBTA_AV *p_bta_data = (tBTA_AV*)p_data; + btav_connection_state_t state = BTAV_CONNECTION_STATE_DISCONNECTED; + 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); + } + 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); + } + /* inform the application of the event */ + CHECK_CALL_CBACK(bt_av_callbacks, connection_state_cb, + state, &(btif_av_cb.peer_bda)); + } break; + + default: + BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__, + dump_av_sm_event_name(event)); + } + return TRUE; +} + + +static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) +{ + BTIF_TRACE_DEBUG2("%s event:%s", __FUNCTION__, dump_av_sm_event_name(event)); + + switch (event) + { + case BTIF_SM_ENTER_EVT: + + BTIF_TRACE_DEBUG0("starting av"); + + btif_a2dp_upon_start_req(); + + /* autostart for now to test media task */ + BTA_AvStart(); + + break; + + case BTIF_SM_EXIT_EVT: + break; + + case BTIF_AV_START_STREAM_REQ_EVT: + /* fixme */ + break; + + case BTA_AV_START_EVT: + { + tBTA_AV *p_bta_data = (tBTA_AV*)p_data; + + if (p_bta_data->start.status == BTA_AV_SUCCESS) + { + /* change state to started */ + btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED); + } + else + { + /* fixme */ + } + } break; + + case BTIF_AV_DISCONNECT_REQ_EVT: + { + BTA_AvClose(btif_av_cb.bta_handle); + /* inform the application that we are disconnecting */ + CHECK_CALL_CBACK(bt_av_callbacks, connection_state_cb, + BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda)); + } break; + + case BTA_AV_CLOSE_EVT: + { + /* inform the application that we are disconnecting */ + CHECK_CALL_CBACK(bt_av_callbacks, connection_state_cb, + BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda)); + btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE); + } break; + + default: + BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__, + dump_av_sm_event_name(event)); + } + return TRUE; +} + +static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data) +{ + BTIF_TRACE_DEBUG2("%s event:%s", __FUNCTION__, dump_av_sm_event_name(event)); + + switch (event) + { + case BTIF_SM_ENTER_EVT: + btif_a2dp_upon_started(); + break; + + case BTIF_SM_EXIT_EVT: + break; + case BTIF_AV_DISCONNECT_REQ_EVT: + { + BTA_AvClose(btif_av_cb.bta_handle); + /* inform the application that we are disconnecting */ + CHECK_CALL_CBACK(bt_av_callbacks, connection_state_cb, + BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda)); + } break; + + case BTA_AV_STOP_EVT: + { + /* inform the application that we are disconnecting */ + btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED); + } break; + + default: + BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__, + dump_av_sm_event_name(event)); + } + return TRUE; +} + +static void btif_av_handle_event(UINT16 event, char* p_param) +{ + btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param); +} + +static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data) +{ + /* Switch to BTIF context */ + btif_transfer_context(btif_av_handle_event, event, + (char*)p_data, sizeof(tBTA_AV), NULL); +} +/***************************************************************************** +** Externs +******************************************************************************/ + +/***************************************************************************** +** Functions +******************************************************************************/ + +/******************************************************************************* +** +** Function init +** +** Description Initializes the AV interface +** +** Returns bt_status_t +** +*******************************************************************************/ + +static bt_status_t init(btav_callbacks_t* callbacks ) +{ + int status; + + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + + status = btif_a2dp_start_media_task(); + + if (status != GKI_SUCCESS) + return BT_STATUS_FAIL; + + bt_av_callbacks = callbacks; + + btif_enable_service(BTA_A2DP_SERVICE_ID); + /* 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); + + btif_a2dp_upon_init(); + + return BT_STATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function connect +** +** Description Establishes the AV signalling channel with the remote headset +** +** Returns bt_status_t +** +*******************************************************************************/ +static bt_status_t connect(bt_bdaddr_t *bd_addr) +{ + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + + BTIF_TRACE_ERROR1("callbacks is 0x%x", bt_av_callbacks); + CHECK_BTAV_INIT(); + + /* Switch to BTIF context */ + return btif_transfer_context(btif_av_handle_event, BTIF_AV_CONNECT_REQ_EVT, + (char*)bd_addr, sizeof(bt_bdaddr_t), NULL); +} + +/******************************************************************************* +** +** Function disconnect +** +** Description Tears down the AV signalling channel with the remote headset +** +** Returns bt_status_t +** +*******************************************************************************/ +static bt_status_t disconnect(bt_bdaddr_t *bd_addr) +{ + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + + CHECK_BTAV_INIT(); + + /* Switch to BTIF context */ + return btif_transfer_context(btif_av_handle_event, BTIF_AV_DISCONNECT_REQ_EVT, + (char*)bd_addr, sizeof(bt_bdaddr_t), NULL); +} + +/******************************************************************************* +** +** Function cleanup +** +** Description Shuts down the AV interface and does the cleanup +** +** Returns None +** +*******************************************************************************/ +static void cleanup(void) +{ + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + + if (bt_av_callbacks) + { + btif_a2dp_stop_media_task(); + + btif_disable_service(BTA_A2DP_SERVICE_ID); + bt_av_callbacks = NULL; + + /* Also shut down the AV state machine */ + btif_sm_shutdown(btif_av_cb.sm_handle); + btif_av_cb.sm_handle = NULL; + } + return; +} + +static const btav_interface_t bt_av_interface = { + sizeof(btav_interface_t), + init, + connect, + disconnect, + cleanup, +}; + +/******************************************************************************* +** +** Function btif_av_execute_service +** +** Description Initializes/Shuts down the service +** +** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btif_av_execute_service(BOOLEAN b_enable) +{ + if (b_enable) + { +#if (AVRC_METADATA_INCLUDED == TRUE) + BTA_AvEnable(BTA_SEC_AUTHENTICATE|BTA_SEC_AUTHORIZE, + 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, + bte_av_callback); +#endif + BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0); + } + else { + BTA_AvDeregister(btif_av_cb.bta_handle); + BTA_AvDisable(); + } + return BT_STATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function btif_av_get_interface +** +** Description Get the AV callback interface +** +** Returns btav_interface_t +** +*******************************************************************************/ +const btav_interface_t *btif_av_get_interface() +{ + BTIF_TRACE_EVENT1("%s", __FUNCTION__); + return &bt_av_interface; +} |