diff options
Diffstat (limited to 'btif/src/btif_av.c')
-rw-r--r-- | btif/src/btif_av.c | 576 |
1 files changed, 406 insertions, 170 deletions
diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c index a822c7f..87ee8fb 100644 --- a/btif/src/btif_av.c +++ b/btif/src/btif_av.c @@ -3,44 +3,44 @@ * 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. + * 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 + * 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 + * 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 + * 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 + * 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. * *****************************************************************************/ @@ -51,15 +51,18 @@ * 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 "btif_av.h" +#include "btif_util.h" #include "bta_api.h" +#include "btif_media.h" #include "bta_av_api.h" #include "gki.h" #include "bd.h" @@ -70,24 +73,16 @@ ******************************************************************************/ #define BTIF_AV_SERVICE_NAME "Advanced Audio" -#define BTIF_TIMEOUT_AV_OPEN_ON_RC 2 /* 2 seconds */ +#define BTIF_TIMEOUT_AV_OPEN_ON_RC_SECS 2 typedef enum { BTIF_AV_STATE_IDLE = 0x0, BTIF_AV_STATE_OPENING, BTIF_AV_STATE_OPENED, - BTIF_AV_STATE_STARTED + BTIF_AV_STATE_STARTED, + BTIF_AV_STATE_CLOSING } 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 ******************************************************************************/ @@ -131,16 +126,17 @@ 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 BOOLEAN btif_av_state_closing_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 + btif_av_state_started_handler, + btif_av_state_closing_handler }; - /************************************************************************* ** Extern functions *************************************************************************/ @@ -151,54 +147,57 @@ extern BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr); /***************************************************************************** ** 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"; - } + switch (state) + { + CASE_RETURN_STR(BTIF_AV_STATE_IDLE) + CASE_RETURN_STR(BTIF_AV_STATE_OPENING) + CASE_RETURN_STR(BTIF_AV_STATE_OPENED) + CASE_RETURN_STR(BTIF_AV_STATE_STARTED) + CASE_RETURN_STR(BTIF_AV_STATE_CLOSING) + 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"; + switch(event) + { + CASE_RETURN_STR(BTA_AV_ENABLE_EVT) + CASE_RETURN_STR(BTA_AV_REGISTER_EVT) + CASE_RETURN_STR(BTA_AV_OPEN_EVT) + CASE_RETURN_STR(BTA_AV_CLOSE_EVT) + CASE_RETURN_STR(BTA_AV_START_EVT) + CASE_RETURN_STR(BTA_AV_STOP_EVT) + CASE_RETURN_STR(BTA_AV_PROTECT_REQ_EVT) + CASE_RETURN_STR(BTA_AV_PROTECT_RSP_EVT) + CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT) + CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT) + CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT) + CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT) + CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT) + CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT) + CASE_RETURN_STR(BTA_AV_RECONFIG_EVT) + CASE_RETURN_STR(BTA_AV_SUSPEND_EVT) + CASE_RETURN_STR(BTA_AV_PENDING_EVT) + CASE_RETURN_STR(BTA_AV_META_MSG_EVT) + CASE_RETURN_STR(BTA_AV_REJECT_EVT) + CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT) + CASE_RETURN_STR(BTIF_SM_ENTER_EVT) + CASE_RETURN_STR(BTIF_SM_EXIT_EVT) + CASE_RETURN_STR(BTIF_AV_CONNECT_REQ_EVT) + CASE_RETURN_STR(BTIF_AV_DISCONNECT_REQ_EVT) + CASE_RETURN_STR(BTIF_AV_START_STREAM_REQ_EVT) + CASE_RETURN_STR(BTIF_AV_STOP_STREAM_REQ_EVT) + CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT) + CASE_RETURN_STR(BTIF_AV_RECONFIGURE_REQ_EVT) + default: return "UNKNOWN_EVENT"; } } - /**************************************************************************** ** Local helper functions *****************************************************************************/ @@ -232,13 +231,15 @@ static void btif_initiate_av_open_tmr_hdlr(TIMER_LIST_ENT *tle) ** 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); +/***************************************************************************** +** +** Function btif_av_state_idle_handler +** +** Description State managing disconnected AV link +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) { @@ -247,41 +248,38 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) 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; - + btif_a2dp_on_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; + break; case BTA_AV_REGISTER_EVT: - { btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl; - } break; + break; + case BTA_AV_PENDING_EVT: case BTIF_AV_CONNECT_REQ_EVT: { if (event == BTIF_AV_CONNECT_REQ_EVT) { - memcpy(&btif_av_cb.peer_bda, (bt_bdaddr_t*)p_data, sizeof(bt_bdaddr_t)); - BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, - TRUE, BTA_SEC_NONE); + memcpy(&btif_av_cb.peer_bda, (bt_bdaddr_t*)p_data, sizeof(bt_bdaddr_t)); } else if (event == BTA_AV_PENDING_EVT) { bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr); } + 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; + case BTA_AV_RC_OPEN_EVT: - { /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So * as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore, * we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state. @@ -291,35 +289,48 @@ static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data) * * TODO: We may need to do this only on an AVRCP Play. FixMe */ + BTIF_TRACE_DEBUG0("BTA_AV_RC_OPEN_EVT received w/o AV"); memset(&tle_av_open_on_rc, 0, sizeof(tle_av_open_on_rc)); tle_av_open_on_rc.param = (UINT32)btif_initiate_av_open_tmr_hdlr; btu_start_timer(&tle_av_open_on_rc, BTU_TTYPE_USER_FUNC, - BTIF_TIMEOUT_AV_OPEN_ON_RC); + BTIF_TIMEOUT_AV_OPEN_ON_RC_SECS); btif_rc_handler(event, p_data); - }break; + break; + case BTA_AV_REMOTE_CMD_EVT: case BTA_AV_VENDOR_CMD_EVT: case BTA_AV_META_MSG_EVT: case BTA_AV_RC_FEAT_EVT: - { btif_rc_handler(event, (tBTA_AV*)p_data); - }break; + break; + case BTA_AV_RC_CLOSE_EVT: - { if (tle_av_open_on_rc.in_use) { BTIF_TRACE_DEBUG0("BTA_AV_RC_CLOSE_EVT: Stopping AV timer."); btu_stop_timer(&tle_av_open_on_rc); } btif_rc_handler(event, p_data); - }break; + break; default: - BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__, + BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__, dump_av_sm_event_name(event)); + return FALSE; + } return TRUE; } +/***************************************************************************** +** +** Function btif_av_state_opening_handler +** +** Description Intermediate state managing events during establishment +** of avdtp channel +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data) { @@ -328,11 +339,10 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data 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, + /* inform the application that we are entering connecting state */ + HAL_CBACK(bt_av_callbacks, connection_state_cb, BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb.peer_bda)); - } break; + break; case BTIF_SM_EXIT_EVT: break; @@ -343,6 +353,7 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data btav_connection_state_t state; btif_sm_state_t av_state; BTIF_TRACE_DEBUG1("status:%d", p_bta_data->open.status); + if (p_bta_data->open.status == BTA_AV_SUCCESS) { state = BTAV_CONNECTION_STATE_CONNECTED; @@ -355,9 +366,11 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data state = BTAV_CONNECTION_STATE_DISCONNECTED; av_state = BTIF_AV_STATE_IDLE; } + /* inform the application of the event */ - CHECK_CALL_CBACK(bt_av_callbacks, connection_state_cb, + HAL_CBACK(bt_av_callbacks, connection_state_cb, state, &(btif_av_cb.peer_bda)); + /* change state to open/idle based on the status */ btif_sm_change_state(btif_av_cb.sm_handle, av_state); } break; @@ -365,14 +378,27 @@ static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data CHECK_RC_EVENT(event, p_data); default: - BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__, + BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__, dump_av_sm_event_name(event)); + return FALSE; + } return TRUE; } -static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) +/***************************************************************************** +** +** Function btif_av_state_closing_handler +** +** Description Intermediate state managing events during closing +** of avdtp channel +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ + +static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data) { BTIF_TRACE_DEBUG2("%s event:%s", __FUNCTION__, dump_av_sm_event_name(event)); @@ -380,105 +406,251 @@ static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) { case BTIF_SM_ENTER_EVT: - BTIF_TRACE_DEBUG0("starting av...sleeping before that"); + /* immediately stop transmission of frames */ + btif_a2dp_set_tx_flush(TRUE); - /* Auto-starting on Open could introduce race conditions. So delaying - * the start. - * - * This is anyway temporary and will be removed once the START/STOP stream - * requests are processed. - */ - GKI_delay(3000); + /* wait for audioflinger to stop a2dp */ + break; - btif_a2dp_upon_start_req(); + case BTIF_AV_STOP_STREAM_REQ_EVT: + /* immediately flush any pending tx frames while suspend is pending */ + btif_a2dp_set_tx_flush(TRUE); - /* autostart for now to test media task */ - BTA_AvStart(); + btif_a2dp_on_stopped(NULL); + + break; + + case BTIF_SM_EXIT_EVT: + break; + + case BTA_AV_CLOSE_EVT: + + /* inform the application that we are disconnecting */ + HAL_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 FALSE; + } + return TRUE; +} + + +/***************************************************************************** +** +** Function btif_av_state_opened_handler +** +** Description Handles AV events while AVDTP is in OPEN state +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ + +static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data) +{ + tBTA_AV *p_av = (tBTA_AV*)p_data; + + BTIF_TRACE_DEBUG2("%s event:%s", __FUNCTION__, dump_av_sm_event_name(event)); + switch (event) + { + case BTIF_SM_ENTER_EVT: break; case BTIF_SM_EXIT_EVT: break; case BTIF_AV_START_STREAM_REQ_EVT: - /* fixme */ + /* prepare media task */ + btif_a2dp_on_start_req(); + BTA_AvStart(); break; case BTA_AV_START_EVT: { - tBTA_AV *p_bta_data = (tBTA_AV*)p_data; + BTIF_TRACE_EVENT3("BTA_AV_START_EVT status %d, suspending %d, init %d", + p_av->start.status, p_av->start.suspending, p_av->start.initiator); + + if ((p_av->start.status == BTA_SUCCESS) && (p_av->start.suspending == TRUE)) + return TRUE; + + btif_a2dp_on_started(&p_av->start); + + /* remain in open state if status failed */ + if (p_av->start.status != BTA_AV_SUCCESS) + return FALSE; + + /* change state to started */ + btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED); - 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, + BTA_AvClose(btif_av_cb.bta_handle); + + /* inform the application that we are disconnecting */ + HAL_CBACK(bt_av_callbacks, connection_state_cb, BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda)); - } break; + break; case BTA_AV_CLOSE_EVT: - { - /* inform the application that we are disconnecting */ - CHECK_CALL_CBACK(bt_av_callbacks, connection_state_cb, + + /* inform the application that we are disconnected */ + HAL_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; + break; CHECK_RC_EVENT(event, p_data); default: - BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__, + BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__, dump_av_sm_event_name(event)); + return FALSE; + } return TRUE; } +/***************************************************************************** +** +** Function btif_av_state_started_handler +** +** Description Handles AV events while A2DP stream is started +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ + static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data) { + tBTA_AV *p_av = (tBTA_AV*)p_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(); + case BTIF_SM_ENTER_EVT: +#ifdef ENABLE_AUDIO_STATE_CB + HAL_CBACK(bt_av_callbacks, audio_state_cb, + BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda)); +#endif break; - + case BTIF_SM_EXIT_EVT: break; + + case BTIF_AV_STOP_STREAM_REQ_EVT: + /* immediately flush any pending tx frames while suspend is pending */ + btif_a2dp_set_tx_flush(TRUE); + + BTA_AvStop(TRUE); + break; + + case BTIF_AV_SUSPEND_STREAM_REQ_EVT: + + /* immediately stop transmission of frames whiel suspend is pending */ + btif_a2dp_set_tx_flush(TRUE); + + BTA_AvStop(TRUE); + 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: - { + /* request avdtp to close */ + BTA_AvClose(btif_av_cb.bta_handle); + /* inform the application that we are disconnecting */ + HAL_CBACK(bt_av_callbacks, connection_state_cb, + BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda)); + + /* wait in closing state until fully closed */ + btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_CLOSING); + break; + + case BTA_AV_SUSPEND_EVT: + + BTIF_TRACE_EVENT2("BTA_AV_SUSPEND_EVT status %d, init %d", + p_av->suspend.status, p_av->suspend.initiator); + + /* a2dp suspended, stop media task until resumed */ + btif_a2dp_on_suspended(&p_av->suspend); + + /* if not successful, remain in current state */ + if (p_av->suspend.status != BTA_AV_SUCCESS) + { + /* suspend failed, reset back tx flush state */ + btif_a2dp_set_tx_flush(FALSE); + return FALSE; + } + +#ifdef ENABLE_AUDIO_STATE_CB + if (p_av->suspend.initiator != TRUE) + { + /* remote suspend, notify HAL and await audioflinger to + suspend/stop stream */ + + HAL_CBACK(bt_av_callbacks, audio_state_cb, + BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb.peer_bda)); + } + else + { + HAL_CBACK(bt_av_callbacks, audio_state_cb, + BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda)); + } +#endif btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED); - } break; + break; + + case BTA_AV_STOP_EVT: + + btif_a2dp_on_stopped(&p_av->suspend); + +#ifdef ENABLE_AUDIO_STATE_CB + HAL_CBACK(bt_av_callbacks, audio_state_cb, + BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda)); +#endif + + /* if stop was successful, change state to open */ + if (p_av->suspend.status == BTA_AV_SUCCESS) + btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED); + + break; + + case BTA_AV_CLOSE_EVT: + + /* avdtp link is closed */ + + btif_a2dp_on_stopped(NULL); + + /* inform the application that we are disconnected */ + HAL_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; CHECK_RC_EVENT(event, p_data); default: - BTIF_TRACE_WARNING2("%s Unhandled event:%s", __FUNCTION__, + BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__, dump_av_sm_event_name(event)); + return FALSE; + } return TRUE; } +/***************************************************************************** +** Local event handlers +******************************************************************************/ + static void btif_av_handle_event(UINT16 event, char* p_param) { btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param); @@ -490,13 +662,6 @@ static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data) btif_transfer_context(btif_av_handle_event, event, (char*)p_data, sizeof(tBTA_AV), NULL); } -/***************************************************************************** -** Externs -******************************************************************************/ - -/***************************************************************************** -** Functions -******************************************************************************/ /******************************************************************************* ** @@ -522,12 +687,14 @@ static bt_status_t init(btav_callbacks_t* callbacks ) bt_av_callbacks = callbacks; btif_enable_service(BTA_A2DP_SERVICE_ID); + /* Initialize the AVRC CB */ btif_rc_init(); + /* Also initialize the AV state machine */ btif_av_cb.sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE); - btif_a2dp_upon_init(); + btif_a2dp_on_init(); return BT_STATUS_SUCCESS; } @@ -610,6 +777,75 @@ static const btav_interface_t bt_av_interface = { /******************************************************************************* ** +** Function btif_av_get_sm_handle +** +** Description Fetches current av SM handle +** +** Returns None +** +*******************************************************************************/ + +btif_sm_handle_t btif_av_get_sm_handle(void) +{ + return btif_av_cb.sm_handle; +} + +/******************************************************************************* +** +** Function btif_av_stream_ready +** +** Description Checks whether AV is ready for starting a stream +** +** Returns None +** +*******************************************************************************/ + +BOOLEAN btif_av_stream_ready(void) +{ + btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle); + BTIF_TRACE_EVENT2("btif_av_stream_ready : sm hdl %d, state %d", + btif_av_cb.sm_handle, state); + return (state == BTIF_AV_STATE_OPENED); +} + +/******************************************************************************* +** +** Function btif_av_stream_started +** +** Description Checks whether AV is already started (remotely) +** +** Returns None +** +*******************************************************************************/ + +BOOLEAN btif_av_stream_started(void) +{ + btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle); + BTIF_TRACE_EVENT2("btif_av_stream_started : sm hdl %d, state %d", + btif_av_cb.sm_handle, state); + return (state == BTIF_AV_STATE_STARTED); +} + +/******************************************************************************* +** +** Function btif_dispatch_sm_event +** +** Description Send event to AV statemachine +** +** Returns None +** +*******************************************************************************/ + +/* used to pass events to AV statemachine from other tasks */ +void btif_dispatch_sm_event(btif_av_sm_event_t event, void *p_data, int len) +{ + /* Switch to BTIF context */ + btif_transfer_context(btif_av_handle_event, event, + (char*)p_data, len, NULL); +} + +/******************************************************************************* +** ** Function btif_av_execute_service ** ** Description Initializes/Shuts down the service @@ -650,7 +886,7 @@ bt_status_t btif_av_execute_service(BOOLEAN b_enable) ** Returns btav_interface_t ** *******************************************************************************/ -const btav_interface_t *btif_av_get_interface() +const btav_interface_t *btif_av_get_interface(void) { BTIF_TRACE_EVENT1("%s", __FUNCTION__); return &bt_av_interface; |