]> granicus.if.org Git - esp-idf/commitdiff
component/bt: Merge branch 'master' into feature/btdm_a2dp
authorwangmengyang <wangmengyang@espressif.com>
Mon, 26 Dec 2016 12:35:28 +0000 (20:35 +0800)
committerwangmengyang <wangmengyang@espressif.com>
Mon, 26 Dec 2016 12:35:28 +0000 (20:35 +0800)
16 files changed:
1  2 
components/bt/bluedroid/bta/av/bta_av_aact.c
components/bt/bluedroid/bta/sys/bta_sys_main.c
components/bt/bluedroid/btif/btif_avk.c
components/bt/bluedroid/btif/btif_media_task.c
components/bt/bluedroid/btif/btif_profile_queue.c
components/bt/bluedroid/gki/gki_buffer.c
components/bt/bluedroid/hci/hci_layer.c
components/bt/bluedroid/osi/alarm.c
components/bt/bluedroid/osi/include/thread.h
components/bt/bluedroid/stack/avct/avct_lcb.c
components/bt/bluedroid/stack/avdt/avdt_api.c
components/bt/bluedroid/stack/avdt/avdt_scb_act.c
components/bt/bluedroid/stack/btu/btu_task.c
components/bt/component.mk
examples/09_a2dp/components/bluedroid_demos/app_project/SampleA2dp.c
examples/09_a2dp/main/demo_main.c

index d3f813aebecab22e4870d7c6e826b7fe3c85bdd8,0000000000000000000000000000000000000000..a47d7d3320daa7ed7992d074557b2cc16e8d88be
mode 100755,000000..100755
--- /dev/null
@@@ -1,3111 -1,0 +1,3111 @@@
-     APPL_TRACE_ERROR("bta_av_str_stopped:audio_open_cnt=%d, p_data %x",
 +/******************************************************************************
 + *
 + *  Copyright (C) 2004-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.
 + *
 + ******************************************************************************/
 +
 +/******************************************************************************
 + *
 + *  This file contains action functions for advanced audio/video stream
 + *  state machine. these functions are shared by both audio and video
 + *  streams.
 + *
 + ******************************************************************************/
 +
 +#include "bt_target.h"
 +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
 +
 +// #include <assert.h>
 +#include "bt_trace.h"
 +#include <string.h>
 +
 +// #include <cutils/properties.h>
 +
 +#include "bta_av_int.h"
 +#include "avdt_api.h"
 +#include "utl.h"
 +#include "l2c_api.h"
 +#include "l2cdefs.h"
 +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
 +#include "bta_ar_api.h"
 +#endif
 +
 +/*****************************************************************************
 +**  Constants
 +*****************************************************************************/
 +
 +/* the delay time in milliseconds to start service discovery on AVRCP */
 +#ifndef BTA_AV_RC_DISC_TIME_VAL
 +#define BTA_AV_RC_DISC_TIME_VAL     3500
 +#endif
 +
 +/* the timer in milliseconds to guard against link busy and AVDT_CloseReq failed to be sent */
 +#ifndef BTA_AV_CLOSE_REQ_TIME_VAL
 +#define BTA_AV_CLOSE_REQ_TIME_VAL   4000
 +#endif
 +
 +/* number to retry on reconfigure failure - some headsets requirs this number to be more than 1 */
 +#ifndef BTA_AV_RECONFIG_RETRY
 +#define BTA_AV_RECONFIG_RETRY       6
 +#endif
 +
 +static void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data);
 +
 +/* state machine states */
 +enum
 +{
 +    BTA_AV_INIT_SST,
 +    BTA_AV_INCOMING_SST,
 +    BTA_AV_OPENING_SST,
 +    BTA_AV_OPEN_SST,
 +    BTA_AV_RCFG_SST,
 +    BTA_AV_CLOSING_SST
 +};
 +
 +
 +/* the call out functions for audio stream */
 +/* const tBTA_AV_CO_FUNCTS bta_av_a2d_cos =
 +{
 +    bta_av_co_audio_init,
 +    bta_av_co_audio_disc_res,
 +    bta_av_co_audio_getconfig,
 +    bta_av_co_audio_setconfig,
 +    bta_av_co_audio_open,
 +    bta_av_co_audio_close,
 +    bta_av_co_audio_start,
 +    bta_av_co_audio_stop,
 +    bta_av_co_audio_src_data_path,
 +    bta_av_co_audio_delay
 +};
 +*/
 +tBTA_AV_CO_FUNCTS *p_bta_av_a2d_cos = NULL;
 +
 +
 +
 +/* ssm action functions for audio stream */
 +const tBTA_AV_SACT bta_av_a2d_action[] =
 +{
 +    bta_av_do_disc_a2d,     /* BTA_AV_DO_DISC  */
 +    bta_av_cleanup,         /* BTA_AV_CLEANUP */
 +    bta_av_free_sdb,        /* BTA_AV_FREE_SDB */
 +    bta_av_config_ind,      /* BTA_AV_CONFIG_IND */
 +    bta_av_disconnect_req,  /* BTA_AV_DISCONNECT_REQ */
 +    bta_av_security_req,    /* BTA_AV_SECURITY_REQ */
 +    bta_av_security_rsp,    /* BTA_AV_SECURITY_RSP */
 +    bta_av_setconfig_rsp,   /* BTA_AV_SETCONFIG_RSP */
 +    bta_av_st_rc_timer,     /* BTA_AV_ST_RC_TIMER */
 +    bta_av_str_opened,      /* BTA_AV_STR_OPENED */
 +    bta_av_security_ind,    /* BTA_AV_SECURITY_IND */
 +    bta_av_security_cfm,    /* BTA_AV_SECURITY_CFM */
 +    bta_av_do_close,        /* BTA_AV_DO_CLOSE */
 +    bta_av_connect_req,     /* BTA_AV_CONNECT_REQ */
 +    bta_av_sdp_failed,      /* BTA_AV_SDP_FAILED */
 +    bta_av_disc_results,    /* BTA_AV_DISC_RESULTS */
 +    bta_av_disc_res_as_acp, /* BTA_AV_DISC_RES_AS_ACP */
 +    bta_av_open_failed,     /* BTA_AV_OPEN_FAILED */
 +    bta_av_getcap_results,  /* BTA_AV_GETCAP_RESULTS */
 +    bta_av_setconfig_rej,   /* BTA_AV_SETCONFIG_REJ */
 +    bta_av_discover_req,    /* BTA_AV_DISCOVER_REQ */
 +    bta_av_conn_failed,     /* BTA_AV_CONN_FAILED */
 +    bta_av_do_start,        /* BTA_AV_DO_START */
 +    bta_av_str_stopped,     /* BTA_AV_STR_STOPPED */
 +    bta_av_reconfig,        /* BTA_AV_RECONFIG */
 +    bta_av_data_path,       /* BTA_AV_DATA_PATH */
 +    bta_av_start_ok,        /* BTA_AV_START_OK */
 +    bta_av_start_failed,    /* BTA_AV_START_FAILED */
 +    bta_av_str_closed,      /* BTA_AV_STR_CLOSED */
 +    bta_av_clr_cong,        /* BTA_AV_CLR_CONG */
 +    bta_av_suspend_cfm,     /* BTA_AV_SUSPEND_CFM */
 +    bta_av_rcfg_str_ok,     /* BTA_AV_RCFG_STR_OK */
 +    bta_av_rcfg_failed,     /* BTA_AV_RCFG_FAILED */
 +    bta_av_rcfg_connect,    /* BTA_AV_RCFG_CONNECT */
 +    bta_av_rcfg_discntd,    /* BTA_AV_RCFG_DISCNTD */
 +    bta_av_suspend_cont,    /* BTA_AV_SUSPEND_CONT */
 +    bta_av_rcfg_cfm,        /* BTA_AV_RCFG_CFM */
 +    bta_av_rcfg_open,       /* BTA_AV_RCFG_OPEN */
 +    bta_av_security_rej,    /* BTA_AV_SECURITY_REJ */
 +    bta_av_open_rc,         /* BTA_AV_OPEN_RC */
 +    bta_av_chk_2nd_start,   /* BTA_AV_CHK_2ND_START */
 +    bta_av_save_caps,       /* BTA_AV_SAVE_CAPS */
 +    bta_av_set_use_rc,      /* BTA_AV_SET_USE_RC */
 +    bta_av_cco_close,       /* BTA_AV_CCO_CLOSE */
 +    bta_av_switch_role,     /* BTA_AV_SWITCH_ROLE */
 +    bta_av_role_res,        /* BTA_AV_ROLE_RES */
 +    bta_av_delay_co,        /* BTA_AV_DELAY_CO */
 +    bta_av_open_at_inc,     /* BTA_AV_OPEN_AT_INC */
 +    NULL
 +};
 +
 +/* these tables translate AVDT events to SSM events */
 +static const UINT16 bta_av_stream_evt_ok[] = {
 +    BTA_AV_STR_DISC_OK_EVT,         /* AVDT_DISCOVER_CFM_EVT */
 +    BTA_AV_STR_GETCAP_OK_EVT,       /* AVDT_GETCAP_CFM_EVT */
 +    BTA_AV_STR_OPEN_OK_EVT,         /* AVDT_OPEN_CFM_EVT */
 +    BTA_AV_STR_OPEN_OK_EVT,         /* AVDT_OPEN_IND_EVT */
 +    BTA_AV_STR_CONFIG_IND_EVT,      /* AVDT_CONFIG_IND_EVT */
 +    BTA_AV_STR_START_OK_EVT,        /* AVDT_START_CFM_EVT */
 +    BTA_AV_STR_START_OK_EVT,        /* AVDT_START_IND_EVT */
 +    BTA_AV_STR_SUSPEND_CFM_EVT,     /* AVDT_SUSPEND_CFM_EVT */
 +    BTA_AV_STR_SUSPEND_CFM_EVT,     /* AVDT_SUSPEND_IND_EVT */
 +    BTA_AV_STR_CLOSE_EVT,           /* AVDT_CLOSE_CFM_EVT */
 +    BTA_AV_STR_CLOSE_EVT,           /* AVDT_CLOSE_IND_EVT */
 +    BTA_AV_STR_RECONFIG_CFM_EVT,    /* AVDT_RECONFIG_CFM_EVT */
 +    0,                              /* AVDT_RECONFIG_IND_EVT */
 +    BTA_AV_STR_SECURITY_CFM_EVT,    /* AVDT_SECURITY_CFM_EVT */
 +    BTA_AV_STR_SECURITY_IND_EVT,    /* AVDT_SECURITY_IND_EVT */
 +    BTA_AV_STR_WRITE_CFM_EVT,       /* AVDT_WRITE_CFM_EVT */
 +    BTA_AV_AVDT_CONNECT_EVT,        /* AVDT_CONNECT_IND_EVT */
 +    BTA_AV_AVDT_DISCONNECT_EVT,     /* AVDT_DISCONNECT_IND_EVT */
 +#if (AVDT_REPORTING == TRUE)
 +    BTA_AV_AVDT_RPT_CONN_EVT,       /* AVDT_REPORT_CONN_EVT */
 +    BTA_AV_AVDT_RPT_CONN_EVT,       /* AVDT_REPORT_DISCONN_EVT */
 +#endif
 +    BTA_AV_AVDT_DELAY_RPT_EVT,      /* AVDT_DELAY_REPORT_EVT */
 +    0                               /* AVDT_DELAY_REPORT_CFM_EVT */
 +};
 +
 +static const UINT16 bta_av_stream_evt_fail[] = {
 +    BTA_AV_STR_DISC_FAIL_EVT,       /* AVDT_DISCOVER_CFM_EVT */
 +    BTA_AV_STR_GETCAP_FAIL_EVT,     /* AVDT_GETCAP_CFM_EVT */
 +    BTA_AV_STR_OPEN_FAIL_EVT,       /* AVDT_OPEN_CFM_EVT */
 +    BTA_AV_STR_OPEN_OK_EVT,         /* AVDT_OPEN_IND_EVT */
 +    BTA_AV_STR_CONFIG_IND_EVT,      /* AVDT_CONFIG_IND_EVT */
 +    BTA_AV_STR_START_FAIL_EVT,      /* AVDT_START_CFM_EVT */
 +    BTA_AV_STR_START_OK_EVT,        /* AVDT_START_IND_EVT */
 +    BTA_AV_STR_SUSPEND_CFM_EVT,     /* AVDT_SUSPEND_CFM_EVT */
 +    BTA_AV_STR_SUSPEND_CFM_EVT,     /* AVDT_SUSPEND_IND_EVT */
 +    BTA_AV_STR_CLOSE_EVT,           /* AVDT_CLOSE_CFM_EVT */
 +    BTA_AV_STR_CLOSE_EVT,           /* AVDT_CLOSE_IND_EVT */
 +    BTA_AV_STR_RECONFIG_CFM_EVT,    /* AVDT_RECONFIG_CFM_EVT */
 +    0,                              /* AVDT_RECONFIG_IND_EVT */
 +    BTA_AV_STR_SECURITY_CFM_EVT,    /* AVDT_SECURITY_CFM_EVT */
 +    BTA_AV_STR_SECURITY_IND_EVT,    /* AVDT_SECURITY_IND_EVT */
 +    BTA_AV_STR_WRITE_CFM_EVT,       /* AVDT_WRITE_CFM_EVT */
 +    BTA_AV_AVDT_CONNECT_EVT,        /* AVDT_CONNECT_IND_EVT */
 +    BTA_AV_AVDT_DISCONNECT_EVT,     /* AVDT_DISCONNECT_IND_EVT */
 +#if (AVDT_REPORTING == TRUE)
 +    BTA_AV_AVDT_RPT_CONN_EVT,       /* AVDT_REPORT_CONN_EVT */
 +    BTA_AV_AVDT_RPT_CONN_EVT,       /* AVDT_REPORT_DISCONN_EVT */
 +#endif
 +    BTA_AV_AVDT_DELAY_RPT_EVT,      /* AVDT_DELAY_REPORT_EVT */
 +    0                               /* AVDT_DELAY_REPORT_CFM_EVT */
 +};
 +
 +void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt);
 +static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
 +static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
 +#if BTA_AV_NUM_STRS > 2
 +static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
 +#endif
 +#if BTA_AV_NUM_STRS > 3
 +static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
 +#endif
 +#if BTA_AV_NUM_STRS > 4
 +static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
 +#endif
 +#if BTA_AV_NUM_STRS > 5
 +static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data);
 +#endif
 +/* the array of callback functions to receive events from AVDT control channel */
 +tAVDT_CTRL_CBACK * const bta_av_dt_cback[] =
 +{
 +    bta_av_stream0_cback
 +    ,bta_av_stream1_cback
 +#if BTA_AV_NUM_STRS > 2
 +    ,bta_av_stream2_cback
 +#endif
 +#if BTA_AV_NUM_STRS > 3
 +    ,bta_av_stream3_cback
 +#endif
 +#if BTA_AV_NUM_STRS > 4
 +    ,bta_av_stream4_cback
 +#endif
 +#if BTA_AV_NUM_STRS > 5
 +    ,bta_av_stream5_cback
 +#endif
 +};
 +/***********************************************
 +**
 +** Function         bta_get_scb_handle
 +**
 +** Description      gives the registered AVDT handle.by checking with sep_type.
 +**
 +**
 +** Returns          void
 +***********************************************/
 +static UINT8 bta_av_get_scb_handle(tBTA_AV_SCB *p_scb, UINT8 local_sep)
 +{
 +    UINT8 xx =0;
 +    for (xx = 0; xx<BTA_AV_MAX_SEPS; xx++)
 +    {
 +        if ((p_scb->seps[xx].tsep == local_sep) &&
 +            (p_scb->seps[xx].codec_type == p_scb->codec_type))
 +            return (p_scb->seps[xx].av_handle);
 +    }
 +    APPL_TRACE_DEBUG(" bta_av_get_scb_handle appropiate sep_type not found")
 +    return 0; /* return invalid handle */
 +}
 +
 +/***********************************************
 +**
 +** Function         bta_av_get_scb_sep_type
 +**
 +** Description      gives the sep type by cross-checking with AVDT handle
 +**
 +**
 +** Returns          void
 +***********************************************/
 +static UINT8 bta_av_get_scb_sep_type(tBTA_AV_SCB *p_scb, UINT8 tavdt_handle)
 +{
 +    UINT8 xx =0;
 +    for (xx = 0; xx<BTA_AV_MAX_SEPS; xx++)
 +    {
 +        if (p_scb->seps[xx].av_handle == tavdt_handle)
 +            return (p_scb->seps[xx].tsep);
 +    }
 +    APPL_TRACE_DEBUG(" bta_av_get_scb_sep_type appropiate handle not found")
 +    return 3; /* return invalid sep type */
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_save_addr
 +**
 +** Description      copy the bd_addr and maybe reset the supported flags
 +**
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void bta_av_save_addr(tBTA_AV_SCB *p_scb, const BD_ADDR b)
 +{
 +    APPL_TRACE_DEBUG("bta_av_save_addr r:%d, s:%d",
 +        p_scb->recfg_sup, p_scb->suspend_sup);
 +    if(bdcmp(p_scb->peer_addr, b) != 0)
 +    {
 +        APPL_TRACE_ERROR("reset flags");
 +        /* a new addr, reset the supported flags */
 +        p_scb->recfg_sup    = TRUE;
 +        p_scb->suspend_sup  = TRUE;
 +    }
 +
 +    /* do this copy anyway, just in case the first addr matches
 +     * the control block one by accident */
 +    bdcpy(p_scb->peer_addr, b);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         notify_start_failed
 +**
 +** Description      notify up-layer AV start failed
 +**
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void notify_start_failed(tBTA_AV_SCB *p_scb)
 +{
 +    tBTA_AV_START   start;
 +    /* if start failed, clear role */
 +    p_scb->role &= ~BTA_AV_ROLE_START_INT;
 +    start.chnl   = p_scb->chnl;
 +    start.status = BTA_AV_FAIL;
 +    start.initiator = TRUE;
 +    start.hndl   = p_scb->hndl;
 +    (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_st_rc_timer
 +**
 +** Description      start the AVRC timer if no RC connection & CT is supported &
 +**                  RC is used or
 +**                  as ACP (we do not really know if we want AVRC)
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    APPL_TRACE_DEBUG("bta_av_st_rc_timer rc_handle:%d, use_rc: %d",
 +        p_scb->rc_handle, p_scb->use_rc);
 +    /* for outgoing RC connection as INT/CT */
 +    if( (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) &&
 +        /*(bta_av_cb.features & BTA_AV_FEAT_RCCT) &&*/
 +        (p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP)) )
 +    {
 +        if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0)
 +            bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
 +        else
 +            p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
 +    }
 +
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_next_getcap
 +**
 +** Description      The function gets the capabilities of the next available
 +**                  stream found in the discovery results.
 +**
 +** Returns          TRUE if we sent request to AVDT, FALSE otherwise.
 +**
 +*******************************************************************************/
 +static BOOLEAN bta_av_next_getcap(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    int     i;
 +    tAVDT_GETCAP_REQ    *p_req;
 +    BOOLEAN     sent_cmd = FALSE;
 +    UINT16 uuid_int = p_scb->uuid_int;
 +    UINT8 sep_requested = 0;
 +
 +    if(uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
 +       sep_requested = AVDT_TSEP_SNK;
 +    else if(uuid_int == UUID_SERVCLASS_AUDIO_SINK)
 +       sep_requested = AVDT_TSEP_SRC;
 +
 +    for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++)
 +    {
 +        /* steam not in use, is a sink, and is the right media type (audio/video) */
 +        if ((p_scb->sep_info[i].in_use == FALSE) &&
 +            (p_scb->sep_info[i].tsep == sep_requested) &&
 +            (p_scb->sep_info[i].media_type == p_scb->media_type))
 +        {
 +            p_scb->sep_info_idx = i;
 +
 +            /* we got a stream; get its capabilities */
 +            if (p_scb->p_cap == NULL)
 +            {
 +                p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG));
 +            }
 +            if (p_scb->p_cap == NULL)
 +            {
 +                i = p_scb->num_seps;
 +                break;
 +            }
 +            if (p_scb->avdt_version >= AVDT_VERSION_SYNC)
 +            {
 +                p_req = AVDT_GetAllCapReq;
 +            }
 +            else
 +            {
 +                p_req = AVDT_GetCapReq;
 +            }
 +            (*p_req)(p_scb->peer_addr,
 +                           p_scb->sep_info[i].seid,
 +                           p_scb->p_cap, bta_av_dt_cback[p_scb->hdi]);
 +            sent_cmd = TRUE;
 +            break;
 +        }
 +    }
 +
 +    /* if no streams available then stream open fails */
 +    if (!sent_cmd)
 +    {
 +        bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data);
 +    }
 +
 +    return sent_cmd;
 +
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_proc_stream_evt
 +**
 +** Description      Utility function to compose stream events.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data, int index)
 +{
 +    tBTA_AV_STR_MSG     *p_msg;
 +    UINT16              sec_len = 0;
 +    tBTA_AV_SCB         *p_scb = bta_av_cb.p_scb[index];
 +    int                 xx;
 +
 +    if (p_data)
 +    {
 +        if (event == AVDT_SECURITY_IND_EVT)
 +        {
 +            sec_len = (p_data->security_ind.len < BTA_AV_SECURITY_MAX_LEN) ?
 +                       p_data->security_ind.len : BTA_AV_SECURITY_MAX_LEN;
 +        }
 +        else if (event == AVDT_SECURITY_CFM_EVT && p_data->hdr.err_code == 0)
 +        {
 +            sec_len = (p_data->security_cfm.len < BTA_AV_SECURITY_MAX_LEN) ?
 +                       p_data->security_cfm.len : BTA_AV_SECURITY_MAX_LEN;
 +        }
 +    }
 +
 +    if (p_scb && (p_msg = (tBTA_AV_STR_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_STR_MSG) + sec_len))) != NULL)
 +    {
 +
 +        /* copy event data, bd addr, and handle to event message buffer */
 +        p_msg->hdr.offset = 0;
 +
 +        if (bd_addr != NULL)
 +        {
 +            bdcpy(p_msg->bd_addr, bd_addr);
 +            APPL_TRACE_DEBUG("  bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
 +                          bd_addr[0], bd_addr[1],
 +                          bd_addr[2], bd_addr[3],
 +                          bd_addr[4], bd_addr[5]);
 +        }
 +
 +        if (p_data != NULL)
 +        {
 +            memcpy(&p_msg->msg, p_data, sizeof (tAVDT_CTRL));
 +            /* copy config params to event message buffer */
 +            switch (event)
 +            {
 +            case AVDT_RECONFIG_CFM_EVT:
 +            APPL_TRACE_DEBUG("reconfig cfm event codec info = 0x%06x-%06x-%06x-%02x",
 +                (p_msg->msg.reconfig_cfm.p_cfg->codec_info[0]<<16)+(p_msg->msg.reconfig_cfm.p_cfg->codec_info[1]<<8)+p_msg->msg.reconfig_cfm.p_cfg->codec_info[2],
 +                (p_msg->msg.reconfig_cfm.p_cfg->codec_info[3]<<16)+(p_msg->msg.reconfig_cfm.p_cfg->codec_info[4]<<8)+p_msg->msg.reconfig_cfm.p_cfg->codec_info[5],
 +                (p_msg->msg.reconfig_cfm.p_cfg->codec_info[6]<<16)+(p_msg->msg.reconfig_cfm.p_cfg->codec_info[7]<<8)+p_msg->msg.reconfig_cfm.p_cfg->codec_info[8],
 +                p_msg->msg.reconfig_cfm.p_cfg->codec_info[9]);
 +            break;
 +
 +
 +
 +            case AVDT_CONFIG_IND_EVT:
 +            /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on one L2CAP.
 +             * If we already have a signalling connection with the bd_addr and the streaming
 +             * SST is at INIT state, change it to INCOMING state to handle the signalling
 +             * from the 2nd SEP.                                                                */
 +            if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb)))
 +            {
 +                bta_av_set_scb_sst_incoming (p_scb);
 +
 +                /* When ACP_CONNECT_EVT was received, we put first available scb to incoming state.
 +                 * Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and set its state to
 +                 * incoming which we do it above.
 +                 * We also have to set the old p_scb state to init to be used later             */
 +                for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
 +                {
 +                    if ((bta_av_cb.p_scb[xx]) && (xx != index))
 +                    {
 +                        if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST)
 +                        {
 +                            bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
 +                            bta_av_cb.p_scb[xx]->coll_mask = 0;
 +                            break;
 +                        }
 +                    }
 +                }
 +            }
 +
 +            memcpy(&p_msg->cfg, p_data->config_ind.p_cfg, sizeof(tAVDT_CFG));
 +            break;
 +
 +            case AVDT_SECURITY_IND_EVT:
 +                p_msg->msg.security_ind.p_data = (UINT8 *) (p_msg + 1);
 +                memcpy(p_msg->msg.security_ind.p_data, p_data->security_ind.p_data, sec_len);
 +                break;
 +
 +            case AVDT_SECURITY_CFM_EVT:
 +                p_msg->msg.security_cfm.p_data = (UINT8 *) (p_msg + 1);
 +                if (p_data->hdr.err_code == 0)
 +                {
 +                    memcpy(p_msg->msg.security_cfm.p_data, p_data->security_cfm.p_data, sec_len);
 +                }
 +                break;
 +            case AVDT_SUSPEND_IND_EVT:
 +                    p_msg->msg.hdr.err_code = 0;
 +                break;
 +
 +            default:
 +                break;
 +            }
 +        }
 +        else
 +            p_msg->msg.hdr.err_code = 0;
 +
 +        /* look up application event */
 +        if ((p_data == NULL) || (p_data->hdr.err_code == 0))
 +        {
 +            p_msg->hdr.event = bta_av_stream_evt_ok[event];
 +        }
 +        else
 +        {
 +            p_msg->hdr.event = bta_av_stream_evt_fail[event];
 +        }
 +
 +        p_msg->initiator = FALSE;
 +        if (event == AVDT_SUSPEND_CFM_EVT)
 +            p_msg->initiator = TRUE;
 +
 +        APPL_TRACE_VERBOSE("hndl:x%x", p_scb->hndl);
 +        p_msg->hdr.layer_specific = p_scb->hndl;
 +        p_msg->handle   = handle;
 +        p_msg->avdt_event = event;
 +        bta_sys_sendmsg(p_msg);
 +    }
 +
 +/* coverity[var_deref_model] */
 +/* false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event
 + *                 these 2 events always have associated p_data */
 +    if (p_data)
 +    {
 +        bta_av_conn_cback(handle, bd_addr, event, p_data);
 +    }
 +    else
 +    {
 +        APPL_TRACE_ERROR("%s: p_data is null", __func__);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_stream_data_cback
 +**
 +** Description      This is the AVDTP callback function for stream events.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt)
 +{
 +    int index = 0;
 +    tBTA_AV_SCB         *p_scb ;
 +    APPL_TRACE_DEBUG("bta_av_stream_data_cback avdt_handle: %d pkt_len=0x%x  ofst = 0x%x", handle,p_pkt->len,p_pkt->offset);
 +    APPL_TRACE_DEBUG(" Number of frames 0x%x",*((UINT8*)(p_pkt + 1) + p_pkt->offset));
 +    APPL_TRACE_DEBUG("Sequence Number 0x%x",p_pkt->layer_specific);
 +    /* Get  SCB  and correct sep type*/
 +    for(index = 0; index < BTA_AV_NUM_STRS;index ++ )
 +    {
 +        p_scb = bta_av_cb.p_scb[index];
 +        if((p_scb->avdt_handle == handle)&&(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK))
 +            break;
 +    }
 +    if(index == BTA_AV_NUM_STRS) /* cannot find correct handler */
 +    {
 +        GKI_freebuf(p_pkt);
 +        return;
 +    }
 +    p_pkt->event = BTA_AV_MEDIA_DATA_EVT;
 +    p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_DATA_EVT, (tBTA_AV_MEDIA*)p_pkt);
 +    GKI_freebuf(p_pkt);  /* a copy of packet had been delivered, we free this buffer */
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_stream0_cback
 +**
 +** Description      This is the AVDTP callback function for stream events.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
 +{
 +    APPL_TRACE_VERBOSE("bta_av_stream0_cback avdt_handle: %d event=0x%x", handle, event);
 +    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_stream1_cback
 +**
 +** Description      This is the AVDTP callback function for stream events.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
 +{
 +    APPL_TRACE_EVENT("bta_av_stream1_cback avdt_handle: %d event=0x%x", handle, event);
 +    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 1);
 +}
 +
 +#if BTA_AV_NUM_STRS > 2
 +/*******************************************************************************
 +**
 +** Function         bta_av_stream2_cback
 +**
 +** Description      This is the AVDTP callback function for stream events.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
 +{
 +    APPL_TRACE_EVENT("bta_av_stream2_cback avdt_handle: %d event=0x%x", handle, event);
 +    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 2);
 +}
 +#endif
 +
 +#if BTA_AV_NUM_STRS > 3
 +/*******************************************************************************
 +**
 +** Function         bta_av_stream3_cback
 +**
 +** Description      This is the AVDTP callback function for stream events.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
 +{
 +    APPL_TRACE_EVENT("bta_av_stream3_cback avdt_handle: %d event=0x%x", handle, event);
 +    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 3);
 +}
 +#endif
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_stream4_cback
 +**
 +** Description      This is the AVDTP callback function for stream events.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +#if BTA_AV_NUM_STRS > 4
 +static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
 +{
 +    APPL_TRACE_EVENT("bta_av_stream4_cback avdt_handle: %d event=0x%x", handle, event);
 +    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 4);
 +}
 +#endif
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_stream5_cback
 +**
 +** Description      This is the AVDTP callback function for stream events.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +#if BTA_AV_NUM_STRS > 5
 +static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
 +{
 +    APPL_TRACE_EVENT("bta_av_stream5_cback avdt_handle: %d event=0x%x", handle, event);
 +    bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 5);
 +}
 +#endif
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_a2d_sdp_cback
 +**
 +** Description      A2DP service discovery callback.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +static void bta_av_a2d_sdp_cback(BOOLEAN found, tA2D_Service *p_service)
 +{
 +    tBTA_AV_SDP_RES *p_msg;
 +    tBTA_AV_SCB     *p_scb;
 +
 +    if ((p_msg = (tBTA_AV_SDP_RES *) GKI_getbuf(sizeof(tBTA_AV_SDP_RES))) != NULL)
 +    {
 +        p_msg->hdr.event = (found) ? BTA_AV_SDP_DISC_OK_EVT : BTA_AV_SDP_DISC_FAIL_EVT;
 +
 +        p_scb = bta_av_hndl_to_scb(bta_av_cb.handle);
 +        if (p_scb)
 +        {
 +            if (found && (p_service != NULL))
 +                p_scb->avdt_version = p_service->avdt_version;
 +            else
 +                p_scb->avdt_version = 0x00;
 +
 +            p_msg->hdr.layer_specific = bta_av_cb.handle;
 +            bta_sys_sendmsg(p_msg);
 +        }
 +        else
 +        {
 +            APPL_TRACE_ERROR ("bta_av_a2d_sdp_cback, no scb found for handle(0x%x)", bta_av_cb.handle);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_adjust_seps_idx
 +**
 +** Description      adjust the sep_idx
 +**
 +** Returns
 +**
 +*******************************************************************************/
 +static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb, UINT8 avdt_handle)
 +{
 +    int xx;
 +    APPL_TRACE_DEBUG("bta_av_adjust_seps_idx codec_type: %d", p_scb->codec_type);
 +    for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
 +    {
 +        APPL_TRACE_DEBUG("av_handle: %d codec_type: %d",
 +            p_scb->seps[xx].av_handle, p_scb->seps[xx].codec_type);
 +        if((p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type)
 +            && (p_scb->seps[xx].av_handle == avdt_handle))
 +        {
 +            p_scb->sep_idx      = xx;
 +            p_scb->avdt_handle  = p_scb->seps[xx].av_handle;
 +            break;
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_switch_role
 +**
 +** Description      Switch role was not started and a timer was started.
 +**                  another attempt to switch role now - still opening.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_switch_role (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_RS_RES      switch_res = BTA_AV_RS_NONE;
 +    tBTA_AV_API_OPEN  *p_buf = &p_scb->q_info.open;
 +    UNUSED(p_data);
 +
 +    APPL_TRACE_DEBUG("bta_av_switch_role wait:x%x", p_scb->wait);
 +    if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
 +        p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY;
 +
 +    /* clear the masks set when the timer is started */
 +    p_scb->wait &= ~(BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START);
 +
 +    if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN)
 +    {
 +        if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
 +        {
 +            p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
 +        }
 +        else
 +        {
 +            /* this should not happen in theory. Just in case...
 +             * continue to do_disc_a2d */
 +            switch_res = BTA_AV_RS_DONE;
 +        }
 +    }
 +    else
 +    {
 +        /* report failure on OPEN */
 +        switch_res = BTA_AV_RS_FAIL;
 +    }
 +
 +    if (switch_res != BTA_AV_RS_NONE)
 +    {
 +        if (bta_av_cb.rs_idx == (p_scb->hdi + 1))
 +        {
 +            bta_av_cb.rs_idx = 0;
 +        }
 +        p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_RETRY;
 +        p_scb->q_tag = 0;
 +        p_buf->switch_res = switch_res;
 +        bta_av_do_disc_a2d(p_scb, (tBTA_AV_DATA *)p_buf);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_role_res
 +**
 +** Description      Handle the role changed event
 +**
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    BOOLEAN         initiator = FALSE;
 +    tBTA_AV_START   start;
 +    tBTA_AV_OPEN    av_open;
 +
 +    APPL_TRACE_DEBUG("bta_av_role_res q_tag:%d, wait:x%x, role:x%x", p_scb->q_tag, p_scb->wait, p_scb->role);
 +    if (p_scb->role & BTA_AV_ROLE_START_INT)
 +        initiator = TRUE;
 +
 +    if (p_scb->q_tag == BTA_AV_Q_TAG_START)
 +    {
 +        if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED)
 +        {
 +            p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
 +            if (p_data->role_res.hci_status != HCI_SUCCESS)
 +            {
 +                p_scb->role &= ~BTA_AV_ROLE_START_INT;
 +                bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
 +                /* start failed because of role switch. */
 +                start.chnl   = p_scb->chnl;
 +                start.status = BTA_AV_FAIL_ROLE;
 +                start.hndl   = p_scb->hndl;
 +                start.initiator = initiator;
 +                (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
 +            }
 +            else
 +            {
 +                bta_av_start_ok(p_scb, p_data);
 +            }
 +        }
 +        else if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
 +            p_scb->wait |= BTA_AV_WAIT_ROLE_SW_FAILED;
 +    }
 +    else if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN)
 +    {
 +        if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_OPEN)
 +        {
 +            p_scb->role &= ~BTA_AV_ROLE_START_INT;
 +            p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
 +
 +            if (p_data->role_res.hci_status != HCI_SUCCESS)
 +            {
 +                /* Open failed because of role switch. */
 +                bdcpy(av_open.bd_addr, p_scb->peer_addr);
 +                av_open.chnl   = p_scb->chnl;
 +                av_open.hndl   = p_scb->hndl;
 +                start.status = BTA_AV_FAIL_ROLE;
 +                if(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC )
 +                    av_open.sep = AVDT_TSEP_SNK;
 +                else if(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK )
 +                    av_open.sep = AVDT_TSEP_SRC;
 +                (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *)&av_open);
 +            }
 +            else
 +            {
 +                /* Continue av open process */
 +                p_scb->q_info.open.switch_res = BTA_AV_RS_DONE;
 +                bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open));
 +            }
 +        }
 +        else
 +        {
 +            APPL_TRACE_WARNING ("Unexpected role switch event: q_tag = %d wait = %d", p_scb->q_tag, p_scb->wait);
 +        }
 +    }
 +
 +    APPL_TRACE_DEBUG("wait:x%x, role:x%x", p_scb->wait, p_scb->role);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_delay_co
 +**
 +** Description      Call the delay call-out function to report the delay report
 +**                  from SNK
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    p_scb->p_cos->delay(p_scb->hndl, p_data->str_msg.msg.delay_rpt_cmd.delay);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_do_disc_a2d
 +**
 +** Description      Do service discovery for A2DP.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    BOOLEAN     ok_continue = FALSE;
 +    tA2D_SDP_DB_PARAMS  db_params;
 +    UINT16              attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
 +                                       ATTR_ID_PROTOCOL_DESC_LIST,
 +                                       ATTR_ID_BT_PROFILE_DESC_LIST};
 +    UINT16 sdp_uuid = 0; /* UUID for which SDP has to be done */
 +
 +    APPL_TRACE_DEBUG("bta_av_do_disc_a2d use_rc: %d rs:%d, oc:%d",
 +        p_data->api_open.use_rc, p_data->api_open.switch_res, bta_av_cb.audio_open_cnt);
 +
 +    memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
 +
 +    switch(p_data->api_open.switch_res)
 +    {
 +    case BTA_AV_RS_NONE:
 +        if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
 +        {
 +            /* waiting for role switch result. save the api to control block */
 +            memcpy(&p_scb->q_info.open, &p_data->api_open, sizeof(tBTA_AV_API_OPEN));
 +            p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
 +            p_scb->q_tag = BTA_AV_Q_TAG_OPEN;
 +        }
 +        else
 +        {
 +            ok_continue = TRUE;
 +        }
 +        break;
 +
 +    case BTA_AV_RS_FAIL:
 +        /* report a new failure event  */
 +        p_scb->open_status = BTA_AV_FAIL_ROLE;
 +        bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL);
 +        break;
 +
 +    case BTA_AV_RS_OK:
 +        p_data = (tBTA_AV_DATA *)&p_scb->q_info.open;
 +        /* continue to open if link role is ok */
 +        if (bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT))
 +        {
 +            ok_continue = TRUE;
 +        }
 +        else
 +        {
 +            p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
 +        }
 +        break;
 +
 +    case BTA_AV_RS_DONE:
 +        ok_continue = TRUE;
 +        break;
 +    }
 +
 +    APPL_TRACE_DEBUG("ok_continue: %d wait:x%x, q_tag: %d", ok_continue, p_scb->wait, p_scb->q_tag);
 +    if (!ok_continue)
 +        return;
 +
 +    /* clear the role switch bits */
 +    p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
 +
 +    if (p_scb->wait & BTA_AV_WAIT_CHECK_RC)
 +    {
 +        p_scb->wait &= ~BTA_AV_WAIT_CHECK_RC;
 +        bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
 +    }
 +
 +    if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
 +    {
 +        L2CA_SetDesireRole(L2CAP_ROLE_DISALLOW_SWITCH);
 +
 +        if (bta_av_cb.audio_open_cnt == 1)
 +        {
 +            /* there's already an A2DP connection. do not allow switch */
 +            bta_sys_clear_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
 +        }
 +    }
 +    /* store peer addr other parameters */
 +    bta_av_save_addr(p_scb, p_data->api_open.bd_addr);
 +    p_scb->sec_mask = p_data->api_open.sec_mask;
 +    p_scb->use_rc = p_data->api_open.use_rc;
 +
 +    bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
 +
 +    /* allocate discovery database */
 +    if (p_scb->p_disc_db == NULL)
 +    {
 +        p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE);
 +    }
 +
 +    /* only one A2D find service is active at a time */
 +    bta_av_cb.handle = p_scb->hndl;
 +
 +    if(p_scb->p_disc_db)
 +    {
 +        /* set up parameters */
 +        db_params.db_len = BTA_AV_DISC_BUF_SIZE;
 +        db_params.num_attr = 3;
 +        db_params.p_db = p_scb->p_disc_db;
 +        db_params.p_attrs = attr_list;
 +        p_scb->uuid_int = p_data->api_open.uuid;
 +        if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK)
 +            sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE;
 +        else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
 +            sdp_uuid = UUID_SERVCLASS_AUDIO_SINK;
 +
 +        APPL_TRACE_DEBUG("uuid_int 0x%x, Doing SDP For 0x%x", p_scb->uuid_int, sdp_uuid);
 +        if(A2D_FindService(sdp_uuid, p_scb->peer_addr, &db_params,
 +                        bta_av_a2d_sdp_cback) == A2D_SUCCESS)
 +        {
 +            return;
 +        }
 +    }
 +
 +    /* when the code reaches here, either the DB is NULL
 +     * or A2D_FindService is not successful */
 +    bta_av_a2d_sdp_cback(FALSE, NULL);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_cleanup
 +**
 +** Description      cleanup AV stream control block.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_CONN_CHG msg;
 +    int             xx;
 +    UINT8           role = BTA_AV_ROLE_AD_INT;
 +    UNUSED(p_data);
 +
 +    APPL_TRACE_DEBUG("bta_av_cleanup");
 +
 +    /* free any buffers */
 +    utl_freebuf((void **) &p_scb->p_cap);
 +    utl_freebuf((void **) &p_scb->p_disc_db);
 +    p_scb->avdt_version = 0;
 +
 +    /* initialize some control block variables */
 +    p_scb->open_status = BTA_AV_SUCCESS;
 +
 +    /* if de-registering shut everything down */
 +    msg.hdr.layer_specific  = p_scb->hndl;
 +    p_scb->started  = FALSE;
 +    p_scb->cong = FALSE;
 +    p_scb->role = role;
 +    p_scb->cur_psc_mask = 0;
 +    p_scb->wait = 0;
 +    p_scb->num_disc_snks = 0;
 +    bta_sys_stop_timer(&p_scb->timer);
 +    if (p_scb->deregistring)
 +    {
 +        /* remove stream */
 +        for(xx=0; xx<BTA_AV_MAX_SEPS; xx++)
 +        {
 +            if(p_scb->seps[xx].av_handle)
 +                AVDT_RemoveStream(p_scb->seps[xx].av_handle);
 +            p_scb->seps[xx].av_handle = 0;
 +        }
 +
 +        bta_av_dereg_comp((tBTA_AV_DATA *) &msg);
 +    }
 +    else
 +    {
 +        /* report stream closed to main SM */
 +        msg.is_up = FALSE;
 +        bdcpy(msg.peer_addr, p_scb->peer_addr);
 +        bta_av_conn_chg((tBTA_AV_DATA *) &msg);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_free_sdb
 +**
 +** Description      Free service discovery db buffer.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_free_sdb(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +    utl_freebuf((void **) &p_scb->p_disc_db);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_config_ind
 +**
 +** Description      Handle a stream configuration indication from the peer.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_CI_SETCONFIG setconfig;
 +    tAVDT_SEP_INFO       *p_info;
 +    tAVDT_CFG            *p_evt_cfg = &p_data->str_msg.cfg;
 +    UINT8   psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask);
 +    UINT8 local_sep;    /* sep type of local handle on which connection was received */
 +    tBTA_AV_STR_MSG  *p_msg = (tBTA_AV_STR_MSG *)p_data;
 +    UNUSED(p_data);
 +
 +    local_sep = bta_av_get_scb_sep_type(p_scb, p_msg->handle);
 +    p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
 +    memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE);
 +    p_scb->codec_type = p_evt_cfg->codec_info[BTA_AV_CODEC_TYPE_IDX];
 +    bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
 +
 +    /* Clear collision mask */
 +    p_scb->coll_mask = 0;
 +    bta_sys_stop_timer(&bta_av_cb.acp_sig_tmr);
 +
 +    /* if no codec parameters in configuration, fail */
 +    if ((p_evt_cfg->num_codec == 0) ||
 +    /* or the peer requests for a service we do not support */
 +        ((psc_mask != p_scb->cfg.psc_mask) &&
 +        (psc_mask != (p_scb->cfg.psc_mask&~AVDT_PSC_DELAY_RPT))) )
 +    {
 +        setconfig.hndl      = p_scb->hndl; /* we may not need this */
 +        setconfig.err_code  = AVDT_ERR_UNSUP_CFG;
 +        bta_av_ssm_execute(p_scb, BTA_AV_CI_SETCONFIG_FAIL_EVT, (tBTA_AV_DATA *) &setconfig);
 +    }
 +    else
 +    {
 +        p_info = &p_scb->sep_info[0];
 +        p_info->in_use = 0;
 +        p_info->media_type = p_scb->media_type;
 +        p_info->seid = p_data->str_msg.msg.config_ind.int_seid;
 +
 +        /* Sep type of Peer will be oppsite role to our local sep */
 +        if (local_sep == AVDT_TSEP_SRC)
 +            p_info->tsep = AVDT_TSEP_SNK;
 +        else if (local_sep == AVDT_TSEP_SNK)
 +            p_info->tsep = AVDT_TSEP_SRC;
 +
 +        p_scb->role      |= BTA_AV_ROLE_AD_ACP;
 +        p_scb->cur_psc_mask = p_evt_cfg->psc_mask;
 +        if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
 +            p_scb->use_rc = TRUE;
 +        else
 +            p_scb->use_rc = FALSE;
 +
 +        p_scb->num_seps  = 1;
 +        p_scb->sep_info_idx = 0;
 +        APPL_TRACE_DEBUG("bta_av_config_ind: SEID: %d use_rc: %d cur_psc_mask:0x%x", p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask);
 +        /*  in case of A2DP SINK this is the first time peer data is being sent to co functions */
 +        if (local_sep == AVDT_TSEP_SNK)
 +        {
 +            p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type,
 +                             p_evt_cfg->codec_info,
 +                             p_info->seid,
 +                             p_scb->peer_addr,
 +                             p_evt_cfg->num_protect,
 +                             p_evt_cfg->protect_info,
 +                             AVDT_TSEP_SNK,
 +                             p_msg->handle);
 +        }
 +        else
 +        {
 +            p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type,
 +                             p_evt_cfg->codec_info,
 +                             p_info->seid,
 +                             p_scb->peer_addr,
 +                             p_evt_cfg->num_protect,
 +                             p_evt_cfg->protect_info,
 +                             AVDT_TSEP_SRC,
 +                             p_msg->handle);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_disconnect_req
 +**
 +** Description      Disconnect AVDTP connection.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_disconnect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_RCB *p_rcb;
 +    UNUSED(p_data);
 +
 +    APPL_TRACE_DEBUG("bta_av_disconnect_req conn_lcb: 0x%x", bta_av_cb.conn_lcb);
 +
 +    bta_sys_stop_timer(&bta_av_cb.sig_tmr);
 +    bta_sys_stop_timer(&p_scb->timer);
 +    if(bta_av_cb.conn_lcb)
 +    {
 +        p_rcb = bta_av_get_rcb_by_shdl((UINT8)(p_scb->hdi + 1));
 +        if (p_rcb)
 +            bta_av_del_rc(p_rcb);
 +        AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
 +    }
 +    else
 +    {
 +        bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_security_req
 +**
 +** Description      Send an AVDTP security request.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_security_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
 +    {
 +        AVDT_SecurityReq(p_scb->avdt_handle, p_data->api_protect_req.p_data,
 +                         p_data->api_protect_req.len);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_security_rsp
 +**
 +** Description      Send an AVDTP security response.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
 +    {
 +        AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->api_protect_rsp.error_code,
 +                         p_data->api_protect_rsp.p_data, p_data->api_protect_rsp.len);
 +    }
 +    else
 +    {
 +        AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC,
 +                     NULL, 0);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_setconfig_rsp
 +**
 +** Description      setconfig is OK
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UINT8   num = p_data->ci_setconfig.num_seid + 1;
 +    UINT8   avdt_handle = p_data->ci_setconfig.avdt_handle;
 +    UINT8   *p_seid = p_data->ci_setconfig.p_seid;
 +    int     i;
 +    UINT8   local_sep;
 +
 +    /* we like this codec_type. find the sep_idx */
 +    local_sep = bta_av_get_scb_sep_type(p_scb,avdt_handle);
 +    bta_av_adjust_seps_idx(p_scb, avdt_handle);
 +    APPL_TRACE_DEBUG("bta_av_setconfig_rsp: sep_idx: %d cur_psc_mask:0x%x", p_scb->sep_idx, p_scb->cur_psc_mask);
 +
 +    if ((AVDT_TSEP_SNK == local_sep) && (p_data->ci_setconfig.err_code == AVDT_SUCCESS) &&
 +                                     (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL))
 +        p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT,
 +                                              (tBTA_AV_MEDIA*)p_scb->cfg.codec_info);
 +
 +
 +    AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code,
 +                   p_data->ci_setconfig.category);
 +
 +    bta_sys_stop_timer(&bta_av_cb.sig_tmr);
 +
 +    if(p_data->ci_setconfig.err_code == AVDT_SUCCESS)
 +    {
 +        p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON;
 +        if(p_data->ci_setconfig.recfg_needed)
 +            p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT;
 +        APPL_TRACE_DEBUG("bta_av_setconfig_rsp recfg_needed:%d role:x%x num:%d",
 +            p_data->ci_setconfig.recfg_needed, p_scb->role, num);
 +        /* callout module tells BTA the number of "good" SEPs and their SEIDs.
 +         * getcap on these SEID */
 +        p_scb->num_seps = num;
 +
 +        if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT)
 +            p_scb->avdt_version = AVDT_VERSION_SYNC;
 +
 +
 +        if (p_scb->codec_type == BTA_AV_CODEC_SBC || num > 1)
 +        {
 +            /* if SBC is used by the SNK as INT, discover req is not sent in bta_av_config_ind.
 +                       * call disc_res now */
 +           /* this is called in A2DP SRC path only, In case of SINK we don't need it  */
 +            if (local_sep == AVDT_TSEP_SRC)
 +                p_scb->p_cos->disc_res(p_scb->hndl, num, num, 0, p_scb->peer_addr,
 +                                                      UUID_SERVCLASS_AUDIO_SOURCE);
 +        }
 +        else
 +        {
 +            /* we do not know the peer device and it is using non-SBC codec
 +             * we need to know all the SEPs on SNK */
 +            bta_av_discover_req(p_scb, NULL);
 +            return;
 +        }
 +
 +        for (i = 1; i < num; i++)
 +        {
 +            APPL_TRACE_DEBUG("sep_info[%d] SEID: %d", i, p_seid[i-1]);
 +            /* initialize the sep_info[] to get capabilities */
 +            p_scb->sep_info[i].in_use = FALSE;
 +            p_scb->sep_info[i].tsep = AVDT_TSEP_SNK;
 +            p_scb->sep_info[i].media_type = p_scb->media_type;
 +            p_scb->sep_info[i].seid = p_seid[i-1];
 +        }
 +
 +        /* only in case of local sep as SRC we need to look for other SEPs, In case of SINK we don't */
 +        if (local_sep == AVDT_TSEP_SRC)
 +        {
 +            /* Make sure UUID has been initialized... */
 +            if (p_scb->uuid_int == 0)
 +                p_scb->uuid_int = p_scb->open_api.uuid;
 +            bta_av_next_getcap(p_scb, p_data);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_str_opened
 +**
 +** Description      Stream opened OK (incoming/outgoing).
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_CONN_CHG msg;
 +    tBTA_AV_OPEN    open;
 +    UINT8 *p;
 +    UINT16 mtu;
 +
 +    msg.hdr.layer_specific = p_scb->hndl;
 +    msg.is_up = TRUE;
 +    bdcpy(msg.peer_addr, p_scb->peer_addr);
 +    p_scb->l2c_cid      = AVDT_GetL2CapChannel(p_scb->avdt_handle);
 +    bta_av_conn_chg((tBTA_AV_DATA *) &msg);
 +    /* set the congestion flag, so AV would not send media packets by accident */
 +    p_scb->cong = TRUE;
 +
 +
 +    p_scb->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
 +    mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
 +    APPL_TRACE_DEBUG("bta_av_str_opened l2c_cid: 0x%x stream_mtu: %d mtu: %d",
 +        p_scb->l2c_cid, p_scb->stream_mtu, mtu);
 +    if(mtu == 0 || mtu > p_scb->stream_mtu)
 +        mtu = p_scb->stream_mtu;
 +
 +    /* Set the media channel as medium priority */
 +    L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM);
 +    L2CA_SetChnlFlushability (p_scb->l2c_cid, TRUE);
 +
 +    bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
 +    memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO));
 +
 +    p_scb->l2c_bufs = 0;
 +    p_scb->p_cos->open(p_scb->hndl,
 +        p_scb->codec_type, p_scb->cfg.codec_info, mtu);
 +
 +    {
 +        /* TODO check if other audio channel is open.
 +         * If yes, check if reconfig is needed
 +         * Rigt now we do not do this kind of checking.
 +         * BTA-AV is INT for 2nd audio connection.
 +         * The application needs to make sure the current codec_info is proper.
 +         * If one audio connection is open and another SNK attempts to connect to AV,
 +         * the connection will be rejected.
 +         */
 +        /* check if other audio channel is started. If yes, start */
 +        bdcpy(open.bd_addr, p_scb->peer_addr);
 +        open.chnl   = p_scb->chnl;
 +        open.hndl   = p_scb->hndl;
 +        open.status = BTA_AV_SUCCESS;
 +        open.starting = bta_av_chk_start(p_scb);
 +        open.edr    = 0;
 +        if( NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr)))
 +        {
 +            if(HCI_EDR_ACL_2MPS_SUPPORTED(p))
 +                open.edr |= BTA_AV_EDR_2MBPS;
 +            if(HCI_EDR_ACL_3MPS_SUPPORTED(p))
 +                open.edr |= BTA_AV_EDR_3MBPS;
 +        }
 +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
 +        bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr);
 +#endif
 +        if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC )
 +            open.sep = AVDT_TSEP_SNK;
 +        else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK )
 +            open.sep = AVDT_TSEP_SRC;
 +
 +        (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open);
 +        if(open.starting)
 +        {
 +            bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
 +        }
 +    }
 +
 +#if 0 /* TODO: implement the property enable/disable */   
 +    // This code is used to pass PTS TC for AVDTP ABORT
 +    char value[PROPERTY_VALUE_MAX] = {0};
 +    if ((property_get("bluetooth.pts.force_a2dp_abort", value, "false"))
 +        && (!strcmp(value, "true")))
 +    {
 +        APPL_TRACE_ERROR ("%s: Calling AVDT_AbortReq", __func__);
 +        AVDT_AbortReq(p_scb->avdt_handle);
 +    }
 +#endif /* #if 0*/
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_security_ind
 +**
 +** Description      Handle an AVDTP security indication.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_security_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_PROTECT_REQ protect_req;
 +
 +    p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
 +
 +    if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
 +    {
 +        protect_req.chnl    = p_scb->chnl;
 +        protect_req.hndl    = p_scb->hndl;
 +        /*
 +        APPL_TRACE_EVENT("sec ind handle: x%x", protect_req.hndl);
 +        */
 +        protect_req.p_data  = p_data->str_msg.msg.security_ind.p_data;
 +        protect_req.len     = p_data->str_msg.msg.security_ind.len;
 +
 +        (*bta_av_cb.p_cback)(BTA_AV_PROTECT_REQ_EVT, (tBTA_AV *) &protect_req);
 +    }
 +    /* app doesn't support security indication; respond with failure */
 +    else
 +    {
 +        AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL, 0);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_security_cfm
 +**
 +** Description      Handle an AVDTP security confirm.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_security_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_PROTECT_RSP protect_rsp;
 +
 +    if (bta_av_cb.features & BTA_AV_FEAT_PROTECT)
 +    {
 +        protect_rsp.chnl    = p_scb->chnl;
 +        protect_rsp.hndl    = p_scb->hndl;
 +        protect_rsp.p_data  = p_data->str_msg.msg.security_cfm.p_data;
 +        protect_rsp.len     = p_data->str_msg.msg.security_cfm.len;
 +        protect_rsp.err_code= p_data->str_msg.msg.hdr.err_code;
 +
 +        (*bta_av_cb.p_cback)(BTA_AV_PROTECT_RSP_EVT, (tBTA_AV *) &protect_rsp);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_do_close
 +**
 +** Description      Close stream.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    /* stop stream if started */
 +    if (p_scb->co_started)
 +    {
 +        bta_av_str_stopped(p_scb, NULL);
 +    }
 +    bta_sys_stop_timer(&bta_av_cb.sig_tmr);
 +
 +    /* close stream */
 +    p_scb->started = FALSE;
 +
 +    /* drop the buffers queued in L2CAP */
 +    L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
 +
 +    AVDT_CloseReq(p_scb->avdt_handle);
 +    /* just in case that the link is congested, link is flow controled by peer or
 +     * for whatever reason the the close request can not be sent in time.
 +     * when this timer expires, AVDT_DisconnectReq will be called to disconnect the link
 +     */
 +    bta_sys_start_timer(&p_scb->timer,
 +                        (UINT16)BTA_AV_API_CLOSE_EVT,
 +                        BTA_AV_CLOSE_REQ_TIME_VAL);
 +
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_connect_req
 +**
 +** Description      Connect AVDTP connection.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    utl_freebuf((void **) &p_scb->p_disc_db);
 +
 +    if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
 +    {
 +        /* SNK initiated L2C connection while SRC was doing SDP.    */
 +        /* Wait until timeout to check if SNK starts signalling.    */
 +        APPL_TRACE_EVENT("bta_av_connect_req: coll_mask = 0x%2X", p_scb->coll_mask);
 +        return;
 +    }
 +
 +    AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_sdp_failed
 +**
 +** Description      Service discovery failed.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    if (!p_scb->open_status)
 +        p_scb->open_status = BTA_AV_FAIL_SDP;
 +
 +    utl_freebuf((void **) &p_scb->p_disc_db);
 +    bta_av_str_closed(p_scb, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_disc_results
 +**
 +** Description      Handle the AVDTP discover results.  Search through the
 +**                  results and find the first available stream, and get
 +**                  its capabilities.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UINT8 num_snks = 0, num_srcs =0, i;
 +    /* our uuid in case we initiate connection */
 +    UINT16 uuid_int = p_scb->uuid_int;
 +
 +    APPL_TRACE_DEBUG(" initiator UUID 0x%x", uuid_int);
 +    /* store number of stream endpoints returned */
 +    p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
 +
 +    for (i = 0; i < p_scb->num_seps; i++)
 +    {
 +        /* steam not in use, is a sink, and is audio */
 +        if ((p_scb->sep_info[i].in_use == FALSE) &&
 +            (p_scb->sep_info[i].media_type == p_scb->media_type))
 +        {
 +            if((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
 +               (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE))
 +                num_snks++;
 +
 +            if((p_scb->sep_info[i].tsep == AVDT_TSEP_SRC) &&
 +               (uuid_int == UUID_SERVCLASS_AUDIO_SINK))
 +                num_srcs++;
 +
 +        }
 +    }
 +
 +    p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, num_srcs, p_scb->peer_addr,
 +                                                                                    uuid_int);
 +    p_scb->num_disc_snks = num_snks;
 +    p_scb->num_disc_srcs = num_srcs;
 +
 +    /* if we got any */
 +    if (p_scb->num_seps > 0)
 +    {
 +        /* initialize index into discovery results */
 +        p_scb->sep_info_idx = 0;
 +
 +        /* get the capabilities of the first available stream */
 +        bta_av_next_getcap(p_scb, p_data);
 +    }
 +    /* else we got discover response but with no streams; we're done */
 +    else
 +    {
 +        bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_disc_res_as_acp
 +**
 +** Description      Handle the AVDTP discover results.  Search through the
 +**                  results and find the first available stream, and get
 +**                  its capabilities.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UINT8 num_snks = 0, i;
 +
 +    /* store number of stream endpoints returned */
 +    p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
 +
 +
 +
 +    for (i = 0; i < p_scb->num_seps; i++)
 +    {
 +        /* steam is a sink, and is audio */
 +        if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
 +            (p_scb->sep_info[i].media_type == p_scb->media_type))
 +        {
 +            p_scb->sep_info[i].in_use = FALSE;
 +            num_snks++;
 +        }
 +    }
 +    p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, 0, p_scb->peer_addr,
 +                                                          UUID_SERVCLASS_AUDIO_SOURCE);
 +    p_scb->num_disc_snks = num_snks;
 +    p_scb->num_disc_srcs = 0;
 +
 +    /* if we got any */
 +    if (p_scb->num_seps > 0)
 +    {
 +        /* initialize index into discovery results */
 +        p_scb->sep_info_idx = 0;
 +
 +        /* get the capabilities of the first available stream */
 +        bta_av_next_getcap(p_scb, p_data);
 +    }
 +    /* else we got discover response but with no streams; we're done */
 +    else
 +    {
 +        bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_save_caps
 +**
 +** Description      report the SNK SEP capabilities to application
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_save_caps(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tAVDT_CFG   cfg;
 +    tAVDT_SEP_INFO  *p_info = &p_scb->sep_info[p_scb->sep_info_idx];
 +    UINT8       old_wait = p_scb->wait;
 +    BOOLEAN     getcap_done = FALSE;
 +
 +    APPL_TRACE_DEBUG("bta_av_save_caps num_seps:%d sep_info_idx:%d wait:x%x",
 +        p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait);
 +    memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG));
 +    /* let application know the capability of the SNK */
 +    p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info[BTA_AV_CODEC_TYPE_IDX],
 +        cfg.codec_info, &p_scb->sep_info_idx, p_info->seid,
 +        &cfg.num_protect, cfg.protect_info);
 +
 +    p_scb->sep_info_idx++;
 +    if(p_scb->num_seps > p_scb->sep_info_idx)
 +    {
 +        /* Some devices have seps at the end of the discover list, which is not */
 +        /* matching media type(video not audio).                                */
 +        /* In this case, we are done with getcap without sending another        */
 +        /* request to AVDT.                                                     */
 +        if (!bta_av_next_getcap(p_scb, p_data))
 +            getcap_done = TRUE;
 +    }
 +    else
 +        getcap_done = TRUE;
 +
 +    if (getcap_done)
 +    {
 +        /* we are done getting capabilities. restore the p_cb->sep_info_idx */
 +        p_scb->sep_info_idx = 0;
 +        p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON|BTA_AV_WAIT_ACP_CAPS_STARTED);
 +        if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED)
 +        {
 +            bta_av_start_ok (p_scb, NULL);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_set_use_rc
 +**
 +** Description      set to use AVRC for this stream control block.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_set_use_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    p_scb->use_rc = TRUE;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_cco_close
 +**
 +** Description      call close call-out function.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UINT16 mtu;
 +    UNUSED(p_data);
 +
 +    mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
 +
 +    p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_open_failed
 +**
 +** Description      Failed to open an AVDT stream
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +
 +    BOOLEAN is_av_opened = FALSE;
 +    tBTA_AV_SCB * p_opened_scb = NULL;
 +    UINT8 idx;
 +    tBTA_AV_OPEN    open;
 +
 +    APPL_TRACE_DEBUG("bta_av_open_failed");
 +    p_scb->open_status = BTA_AV_FAIL_STREAM;
 +    bta_av_cco_close(p_scb, p_data);
 +
 +    /* check whether there is already an opened audio or video connection with the same device */
 +    for (idx = 0; (idx < BTA_AV_NUM_STRS) && (is_av_opened == FALSE); idx++ )
 +    {
 +        p_opened_scb = bta_av_cb.p_scb[idx];
 +        if (p_opened_scb && (p_opened_scb->state == BTA_AV_OPEN_SST) && (!bdcmp(p_opened_scb->peer_addr,p_scb->peer_addr )) )
 +            is_av_opened = TRUE;
 +
 +    }
 +
 +    /* if there is already an active AV connnection with the same bd_addr,
 +       don't send disconnect req, just report the open event with BTA_AV_FAIL_GET_CAP status */
 +    if (is_av_opened == TRUE)
 +    {
 +        bdcpy(open.bd_addr, p_scb->peer_addr);
 +        open.chnl   = p_scb->chnl;
 +        open.hndl   = p_scb->hndl;
 +        open.status = BTA_AV_FAIL_GET_CAP;
 +        open.starting = bta_av_chk_start(p_scb);
 +        open.edr    = 0;
 +        /* set the state back to initial state */
 +        bta_av_set_scb_sst_init(p_scb);
 +
 +        if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC )
 +            open.sep = AVDT_TSEP_SNK;
 +        else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK )
 +            open.sep = AVDT_TSEP_SRC;
 +
 +        (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open);
 +
 +    }
 +    else
 +    {
 +        AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
 +    }
 +}
 +
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_getcap_results
 +**
 +** Description      Handle the AVDTP get capabilities results.  Check the codec
 +**                  type and see if it matches ours.  If it does not, get the
 +**                  capabilities of the next stream, if any.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tAVDT_CFG   cfg;
 +    UINT8       media_type;
 +    tAVDT_SEP_INFO  *p_info = &p_scb->sep_info[p_scb->sep_info_idx];
 +    UINT16 uuid_int; /* UUID for which connection was initiatied */
 +
 +    memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
 +    cfg.num_codec = 1;
 +    cfg.num_protect = p_scb->p_cap->num_protect;
 +    memcpy(cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
 +    memcpy(cfg.protect_info, p_scb->p_cap->protect_info, AVDT_PROTECT_SIZE);
 +    media_type = p_scb->p_cap->codec_info[BTA_AV_MEDIA_TYPE_IDX] >> 4;
 +
 +    APPL_TRACE_DEBUG("num_codec %d", p_scb->p_cap->num_codec);
 +    APPL_TRACE_DEBUG("media type x%x, x%x", media_type, p_scb->media_type);
 +#if AVDT_MULTIPLEXING == TRUE
 +    APPL_TRACE_DEBUG("mux x%x, x%x", cfg.mux_mask, p_scb->p_cap->mux_mask);
 +#endif
 +
 +    /* if codec present and we get a codec configuration */
 +    if ((p_scb->p_cap->num_codec != 0) &&
 +        (media_type == p_scb->media_type) &&
 +        (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX],
 +            cfg.codec_info, &p_scb->sep_info_idx, p_info->seid,
 +            &cfg.num_protect, cfg.protect_info) == 0))
 +    {
 +#if AVDT_MULTIPLEXING == TRUE
 +        cfg.mux_mask &= p_scb->p_cap->mux_mask;
 +        APPL_TRACE_DEBUG("mux_mask used x%x", cfg.mux_mask);
 +#endif
 +        /* save copy of codec type and configuration */
 +        p_scb->codec_type = cfg.codec_info[BTA_AV_CODEC_TYPE_IDX];
 +        memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG));
 +
 +        uuid_int = p_scb->uuid_int;
 +        APPL_TRACE_DEBUG(" initiator UUID = 0x%x ", uuid_int);
 +        if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
 +            bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC));
 +        else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK)
 +            bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SNK));
 +
 +        /* use only the services peer supports */
 +        cfg.psc_mask &= p_scb->p_cap->psc_mask;
 +        p_scb->cur_psc_mask = cfg.psc_mask;
 +
 +        if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) &&
 +            (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL))
 +        {
 +            APPL_TRACE_DEBUG(" Configure Deoder for Sink Connection ");
 +            p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT,
 +                     (tBTA_AV_MEDIA*)p_scb->cfg.codec_info);
 +        }
 +
 +        /* open the stream */
 +        AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
 +                     p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg);
 +
 +        if (!bta_av_is_rcfg_sst(p_scb))
 +        {
 +            /* free capabilities buffer */
 +            utl_freebuf((void **) &p_scb->p_cap);
 +        }
 +    }
 +    else
 +    {
 +        /* try the next stream, if any */
 +        p_scb->sep_info_idx++;
 +        bta_av_next_getcap(p_scb, p_data);
 +    }
 +
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_setconfig_rej
 +**
 +** Description      Send AVDTP set config reject.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_REJECT reject;
 +    UINT8   avdt_handle = p_data->ci_setconfig.avdt_handle;
 +
 +    bta_av_adjust_seps_idx(p_scb, avdt_handle);
 +    APPL_TRACE_DEBUG("bta_av_setconfig_rej: sep_idx: %d",p_scb->sep_idx);
 +    AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_UNSUP_CFG, 0);
 +
 +    bdcpy(reject.bd_addr, p_data->str_msg.bd_addr);
 +    reject.hndl = p_scb->hndl;
 +    (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_discover_req
 +**
 +** Description      Send an AVDTP discover request to the peer.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_discover_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    /* send avdtp discover request */
 +
 +    AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_conn_failed
 +**
 +** Description      AVDTP connection failed.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_conn_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    p_scb->open_status = BTA_AV_FAIL_STREAM;
 +    bta_av_str_closed(p_scb, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_do_start
 +**
 +** Description      Start stream.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_do_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UINT8 policy = HCI_ENABLE_SNIFF_MODE;
 +    UINT8       cur_role;
 +
 +    APPL_TRACE_DEBUG("bta_av_do_start sco_occupied:%d, role:x%x, started:%d", bta_av_cb.sco_occupied, p_scb->role, p_scb->started);
 +    if (bta_av_cb.sco_occupied)
 +    {
 +        bta_av_start_failed(p_scb, p_data);
 +        return;
 +    }
 +
 +    /* disallow role switch during streaming, only if we are the master role
 +     * i.e. allow role switch, if we are slave.
 +     * It would not hurt us, if the peer device wants us to be master */
 +    if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
 +        (cur_role == BTM_ROLE_MASTER) )
 +    {
 +        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
 +    }
 +
 +    bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
 +
 +    if ((p_scb->started == FALSE) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0))
 +    {
 +        p_scb->role |= BTA_AV_ROLE_START_INT;
 +        bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
 +
 +        AVDT_StartReq(&p_scb->avdt_handle, 1);
 +    }
 +    else if (p_scb->started)
 +    {
 +        p_scb->role |= BTA_AV_ROLE_START_INT;
 +        if ( p_scb->wait == 0 ) {
 +            if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
 +                notify_start_failed(p_scb);
 +            } else {
 +                bta_av_start_ok(p_scb, NULL);
 +            }
 +        }
 +    }
 +    APPL_TRACE_DEBUG("started %d role:x%x", p_scb->started, p_scb->role);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_str_stopped
 +**
 +** Description      Stream stopped.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_SUSPEND suspend_rsp;
 +    UINT8   start = p_scb->started;
 +    BOOLEAN sus_evt = TRUE;
 +    BT_HDR  *p_buf;
 +    UINT8 policy = HCI_ENABLE_SNIFF_MODE;
 +
++    APPL_TRACE_ERROR("bta_av_str_stopped:audio_open_cnt=%d, p_data %p",
 +            bta_av_cb.audio_open_cnt, p_data);
 +
 +    bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
 +    if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
 +        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
 +    bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
 +
 +    if (p_scb->co_started)
 +    {
 +        bta_av_stream_chg(p_scb, FALSE);
 +        p_scb->co_started = FALSE;
 +
 +        p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
 +        L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
 +    }
 +
 +    /* if q_info.a2d_list is not empty, drop it now */
 +    if (BTA_AV_CHNL_AUDIO == p_scb->chnl) {
 +        while (!list_is_empty(p_scb->a2d_list))
 +        {
 +            p_buf = (BT_HDR *)list_front(p_scb->a2d_list);
 +            list_remove(p_scb->a2d_list, p_buf);
 +            GKI_freebuf(p_buf);
 +        }
 +
 +    /* drop the audio buffers queued in L2CAP */
 +        if (p_data && p_data->api_stop.flush)
 +            L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
 +    }
 +
 +    suspend_rsp.chnl = p_scb->chnl;
 +    suspend_rsp.hndl = p_scb->hndl;
 +
 +    if (p_data && p_data->api_stop.suspend)
 +    {
 +        APPL_TRACE_DEBUG("suspending: %d, sup:%d", start, p_scb->suspend_sup);
 +        if ((start)  && (p_scb->suspend_sup))
 +        {
 +            sus_evt = FALSE;
 +            p_scb->l2c_bufs = 0;
 +            AVDT_SuspendReq(&p_scb->avdt_handle, 1);
 +        }
 +
 +        /* send SUSPEND_EVT event only if not in reconfiguring state and sus_evt is TRUE*/
 +        if ((sus_evt)&&(p_scb->state != BTA_AV_RCFG_SST))
 +        {
 +            suspend_rsp.status = BTA_AV_SUCCESS;
 +            suspend_rsp.initiator = TRUE;
 +            (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp);
 +        }
 +    }
 +    else
 +    {
 +        suspend_rsp.status = BTA_AV_SUCCESS;
 +        suspend_rsp.initiator = TRUE;
 +        APPL_TRACE_EVENT("bta_av_str_stopped status %d", suspend_rsp.status);
 +
 +        /* send STOP_EVT event only if not in reconfiguring state */
 +        if (p_scb->state != BTA_AV_RCFG_SST)
 +        {
 +            (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV *) &suspend_rsp);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_reconfig
 +**
 +** Description      process the reconfigure request.
 +**                  save the parameter in control block and
 +**                  suspend, reconfigure or close the stream
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_reconfig (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tAVDT_CFG   *p_cfg;
 +    tBTA_AV_API_STOP    stop;
 +    tBTA_AV_RECONFIG    evt;
 +    tBTA_AV_API_RCFG    *p_rcfg = &p_data->api_reconfig;
 +
 +    APPL_TRACE_DEBUG("bta_av_reconfig r:%d, s:%d idx: %d (o:%d)",
 +        p_scb->recfg_sup, p_scb->suspend_sup,
 +        p_scb->rcfg_idx, p_scb->sep_info_idx);
 +
 +    p_scb->num_recfg = 0;
 +    /* store the new configuration in control block */
 +    if (p_scb->p_cap == NULL)
 +    {
 +        p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG));
 +    }
 +    if((p_cfg = p_scb->p_cap) == NULL)
 +    {
 +        /* report failure */
 +        evt.status = BTA_AV_FAIL_RESOURCES;
 +        evt.chnl   = p_scb->chnl;
 +        evt.hndl   = p_scb->hndl;
 +        (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
 +
 +        /* this event is not possible in this state.
 +         * use it to bring the SSM back to open state */
 +        bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_OK_EVT, NULL);
 +        return;
 +    }
 +
 +    /*if(bta_av_cb.features & BTA_AV_FEAT_RCCT)*/
 +        bta_sys_stop_timer(&p_scb->timer);
 +
 +    memcpy(p_cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
 +    p_cfg->num_protect = p_rcfg->num_protect;
 +    memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE);
 +    memcpy(p_cfg->protect_info, p_rcfg->p_protect_info, p_rcfg->num_protect);
 +    p_scb->rcfg_idx = p_rcfg->sep_info_idx;
 +    p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
 +
 +    /* if the requested index differs from the current one, we can only close/open */
 +    if ((p_scb->rcfg_idx == p_scb->sep_info_idx) &&
 +        (p_rcfg->suspend)&& (p_scb->recfg_sup) && (p_scb->suspend_sup))
 +    {
 +        if(p_scb->started)
 +        {
 +            stop.flush   = FALSE;
 +            stop.suspend = TRUE;
 +            bta_av_str_stopped(p_scb, (tBTA_AV_DATA *)&stop);
 +        }
 +        else
 +        {
 +            APPL_TRACE_DEBUG("Reconfig");
 +            AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
 +            p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
 +        }
 +    }
 +    else
 +    {
 +        /* close the stream */
 +        APPL_TRACE_DEBUG("close/open num_protect: %d", p_cfg->num_protect);
 +        if(p_scb->started)
 +        {
 +            bta_av_str_stopped(p_scb, NULL);
 +            p_scb->started = FALSE;
 +
 +            /* drop the buffers queued in L2CAP */
 +            L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
 +
 +            AVDT_CloseReq(p_scb->avdt_handle);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_data_path
 +**
 +** Description      Handle stream data path.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    BT_HDR  *p_buf = NULL;
 +    UINT32  data_len;
 +    UINT32  timestamp;
 +    BOOLEAN new_buf = FALSE;
 +    UINT8   m_pt = 0x60 | p_scb->codec_type;
 +    tAVDT_DATA_OPT_MASK     opt;
 +    UNUSED(p_data);
 +
 +    if (p_scb->cong)
 +    {
 +        return;
 +    }
 +
 +    /*
 +    APPL_TRACE_ERROR("q: %d", p_scb->l2c_bufs);
 +    */
 +    //Always get the current number of bufs que'd up
 +    p_scb->l2c_bufs = (UINT8)L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET);
 +
 +    if (!list_is_empty(p_scb->a2d_list)) {
 +        p_buf = (BT_HDR *)list_front(p_scb->a2d_list);
 +        list_remove(p_scb->a2d_list, p_buf);
 +         /* use q_info.a2d data, read the timestamp */
 +        timestamp = *(UINT32 *)(p_buf + 1);
 +    }
 +    else
 +    {
 +        new_buf = TRUE;
 +        /* a2d_list empty, call co_data, dup data to other channels */
 +        p_buf = (BT_HDR *)p_scb->p_cos->data(p_scb->codec_type, &data_len,
 +                                         &timestamp);
 +
 +        if (p_buf)
 +        {
 +            /* use the offset area for the time stamp */
 +            *(UINT32 *)(p_buf + 1) = timestamp;
 +
 +            /* dup the data to other channels */
 +            bta_av_dup_audio_buf(p_scb, p_buf);
 +        }
 +    }
 +
 +    if(p_buf)
 +    {
 +        if(p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM))
 +        {
 +            /* there's a buffer, just queue it to L2CAP */
 +            /*  There's no need to increment it here, it is always read from L2CAP see above */
 +            /* p_scb->l2c_bufs++; */
 +            /*
 +            APPL_TRACE_ERROR("qw: %d", p_scb->l2c_bufs);
 +            */
 +
 +            /* opt is a bit mask, it could have several options set */
 +            opt = AVDT_DATA_OPT_NONE;
 +            if (p_scb->no_rtp_hdr)
 +            {
 +                opt |= AVDT_DATA_OPT_NO_RTP;
 +            }
 +
 +            AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf, timestamp, m_pt, opt);
 +            p_scb->cong = TRUE;
 +        }
 +        else
 +        {
 +            /* there's a buffer, but L2CAP does not seem to be moving data */
 +            if(new_buf)
 +            {
 +                /* just got this buffer from co_data,
 +                 * put it in queue */
 +                list_append(p_scb->a2d_list, p_buf);
 +            }
 +            else
 +            {
 +                /* just dequeue it from the a2d_list */
 +                if (list_length(p_scb->a2d_list) < 3) {
 +                    /* put it back to the queue */
 +                    list_prepend(p_scb->a2d_list, p_buf);
 +                }
 +                else
 +                {
 +                    /* too many buffers in a2d_list, drop it. */
 +                    bta_av_co_audio_drop(p_scb->hndl);
 +                    GKI_freebuf(p_buf);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_start_ok
 +**
 +** Description      Stream started.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_START   start;
 +    tBTA_AV_API_STOP stop;
 +    BOOLEAN         initiator = FALSE;
 +    BOOLEAN         suspend = FALSE;
 +    UINT16          flush_to;
 +    UINT8           new_role = p_scb->role;
 +    BT_HDR          hdr;
 +    UINT8           policy = HCI_ENABLE_SNIFF_MODE;
 +    UINT8           cur_role;
 +
 +    APPL_TRACE_DEBUG("bta_av_start_ok wait:x%x, role:x%x", p_scb->wait, p_scb->role);
 +
 +    p_scb->started = TRUE;
 +    if (p_scb->sco_suspend)
 +    {
 +        p_scb->sco_suspend = FALSE;
 +    }
 +
 +    if (new_role & BTA_AV_ROLE_START_INT)
 +        initiator = TRUE;
 +
 +    /* for A2DP SINK we do not send get_caps */
 +    if ((p_scb->avdt_handle == p_scb->seps[p_scb->sep_idx].av_handle)
 +         &&(p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK))
 +    {
 +        p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON);
 +        APPL_TRACE_DEBUG(" Local SEP type is SNK  new wait is 0x%x",p_scb->wait);
 +    }
 +    if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED)
 +    {
 +        /* role switch has failed */
 +        p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_FAILED;
 +        p_data = (tBTA_AV_DATA *)&hdr;
 +        hdr.offset = BTA_AV_RS_FAIL;
 +    }
 +    APPL_TRACE_DEBUG("wait:x%x", p_scb->wait);
 +
 +    if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE))
 +    {
 +        p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
 +        if (p_data->hdr.offset == BTA_AV_RS_FAIL)
 +        {
 +            bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
 +            start.chnl   = p_scb->chnl;
 +            start.status = BTA_AV_FAIL_ROLE;
 +            start.hndl   = p_scb->hndl;
 +            start.initiator = initiator;
 +            (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
 +            return;
 +        }
 +    }
 +
 +    if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT))
 +        p_scb->q_tag = BTA_AV_Q_TAG_START;
 +    else
 +    {
 +        /* The wait flag may be set here while we are already master on the link */
 +        /* this could happen if a role switch complete event occurred during reconfig */
 +        /* if we are now master on the link, there is no need to wait for the role switch, */
 +        /* complete anymore so we can clear the wait for role switch flag */
 +        p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
 +    }
 +
 +    if (p_scb->wait & (BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START))
 +    {
 +        p_scb->wait |= BTA_AV_WAIT_ROLE_SW_STARTED;
 +        p_scb->q_tag = BTA_AV_Q_TAG_START;
 +    }
 +
 +    if (p_scb->wait)
 +    {
 +        APPL_TRACE_ERROR("wait:x%x q_tag:%d- not started", p_scb->wait, p_scb->q_tag);
 +        /* Clear first bit of p_scb->wait and not to return from this point else
 +         * HAL layer gets blocked. And if there is delay in Get Capability response as
 +         * first bit of p_scb->wait is cleared hence it ensures bt_av_start_ok is not called
 +         * again from bta_av_save_caps.
 +        */
 +        p_scb->wait &= ~BTA_AV_WAIT_ACP_CAPS_ON;
 +    }
 +
 +    /* tell role manager to check M/S role */
 +    bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
 +
 +    bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
 +
 +    if(p_scb->media_type == AVDT_MEDIA_AUDIO)
 +    {
 +        /* in normal logic, conns should be bta_av_cb.audio_count - 1,
 +         * However, bta_av_stream_chg is not called to increase bta_av_cb.audio_count yet.
 +         * If the code were to be re-arranged for some reasons, this number may need to be changed
 +         */
 +        p_scb->co_started = bta_av_cb.audio_open_cnt;
 +        flush_to = p_bta_av_cfg->p_audio_flush_to[p_scb->co_started - 1];
 +    }
 +    else
 +    {
 +        flush_to = p_bta_av_cfg->video_flush_to;
 +    }
 +    L2CA_SetFlushTimeout(p_scb->peer_addr, flush_to );
 +
 +    /* clear the congestion flag */
 +    p_scb->cong = FALSE;
 +
 +    if (new_role & BTA_AV_ROLE_START_INT)
 +    {
 +        new_role &= ~BTA_AV_ROLE_START_INT;
 +    }
 +    else if ((new_role & BTA_AV_ROLE_AD_ACP) && (new_role & BTA_AV_ROLE_SUSPEND_OPT))
 +    {
 +        suspend = TRUE;
 +    }
 +
 +    if (!suspend)
 +    {
 +        p_scb->q_tag = BTA_AV_Q_TAG_STREAM;
 +        bta_av_stream_chg(p_scb, TRUE);
 +    }
 +
 +    {
 +        /* If sink starts stream, disable sniff mode here */
 +        if (!initiator)
 +        {
 +             /* If souce is the master role, disable role switch during streaming.
 +             * Otherwise allow role switch, if source is slave.
 +             * Because it would not hurt source, if the peer device wants source to be master */
 +            if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
 +                (cur_role == BTM_ROLE_MASTER) )
 +            {
 +                policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
 +            }
 +
 +            bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
 +        }
 +
 +        p_scb->role = new_role;
 +        p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
 +        p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
 +
 +        p_scb->no_rtp_hdr = FALSE;
 +        p_scb->p_cos->start(p_scb->hndl, p_scb->codec_type, p_scb->cfg.codec_info, &p_scb->no_rtp_hdr);
 +        p_scb->co_started = TRUE;
 +
 +        APPL_TRACE_DEBUG("bta_av_start_ok suspending: %d, role:x%x, init %d",
 +            suspend, p_scb->role, initiator);
 +
 +        start.suspending = suspend;
 +        start.initiator = initiator;
 +        start.chnl   = p_scb->chnl;
 +        start.status = BTA_AV_SUCCESS;
 +        start.hndl   = p_scb->hndl;
 +        (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
 +
 +        if(suspend)
 +        {
 +            p_scb->role |= BTA_AV_ROLE_SUSPEND;
 +            p_scb->cong = TRUE;  /* do not allow the media data to go through */
 +            /* do not duplicate the media packets to this channel */
 +            p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
 +            p_scb->co_started = FALSE;
 +            stop.flush   = FALSE;
 +            stop.suspend = TRUE;
 +            bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA *)&stop);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_start_failed
 +**
 +** Description      Stream start failed.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_start_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    if(p_scb->started == FALSE && p_scb->co_started == FALSE)
 +    {
 +        bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
 +        notify_start_failed(p_scb);
 +    }
 +
 +    bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_SNIFF_MODE|HCI_ENABLE_MASTER_SLAVE_SWITCH), p_scb->peer_addr);
 +    p_scb->sco_suspend = FALSE;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_str_closed
 +**
 +** Description      Stream closed.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV     data;
 +    tBTA_AV_EVT event;
 +    UINT16      mtu;
 +    UINT8 policy = HCI_ENABLE_SNIFF_MODE;
 +
 +    if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
 +        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
 +    bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
 +    if (bta_av_cb.audio_open_cnt <= 1)
 +    {
 +        /* last connection - restore the allow switch flag */
 +        L2CA_SetDesireRole(L2CAP_ROLE_ALLOW_SWITCH);
 +    }
 +
 +    if (p_scb->open_status)
 +    {
 +        /* must be failure when opening the stream */
 +        bdcpy(data.open.bd_addr, p_scb->peer_addr);
 +        data.open.status = p_scb->open_status;
 +        data.open.chnl   = p_scb->chnl;
 +        data.open.hndl   = p_scb->hndl;
 +
 +        if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC )
 +            data.open.sep = AVDT_TSEP_SNK;
 +        else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK )
 +            data.open.sep = AVDT_TSEP_SRC;
 +
 +        event = BTA_AV_OPEN_EVT;
 +        p_scb->open_status = BTA_AV_SUCCESS;
 +
 +        bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
 +        bta_av_cleanup(p_scb, p_data);
 +        (*bta_av_cb.p_cback)(event, &data);
 +    }
 +    else
 +    {
 +        /* do stop if we were started */
 +        if (p_scb->co_started)
 +        {
 +            bta_av_str_stopped(p_scb, NULL);
 +        }
 +
 +        /* Update common mtu shared by remaining connectons */
 +        mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
 +
 +        {
 +            p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu);
 +            data.close.chnl = p_scb->chnl;
 +            data.close.hndl = p_scb->hndl;
 +            event = BTA_AV_CLOSE_EVT;
 +
 +            bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
 +            bta_av_cleanup(p_scb, p_data);
 +            (*bta_av_cb.p_cback)(event, &data);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_clr_cong
 +**
 +** Description      Clear stream congestion flag.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_clr_cong (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    if(p_scb->co_started)
 +        p_scb->cong = FALSE;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_suspend_cfm
 +**
 +** Description      process the suspend response
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_SUSPEND suspend_rsp;
 +    UINT8           err_code = p_data->str_msg.msg.hdr.err_code;
 +    UINT8 policy = HCI_ENABLE_SNIFF_MODE;
 +
 +    APPL_TRACE_DEBUG ("bta_av_suspend_cfm:audio_open_cnt = %d, err_code = %d",
 +        bta_av_cb.audio_open_cnt, err_code);
 +
 +    if (p_scb->started == FALSE)
 +    {
 +        /* handle the condition where there is a collision of SUSPEND req from either side
 +        ** Second SUSPEND req could be rejected. Do not treat this as a failure
 +        */
 +        APPL_TRACE_WARNING("bta_av_suspend_cfm: already suspended, ignore, err_code %d",
 +                            err_code);
 +        return;
 +    }
 +
 +    suspend_rsp.status = BTA_AV_SUCCESS;
 +    if (err_code && (err_code != AVDT_ERR_BAD_STATE))
 +    {
 +         /* Disable suspend feature only with explicit rejection(not with timeout) */
 +        if (err_code != AVDT_ERR_TIMEOUT)
 +        {
 +            p_scb->suspend_sup = FALSE;
 +        }
 +        suspend_rsp.status = BTA_AV_FAIL;
 +
 +        APPL_TRACE_ERROR ("bta_av_suspend_cfm: suspend failed, closing connection");
 +
 +        /* SUSPEND failed. Close connection. */
 +        bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
 +    }
 +    else
 +    {
 +        /* only set started to FALSE when suspend is successful */
 +        p_scb->started = FALSE;
 +    }
 +
 +    if (p_scb->role & BTA_AV_ROLE_SUSPEND)
 +    {
 +        p_scb->role &= ~BTA_AV_ROLE_SUSPEND;
 +        p_scb->cong = FALSE;
 +    }
 +
 +    bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
 +    if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1)
 +        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
 +    bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
 +
 +    /* in case that we received suspend_ind, we may need to call co_stop here */
 +    if(p_scb->co_started)
 +    {
 +        bta_av_stream_chg(p_scb, FALSE);
 +
 +        {
 +            p_scb->co_started = FALSE;
 +            p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
 +        }
 +        L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
 +    }
 +
 +    {
 +        suspend_rsp.chnl = p_scb->chnl;
 +        suspend_rsp.hndl = p_scb->hndl;
 +        suspend_rsp.initiator = p_data->str_msg.initiator;
 +        (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_rcfg_str_ok
 +**
 +** Description      report reconfigure successful
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_rcfg_str_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_RECONFIG    evt;
 +    UNUSED(p_data);
 +
 +    p_scb->l2c_cid      = AVDT_GetL2CapChannel(p_scb->avdt_handle);
 +    APPL_TRACE_DEBUG("bta_av_rcfg_str_ok: l2c_cid: %d", p_scb->l2c_cid);
 +
 +    /* rc listen */
 +    bta_av_st_rc_timer(p_scb, NULL);
 +    utl_freebuf((void **)&p_scb->p_cap);
 +
 +    /* No need to keep the role bits once reconfig is done. */
 +    p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
 +    p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
 +    p_scb->role &= ~BTA_AV_ROLE_START_INT;
 +
 +    {
 +        /* reconfigure success  */
 +        evt.status = BTA_AV_SUCCESS;
 +        evt.chnl   = p_scb->chnl;
 +        evt.hndl   = p_scb->hndl;
 +        (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_rcfg_failed
 +**
 +** Description      process reconfigure failed
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_rcfg_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_RECONFIG evt;
 +
 +    APPL_TRACE_DEBUG("bta_av_rcfg_failed num_recfg: %d, conn_lcb:0x%x",
 +        p_scb->num_recfg, bta_av_cb.conn_lcb);
 +    if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
 +    {
 +        bta_av_cco_close(p_scb, p_data);
 +        /* report failure */
 +        evt.status = BTA_AV_FAIL_STREAM;
 +        evt.chnl   = p_scb->chnl;
 +        evt.hndl   = p_scb->hndl;
 +        (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
 +        /* go to closing state */
 +        bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
 +    }
 +    else
 +    {
 +        /* open failed. try again */
 +        p_scb->num_recfg++;
 +        if(bta_av_cb.conn_lcb)
 +        {
 +            AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
 +        }
 +        else
 +        {
 +            bta_av_connect_req(p_scb, NULL);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_rcfg_connect
 +**
 +** Description      stream closed. reconnect the stream
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_rcfg_connect (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    p_scb->cong    = FALSE;
 +    p_scb->num_recfg++;
 +    APPL_TRACE_DEBUG("bta_av_rcfg_connect num_recfg: %d", p_scb->num_recfg);
 +    if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
 +    {
 +        /* let bta_av_rcfg_failed report fail */
 +        bta_av_rcfg_failed(p_scb, NULL);
 +    }
 +    else
 +        AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_rcfg_discntd
 +**
 +** Description      AVDT disconnected. reconnect the stream
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_rcfg_discntd (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_RECONFIG    evt;
 +    UNUSED(p_data);
 +
 +    APPL_TRACE_DEBUG("bta_av_rcfg_discntd num_recfg: %d", p_scb->num_recfg);
 +    p_scb->num_recfg++;
 +    if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY)
 +    {
 +        /* report failure */
 +        evt.status = BTA_AV_FAIL_STREAM;
 +        evt.chnl   = p_scb->chnl;
 +        evt.hndl   = p_scb->hndl;
 +        (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
 +        /* report close event & go to init state */
 +        bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
 +    }
 +    else
 +        AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_suspend_cont
 +**
 +** Description      received the suspend response.
 +**                  continue to reconfigure the stream
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UINT8       err_code = p_data->str_msg.msg.hdr.err_code;
 +    tBTA_AV_RECONFIG    evt;
 +
 +    p_scb->started = FALSE;
 +    p_scb->cong    = FALSE;
 +    if (err_code)
 +    {
 +        if (AVDT_ERR_CONNECT == err_code)
 +        {
 +            /* report failure */
 +            evt.status = BTA_AV_FAIL;
 +            (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt);
 +            bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
 +        }
 +        else
 +        {
 +            APPL_TRACE_ERROR("suspend rejected, try close");
 +             /* Disable suspend feature only with explicit rejection(not with timeout) */
 +            if (err_code != AVDT_ERR_TIMEOUT)
 +            {
 +                p_scb->suspend_sup = FALSE;
 +            }
 +            /* drop the buffers queued in L2CAP */
 +            L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
 +
 +            AVDT_CloseReq(p_scb->avdt_handle);
 +        }
 +    }
 +    else
 +    {
 +        APPL_TRACE_DEBUG("bta_av_suspend_cont calling AVDT_ReconfigReq");
 +        /* reconfig the stream */
 +
 +        AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
 +        p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_rcfg_cfm
 +**
 +** Description      if reconfigure is successful, report the event
 +**                  otherwise, close the stream.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UINT8   err_code = p_data->str_msg.msg.hdr.err_code;
 +
 +    /*
 +    APPL_TRACE_DEBUG("bta_av_rcfg_cfm");
 +    */
 +    if (err_code)
 +    {
 +        APPL_TRACE_ERROR("reconfig rejected, try close");
 +         /* Disable reconfiguration feature only with explicit rejection(not with timeout) */
 +        if (err_code != AVDT_ERR_TIMEOUT)
 +        {
 +            p_scb->recfg_sup = FALSE;
 +        }
 +        /* started flag is FALSE when reconfigure command is sent */
 +        /* drop the buffers queued in L2CAP */
 +        L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
 +        AVDT_CloseReq(p_scb->avdt_handle);
 +    }
 +    else
 +    {
 +        /* update the codec info after rcfg cfm */
 +        memcpy(p_scb->cfg.codec_info,p_data->str_msg.msg.reconfig_cfm.p_cfg->codec_info,AVDT_CODEC_SIZE);
 +        /* take the SSM back to OPEN state */
 +        bta_av_ssm_execute(p_scb, BTA_AV_STR_OPEN_OK_EVT, NULL);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_rcfg_open
 +**
 +** Description      AVDT is connected. open the stream with the new configuration
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +      APPL_TRACE_DEBUG("bta_av_rcfg_open, num_disc_snks = %d", p_scb->num_disc_snks);
 +
 +    if (p_scb->num_disc_snks == 0)
 +    {
 +        /* Need to update call-out module so that it will be ready for discover */
 +        p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type);
 +
 +        /* send avdtp discover request */
 +        AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]);
 +    }
 +    else
 +    {
 +        p_scb->codec_type = p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX];
 +        memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
 +        /* we may choose to use a different SEP at reconfig.
 +         * adjust the sep_idx now */
 +        bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC));
 +
 +        /* open the stream with the new config */
 +        p_scb->sep_info_idx = p_scb->rcfg_idx;
 +        AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr,
 +                     p_scb->sep_info[p_scb->sep_info_idx].seid, p_scb->p_cap);
 +    }
 +
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_security_rej
 +**
 +** Description      Send an AVDTP security reject.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_security_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_BAD_STATE,
 +                     NULL, 0);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_chk_2nd_start
 +**
 +** Description      check if this is 2nd stream and if it needs to be started.
 +**                  This function needs to be kept very similar to bta_av_chk_start
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_chk_2nd_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_SCB *p_scbi;
 +    int i;
 +    BOOLEAN new_started = FALSE;
 +    UNUSED(p_data);
 +
 +    if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2))
 +    {
 +        /* more than one audio channel is connected */
 +        if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT))
 +        {
 +            /* this channel does not need to be reconfigured.
 +             * if there is other channel streaming, start the stream now */
 +            for(i=0; i<BTA_AV_NUM_STRS; i++)
 +            {
 +                p_scbi = bta_av_cb.p_scb[i];
 +                if(p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started)
 +                {
 +                    if (!new_started)
 +                    {
 +                        /* start the new stream */
 +                        new_started = TRUE;
 +                        bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
 +                    }
 +                    /* may need to update the flush timeout of this already started stream */
 +                    if (p_scbi->co_started != bta_av_cb.audio_open_cnt)
 +                    {
 +                        p_scbi->co_started = bta_av_cb.audio_open_cnt;
 +                        L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] );
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_open_rc
 +**
 +** Description      Send a message to main SM to open RC channel.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_open_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_START   start;
 +
 +    APPL_TRACE_DEBUG("bta_av_open_rc use_rc: %d, wait: x%x role:x%x", p_scb->use_rc, p_scb->wait, p_scb->role);
 +    if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) && (p_scb->q_tag == BTA_AV_Q_TAG_START))
 +    {
 +        /* waiting for role switch for some reason & the timer expires */
 +        if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT))
 +        {
 +            APPL_TRACE_ERROR ("failed to start streaming for role management reasons!!");
 +            bta_sys_stop_timer(&p_scb->timer);
 +            start.chnl   = p_scb->chnl;
 +            start.status = BTA_AV_FAIL_ROLE;
 +            start.initiator = TRUE;
 +            start.hndl   = p_scb->hndl;
 +            p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
 +            bta_av_cb.rs_idx = 0;
 +            (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start);
 +        }
 +        else
 +        {
 +            /* role switch is done. continue to start streaming */
 +            bta_av_cb.rs_idx = 0;
 +            p_data->hdr.offset = BTA_AV_RS_OK;
 +            bta_av_start_ok (p_scb, p_data);
 +        }
 +        return;
 +    }
 +
 +    if(p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP) )
 +    {
 +        if(bta_av_cb.disc)
 +        {
 +            /* AVRC discover db is in use */
 +            if(p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE)
 +            {
 +                /* AVRC channel is not connected. delay a little bit */
 +                if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0)
 +                    bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL);
 +                else
 +                    p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
 +            }
 +        }
 +        else
 +        {
 +            /* use main SM for AVRC SDP activities */
 +            bta_av_rc_disc((UINT8)(p_scb->hdi + 1));
 +        }
 +    }
 +    else
 +    {
 +        if(BTA_AV_RC_HANDLE_NONE != p_scb->rc_handle)
 +        {
 +            /* the open API said that this handle does not want a RC connection.
 +             * disconnect it now */
 +            AVRC_Close(p_scb->rc_handle);
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         bta_av_open_at_inc
 +**
 +** Description      This function is called if API open is called by application
 +**                  while state-machine is at incoming state.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data)
 +{
 +    tBTA_AV_API_OPEN  *p_buf;
 +
 +    memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
 +
 +    if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR)
 +    {
 +        p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
 +
 +        /* API open will be handled at timeout if SNK did not start signalling. */
 +        /* API open will be ignored if SNK starts signalling.                   */
 +    }
 +    else
 +    {
 +        /* SNK did not start signalling, API was called N seconds timeout. */
 +        /* We need to switch to INIT state and start opening connection. */
 +        p_scb->coll_mask = 0;
 +        bta_av_set_scb_sst_init (p_scb);
 +
 +        if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL)
 +        {
 +            memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
 +            bta_sys_sendmsg(p_buf);
 +        }
 +    }
 +}
 +
 +#endif /* BTA_AV_INCLUDED */
index e14cdfd86c0b100b9cd38bd82aba92b3d01abe2e,0000000000000000000000000000000000000000..2ce6b481f1cbd48e26fb35b034e3721c47daf572
mode 100644,000000..100644
--- /dev/null
@@@ -1,1187 -1,0 +1,1188 @@@
 +/******************************************************************************
 + *
 + *  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_av.c
 + *
 + *  Description:   Bluedroid AV implementation
 + *
 + *****************************************************************************/
 +
 +#include "bt_trace.h"
 +#include <string.h>
 +
 +#include "bt_defs.h"
 +#include "esp_bt_defs.h"
 +#include "esp_a2dp_api.h"
 +#include "allocator.h"
 +
 +#define LOG_TAG "bt_btif_av"
 +
 +#include "btif_av.h"
 +#include "btif_util.h"
 +#include "btif_profile_queue.h"
 +#include "bta_api.h"
 +#include "btif_media.h"
 +#include "bta_av_api.h"
 +#include "gki.h"
 +#include "btu.h"
 +#include "bt_utils.h"
 +
 +/*****************************************************************************
 +**  Constants & Macros
 +******************************************************************************/
 +#define BTIF_AV_SERVICE_NAME "Advanced Audio"
 +
 +#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_CLOSING
 +} btif_av_state_t;
 +
 +/* Should not need dedicated suspend state as actual actions are no
 +   different than open state. Suspend flags are needed however to prevent
 +   media task from trying to restart stream during remote suspend or while
 +   we are in the process of a local suspend */
 +
 +#define BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING 0x1
 +#define BTIF_AV_FLAG_REMOTE_SUSPEND        0x2
 +#define BTIF_AV_FLAG_PENDING_START         0x4
 +#define BTIF_AV_FLAG_PENDING_STOP          0x8
 +
 +/*****************************************************************************
 +**  Local type definitions
 +******************************************************************************/
 +
 +typedef struct {
 +    tBTA_AV_HNDL bta_handle;
 +    bt_bdaddr_t peer_bda;
 +    btif_sm_handle_t sm_handle;
 +    UINT8 flags;
 +    tBTA_AV_EDR edr;
 +    UINT8   peer_sep;  /* sep type of peer device */
 +} btif_av_cb_t;
 +
 +typedef struct {
 +    bt_bdaddr_t *target_bda;
 +    uint16_t uuid;
 +} btif_av_connect_req_t;
 +
 +/*****************************************************************************
 +**  Static variables
 +******************************************************************************/
 +
 +static esp_profile_cb_t bt_av_sink_callback = NULL;
 +
 +static btif_av_cb_t btif_av_cb = {0};
 +// static TIMER_LIST_ENT tle_av_open_on_rc;
 +
 +// TODO: need protection against race
 +#define BTIF_A2D_CB_TO_APP(_event, _param)    do { \
 +      if (bt_av_sink_callback) { \
 +          bt_av_sink_callback(_event, _param); \
 +      } \
 +    } while (0)
 +
 +/* both interface and media task needs to be ready to alloc incoming request */
 +#define CHECK_BTAV_INIT() if (btif_av_cb.sm_handle == NULL)\
 +{\
 +     BTIF_TRACE_WARNING("%s: BTAV not initialized\n", __FUNCTION__);\
 +     return ESP_ERR_INVALID_STATE;\
 +}\
 +else\
 +{\
 +     BTIF_TRACE_EVENT("%s\n", __FUNCTION__);\
 +}
 +
 +/* Helper macro to avoid code duplication in the state machine handlers */
 +#define CHECK_RC_EVENT(e, d) \
 +    case BTA_AV_RC_OPEN_EVT: \
 +    case BTA_AV_RC_CLOSE_EVT: \
 +    case BTA_AV_REMOTE_CMD_EVT: \
 +    case BTA_AV_VENDOR_CMD_EVT: \
 +    case BTA_AV_META_MSG_EVT: \
 +    case BTA_AV_RC_FEAT_EVT: \
 +    case BTA_AV_REMOTE_RSP_EVT: \
 +    { \
 +    }break; \
 +
 +static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data);
 +static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *data);
 +static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *data);
 +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_closing_handler
 +};
 +
 +static void btif_av_event_free_data(btif_sm_event_t event, void *p_data);
 +
 +/*************************************************************************
 +** Extern functions
 +*************************************************************************/
 +
 +extern tBTA_AV_CO_FUNCTS bta_av_a2d_cos;
 +/*****************************************************************************
 +** Local helper functions
 +******************************************************************************/
 +
 +const char *dump_av_sm_state_name(btif_av_state_t 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 ((int)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_SINK_CONFIG_REQ_EVT)
 +    default: return "UNKNOWN_EVENT";
 +    }
 +}
 +
 +/****************************************************************************
 +**  Local helper functions
 +*****************************************************************************/
 +
 +/*****************************************************************************
 +**  Static functions
 +******************************************************************************/
 +static void btif_report_connection_state(esp_a2d_connection_state_t state, bt_bdaddr_t *bd_addr)
 +{
 +    esp_a2d_cb_param_t param;
 +    memset(&param, 0, sizeof(esp_a2d_cb_param_t));
 +    
 +    param.conn_stat.state = state;
 +    if (bd_addr) {
 +        memcpy(param.conn_stat.remote_bda, bd_addr, sizeof(esp_bd_addr_t));
 +    }
 +    BTIF_A2D_CB_TO_APP(ESP_A2D_CONNECTION_STATE_EVT, &param);
 +}
 +
 +static void btif_report_audio_state(esp_a2d_audio_state_t state, bt_bdaddr_t *bd_addr)
 +{
 +    esp_a2d_cb_param_t param;
 +    memset(&param, 0, sizeof(esp_a2d_cb_param_t));
 +
 +    param.audio_stat.state = state;
 +    if (bd_addr) {
 +        memcpy(param.audio_stat.remote_bda, bd_addr, sizeof(esp_bd_addr_t));
 +    }
 +    BTIF_A2D_CB_TO_APP(ESP_A2D_AUDIO_STATE_EVT, &param);
 +}
 +
 +/*****************************************************************************
 +**
 +** 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)
 +{
 +    BTIF_TRACE_DEBUG("%s event:%s flags %x\n", __FUNCTION__,
 +                     dump_av_sm_event_name(event), btif_av_cb.flags);
 +
 +    switch (event) {
 +    case BTIF_SM_ENTER_EVT:
 +        /* clear the peer_bda */
 +        memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t));
 +        btif_av_cb.flags = 0;
 +        btif_av_cb.edr = 0;
 +        btif_a2dp_on_idle();
 +        break;
 +
 +    case BTIF_SM_EXIT_EVT:
 +        break;
 +
 +    case BTA_AV_ENABLE_EVT:
 +        break;
 +
 +    case BTA_AV_REGISTER_EVT:
 +        btif_av_cb.bta_handle = ((tBTA_AV *)p_data)->registr.hndl;
 +        break;
 +
 +    case BTA_AV_PENDING_EVT:
 +    case BTIF_AV_CONNECT_REQ_EVT: {
 +        if (event == BTIF_AV_CONNECT_REQ_EVT) {
 +            memcpy(&btif_av_cb.peer_bda, ((btif_av_connect_req_t *)p_data)->target_bda,
 +                   sizeof(bt_bdaddr_t));
 +            BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
 +                       TRUE, BTA_SEC_AUTHENTICATE, ((btif_av_connect_req_t *)p_data)->uuid);
 +        } 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_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
 +        }
 +        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
 +    } break;
 +
 +    case BTA_AV_RC_OPEN_EVT:
 +    case BTA_AV_REMOTE_CMD_EVT:
 +    case BTA_AV_VENDOR_CMD_EVT:
 +    case BTA_AV_META_MSG_EVT:
 +    case BTA_AV_RC_FEAT_EVT:
 +    case BTA_AV_REMOTE_RSP_EVT:
 +    case BTA_AV_RC_CLOSE_EVT:
 +        BTIF_TRACE_WARNING("%s : unhandled RC event:%s\n", __FUNCTION__,
 +                           dump_av_sm_event_name(event));
 +        break;
 +    default:
 +        BTIF_TRACE_WARNING("%s : unhandled event:%s\n", __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)
 +{
 +    BTIF_TRACE_DEBUG("%s event:%s flags %x\n", __FUNCTION__,
 +                     dump_av_sm_event_name(event), btif_av_cb.flags);
 +
 +    switch (event) {
 +    case BTIF_SM_ENTER_EVT:
 +        /* inform the application that we are entering connecting state */
 +        btif_report_connection_state(ESP_A2D_CONNECTION_STATE_CONNECTING, &(btif_av_cb.peer_bda));
 +        break;
 +
 +    case BTIF_SM_EXIT_EVT:
 +        break;
 +
 +    case BTA_AV_REJECT_EVT:
 +        BTIF_TRACE_DEBUG(" Received  BTA_AV_REJECT_EVT \n");
 +        btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
 +        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
 +        break;
 +
 +    case BTA_AV_OPEN_EVT: {
 +        tBTA_AV *p_bta_data = (tBTA_AV *)p_data;
 +        esp_a2d_connection_state_t state;
 +        btif_sm_state_t av_state;
 +        BTIF_TRACE_DEBUG("status:%d, edr 0x%x\n", p_bta_data->open.status,
 +                         p_bta_data->open.edr);
 +
 +        if (p_bta_data->open.status == BTA_AV_SUCCESS) {
 +            state = ESP_A2D_CONNECTION_STATE_CONNECTED;
 +            av_state = BTIF_AV_STATE_OPENED;
 +            btif_av_cb.edr = p_bta_data->open.edr;
 +
 +            btif_av_cb.peer_sep = p_bta_data->open.sep;
 +            btif_a2dp_set_peer_sep(p_bta_data->open.sep);
 +        } else {
 +            BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d\n",
 +                               p_bta_data->open.status );
 +            state = ESP_A2D_CONNECTION_STATE_DISCONNECTED;
 +            av_state  = BTIF_AV_STATE_IDLE;
 +        }
 +
 +        /* inform the application of the event */
 +        btif_report_connection_state(state, &(btif_av_cb.peer_bda));
 +        /* change state to open/idle based on the status */
 +        btif_sm_change_state(btif_av_cb.sm_handle, av_state);
 +#if (BTIF_AV_SRC_INCLUDED == TRUE)
 +        if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
 +            /* if queued PLAY command,  send it now */
 +            btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
 +                                              (p_bta_data->open.status == BTA_AV_SUCCESS));
 +        } else if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
 +            /* if queued PLAY command,  send it now */
 +            btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr, FALSE);
 +            /* Bring up AVRCP connection too */
 +            BTA_AvOpenRc(btif_av_cb.bta_handle);
 +        }
 +#endif
 +        btif_queue_advance();
 +    } break;
 +
 +    case BTIF_AV_SINK_CONFIG_REQ_EVT: {
 +        if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
 +            esp_a2d_cb_param_t param;
 +            memcpy(param.audio_cfg.remote_bda, &btif_av_cb.peer_bda, sizeof(esp_bd_addr_t));
 +            memcpy(&param.audio_cfg.mcc, p_data, sizeof(esp_a2d_mcc_t));
 +            BTIF_A2D_CB_TO_APP(ESP_A2D_AUDIO_CFG_EVT, &param);
 +        }
 +    } break;
 +
 +    case BTIF_AV_CONNECT_REQ_EVT:
 +        // Check for device, if same device which moved to opening then ignore callback
 +        if (memcmp ((bt_bdaddr_t *)p_data, &(btif_av_cb.peer_bda),
 +                    sizeof(btif_av_cb.peer_bda)) == 0) {
 +            BTIF_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Connect Req\n", __func__);
 +            btif_queue_advance();
 +            break;
 +        } else {
 +            BTIF_TRACE_DEBUG("%s: Moved from idle by Incoming Connection request\n", __func__);
 +            btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, (bt_bdaddr_t *)p_data);
 +            btif_queue_advance();
 +            break;
 +        }
 +
 +    case BTA_AV_PENDING_EVT:
 +        // Check for device, if same device which moved to opening then ignore callback
 +        if (memcmp (((tBTA_AV *)p_data)->pend.bd_addr, &(btif_av_cb.peer_bda),
 +                    sizeof(btif_av_cb.peer_bda)) == 0) {
 +            BTIF_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Pending Req\n", __func__);
 +            break;
 +        } else {
 +            BTIF_TRACE_DEBUG("%s: Moved from idle by outgoing Connection request\n", __func__);
 +            BTA_AvDisconnect(((tBTA_AV *)p_data)->pend.bd_addr);
 +            break;
 +        }
 +
 +        CHECK_RC_EVENT(event, p_data);
 +
 +    default:
 +        BTIF_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__,
 +                           dump_av_sm_event_name(event));
 +        return FALSE;
 +
 +    }
 +    return TRUE;
 +}
 +
 +
 +/*****************************************************************************
 +**
 +** 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_DEBUG("%s event:%s flags %x\n", __FUNCTION__,
 +                     dump_av_sm_event_name(event), btif_av_cb.flags);
 +
 +    switch (event) {
 +    case BTIF_SM_ENTER_EVT:
 +        if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
 +            btif_a2dp_set_rx_flush(TRUE);
 +        }
 +        break;
 +
 +    case BTA_AV_STOP_EVT:
 +    case BTIF_AV_STOP_STREAM_REQ_EVT:
 +        if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
 +            btif_a2dp_set_rx_flush(TRUE);
 +        }
 +
 +        btif_a2dp_on_stopped(NULL);
 +        break;
 +
 +    case BTIF_SM_EXIT_EVT:
 +        break;
 +
 +    case BTA_AV_CLOSE_EVT:
 +
 +        /* inform the application that we are disconnecting */
 +        btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
 +
 +        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
 +        break;
 +
 +    /* Handle the RC_CLOSE event for the cleanup */
 +    case BTA_AV_RC_CLOSE_EVT:
 +        BTIF_TRACE_WARNING("%s : unhandled RC event:%s\n", __FUNCTION__,
 +                           dump_av_sm_event_name(event));
 +        break;
 +
 +    default:
 +        BTIF_TRACE_WARNING("%s : unhandled event:%s\n", __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_DEBUG("%s event:%s flags %x\n", __FUNCTION__,
 +                     dump_av_sm_event_name(event), btif_av_cb.flags);
 +
 +    if ( (event == BTA_AV_REMOTE_CMD_EVT) && (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND) &&
 +            (p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY) ) {
 +        BTIF_TRACE_EVENT("%s: Resetting remote suspend flag on RC PLAY\n", __FUNCTION__);
 +        btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
 +    }
 +
 +    switch (event) {
 +    case BTIF_SM_ENTER_EVT:
 +        btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_STOP;
 +        btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
 +        break;
 +
 +    case BTIF_SM_EXIT_EVT:
 +        btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
 +        break;
 +
 +    case BTIF_AV_START_STREAM_REQ_EVT:
 +        BTA_AvStart();
 +        btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START;
 +        break;
 +
 +    case BTA_AV_START_EVT: {
 +        BTIF_TRACE_EVENT("BTA_AV_START_EVT status %d, suspending %d, init %d\n",
 +                         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;
 +        }
 +
 +        /* remain in open state if status failed */
 +        if (p_av->start.status != BTA_AV_SUCCESS) {
 +            return FALSE;
 +        }
 +
 +        if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
 +            btif_a2dp_set_rx_flush(FALSE); /*  remove flush state, ready for streaming*/
 +        }
 +
 +        /* change state to started, send acknowledgement if start is pending */
 +        if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
 +
 +            /* pending start flag will be cleared when exit current state */
 +        }
 +        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED);
 +
 +    } break;
 +
 +    case BTIF_AV_DISCONNECT_REQ_EVT:
 +        BTA_AvClose(btif_av_cb.bta_handle);
 +
 +        /* inform the application that we are disconnecting */
 +        btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
 +        break;
 +
 +    case BTA_AV_CLOSE_EVT:
 +        /* avdtp link is closed */
 +        btif_a2dp_on_stopped(NULL);
 +
 +        /* inform the application that we are disconnected */
 +        btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
 +
 +        /* change state to idle, send acknowledgement if start is pending */
 +        if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
 +            /* pending start flag will be cleared when exit current state */
 +        }
 +        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
 +        break;
 +
 +    case BTA_AV_RECONFIG_EVT:
 +        if ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) &&
 +                (p_av->reconfig.status == BTA_AV_SUCCESS)) {
 +            APPL_TRACE_WARNING("reconfig done BTA_AVstart()\n");
 +            BTA_AvStart();
 +        } else if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
 +            btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
 +        }
 +        break;
 +
 +    case BTIF_AV_CONNECT_REQ_EVT:
 +        if (memcmp ((bt_bdaddr_t *)p_data, &(btif_av_cb.peer_bda),
 +                    sizeof(btif_av_cb.peer_bda)) == 0) {
 +            BTIF_TRACE_DEBUG("%s: Ignore BTIF_AV_CONNECT_REQ_EVT for same device\n", __func__);
 +        } else {
 +            BTIF_TRACE_DEBUG("%s: Moved to opened by Other Incoming Conn req\n", __func__);
 +            btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED,
 +                                         (bt_bdaddr_t *)p_data);
 +        }
 +        btif_queue_advance();
 +        break;
 +
 +        CHECK_RC_EVENT(event, p_data);
 +
 +    default:
 +        BTIF_TRACE_WARNING("%s : unhandled event:%s\n", __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_DEBUG("%s event:%s flags %x\n", __FUNCTION__,
 +                     dump_av_sm_event_name(event), btif_av_cb.flags);
 +
 +    switch (event) {
 +    case BTIF_SM_ENTER_EVT:
 +
 +        /* we are again in started state, clear any remote suspend flags */
 +        btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
 +
 +        btif_report_audio_state(ESP_A2D_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda));
 +
 +        /* increase the a2dp consumer task priority temporarily when start
 +        ** audio playing, to avoid overflow the audio packet queue. */
 +        adjust_priority_a2dp(TRUE);
 +
 +        break;
 +
 +    case BTIF_SM_EXIT_EVT:
 +        /* restore the a2dp consumer task priority when stop audio playing. */
 +        adjust_priority_a2dp(FALSE);
 +
 +        break;
 +
 +    case BTIF_AV_START_STREAM_REQ_EVT:
 +        break;
 +
 +    /* fixme -- use suspend = true always to work around issue with BTA AV */
 +    case BTIF_AV_STOP_STREAM_REQ_EVT:
 +    case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
 +
 +        /* set pending flag to ensure btif task is not trying to restart
 +           stream while suspend is in progress */
 +        btif_av_cb.flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
 +
 +        /* if we were remotely suspended but suspend locally, local suspend
 +           always overrides */
 +        btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
 +
 +        if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
 +            btif_a2dp_set_rx_flush(TRUE);
 +            btif_a2dp_on_stopped(NULL);
 +        }
 +
 +        BTA_AvStop(TRUE);
 +        break;
 +
 +    case BTIF_AV_DISCONNECT_REQ_EVT:
 +
 +        /* request avdtp to close */
 +        BTA_AvClose(btif_av_cb.bta_handle);
 +
 +        /* inform the application that we are disconnecting */
 +        btif_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
 +
 +        /* 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_EVENT("BTA_AV_SUSPEND_EVT status %d, init %d\n",
 +                         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) {
 +            btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
 +
 +            return FALSE;
 +        }
 +
 +        if (p_av->suspend.initiator != TRUE) {
 +            /* remote suspend, notify HAL and await audioflinger to
 +               suspend/stop stream */
 +
 +            /* set remote suspend flag to block media task from restarting
 +               stream only if we did not already initiate a local suspend */
 +            if ((btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0) {
 +                btif_av_cb.flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
 +            }
 +
 +            btif_report_audio_state(ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb.peer_bda));
 +        } else {
 +            btif_report_audio_state(ESP_A2D_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
 +        }
 +
 +        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
 +
 +        /* suspend completed and state changed, clear pending status */
 +        btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
 +        break;
 +
 +    case BTA_AV_STOP_EVT:
 +
 +        btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
 +        btif_a2dp_on_stopped(&p_av->suspend);
 +
 +        btif_report_audio_state(ESP_A2D_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
 +
 +        /* 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:
 +
 +        btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
 +
 +        /* avdtp link is closed */
 +        btif_a2dp_on_stopped(NULL);
 +
 +        /* inform the application that we are disconnected */
 +        btif_report_connection_state(ESP_A2D_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_WARNING("%s : unhandled event:%s\n", __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);
 +    btif_av_event_free_data(event, p_param);
 +}
 +
 +void btif_av_event_deep_copy(UINT16 event, char *p_dest, char *p_src)
 +{
 +    tBTA_AV *av_src = (tBTA_AV *)p_src;
 +    tBTA_AV *av_dest = (tBTA_AV *)p_dest;
 +
 +    // First copy the structure
 +    memcpy(p_dest, p_src, sizeof(tBTA_AV));
 +
 +    switch (event) {
 +    case BTA_AV_META_MSG_EVT:
 +        if (av_src->meta_msg.p_data && av_src->meta_msg.len) {
 +            av_dest->meta_msg.p_data = osi_calloc(av_src->meta_msg.len);
 +            assert(av_dest->meta_msg.p_data);
 +            memcpy(av_dest->meta_msg.p_data, av_src->meta_msg.p_data, av_src->meta_msg.len);
 +        }
 +
 +        if (av_src->meta_msg.p_msg) {
 +            av_dest->meta_msg.p_msg = osi_calloc(sizeof(tAVRC_MSG));
 +            assert(av_dest->meta_msg.p_msg);
 +            memcpy(av_dest->meta_msg.p_msg, av_src->meta_msg.p_msg, sizeof(tAVRC_MSG));
 +
 +            if (av_src->meta_msg.p_msg->vendor.p_vendor_data &&
 +                    av_src->meta_msg.p_msg->vendor.vendor_len) {
 +                av_dest->meta_msg.p_msg->vendor.p_vendor_data = osi_calloc(
 +                            av_src->meta_msg.p_msg->vendor.vendor_len);
 +                assert(av_dest->meta_msg.p_msg->vendor.p_vendor_data);
 +                memcpy(av_dest->meta_msg.p_msg->vendor.p_vendor_data,
 +                       av_src->meta_msg.p_msg->vendor.p_vendor_data,
 +                       av_src->meta_msg.p_msg->vendor.vendor_len);
 +            }
 +        }
 +        break;
 +
 +    default:
 +        break;
 +    }
 +}
 +
 +static void btif_av_event_free_data(btif_sm_event_t event, void *p_data)
 +{
 +    switch (event) {
 +    case BTA_AV_META_MSG_EVT: {
 +        tBTA_AV *av = (tBTA_AV *)p_data;
 +        if (av->meta_msg.p_data) {
 +            osi_free(av->meta_msg.p_data);
 +        }
 +
 +        if (av->meta_msg.p_msg) {
 +            if (av->meta_msg.p_msg->vendor.p_vendor_data) {
 +                osi_free(av->meta_msg.p_msg->vendor.p_vendor_data);
 +            }
 +            osi_free(av->meta_msg.p_msg);
 +        }
 +    }
 +    break;
 +
 +    default:
 +        break;
 +    }
 +}
 +
 +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), btif_av_event_deep_copy);
 +}
 +
 +static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
 +{
 +    btif_sm_state_t state;
 +    UINT8 que_len;
 +    tA2D_STATUS a2d_status;
 +    tA2D_SBC_CIE sbc_cie;
 +    esp_a2d_mcc_t mcc;
 +
 +    if (event == BTA_AV_MEDIA_DATA_EVT) { /* Switch to BTIF_MEDIA context */
 +        state = btif_sm_get_state(btif_av_cb.sm_handle);
 +        if ( (state == BTIF_AV_STATE_STARTED) || /* send SBC packets only in Started State */
 +                (state == BTIF_AV_STATE_OPENED) ) {
 +            que_len = btif_media_sink_enque_buf((BT_HDR *)p_data);
 +            BTIF_TRACE_DEBUG(" Packets in Que %d\n", que_len);
 +        } else {
 +            return;
 +        }
 +    }
 +
 +    if (event == BTA_AV_MEDIA_SINK_CFG_EVT) {
 +        /* send a command to BT Media Task */
 +        btif_reset_decoder((UINT8 *)p_data);
 +
 +      /* currently only supportes SBC */
 +        a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)p_data, FALSE);
 +        if (a2d_status == A2D_SUCCESS) {
 +            mcc.type = ESP_A2D_MCT_SBC;
 +            memcpy(&mcc.cie, (uint8_t *)p_data + 3, ESP_A2D_CIE_LEN_SBC);
 +            /* Switch to BTIF context */
 +            btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_CONFIG_REQ_EVT,
 +                                  (char *)&mcc, sizeof(mcc), NULL);
 +        } else {
 +            APPL_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status);
 +        }
 +    }
 +}
 +/*******************************************************************************
 +**
 +** Function         btif_av_init
 +**
 +** Description      Initializes btif AV if not already done
 +**
 +** Returns          bt_status_t
 +**
 +*******************************************************************************/
 +
 +bt_status_t btif_av_init()
 +{
 +    if (btif_av_cb.sm_handle == NULL) {
 +        if (!btif_a2dp_start_media_task()) {
 +            return BT_STATUS_FAIL;
 +        }
 +
 +        /* 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_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +        btif_enable_service(BTA_A2DP_SINK_SERVICE_ID);
 +#endif
 +
 +        btif_a2dp_on_init();
 +    }
 +
 +    return BT_STATUS_SUCCESS;
 +}
 +
 +/**
 + *
 + * Function         register A2DP callback
 + *
 + * Description      Initializes the AV interface for sink mode
 + *
 + * Returns          bt_status_t
 + *
 + */
 +esp_err_t esp_a2d_register_callback(esp_profile_cb_t callback)
 +{
 +    // TODO: need protection against race
 +    bt_av_sink_callback = callback;
++    return ESP_OK;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         init_sink
 +**
 +** Description      Initializes the AV interface for sink mode
 +**
 +** Returns          bt_status_t
 +**
 +*******************************************************************************/
 +esp_err_t esp_a2d_sink_init(void)
 +{
 +    BTIF_TRACE_EVENT("%s()\n", __func__);
 +
 +    bt_status_t status = btif_av_init();
 +
 +    return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         connect
 +**
 +** Description      Establishes the AV signalling channel with the remote headset
 +**
 +** Returns          bt_status_t
 +**
 +*******************************************************************************/
 +
 +static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid)
 +{
 +    btif_av_connect_req_t connect_req;
 +    connect_req.target_bda = bd_addr;
 +    connect_req.uuid = uuid;
 +    BTIF_TRACE_EVENT("%s\n", __FUNCTION__);
 +
 +    btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char *)&connect_req);
 +
 +    return BT_STATUS_SUCCESS;
 +}
 +
 +esp_err_t esp_a2d_sink_connect(esp_bd_addr_t remote_bda)
 +{
 +    BTIF_TRACE_EVENT("%s\n", __FUNCTION__);
 +    CHECK_BTAV_INIT();
 +
 +    bt_status_t stat;
 +    bt_bdaddr_t bd_addr;
 +    memcpy(&bd_addr, remote_bda, sizeof(bt_bdaddr_t));
 +
 +    stat = btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, &bd_addr, connect_int);
 +    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
 +}
 +
 +esp_err_t esp_a2d_sink_disconnect(esp_bd_addr_t remote_bda)
 +{
 +    bt_status_t stat;
 +    bt_bdaddr_t bd_addr;
 +    BTIF_TRACE_EVENT("%s\n", __FUNCTION__);
 +    CHECK_BTAV_INIT();
 +    memcpy(&bd_addr, remote_bda, sizeof(bt_bdaddr_t));
 +    /* Switch to BTIF context */
 +    stat = btif_transfer_context(btif_av_handle_event, BTIF_AV_DISCONNECT_REQ_EVT,
 +                                 (char *)(&bd_addr), sizeof(bt_bdaddr_t), NULL);
 +    return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
 +}
 +/*******************************************************************************
 +**
 +** Function         cleanup
 +**
 +** Description      Shuts down the AV interface and does the cleanup
 +**
 +** Returns          None
 +**
 +*******************************************************************************/
 +static void cleanup(void)
 +{
 +    BTIF_TRACE_EVENT("%s\n", __FUNCTION__);
 +
 +    btif_a2dp_stop_media_task();
 +
 +    btif_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +    btif_disable_service(BTA_A2DP_SINK_SERVICE_ID);
 +#endif
 +
 +    /* Also shut down the AV state machine */
 +    btif_sm_shutdown(btif_av_cb.sm_handle);
 +    btif_av_cb.sm_handle = NULL;
 +}
 +
 +void esp_a2d_sink_deinit(void)
 +{
 +    BTIF_TRACE_EVENT("%s\n", __FUNCTION__);
 +
 +    if (bt_av_sink_callback) {
 +        bt_av_sink_callback = NULL;
 +        cleanup();
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** 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_DEBUG("btif_av_stream_ready : sm hdl %d, state %d, flags %x\n",
 +                     (int)btif_av_cb.sm_handle, state, btif_av_cb.flags);
 +
 +    /* also make sure main adapter is enabled */
 +    if (btif_is_enabled() == 0) {
 +        BTIF_TRACE_EVENT("main adapter not enabled");
 +        return FALSE;
 +    }
 +
 +    /* check if we are remotely suspended or stop is pending */
 +    if (btif_av_cb.flags & (BTIF_AV_FLAG_REMOTE_SUSPEND | BTIF_AV_FLAG_PENDING_STOP)) {
 +        return FALSE;
 +    }
 +
 +    return (state == BTIF_AV_STATE_OPENED);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         btif_av_stream_started_ready
 +**
 +** Description      Checks whether AV ready for media start in streaming state
 +**
 +** Returns          None
 +**
 +*******************************************************************************/
 +
 +BOOLEAN btif_av_stream_started_ready(void)
 +{
 +    btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
 +
 +    BTIF_TRACE_DEBUG("btif_av_stream_started : sm hdl %d, state %d, flags %x\n",
 +                     (int)btif_av_cb.sm_handle, state, btif_av_cb.flags);
 +
 +    /* disallow media task to start if we have pending actions */
 +    if (btif_av_cb.flags & (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING | BTIF_AV_FLAG_REMOTE_SUSPEND
 +                            | BTIF_AV_FLAG_PENDING_STOP)) {
 +        return FALSE;
 +    }
 +
 +    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
 +**
 +** Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
 +**
 +*******************************************************************************/
 +bt_status_t btif_av_execute_service(BOOLEAN b_enable)
 +{
 +    if (b_enable) {
 +        /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
 +         * handle this request in order to allow incoming connections to succeed.
 +         * We need to put this back once support for this is added */
 +
 +        /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
 +         * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
 +         * be initiated by the app/audioflinger layers */
 +        BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_NO_SCO_SSPD),
 +                     bte_av_callback);
 +        BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos);
 +    } else {
 +        BTA_AvDeregister(btif_av_cb.bta_handle);
 +        BTA_AvDisable();
 +    }
 +    return BT_STATUS_SUCCESS;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         btif_av_sink_execute_service
 +**
 +** Description      Initializes/Shuts down the service
 +**
 +** Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
 +**
 +*******************************************************************************/
 +bt_status_t btif_av_sink_execute_service(BOOLEAN b_enable)
 +{
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +    BTA_AvEnable_Sink(b_enable);
 +#endif
 +    return BT_STATUS_SUCCESS;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         btif_av_is_connected
 +**
 +** Description      Checks if av has a connected sink
 +**
 +** Returns          BOOLEAN
 +**
 +*******************************************************************************/
 +BOOLEAN btif_av_is_connected(void)
 +{
 +    btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
 +    return ((state == BTIF_AV_STATE_OPENED) || (state ==  BTIF_AV_STATE_STARTED));
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         btif_av_is_peer_edr
 +**
 +** Description      Check if the connected a2dp device supports
 +**                  EDR or not. Only when connected this function
 +**                  will accurately provide a true capability of
 +**                  remote peer. If not connected it will always be false.
 +**
 +** Returns          TRUE if remote device is capable of EDR
 +**
 +*******************************************************************************/
 +BOOLEAN btif_av_is_peer_edr(void)
 +{
 +    ASSERTC(btif_av_is_connected(), "No active a2dp connection\n", 0);
 +
 +    if (btif_av_cb.edr) {
 +        return TRUE;
 +    } else {
 +        return FALSE;
 +    }
 +}
 +
 +/******************************************************************************
 +**
 +** Function        btif_av_clear_remote_suspend_flag
 +**
 +** Description     Clears btif_av_cd.flags if BTIF_AV_FLAG_REMOTE_SUSPEND is set
 +**
 +** Returns          void
 +******************************************************************************/
 +void btif_av_clear_remote_suspend_flag(void)
 +{
 +    BTIF_TRACE_DEBUG("%s: flag :%x\n", __func__, btif_av_cb.flags);
 +    btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
 +}
index 99c4711887e2353d3b9f1dbf924d8b2c822c2621,0000000000000000000000000000000000000000..f7b552cf1fe718d4126b859e98cfedec38a0865a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1219 -1,0 +1,1220 @@@
 +/******************************************************************************
 + *
 + *  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.
 + *
 + ******************************************************************************/
 +
 +/******************************************************************************
 + **
 + **  Name:          btif_media_task.c
 + **
 + **  Description:   This is the multimedia module for the BTIF system.  It
 + **                 contains task implementations AV, HS and HF profiles
 + **                 audio & video processing
 + **
 + ******************************************************************************/
 +
 +#define LOG_TAG "bt_btif_media"
 +
 +#include "bt_trace.h"
 +#include <string.h>
 +#include <stdio.h>
 +#include <stdint.h>
 +
 +#include "bt_target.h"
 +#include "fixed_queue.h"
 +#include "gki.h"
 +#include "bta_api.h"
 +#include "btu.h"
 +#include "bta_sys.h"
 +#include "bta_sys_int.h"
 +
 +#include "bta_av_api.h"
 +#include "a2d_api.h"
 +#include "a2d_sbc.h"
 +#include "a2d_int.h"
 +#include "bta_av_sbc.h"
 +#include "bta_av_ci.h"
 +#include "l2c_api.h"
 +
 +#include "btif_av_co.h"
 +#include "btif_media.h"
 +
 +#include "alarm.h"
 +#include "bt_trace.h"
 +#include "thread.h"
 +
 +#include "bt_defs.h"
 +#include "btif_av.h"
 +#include "btif_sm.h"
 +#include "btif_util.h"
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +#include "oi_codec_sbc.h"
 +#include "oi_status.h"
 +#endif
 +#include "stdio.h"
 +
 +#include "btif_media.h"
 +#include "allocator.h"
 +#include "bt_utils.h"
 +#include "esp_a2dp_api.h"
 +
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +OI_CODEC_SBC_DECODER_CONTEXT context;
 +OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
 +OI_INT16 pcmData[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
 +#endif
 +
 +
 +/*****************************************************************************
 + **  Constants
 + *****************************************************************************/
 +
 +#ifndef AUDIO_CHANNEL_OUT_MONO
 +#define AUDIO_CHANNEL_OUT_MONO 0x01
 +#endif
 +
 +#ifndef AUDIO_CHANNEL_OUT_STEREO
 +#define AUDIO_CHANNEL_OUT_STEREO 0x03
 +#endif
 +
 +/* BTIF media cmd event definition : BTIF_MEDIA_TASK_CMD */
 +enum {
 +    BTIF_MEDIA_START_AA_TX = 1,
 +    BTIF_MEDIA_STOP_AA_TX,
 +    BTIF_MEDIA_AA_RX_RDY,
 +    BTIF_MEDIA_UIPC_RX_RDY,
 +    BTIF_MEDIA_SBC_ENC_INIT,
 +    BTIF_MEDIA_SBC_ENC_UPDATE,
 +    BTIF_MEDIA_SBC_DEC_INIT,
 +    BTIF_MEDIA_VIDEO_DEC_INIT,
 +    BTIF_MEDIA_FLUSH_AA_TX,
 +    BTIF_MEDIA_FLUSH_AA_RX,
 +    BTIF_MEDIA_AUDIO_FEEDING_INIT,
 +    BTIF_MEDIA_AUDIO_RECEIVING_INIT,
 +    BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE,
 +    BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK
 +};
 +
 +enum {
 +    MEDIA_TASK_STATE_OFF = 0,
 +    MEDIA_TASK_STATE_ON = 1,
 +    MEDIA_TASK_STATE_SHUTTING_DOWN = 2
 +};
 +
 +enum {
 +    SIG_MEDIA_TASK_INIT = 0xf0,
 +    SIG_MEDIA_TASK_CLEAN_UP = 0xf1,
 +    SIG_MEDIA_TASK_AVK_ALARM_TO = 0xf2,
 +    SIG_MEDIA_TASK_AA_ALARM_TO = 0xf3,
 +    SIG_MEDIA_TASK_CMD_READY = 0xf4
 +};
 +
 +/* Macro to multiply the media task tick */
 +#ifndef BTIF_MEDIA_NUM_TICK
 +#define BTIF_MEDIA_NUM_TICK      1
 +#endif
 +
 +/* Media task tick in milliseconds, must be set to multiple of
 +   (1000/TICKS_PER_SEC) (10) */
 +
 +#define BTIF_MEDIA_TIME_TICK                     (20 * BTIF_MEDIA_NUM_TICK)
 +#define A2DP_DATA_READ_POLL_MS    (BTIF_MEDIA_TIME_TICK / 2)
 +#define BTIF_SINK_MEDIA_TIME_TICK                (20 * BTIF_MEDIA_NUM_TICK)
 +
 +
 +/* buffer pool */
 +#define BTIF_MEDIA_AA_POOL_ID GKI_POOL_ID_3
 +#define BTIF_MEDIA_AA_BUF_SIZE GKI_BUF3_SIZE
 +
 +/* offset */
 +#if (BTA_AV_CO_CP_SCMS_T == TRUE)
 +#define BTIF_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE + 1)
 +#else
 +#define BTIF_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE)
 +#endif
 +
 +/* Define the bitrate step when trying to match bitpool value */
 +#ifndef BTIF_MEDIA_BITRATE_STEP
 +#define BTIF_MEDIA_BITRATE_STEP 5
 +#endif
 +
 +/* Middle quality quality setting @ 44.1 khz */
 +#define DEFAULT_SBC_BITRATE 328
 +
 +#ifndef BTIF_A2DP_NON_EDR_MAX_RATE
 +#define BTIF_A2DP_NON_EDR_MAX_RATE 229
 +#endif
 +
 +#define USEC_PER_SEC 1000000L
 +#define TPUT_STATS_INTERVAL_US (3000*1000)
 +
 +/*
 + * CONGESTION COMPENSATION CTRL ::
 + *
 + * Thus setting controls how many buffers we will hold in media task
 + * during temp link congestion. Together with the stack buffer queues
 + * it controls much temporary a2dp link congestion we can
 + * compensate for. It however also depends on the default run level of sinks
 + * jitterbuffers. Depending on type of sink this would vary.
 + * Ideally the (SRC) max tx buffer capacity should equal the sinks
 + * jitterbuffer runlevel including any intermediate buffers on the way
 + * towards the sinks codec.
 + */
 +
 +/* fixme -- define this in pcm time instead of buffer count */
 +
 +/* The typical runlevel of the tx queue size is ~1 buffer
 +   but due to link flow control or thread preemption in lower
 +   layers we might need to temporarily buffer up data */
 +
 +/* 18 frames is equivalent to 6.89*18*2.9 ~= 360 ms @ 44.1 khz, 20 ms mediatick */
 +#define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ 18
 +
 +#ifndef MAX_PCM_FRAME_NUM_PER_TICK
 +#define MAX_PCM_FRAME_NUM_PER_TICK     14
 +#endif
 +
 +/* In case of A2DP SINK, we will delay start by 5 AVDTP Packets*/
 +#define MAX_A2DP_DELAYED_START_FRAME_COUNT 5
 +#define PACKET_PLAYED_PER_TICK_48 8
 +#define PACKET_PLAYED_PER_TICK_44 7
 +#define PACKET_PLAYED_PER_TICK_32 5
 +#define PACKET_PLAYED_PER_TICK_16 3
 +
 +typedef struct {
 +    UINT16 num_frames_to_be_processed;
 +    UINT16 len;
 +    UINT16 offset;
 +    UINT16 layer_specific;
 +} tBT_SBC_HDR;
 +
 +typedef struct {
 +    UINT32 aa_frame_counter;
 +    INT32  aa_feed_counter;
 +    INT32  aa_feed_residue;
 +    UINT32 counter;
 +    UINT32 bytes_per_tick;  /* pcm bytes read each media task tick */
 +} tBTIF_AV_MEDIA_FEEDINGS_PCM_STATE;
 +
 +typedef union {
 +    tBTIF_AV_MEDIA_FEEDINGS_PCM_STATE pcm;
 +} tBTIF_AV_MEDIA_FEEDINGS_STATE;
 +
 +typedef struct {
 +#if (BTA_AV_INCLUDED == TRUE)
 +    BUFFER_Q RxSbcQ;
 +    BOOLEAN is_tx_timer;
 +    BOOLEAN is_rx_timer;
 +    UINT8 busy_level;
 +    void *av_sm_hdl;
 +    UINT8 a2dp_cmd_pending; /* we can have max one command pending */
 +    BOOLEAN rx_flush; /* discards any incoming data when true */
 +    UINT8 peer_sep;
 +    BOOLEAN data_channel_open;
 +    UINT8   frames_to_process;
 +
 +    UINT32  sample_rate;
 +    UINT8   channel_count;
 +    osi_alarm_t *decode_alarm;
 +#endif
 +
 +} tBTIF_MEDIA_CB;
 +
 +typedef struct {
 +    long long rx;
 +    long long rx_tot;
 +    long long tx;
 +    long long tx_tot;
 +    long long ts_prev_us;
 +} t_stat;
 +
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +extern OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
 +        const OI_BYTE **frameData,
 +        unsigned long *frameBytes,
 +        OI_INT16 *pcmData,
 +        unsigned long *pcmBytes);
 +extern OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
 +        unsigned long *decoderData,
 +        unsigned long decoderDataBytes,
 +        OI_UINT8 maxChannels,
 +        OI_UINT8 pcmStride,
 +        OI_BOOL enhanced);
 +#endif
 +static void btif_media_flush_q(BUFFER_Q *p_q);
 +static void btif_media_task_aa_handle_stop_decoding(void );
 +static void btif_media_task_aa_rx_flush(void);
 +
 +static const char *dump_media_event(UINT16 event);
 +static void btif_media_thread_handle_cmd(fixed_queue_t *queue);
 +
 +/* Handle incoming media packets A2DP SINK streaming*/
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +static void btif_media_task_handle_inc_media(tBT_SBC_HDR *p_msg);
 +#endif
 +
 +#if (BTA_AV_INCLUDED == TRUE)
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +static void btif_media_task_aa_handle_decoder_reset(BT_HDR *p_msg);
 +static void btif_media_task_aa_handle_clear_track(void);
 +#endif
 +static void btif_media_task_aa_handle_start_decoding(void);
 +#endif
 +BOOLEAN btif_media_task_clear_track(void);
 +static void btif_media_task_handler(void *arg);
 +
 +static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context);
 +static void btif_media_thread_init(UNUSED_ATTR void *context);
 +static void btif_media_thread_cleanup(UNUSED_ATTR void *context);
 +extern BOOLEAN btif_hf_is_call_idle();
 +
 +static tBTIF_MEDIA_CB btif_media_cb;
 +static int media_task_running = MEDIA_TASK_STATE_OFF;
 +
 +static fixed_queue_t *btif_media_cmd_msg_queue = NULL;
 +static xTaskHandle  xBtifMediaTaskHandle = NULL;
 +static QueueHandle_t xBtifMediaQueue = NULL;
 +
 +static esp_a2d_data_cb_t bt_av_sink_data_callback = NULL;
 +
 +esp_err_t esp_a2d_register_data_callback(esp_a2d_data_cb_t cb)
 +{
 +    // TODO: need protection against race
 +    bt_av_sink_data_callback = cb;
++    return ESP_OK;
 +}
 +
 +// TODO: need protection against race
 +#define BTIF_A2D_DATA_CB_TO_APP(data, len)    do { \
 +      if (bt_av_sink_data_callback) { \
 +          bt_av_sink_data_callback(data, len); \
 +      } \
 +    } while (0)
 +
 +/*****************************************************************************
 + **  temporary hacked functions. TODO: port these functions or remove them?
 + *****************************************************************************/
 +BOOLEAN btif_hf_is_call_idle(void)
 +{
 +    return FALSE;
 +}
 +
 +/*****************************************************************************
 + **  Misc helper functions
 + *****************************************************************************/
 +
 +UNUSED_ATTR static const char *dump_media_event(UINT16 event)
 +{
 +    switch (event) {
 +        CASE_RETURN_STR(BTIF_MEDIA_START_AA_TX)
 +        CASE_RETURN_STR(BTIF_MEDIA_STOP_AA_TX)
 +        CASE_RETURN_STR(BTIF_MEDIA_AA_RX_RDY)
 +        CASE_RETURN_STR(BTIF_MEDIA_UIPC_RX_RDY)
 +        CASE_RETURN_STR(BTIF_MEDIA_SBC_ENC_INIT)
 +        CASE_RETURN_STR(BTIF_MEDIA_SBC_ENC_UPDATE)
 +        CASE_RETURN_STR(BTIF_MEDIA_SBC_DEC_INIT)
 +        CASE_RETURN_STR(BTIF_MEDIA_VIDEO_DEC_INIT)
 +        CASE_RETURN_STR(BTIF_MEDIA_FLUSH_AA_TX)
 +        CASE_RETURN_STR(BTIF_MEDIA_FLUSH_AA_RX)
 +        CASE_RETURN_STR(BTIF_MEDIA_AUDIO_FEEDING_INIT)
 +        CASE_RETURN_STR(BTIF_MEDIA_AUDIO_RECEIVING_INIT)
 +        CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE)
 +        CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK)
 +
 +    default:
 +        return "UNKNOWN MEDIA EVENT";
 +    }
 +}
 +
 +/*****************************************************************************
 + **  A2DP CTRL PATH
 + *****************************************************************************/
 +#if 0
 +// TODO: consider the necessity to add an API based on this function
 +static void btif_audiopath_detached(void)
 +{
 +    APPL_TRACE_EVENT("## AUDIO PATH DETACHED ##");
 +
 +    /*  send stop request only if we are actively streaming and haven't received
 +        a stop request. Potentially audioflinger detached abnormally */
 +    if (btif_media_cb.is_tx_timer) {
 +        /* post stop event and wait for audio path to stop */
 +        btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
 +    }
 +}
 +#endif
 +
 +/*****************************************************************************
 + **  BTIF ADAPTATION
 + *****************************************************************************/
 +
 +static void btif_media_task_post(uint32_t sig)
 +{
 +    BtTaskEvt_t *evt = (BtTaskEvt_t *)osi_malloc(sizeof(BtTaskEvt_t));
 +    if (evt == NULL) {
 +        return;
 +    }
 +
 +    evt->sig = sig;
 +    evt->par = 0;
 +
 +    if (xQueueSend(xBtifMediaQueue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) {
 +        APPL_TRACE_ERROR("xBtifMediaQueue failed\n");
 +    }
 +}
 +
 +static void btif_media_task_handler(void *arg)
 +{
 +    BtTaskEvt_t *e;
 +    for (;;) {
 +        if (pdTRUE == xQueueReceive(xBtifMediaQueue, &e, (portTickType)portMAX_DELAY)) {
 +            // LOG_ERROR("med evt %d\n", e->sig);
 +            switch (e->sig) {
 +            case SIG_MEDIA_TASK_AVK_ALARM_TO:
 +                btif_media_task_avk_handle_timer(NULL);
 +                break;
 +            case SIG_MEDIA_TASK_CMD_READY:
 +                fixed_queue_process(btif_media_cmd_msg_queue);
 +                break;
 +            case SIG_MEDIA_TASK_INIT:
 +                btif_media_thread_init(NULL);
 +                break;
 +            case SIG_MEDIA_TASK_CLEAN_UP:
 +                btif_media_thread_cleanup(NULL);
 +                break;
 +            default:
 +                APPL_TRACE_ERROR("media task unhandled evt: 0x%x\n", e->sig);
 +            }
 +        }
 +        osi_free(e);
 +    }
 +}
 +
 +bool btif_a2dp_start_media_task(void)
 +{
 +    if (media_task_running != MEDIA_TASK_STATE_OFF) {
 +        APPL_TRACE_ERROR("warning : media task already running");
 +        return false;
 +    }
 +
 +    APPL_TRACE_EVENT("## A2DP START MEDIA THREAD ##");
 +
 +    btif_media_cmd_msg_queue = fixed_queue_new(SIZE_MAX);
 +    if (btif_media_cmd_msg_queue == NULL) {
 +        goto error_exit;
 +    }
 +
 +    xBtifMediaQueue = xQueueCreate(60, sizeof(void *));
 +    if (xBtifMediaQueue == 0) {
 +        goto error_exit;
 +    }
 +    xTaskCreate(btif_media_task_handler, "BtifMediaT\n", 2048, NULL, configMAX_PRIORITIES - 1, &xBtifMediaTaskHandle);
 +    if (xBtifMediaTaskHandle == NULL) {
 +        goto error_exit;
 +    }
 +    fixed_queue_register_dequeue(btif_media_cmd_msg_queue, btif_media_thread_handle_cmd);
 +    btif_media_task_post(SIG_MEDIA_TASK_INIT);
 +
 +    APPL_TRACE_EVENT("## A2DP MEDIA THREAD STARTED ##\n");
 +
 +    return true;
 +
 +error_exit:;
 +    APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__);
 +
 +    if (xBtifMediaTaskHandle != NULL) {
 +        vTaskDelete(xBtifMediaTaskHandle);
 +        xBtifMediaTaskHandle = NULL;
 +    }
 +
 +    if (xBtifMediaQueue != 0) {
 +        vQueueDelete(xBtifMediaQueue);
 +        xBtifMediaQueue = 0;
 +    }
 +    fixed_queue_free(btif_media_cmd_msg_queue, NULL);
 +    btif_media_cmd_msg_queue = NULL;
 +    return false;
 +}
 +
 +void btif_a2dp_stop_media_task(void)
 +{
 +    APPL_TRACE_EVENT("## A2DP STOP MEDIA THREAD ##\n");
 +
 +    // Exit thread
 +    btif_media_task_post(SIG_MEDIA_TASK_CLEAN_UP);
 +    // TODO: wait until CLEAN up is done, then do task delete
 +    vTaskDelete(xBtifMediaTaskHandle);
 +    xBtifMediaTaskHandle = NULL;
 +    vQueueDelete(xBtifMediaQueue);
 +    xBtifMediaQueue = NULL;
 +
 +    fixed_queue_free(btif_media_cmd_msg_queue, NULL);
 +    btif_media_cmd_msg_queue = NULL;
 +}
 +
 +/*****************************************************************************
 +**
 +** Function        btif_a2dp_on_init
 +**
 +** Description
 +**
 +** Returns
 +**
 +*******************************************************************************/
 +
 +void btif_a2dp_on_init(void)
 +{
 +    //tput_mon(1, 0, 1);
 +}
 +
 +
 +/*****************************************************************************
 +**
 +** Function        btif_a2dp_setup_codec
 +**
 +** Description
 +**
 +** Returns
 +**
 +*******************************************************************************/
 +
 +void btif_a2dp_setup_codec(void)
 +{
 +    tBTIF_AV_MEDIA_FEEDINGS media_feeding;
 +    tBTIF_STATUS status;
 +
 +    APPL_TRACE_EVENT("## A2DP SETUP CODEC ##\n");
 +
 +    GKI_disable();
 +
 +    /* for now hardcode 44.1 khz 16 bit stereo PCM format */
 +    media_feeding.cfg.pcm.sampling_freq = 44100;
 +    media_feeding.cfg.pcm.bit_per_sample = 16;
 +    media_feeding.cfg.pcm.num_channel = 2;
 +    media_feeding.format = BTIF_AV_CODEC_PCM;
 +
 +    bta_av_co_audio_set_codec(&media_feeding, &status);
 +
 +    GKI_enable();
 +}
 +
 +
 +/*****************************************************************************
 +**
 +** Function        btif_a2dp_on_idle
 +**
 +** Description
 +**
 +** Returns
 +**
 +*******************************************************************************/
 +
 +void btif_a2dp_on_idle(void)
 +{
 +    APPL_TRACE_EVENT("## ON A2DP IDLE ##\n");
 +
 +    bta_av_co_init();
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +    if (btif_media_cb.peer_sep == AVDT_TSEP_SRC) {
 +        btif_media_cb.rx_flush = TRUE;
 +        btif_media_task_aa_rx_flush_req();
 +        btif_media_task_aa_handle_stop_decoding();
 +        btif_media_task_clear_track();
 +        APPL_TRACE_DEBUG("Stopped BT track");
 +    }
 +#endif
 +}
 +
 +/*******************************************************************************
 + **
 + ** Function         btif_media_task_clear_track
 + **
 + ** Description
 + **
 + ** Returns          TRUE is success
 + **
 + *******************************************************************************/
 +BOOLEAN btif_media_task_clear_track(void)
 +{
 +    BT_HDR *p_buf;
 +
 +    if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) {
 +        return FALSE;
 +    }
 +
 +    p_buf->event = BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK;
 +
 +    fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
 +    btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
 +    return TRUE;
 +}
 +
 +/*****************************************************************************
 +**
 +** Function        btif_reset_decoder
 +**
 +** Description
 +**
 +** Returns
 +**
 +*******************************************************************************/
 +
 +void btif_reset_decoder(UINT8 *p_av)
 +{
 +    APPL_TRACE_EVENT("btif_reset_decoder");
 +    APPL_TRACE_DEBUG("btif_reset_decoder p_codec_info[%x:%x:%x:%x:%x:%x]\n",
 +            p_av[1], p_av[2], p_av[3],
 +            p_av[4], p_av[5], p_av[6]);
 +
 +    tBTIF_MEDIA_SINK_CFG_UPDATE *p_buf;
 +    if (NULL == (p_buf = GKI_getbuf(sizeof(tBTIF_MEDIA_SINK_CFG_UPDATE)))) {
 +        APPL_TRACE_ERROR("btif_reset_decoder No Buffer ");
 +        return;
 +    }
 +
 +    memcpy(p_buf->codec_info, p_av, AVDT_CODEC_SIZE);
 +    p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE;
 +
 +    fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
 +    btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
 +}
 +
 +/*****************************************************************************
 +**
 +** Function        btif_a2dp_on_stopped
 +**
 +** Description
 +**
 +** Returns
 +**
 +*******************************************************************************/
 +
 +void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av)
 +{
 +    APPL_TRACE_EVENT("## ON A2DP STOPPED ##\n");
 +    if (btif_media_cb.peer_sep == AVDT_TSEP_SRC) { /*  Handling for A2DP SINK cases*/
 +        btif_media_cb.rx_flush = TRUE;
 +        btif_media_task_aa_rx_flush_req();
 +        btif_media_task_aa_handle_stop_decoding();
 +        btif_media_cb.data_channel_open = FALSE;
 +        return;
 +    }
 +}
 +
 +
 +/*****************************************************************************
 +**
 +** Function        btif_a2dp_on_suspended
 +**
 +** Description
 +**
 +** Returns
 +**
 +*******************************************************************************/
 +
 +void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av)
 +{
 +    APPL_TRACE_EVENT("## ON A2DP SUSPENDED ##\n");
 +    if (btif_media_cb.peer_sep == AVDT_TSEP_SRC) {
 +        btif_media_cb.rx_flush = TRUE;
 +        btif_media_task_aa_rx_flush_req();
 +        btif_media_task_aa_handle_stop_decoding();
 +        return;
 +    }
 +}
 +
 +/* when true media task discards any rx frames */
 +void btif_a2dp_set_rx_flush(BOOLEAN enable)
 +{
 +    APPL_TRACE_EVENT("## DROP RX %d ##\n", enable);
 +    btif_media_cb.rx_flush = enable;
 +}
 +
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context)
 +{
 +    UINT8 count;
 +    tBT_SBC_HDR *p_msg;
 +    int num_sbc_frames;
 +    int num_frames_to_process;
 +
 +    count = btif_media_cb.RxSbcQ._count;
 +    if (0 == count) {
 +        APPL_TRACE_DEBUG("  QUE  EMPTY ");
 +    } else {
 +        if (btif_media_cb.rx_flush == TRUE) {
 +            btif_media_flush_q(&(btif_media_cb.RxSbcQ));
 +            return;
 +        }
 +
 +        num_frames_to_process = btif_media_cb.frames_to_process;
 +        APPL_TRACE_DEBUG(" Process Frames + ");
 +        do {
 +            p_msg = (tBT_SBC_HDR *)GKI_getfirst(&(btif_media_cb.RxSbcQ));
 +            if (p_msg == NULL) {
 +                return;
 +            }
 +            num_sbc_frames  = p_msg->num_frames_to_be_processed; /* num of frames in Que Packets */
 +            APPL_TRACE_DEBUG(" Frames left in topmost packet %d\n", num_sbc_frames);
 +            APPL_TRACE_DEBUG(" Remaining frames to process in tick %d\n", num_frames_to_process);
 +            APPL_TRACE_DEBUG(" Num of Packets in Que %d\n", btif_media_cb.RxSbcQ._count);
 +
 +            if ( num_sbc_frames > num_frames_to_process) { /*  Que Packet has more frames*/
 +                p_msg->num_frames_to_be_processed = num_frames_to_process;
 +                btif_media_task_handle_inc_media(p_msg);
 +                p_msg->num_frames_to_be_processed = num_sbc_frames - num_frames_to_process;
 +                num_frames_to_process = 0;
 +                break;
 +            } else {                                    /*  Que packet has less frames */
 +                btif_media_task_handle_inc_media(p_msg);
 +                p_msg = (tBT_SBC_HDR *)GKI_dequeue(&(btif_media_cb.RxSbcQ));
 +                if ( p_msg == NULL ) {
 +                    APPL_TRACE_ERROR("Insufficient data in que ");
 +                    break;
 +                }
 +                num_frames_to_process = num_frames_to_process - p_msg->num_frames_to_be_processed;
 +                GKI_freebuf(p_msg);
 +            }
 +        } while (num_frames_to_process > 0);
 +
 +        APPL_TRACE_DEBUG(" Process Frames - ");
 +    }
 +}
 +#else
 +static void btif_media_task_avk_handle_timer(UNUSED_ATTR void *context) {}
 +#endif
 +
 +static void btif_media_thread_init(UNUSED_ATTR void *context)
 +{
 +    memset(&btif_media_cb, 0, sizeof(btif_media_cb));
 +    LOG_ERROR("med thread init\n");
 +#if (UIPC_INCLUDED == TRUE)
 +    UIPC_Init(NULL);
 +    
 +#if (BTA_AV_INCLUDED == TRUE)
 +    UIPC_Open(UIPC_CH_ID_AV_CTRL , btif_a2dp_ctrl_cb);
 +#endif ( BTA_AV_INCLUDED == TRUE)
 +#endif /* UIPC_INCLUDED == TRUE */
 +    btif_media_cb.av_sm_hdl = btif_av_get_sm_handle();
 +    raise_priority_a2dp(TASK_HIGH_MEDIA);
 +    media_task_running = MEDIA_TASK_STATE_ON;
 +}
 +
 +static void btif_media_thread_cleanup(UNUSED_ATTR void *context)
 +{
 +    /* make sure no channels are restarted while shutting down */
 +    media_task_running = MEDIA_TASK_STATE_SHUTTING_DOWN;
 +
 +    btif_media_cb.data_channel_open = FALSE;
 +    /* Clear media task flag */
 +    media_task_running = MEDIA_TASK_STATE_OFF;
 +}
 +
 +/*******************************************************************************
 + **
 + ** Function         btif_media_flush_q
 + **
 + ** Description
 + **
 + ** Returns          void
 + **
 + *******************************************************************************/
 +static void btif_media_flush_q(BUFFER_Q *p_q)
 +{
 +    while (!GKI_queue_is_empty(p_q)) {
 +        GKI_freebuf(GKI_dequeue(p_q));
 +    }
 +}
 +
 +static void btif_media_thread_handle_cmd(fixed_queue_t *queue)
 +{
 +    BT_HDR *p_msg;
 +    while (!fixed_queue_is_empty(queue)) {
 +        p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
 +        LOG_VERBOSE("btif_media_thread_handle_cmd : %d %s\n", p_msg->event,
 +                    dump_media_event(p_msg->event));
 +
 +        switch (p_msg->event) {
 +#if (BTA_AV_INCLUDED == TRUE)
 +        case BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE:
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +            btif_media_task_aa_handle_decoder_reset(p_msg);
 +#endif
 +            break;
 +        case BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK:
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +            btif_media_task_aa_handle_clear_track();
 +#endif
 +            break;
 +        case BTIF_MEDIA_FLUSH_AA_RX:
 +            btif_media_task_aa_rx_flush();
 +            break;
 +#endif
 +        default:
 +            APPL_TRACE_ERROR("ERROR in %s unknown event %d\n", __func__, p_msg->event);
 +        }
 +        GKI_freebuf(p_msg);
 +        LOG_VERBOSE("%s: %s DONE\n", __func__, dump_media_event(p_msg->event));
 +    }
 +}
 +
 +
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +/*******************************************************************************
 + **
 + ** Function         btif_media_task_handle_inc_media
 + **
 + ** Description
 + **
 + ** Returns          void
 + **
 + *******************************************************************************/
 +static void btif_media_task_handle_inc_media(tBT_SBC_HDR *p_msg)
 +{
 +    UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
 +    int count;
 +    UINT32 pcmBytes, availPcmBytes;
 +    OI_INT16 *pcmDataPointer = pcmData; /*Will be overwritten on next packet receipt*/
 +    OI_STATUS status;
 +    int num_sbc_frames = p_msg->num_frames_to_be_processed;
 +    UINT32 sbc_frame_len = p_msg->len - 1;
 +    availPcmBytes = 2 * sizeof(pcmData);
 +
 +    if ((btif_media_cb.peer_sep == AVDT_TSEP_SNK) || (btif_media_cb.rx_flush)) {
 +        APPL_TRACE_DEBUG(" State Changed happened in this tick ");
 +        return;
 +    }
 +
 +    // ignore data if no one is listening
 +    if (!btif_media_cb.data_channel_open) {
 +        return;
 +    }
 +
 +    APPL_TRACE_DEBUG("Number of sbc frames %d, frame_len %d\n", num_sbc_frames, sbc_frame_len);
 +    // LOG_ERROR("Number of sbc frames %d, frame_len %d\n", num_sbc_frames, sbc_frame_len);
 +    for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) {
 +        pcmBytes = availPcmBytes;
 +        status = OI_CODEC_SBC_DecodeFrame(&context, (const OI_BYTE **)&sbc_start_frame,
 +                                          (OI_UINT32 *)&sbc_frame_len,
 +                                          (OI_INT16 *)pcmDataPointer,
 +                                          (OI_UINT32 *)&pcmBytes);
 +        if (!OI_SUCCESS(status)) {
 +            APPL_TRACE_ERROR("Decoding failure: %d\n", status);
 +            break;
 +        }
 +        availPcmBytes -= pcmBytes;
 +        pcmDataPointer += pcmBytes / 2;
 +        p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
 +        p_msg->len = sbc_frame_len + 1;
 +    }
 +    // LOG_ERROR("pre-send: %d\n", availPcmBytes);
 +
 +    // UIPC_Send(UIPC_CH_ID_AV_AUDIO, 0, (UINT8 *)pcmData, (2 * sizeof(pcmData) - availPcmBytes));
 +    BTIF_A2D_DATA_CB_TO_APP((uint8_t *)pcmData, (2 * sizeof(pcmData) - availPcmBytes));
 +
 +}
 +#endif
 +
 +#if (BTA_AV_INCLUDED == TRUE)
 +
 +/*******************************************************************************
 + **
 + ** Function         btif_media_task_aa_rx_flush_req
 + **
 + ** Description
 + **
 + ** Returns          TRUE is success
 + **
 + *******************************************************************************/
 +BOOLEAN btif_media_task_aa_rx_flush_req(void)
 +{
 +    BT_HDR *p_buf;
 +
 +    if (GKI_queue_is_empty(&(btif_media_cb.RxSbcQ)) == TRUE) { /*  Que is already empty */
 +        return TRUE;
 +    }
 +
 +    if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) {
 +        return FALSE;
 +    }
 +
 +    p_buf->event = BTIF_MEDIA_FLUSH_AA_RX;
 +
 +    fixed_queue_enqueue(btif_media_cmd_msg_queue, p_buf);
 +    btif_media_task_post(SIG_MEDIA_TASK_CMD_READY);
 +    return TRUE;
 +}
 +
 +/*******************************************************************************
 + **
 + ** Function         btif_media_task_aa_rx_flush
 + **
 + ** Description
 + **
 + ** Returns          void
 + **
 + *******************************************************************************/
 +static void btif_media_task_aa_rx_flush(void)
 +{
 +    /* Flush all enqueued GKI SBC  buffers (encoded) */
 +    APPL_TRACE_DEBUG("btif_media_task_aa_rx_flush");
 +
 +    btif_media_flush_q(&(btif_media_cb.RxSbcQ));
 +}
 +
 +int btif_a2dp_get_track_frequency(UINT8 frequency)
 +{
 +    int freq = 48000;
 +    switch (frequency) {
 +    case A2D_SBC_IE_SAMP_FREQ_16:
 +        freq = 16000;
 +        break;
 +    case A2D_SBC_IE_SAMP_FREQ_32:
 +        freq = 32000;
 +        break;
 +    case A2D_SBC_IE_SAMP_FREQ_44:
 +        freq = 44100;
 +        break;
 +    case A2D_SBC_IE_SAMP_FREQ_48:
 +        freq = 48000;
 +        break;
 +    }
 +    return freq;
 +}
 +
 +int btif_a2dp_get_track_channel_count(UINT8 channeltype)
 +{
 +    int count = 1;
 +    switch (channeltype) {
 +    case A2D_SBC_IE_CH_MD_MONO:
 +        count = 1;
 +        break;
 +    case A2D_SBC_IE_CH_MD_DUAL:
 +    case A2D_SBC_IE_CH_MD_STEREO:
 +    case A2D_SBC_IE_CH_MD_JOINT:
 +        count = 2;
 +        break;
 +    }
 +    return count;
 +}
 +
 +void btif_a2dp_set_peer_sep(UINT8 sep)
 +{
 +    btif_media_cb.peer_sep = sep;
 +}
 +
 +static void btif_decode_alarm_cb(UNUSED_ATTR void *context)
 +{
 +    btif_media_task_post(SIG_MEDIA_TASK_AVK_ALARM_TO);
 +}
 +
 +static void btif_media_task_aa_handle_stop_decoding(void)
 +{
 +    osi_alarm_free(btif_media_cb.decode_alarm);
 +    btif_media_cb.decode_alarm = NULL;
 +}
 +
 +static void btif_media_task_aa_handle_start_decoding(void)
 +{
 +    if (btif_media_cb.decode_alarm) {
 +        return;
 +    }
 +
 +    btif_media_cb.decode_alarm = osi_alarm_new("dec_timer\n", btif_decode_alarm_cb, NULL, BTIF_SINK_MEDIA_TIME_TICK, true);
 +    if (!btif_media_cb.decode_alarm) {
 +        APPL_TRACE_ERROR("%s unable to allocate decode alarm.\n", __func__);
 +        return;
 +    }
 +    osi_alarm_set(btif_media_cb.decode_alarm, BTIF_SINK_MEDIA_TIME_TICK);
 +}
 +
 +#if (BTA_AV_SINK_INCLUDED == TRUE)
 +
 +static void btif_media_task_aa_handle_clear_track (void)
 +{
 +    APPL_TRACE_DEBUG("btif_media_task_aa_handle_clear_track");
 +}
 +
 +/*******************************************************************************
 + **
 + ** Function         btif_media_task_aa_handle_decoder_reset
 + **
 + ** Description
 + **
 + ** Returns          void
 + **
 + *******************************************************************************/
 +static void btif_media_task_aa_handle_decoder_reset(BT_HDR *p_msg)
 +{
 +    tBTIF_MEDIA_SINK_CFG_UPDATE *p_buf = (tBTIF_MEDIA_SINK_CFG_UPDATE *) p_msg;
 +    tA2D_STATUS a2d_status;
 +    tA2D_SBC_CIE sbc_cie;
 +    OI_STATUS       status;
 +    UINT32          freq_multiple = 48 * 20; /* frequency multiple for 20ms of data , initialize with 48K*/
 +    UINT32          num_blocks = 16;
 +    UINT32          num_subbands = 8;
 +
 +    APPL_TRACE_EVENT("btif_media_task_aa_handle_decoder_reset p_codec_info[%x:%x:%x:%x:%x:%x]\n",
 +              p_buf->codec_info[1], p_buf->codec_info[2], p_buf->codec_info[3],
 +              p_buf->codec_info[4], p_buf->codec_info[5], p_buf->codec_info[6]);
 +
 +    a2d_status = A2D_ParsSbcInfo(&sbc_cie, p_buf->codec_info, FALSE);
 +    if (a2d_status != A2D_SUCCESS) {
 +        APPL_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status);
 +        return;
 +    }
 +
 +    btif_media_cb.sample_rate = btif_a2dp_get_track_frequency(sbc_cie.samp_freq);
 +    btif_media_cb.channel_count = btif_a2dp_get_track_channel_count(sbc_cie.ch_mode);
 +
 +    btif_media_cb.rx_flush = FALSE;
 +    APPL_TRACE_EVENT("Reset to sink role");
 +    status = OI_CODEC_SBC_DecoderReset(&context, contextData, sizeof(contextData), 2, 2, FALSE);
 +    if (!OI_SUCCESS(status)) {
 +        APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
 +    }
 +
 +    btif_media_cb.data_channel_open = TRUE;
 +
 +    switch (sbc_cie.samp_freq) {
 +    case A2D_SBC_IE_SAMP_FREQ_16:
 +        APPL_TRACE_DEBUG("\tsamp_freq:%d (16000)\n", sbc_cie.samp_freq);
 +        freq_multiple = 16 * 20;
 +        break;
 +    case A2D_SBC_IE_SAMP_FREQ_32:
 +        APPL_TRACE_DEBUG("\tsamp_freq:%d (32000)\n", sbc_cie.samp_freq);
 +        freq_multiple = 32 * 20;
 +        break;
 +    case A2D_SBC_IE_SAMP_FREQ_44:
 +        APPL_TRACE_DEBUG("\tsamp_freq:%d (44100)\n", sbc_cie.samp_freq);
 +        freq_multiple = 441 * 2;
 +        break;
 +    case A2D_SBC_IE_SAMP_FREQ_48:
 +        APPL_TRACE_DEBUG("\tsamp_freq:%d (48000)\n", sbc_cie.samp_freq);
 +        freq_multiple = 48 * 20;
 +        break;
 +    default:
 +        APPL_TRACE_DEBUG(" Unknown Frequency ");
 +        break;
 +    }
 +
 +    switch (sbc_cie.ch_mode) {
 +    case A2D_SBC_IE_CH_MD_MONO:
 +        APPL_TRACE_DEBUG("\tch_mode:%d (Mono)\n", sbc_cie.ch_mode);
 +        break;
 +    case A2D_SBC_IE_CH_MD_DUAL:
 +        APPL_TRACE_DEBUG("\tch_mode:%d (DUAL)\n", sbc_cie.ch_mode);
 +        break;
 +    case A2D_SBC_IE_CH_MD_STEREO:
 +        APPL_TRACE_DEBUG("\tch_mode:%d (STEREO)\n", sbc_cie.ch_mode);
 +        break;
 +    case A2D_SBC_IE_CH_MD_JOINT:
 +        APPL_TRACE_DEBUG("\tch_mode:%d (JOINT)\n", sbc_cie.ch_mode);
 +        break;
 +    default:
 +        APPL_TRACE_DEBUG(" Unknown Mode ");
 +        break;
 +    }
 +
 +    switch (sbc_cie.block_len) {
 +    case A2D_SBC_IE_BLOCKS_4:
 +        APPL_TRACE_DEBUG("\tblock_len:%d (4)\n", sbc_cie.block_len);
 +        num_blocks = 4;
 +        break;
 +    case A2D_SBC_IE_BLOCKS_8:
 +        APPL_TRACE_DEBUG("\tblock_len:%d (8)\n", sbc_cie.block_len);
 +        num_blocks = 8;
 +        break;
 +    case A2D_SBC_IE_BLOCKS_12:
 +        APPL_TRACE_DEBUG("\tblock_len:%d (12)\n", sbc_cie.block_len);
 +        num_blocks = 12;
 +        break;
 +    case A2D_SBC_IE_BLOCKS_16:
 +        APPL_TRACE_DEBUG("\tblock_len:%d (16)\n", sbc_cie.block_len);
 +        num_blocks = 16;
 +        break;
 +    default:
 +        APPL_TRACE_DEBUG(" Unknown BlockLen ");
 +        break;
 +    }
 +
 +    switch (sbc_cie.num_subbands) {
 +    case A2D_SBC_IE_SUBBAND_4:
 +        APPL_TRACE_DEBUG("\tnum_subbands:%d (4)\n", sbc_cie.num_subbands);
 +        num_subbands = 4;
 +        break;
 +    case A2D_SBC_IE_SUBBAND_8:
 +        APPL_TRACE_DEBUG("\tnum_subbands:%d (8)\n", sbc_cie.num_subbands);
 +        num_subbands = 8;
 +        break;
 +    default:
 +        APPL_TRACE_DEBUG(" Unknown SubBands ");
 +        break;
 +    }
 +
 +    switch (sbc_cie.alloc_mthd) {
 +    case A2D_SBC_IE_ALLOC_MD_S:
 +        APPL_TRACE_DEBUG("\talloc_mthd:%d (SNR)\n", sbc_cie.alloc_mthd);
 +        break;
 +    case A2D_SBC_IE_ALLOC_MD_L:
 +        APPL_TRACE_DEBUG("\talloc_mthd:%d (Loudness)\n", sbc_cie.alloc_mthd);
 +        break;
 +    default:
 +        APPL_TRACE_DEBUG(" Unknown Allocation Method");
 +        break;
 +    }
 +
 +    APPL_TRACE_EVENT("\tBit pool Min:%d Max:%d\n", sbc_cie.min_bitpool, sbc_cie.max_bitpool);
 +
 +    btif_media_cb.frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1;
 +    APPL_TRACE_EVENT(" Frames to be processed in 20 ms %d\n", btif_media_cb.frames_to_process);
 +}
 +#endif
 +
 +/*******************************************************************************
 + **
 + ** Function         btif_media_sink_enque_buf
 + **
 + ** Description      This function is called by the av_co to fill A2DP Sink Queue
 + **
 + **
 + ** Returns          size of the queue
 + *******************************************************************************/
 +UINT8 btif_media_sink_enque_buf(BT_HDR *p_pkt)
 +{
 +    tBT_SBC_HDR *p_msg;
 +
 +    if (btif_media_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/
 +        return GKI_queue_length(&btif_media_cb.RxSbcQ);
 +    }
 +    if (GKI_queue_length(&btif_media_cb.RxSbcQ) == MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) {
 +        GKI_freebuf(GKI_dequeue(&(btif_media_cb.RxSbcQ)));
 +    }
 +
 +    BTIF_TRACE_VERBOSE("btif_media_sink_enque_buf + ");
 +
 +    /* allocate and Queue this buffer */
 +    if ((p_msg = (tBT_SBC_HDR *) GKI_getbuf(sizeof(tBT_SBC_HDR) +
 +                                            p_pkt->offset + p_pkt->len)) != NULL) {
 +        memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len));
 +        p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
 +        BTIF_TRACE_VERBOSE("btif_media_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed);
 +        // LOG_ERROR("sink enq %d\n", p_msg->num_frames_to_be_processed);
 +        GKI_enqueue(&(btif_media_cb.RxSbcQ), p_msg);
 +        if (GKI_queue_length(&btif_media_cb.RxSbcQ) == MAX_A2DP_DELAYED_START_FRAME_COUNT) {
 +            BTIF_TRACE_DEBUG(" Initiate Decoding ");
 +            btif_media_task_aa_handle_start_decoding();
 +        }
 +    } else {
 +        /* let caller deal with a failed allocation */
 +        BTIF_TRACE_VERBOSE("btif_media_sink_enque_buf No Buffer left - ");
 +    }
 +    return GKI_queue_length(&btif_media_cb.RxSbcQ);
 +}
 +
 +
 +/*******************************************************************************
 + **
 + ** Function         btif_media_aa_readbuf
 + **
 + ** Description      This function is called by the av_co to get the next buffer to send
 + **
 + **
 + ** Returns          void
 + *******************************************************************************/
 +BT_HDR *btif_media_aa_readbuf(void)
 +{
 +    return NULL;
 +}
 +
 +#endif /* BTA_AV_INCLUDED == TRUE */
 +/*******************************************************************************
 + **
 + ** Function         dump_codec_info
 + **
 + ** Description      Decode and display codec_info (for debug)
 + **
 + ** Returns          void
 + **
 + *******************************************************************************/
 +void dump_codec_info(unsigned char *p_codec)
 +{
 +    tA2D_STATUS a2d_status;
 +    tA2D_SBC_CIE sbc_cie;
 +
 +    a2d_status = A2D_ParsSbcInfo(&sbc_cie, p_codec, FALSE);
 +    if (a2d_status != A2D_SUCCESS) {
 +        APPL_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status);
 +        return;
 +    }
 +
 +    APPL_TRACE_DEBUG("dump_codec_info");
 +
 +    if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_16) {
 +        APPL_TRACE_DEBUG("\tsamp_freq:%d (16000)\n", sbc_cie.samp_freq);
 +    } else  if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_32) {
 +        APPL_TRACE_DEBUG("\tsamp_freq:%d (32000)\n", sbc_cie.samp_freq);
 +    } else  if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_44) {
 +        APPL_TRACE_DEBUG("\tsamp_freq:%d (44.100)\n", sbc_cie.samp_freq);
 +    } else  if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_48) {
 +        APPL_TRACE_DEBUG("\tsamp_freq:%d (48000)\n", sbc_cie.samp_freq);
 +    } else {
 +        APPL_TRACE_DEBUG("\tBAD samp_freq:%d\n", sbc_cie.samp_freq);
 +    }
 +
 +    if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_MONO) {
 +        APPL_TRACE_DEBUG("\tch_mode:%d (Mono)\n", sbc_cie.ch_mode);
 +    } else  if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_DUAL) {
 +        APPL_TRACE_DEBUG("\tch_mode:%d (Dual)\n", sbc_cie.ch_mode);
 +    } else  if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_STEREO) {
 +        APPL_TRACE_DEBUG("\tch_mode:%d (Stereo)\n", sbc_cie.ch_mode);
 +    } else  if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_JOINT) {
 +        APPL_TRACE_DEBUG("\tch_mode:%d (Joint)\n", sbc_cie.ch_mode);
 +    } else {
 +        APPL_TRACE_DEBUG("\tBAD ch_mode:%d\n", sbc_cie.ch_mode);
 +    }
 +
 +    if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_4) {
 +        APPL_TRACE_DEBUG("\tblock_len:%d (4)\n", sbc_cie.block_len);
 +    } else  if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_8) {
 +        APPL_TRACE_DEBUG("\tblock_len:%d (8)\n", sbc_cie.block_len);
 +    } else  if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_12) {
 +        APPL_TRACE_DEBUG("\tblock_len:%d (12)\n", sbc_cie.block_len);
 +    } else  if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_16) {
 +        APPL_TRACE_DEBUG("\tblock_len:%d (16)\n", sbc_cie.block_len);
 +    } else {
 +        APPL_TRACE_DEBUG("\tBAD block_len:%d\n", sbc_cie.block_len);
 +    }
 +
 +    if (sbc_cie.num_subbands == A2D_SBC_IE_SUBBAND_4) {
 +        APPL_TRACE_DEBUG("\tnum_subbands:%d (4)\n", sbc_cie.num_subbands);
 +    } else  if (sbc_cie.num_subbands == A2D_SBC_IE_SUBBAND_8) {
 +        APPL_TRACE_DEBUG("\tnum_subbands:%d (8)\n", sbc_cie.num_subbands);
 +    } else {
 +        APPL_TRACE_DEBUG("\tBAD num_subbands:%d\n", sbc_cie.num_subbands);
 +    }
 +
 +    if (sbc_cie.alloc_mthd == A2D_SBC_IE_ALLOC_MD_S) {
 +        APPL_TRACE_DEBUG("\talloc_mthd:%d (SNR)\n", sbc_cie.alloc_mthd);
 +    } else  if (sbc_cie.alloc_mthd == A2D_SBC_IE_ALLOC_MD_L) {
 +        APPL_TRACE_DEBUG("\talloc_mthd:%d (Loundess)\n", sbc_cie.alloc_mthd);
 +    } else {
 +        APPL_TRACE_DEBUG("\tBAD alloc_mthd:%d\n", sbc_cie.alloc_mthd);
 +    }
 +
 +    APPL_TRACE_DEBUG("\tBit pool Min:%d Max:%d\n", sbc_cie.min_bitpool, sbc_cie.max_bitpool);
 +
 +}
index 2b445279fcd35e58c30bed0d5b45039b6ab4e442,0000000000000000000000000000000000000000..fb6aa5f430daa27f82d0f17a80623ff38b8c977e
mode 100644,000000..100644
--- /dev/null
@@@ -1,190 -1,0 +1,190 @@@
-         connect_queue = list_new(osi_free);
 +/******************************************************************************
 + *
 + *  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_profile_queue.c
 + *
 + *  Description:   Bluetooth remote device connection queuing implementation.
 + *
 + ******************************************************************************/
 +
 +// #include <assert.h>
 +#include "bt_trace.h"
 +#include <string.h>
 +// #include <hardware/bluetooth.h>
 +#include "bt_defs.h"
 +#include <string.h>
 +
 +#define LOG_TAG "bt_btif_queue"
 +#include "btif_common.h"
 +#include "btif_profile_queue.h"
 +#include "gki.h"
 +#include "list.h"
 +#include "allocator.h"
 +#include "stack_manager.h"
 +
 +/*******************************************************************************
 +**  Local type definitions
 +*******************************************************************************/
 +
 +typedef enum {
 +    BTIF_QUEUE_CONNECT_EVT,
 +    BTIF_QUEUE_ADVANCE_EVT,
 +} btif_queue_event_t;
 +
 +typedef struct {
 +    bt_bdaddr_t bda;
 +    uint16_t uuid;
 +    bool busy;
 +    btif_connect_cb_t connect_cb;
 +} connect_node_t;
 +
 +/*******************************************************************************
 +**  Static variables
 +*******************************************************************************/
 +
 +static list_t *connect_queue;
 +
 +static const size_t MAX_REASONABLE_REQUESTS = 10;
 +
 +/*******************************************************************************
 +**  Queue helper functions
 +*******************************************************************************/
 +
 +static void queue_int_add(connect_node_t *p_param)
 +{
 +    if (!connect_queue) {
++        connect_queue = list_new(osi_free_func);
 +        assert(connect_queue != NULL);
 +    }
 +
 +    // Sanity check to make sure we're not leaking connection requests
 +    assert(list_length(connect_queue) < MAX_REASONABLE_REQUESTS);
 +
 +    for (const list_node_t *node = list_begin(connect_queue); node != list_end(connect_queue); node = list_next(node)) {
 +        if (((connect_node_t *)list_node(node))->uuid == p_param->uuid) {
 +            LOG_INFO("%s dropping duplicate connect request for uuid: %04x", __func__, p_param->uuid);
 +            return;
 +        }
 +    }
 +
 +    connect_node_t *p_node = osi_malloc(sizeof(connect_node_t));
 +    assert(p_node != NULL);
 +    memcpy(p_node, p_param, sizeof(connect_node_t));
 +    list_append(connect_queue, p_node);
 +}
 +
 +static void queue_int_advance()
 +{
 +    if (connect_queue && !list_is_empty(connect_queue)) {
 +        list_remove(connect_queue, list_front(connect_queue));
 +    }
 +}
 +
 +static void queue_int_handle_evt(UINT16 event, char *p_param)
 +{
 +    switch (event) {
 +    case BTIF_QUEUE_CONNECT_EVT:
 +        queue_int_add((connect_node_t *)p_param);
 +        break;
 +
 +    case BTIF_QUEUE_ADVANCE_EVT:
 +        queue_int_advance();
 +        break;
 +    }
 +
 +    // if (stack_manager_get_interface()->get_stack_is_running())
 +    if (stack_manager_is_stack_running()) {
 +        btif_queue_connect_next();
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         btif_queue_connect
 +**
 +** Description      Add a new connection to the queue and trigger the next
 +**                  scheduled connection.
 +**
 +** Returns          BT_STATUS_SUCCESS if successful
 +**
 +*******************************************************************************/
 +bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda, btif_connect_cb_t connect_cb)
 +{
 +    connect_node_t node;
 +    memset(&node, 0, sizeof(connect_node_t));
 +    memcpy(&node.bda, bda, sizeof(bt_bdaddr_t));
 +    node.uuid = uuid;
 +    node.connect_cb = connect_cb;
 +
 +    return btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CONNECT_EVT,
 +                                 (char *)&node, sizeof(connect_node_t), NULL);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         btif_queue_advance
 +**
 +** Description      Clear the queue's busy status and advance to the next
 +**                  scheduled connection.
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void btif_queue_advance()
 +{
 +    btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_ADVANCE_EVT,
 +                          NULL, 0, NULL);
 +}
 +
 +// This function dispatches the next pending connect request. It is called from
 +// stack_manager when the stack comes up.
 +bt_status_t btif_queue_connect_next(void)
 +{
 +    if (!connect_queue || list_is_empty(connect_queue)) {
 +        return BT_STATUS_FAIL;
 +    }
 +
 +    connect_node_t *p_head = list_front(connect_queue);
 +
 +    // If the queue is currently busy, we return success anyway,
 +    // since the connection has been queued...
 +    if (p_head->busy) {
 +        return BT_STATUS_SUCCESS;
 +    }
 +
 +    p_head->busy = true;
 +    return p_head->connect_cb(&p_head->bda, p_head->uuid);
 +}
 +
 +
 +/*******************************************************************************
 +**
 +** Function         btif_queue_release
 +**
 +** Description      Free up all the queue nodes and set the queue head to NULL
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void btif_queue_release()
 +{
 +    list_free(connect_queue);
 +    connect_queue = NULL;
 +}
index 9ae20df90377ef00e2c704219ffee72db81b981d,201df90e7fa0f62e9d3939f0eb7b5c1d0155b835..bb7ccd17db44ccfb12b33413fbbe760d0ee1a0e6
@@@ -187,26 -178,20 +178,25 @@@ void GKI_init_q (BUFFER_Q *p_q
  ** Returns          A pointer to the buffer, or NULL if none available
  **
  *******************************************************************************/
- void *GKI_getbuf (UINT16 size)
+ void *GKI_getbuf_func(UINT16 size)
  {
      BUFFER_HDR_T *header = osi_malloc(size + BUFFER_HDR_SIZE);
 -    header->status  = BUF_STATUS_UNLINKED;
 -    header->p_next  = NULL;
 -    header->Type    = 0;
 -    header->size = size;
 -
 -    return header + 1;
 +    assert(header != NULL);
 +    if (header != NULL) {
 +        header->status  = BUF_STATUS_UNLINKED;
 +        header->p_next  = NULL;
 +        header->Type    = 0;
 +        header->size = size;
 +
 +        return header + 1;
 +    } else {
 +        return NULL;
 +    }
  }
  
  /*******************************************************************************
  **
- ** Function         GKI_getpoolbuf
+ ** Function         GKI_getpoolbuf_func
  **
  ** Description      Called by an application to get a free buffer from
  **                  a specific buffer pool.
Simple merge
index f29a525d814e2a27c399d593f8efb10a8f3e8b26,61e9487eaf5cdbed01b40cbf2206d622a3dfeb9f..c9bd3c6db4f8e12d8c65aa2d9fb6019e3c05a855
@@@ -40,21 -40,21 +40,21 @@@ enum 
      SIG_PRF_WORK = 0xfd,
      SIG_BTU_START_UP = 0xfe,
      SIG_BTU_WORK = 0xff,
 -    SIG_BTIF_WORK = 0xff
 +    // SIG_BTIF_WORK = 0xff
  };
  
- #define HCI_HOST_TASK_STACK_SIZE      1024
- #define HCI_HOST_TASK_PRIO                    (configMAX_PRIORITIES - 3)
+ #define HCI_HOST_TASK_STACK_SIZE      1500
+ #define HCI_HOST_TASK_PRIO                    (configMAX_PRIORITIES - 2)
  #define HCI_HOST_TASK_NAME                    "hciHostT"
- #define HCI_HOST_QUEUE_NUM                    30
+ #define HCI_HOST_QUEUE_NUM                    40
  
- #define HCI_H4_TASK_STACK_SIZE                1024
+ #define HCI_H4_TASK_STACK_SIZE                1500
  #define HCI_H4_TASK_PRIO                      (configMAX_PRIORITIES - 3)
  #define HCI_H4_TASK_NAME                      "hciH4T"
- #define HCI_H4_QUEUE_NUM                      30
+ #define HCI_H4_QUEUE_NUM                      60
  
  #define BTU_TASK_STACK_SIZE                   4096
- #define BTU_TASK_PRIO                         (configMAX_PRIORITIES - 1)
+ #define BTU_TASK_PRIO                         (configMAX_PRIORITIES - 4)
  #define BTU_TASK_NAME                         "btuT"
  #define BTU_QUEUE_NUM                         50
  
index eabb8aa2b70c51e62bd74c2e34564688d2382ce7,0000000000000000000000000000000000000000..2c5e316a31f3c464b140176feb6c25b78003f0c7
mode 100755,000000..100755
--- /dev/null
@@@ -1,473 -1,0 +1,473 @@@
-         AVCT_TRACE_WARNING("%x: aloc:%d, lcb:0x%x/0x%x, ccb:0x%x/0x%x",
 +/******************************************************************************
 + *
 + *  Copyright (C) 2003-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.
 + *
 + ******************************************************************************/
 +
 +/******************************************************************************
 + *
 + *  This module contains the link control state machine and functions which
 + *  operate on the link control block.
 + *
 + ******************************************************************************/
 +
 +#include <string.h>
 +#include "bt_types.h"
 +#include "bt_target.h"
 +#include "bt_utils.h"
 +#include "avct_api.h"
 +#include "avct_int.h"
 +#include "gki.h"
 +
 +/*****************************************************************************
 +** state machine constants and types
 +*****************************************************************************/
 +
 +#if BT_TRACE_VERBOSE == TRUE
 +
 +/* verbose state strings for trace */
 +const char * const avct_lcb_st_str[] = {
 +    "LCB_IDLE_ST",
 +    "LCB_OPENING_ST",
 +    "LCB_OPEN_ST",
 +    "LCB_CLOSING_ST"
 +};
 +
 +/* verbose event strings for trace */
 +const char * const avct_lcb_evt_str[] = {
 +    "UL_BIND_EVT",
 +    "UL_UNBIND_EVT",
 +    "UL_MSG_EVT",
 +    "INT_CLOSE_EVT",
 +    "LL_OPEN_EVT",
 +    "LL_CLOSE_EVT",
 +    "LL_MSG_EVT",
 +    "LL_CONG_EVT"
 +};
 +
 +#endif
 +
 +/* lcb state machine states */
 +enum {
 +    AVCT_LCB_IDLE_ST,
 +    AVCT_LCB_OPENING_ST,
 +    AVCT_LCB_OPEN_ST,
 +    AVCT_LCB_CLOSING_ST
 +};
 +
 +/* state machine action enumeration list */
 +enum {
 +    AVCT_LCB_CHNL_OPEN,
 +    AVCT_LCB_CHNL_DISC,
 +    AVCT_LCB_SEND_MSG,
 +    AVCT_LCB_OPEN_IND,
 +    AVCT_LCB_OPEN_FAIL,
 +    AVCT_LCB_CLOSE_IND,
 +    AVCT_LCB_CLOSE_CFM,
 +    AVCT_LCB_MSG_IND,
 +    AVCT_LCB_CONG_IND,
 +    AVCT_LCB_BIND_CONN,
 +    AVCT_LCB_BIND_FAIL,
 +    AVCT_LCB_UNBIND_DISC,
 +    AVCT_LCB_CHK_DISC,
 +    AVCT_LCB_DISCARD_MSG,
 +    AVCT_LCB_DEALLOC,
 +    AVCT_LCB_FREE_MSG_IND,
 +    AVCT_LCB_NUM_ACTIONS
 +};
 +
 +#define AVCT_LCB_IGNORE     AVCT_LCB_NUM_ACTIONS
 +
 +/* type for action functions */
 +typedef void (*tAVCT_LCB_ACTION)(tAVCT_LCB *p_ccb, tAVCT_LCB_EVT *p_data);
 +
 +/* action function list */
 +const tAVCT_LCB_ACTION avct_lcb_action[] = {
 +    avct_lcb_chnl_open,
 +    avct_lcb_chnl_disc,
 +    avct_lcb_send_msg,
 +    avct_lcb_open_ind,
 +    avct_lcb_open_fail,
 +    avct_lcb_close_ind,
 +    avct_lcb_close_cfm,
 +    avct_lcb_msg_ind,
 +    avct_lcb_cong_ind,
 +    avct_lcb_bind_conn,
 +    avct_lcb_bind_fail,
 +    avct_lcb_unbind_disc,
 +    avct_lcb_chk_disc,
 +    avct_lcb_discard_msg,
 +    avct_lcb_dealloc,
 +    avct_lcb_free_msg_ind
 +};
 +
 +/* state table information */
 +#define AVCT_LCB_ACTIONS            2       /* number of actions */
 +#define AVCT_LCB_NEXT_STATE         2       /* position of next state */
 +#define AVCT_LCB_NUM_COLS           3       /* number of columns in state tables */
 +
 +/* state table for idle state */
 +const UINT8 avct_lcb_st_idle[][AVCT_LCB_NUM_COLS] = {
 +/* Event                Action 1                    Action 2                    Next state */
 +/* UL_BIND_EVT */       {AVCT_LCB_CHNL_OPEN,        AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
 +/* UL_UNBIND_EVT */     {AVCT_LCB_UNBIND_DISC,      AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST},
 +/* UL_MSG_EVT */        {AVCT_LCB_DISCARD_MSG,      AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST},
 +/* INT_CLOSE_EVT */     {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST},
 +/* LL_OPEN_EVT */       {AVCT_LCB_OPEN_IND,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
 +/* LL_CLOSE_EVT */      {AVCT_LCB_CLOSE_IND,        AVCT_LCB_DEALLOC,           AVCT_LCB_IDLE_ST},
 +/* LL_MSG_EVT */        {AVCT_LCB_FREE_MSG_IND,     AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST},
 +/* LL_CONG_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST}
 +};
 +
 +/* state table for opening state */
 +const UINT8 avct_lcb_st_opening[][AVCT_LCB_NUM_COLS] = {
 +/* Event                Action 1                    Action 2                    Next state */
 +/* UL_BIND_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
 +/* UL_UNBIND_EVT */     {AVCT_LCB_UNBIND_DISC,      AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
 +/* UL_MSG_EVT */        {AVCT_LCB_DISCARD_MSG,      AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
 +/* INT_CLOSE_EVT */     {AVCT_LCB_CHNL_DISC,        AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
 +/* LL_OPEN_EVT */       {AVCT_LCB_OPEN_IND,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
 +/* LL_CLOSE_EVT */      {AVCT_LCB_OPEN_FAIL,        AVCT_LCB_DEALLOC,           AVCT_LCB_IDLE_ST},
 +/* LL_MSG_EVT */        {AVCT_LCB_FREE_MSG_IND,     AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
 +/* LL_CONG_EVT */       {AVCT_LCB_CONG_IND,         AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST}
 +};
 +
 +/* state table for open state */
 +const UINT8 avct_lcb_st_open[][AVCT_LCB_NUM_COLS] = {
 +/* Event                Action 1                    Action 2                    Next state */
 +/* UL_BIND_EVT */       {AVCT_LCB_BIND_CONN,        AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
 +/* UL_UNBIND_EVT */     {AVCT_LCB_CHK_DISC,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
 +/* UL_MSG_EVT */        {AVCT_LCB_SEND_MSG,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
 +/* INT_CLOSE_EVT */     {AVCT_LCB_CHNL_DISC,        AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
 +/* LL_OPEN_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
 +/* LL_CLOSE_EVT */      {AVCT_LCB_CLOSE_IND,        AVCT_LCB_DEALLOC,           AVCT_LCB_IDLE_ST},
 +/* LL_MSG_EVT */        {AVCT_LCB_MSG_IND,          AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
 +/* LL_CONG_EVT */       {AVCT_LCB_CONG_IND,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST}
 +};
 +
 +/* state table for closing state */
 +const UINT8 avct_lcb_st_closing[][AVCT_LCB_NUM_COLS] = {
 +/* Event                Action 1                    Action 2                    Next state */
 +/* UL_BIND_EVT */       {AVCT_LCB_BIND_FAIL,        AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
 +/* UL_UNBIND_EVT */     {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
 +/* UL_MSG_EVT */        {AVCT_LCB_DISCARD_MSG,      AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
 +/* INT_CLOSE_EVT */     {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
 +/* LL_OPEN_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
 +/* LL_CLOSE_EVT */      {AVCT_LCB_CLOSE_CFM,        AVCT_LCB_DEALLOC,           AVCT_LCB_IDLE_ST},
 +/* LL_MSG_EVT */        {AVCT_LCB_FREE_MSG_IND,     AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
 +/* LL_CONG_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST}
 +};
 +
 +/* type for state table */
 +typedef const UINT8 (*tAVCT_LCB_ST_TBL)[AVCT_LCB_NUM_COLS];
 +
 +/* state table */
 +const tAVCT_LCB_ST_TBL avct_lcb_st_tbl[] = {
 +    avct_lcb_st_idle,
 +    avct_lcb_st_opening,
 +    avct_lcb_st_open,
 +    avct_lcb_st_closing
 +};
 +
 +/*******************************************************************************
 +**
 +** Function         avct_lcb_event
 +**
 +** Description      State machine event handling function for lcb
 +**
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data)
 +{
 +    tAVCT_LCB_ST_TBL    state_table;
 +    UINT8               action;
 +    int                 i;
 +
 +#if BT_TRACE_VERBOSE == TRUE
 +    AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
 +#else
 +    AVCT_TRACE_EVENT("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state);
 +#endif
 +
 +    /* look up the state table for the current state */
 +    state_table = avct_lcb_st_tbl[p_lcb->state];
 +
 +    /* set next state */
 +    p_lcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
 +
 +    /* execute action functions */
 +    for (i = 0; i < AVCT_LCB_ACTIONS; i++)
 +    {
 +        if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
 +        {
 +            (*avct_lcb_action[action])(p_lcb, p_data);
 +        }
 +        else
 +        {
 +            break;
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avct_bcb_event
 +**
 +** Description      State machine event handling function for lcb
 +**
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +#if (AVCT_BROWSE_INCLUDED == TRUE)
 +void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data)
 +{
 +    tAVCT_LCB_ST_TBL    state_table;
 +    UINT8               action;
 +    int                 i;
 +
 +#if BT_TRACE_VERBOSE == TRUE
 +    AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
 +#else
 +    AVCT_TRACE_EVENT("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state);
 +#endif
 +
 +    /* look up the state table for the current state */
 +    state_table = avct_lcb_st_tbl[p_bcb->state];
 +
 +    /* set next state */
 +    p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
 +
 +    /* execute action functions */
 +    for (i = 0; i < AVCT_LCB_ACTIONS; i++)
 +    {
 +        if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
 +        {
 +            (*avct_bcb_action[action])(p_bcb, p_data);
 +        }
 +        else
 +        {
 +            break;
 +        }
 +    }
 +}
 +#endif
 +
 +/*******************************************************************************
 +**
 +** Function         avct_lcb_by_bd
 +**
 +** Description      This lookup function finds the lcb for a BD address.
 +**
 +**
 +** Returns          pointer to the lcb, or NULL if none found.
 +**
 +*******************************************************************************/
 +tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr)
 +{
 +    tAVCT_LCB   *p_lcb = &avct_cb.lcb[0];
 +    int         i;
 +
 +    for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
 +    {
 +        /* if allocated lcb has matching lcb */
 +        if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN)))
 +        {
 +            break;
 +        }
 +    }
 +
 +    if (i == AVCT_NUM_LINKS)
 +    {
 +        /* if no lcb found */
 +        p_lcb = NULL;
 +
 +        AVCT_TRACE_DEBUG("No lcb for addr %02x-%02x-%02x-%02x-%02x-%02x",
 +                          bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
 +    }
 +    return p_lcb;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avct_lcb_alloc
 +**
 +** Description      Allocate a link control block.
 +**
 +**
 +** Returns          pointer to the lcb, or NULL if none could be allocated.
 +**
 +*******************************************************************************/
 +tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr)
 +{
 +    tAVCT_LCB   *p_lcb = &avct_cb.lcb[0];
 +    int         i;
 +
 +    for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
 +    {
 +        if (!p_lcb->allocated)
 +        {
 +            p_lcb->allocated = (UINT8)(i + 1);
 +            memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
 +            AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated);
 +            break;
 +        }
 +    }
 +
 +    if (i == AVCT_NUM_LINKS)
 +    {
 +        /* out of lcbs */
 +        p_lcb = NULL;
 +        AVCT_TRACE_WARNING("Out of lcbs");
 +    }
 +    return p_lcb;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avct_lcb_dealloc
 +**
 +** Description      Deallocate a link control block.
 +**
 +**
 +** Returns          void.
 +**
 +*******************************************************************************/
 +void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
 +{
 +    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
 +    BOOLEAN     found = FALSE;
 +    int         i;
 +    UNUSED(p_data);
 +
 +    AVCT_TRACE_DEBUG("avct_lcb_dealloc %d", p_lcb->allocated);
 +
 +    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
 +    {
 +        /* if ccb allocated and */
 +        if (p_ccb->allocated)
 +        {
 +            if (p_ccb->p_lcb == p_lcb)
 +            {
 +                AVCT_TRACE_DEBUG("avct_lcb_dealloc used by ccb: %d", i);
 +                found = TRUE;
 +                break;
 +            }
 +        }
 +    }
 +
 +    if (!found)
 +    {
 +        AVCT_TRACE_DEBUG("avct_lcb_dealloc now");
 +
 +        /* clear reassembled msg buffer if in use */
 +        if (p_lcb->p_rx_msg != NULL)
 +        {
 +            GKI_freebuf(p_lcb->p_rx_msg);
 +        }
 +        memset(p_lcb, 0, sizeof(tAVCT_LCB));
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avct_lcb_by_lcid
 +**
 +** Description      Find the LCB associated with the L2CAP LCID
 +**
 +**
 +** Returns          pointer to the lcb, or NULL if none found.
 +**
 +*******************************************************************************/
 +tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid)
 +{
 +    tAVCT_LCB   *p_lcb = &avct_cb.lcb[0];
 +    int         i;
 +
 +    for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
 +    {
 +        if (p_lcb->allocated && ((p_lcb->ch_lcid == lcid) || (p_lcb->conflict_lcid == lcid)))
 +        {
 +            break;
 +        }
 +    }
 +
 +    if (i == AVCT_NUM_LINKS)
 +    {
 +        /* out of lcbs */
 +        p_lcb = NULL;
 +        AVCT_TRACE_WARNING("No lcb for lcid %x", lcid);
 +    }
 +
 +    return p_lcb;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avct_lcb_has_pid
 +**
 +** Description      See if any ccbs on this lcb have a particular pid.
 +**
 +**
 +** Returns          Pointer to CCB if PID found, NULL otherwise.
 +**
 +*******************************************************************************/
 +tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid)
 +{
 +    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
 +    int         i;
 +
 +    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
 +    {
 +        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid))
 +        {
 +            return p_ccb;
 +        }
 +    }
 +    return NULL;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avct_lcb_last_ccb
 +**
 +** Description      See if given ccb is only one on the lcb.
 +**
 +**
 +** Returns          TRUE if ccb is last, FALSE otherwise.
 +**
 +*******************************************************************************/
 +BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last)
 +{
 +    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
 +    int         i;
 +
 +    AVCT_TRACE_WARNING("avct_lcb_last_ccb");
 +    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
 +    {
++        AVCT_TRACE_WARNING("%x: aloc:%d, lcb:%p/%p, ccb:%p/%p",
 +            i, p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb, p_ccb_last);
 +        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last))
 +        {
 +            return FALSE;
 +        }
 +    }
 +    return TRUE;
 +}
 +
 +
 +
index 029c891a88a929cfddc2ab752a933a8e8097a158,0000000000000000000000000000000000000000..8c274f32c687267281f24edb72a2ee2dfb50b99a
mode 100755,000000..100755
--- /dev/null
@@@ -1,1436 -1,0 +1,1436 @@@
-             AVDT_TRACE_WARNING("p_scb->p_pkt=%x, p_scb->p_ccb=%x, IsQueueEmpty=%x, p_scb->frag_off=%x\n",
 +/******************************************************************************
 + *
 + *  Copyright (C) 2002-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.
 + *
 + ******************************************************************************/
 +
 +/******************************************************************************
 + *
 + *  This module contains API of the audio/video distribution transport
 + *  protocol.
 + *
 + ******************************************************************************/
 +
 +#include <string.h>
 +#include "bt_types.h"
 +#include "bt_target.h"
 +#include "avdt_api.h"
 +#include "avdtc_api.h"
 +#include "avdt_int.h"
 +#include "l2c_api.h"
 +#include "btm_api.h"
 +#include "btu.h"
 +
 +
 +/* Control block for AVDT */
 +#if AVDT_DYNAMIC_MEMORY == FALSE
 +tAVDT_CB avdt_cb;
 +#endif
 +
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_process_timeout
 +**
 +** Description      This function is called by BTU when an AVDTP timer
 +**                  expires.  The function sends a timer event to the
 +**                  appropriate CCB or SCB state machine.
 +**
 +**                  This function is for use internal to the stack only.
 +**
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void avdt_process_timeout(TIMER_LIST_ENT *p_tle)
 +{
 +    UINT8   event = 0;
 +    UINT8   err_code = AVDT_ERR_TIMEOUT;
 +
 +    switch (p_tle->event)
 +    {
 +        case BTU_TTYPE_AVDT_CCB_RET:
 +            event = AVDT_CCB_RET_TOUT_EVT + AVDT_CCB_MKR;
 +            break;
 +
 +        case BTU_TTYPE_AVDT_CCB_RSP:
 +            event = AVDT_CCB_RSP_TOUT_EVT + AVDT_CCB_MKR;
 +            break;
 +
 +        case BTU_TTYPE_AVDT_CCB_IDLE:
 +            event = AVDT_CCB_IDLE_TOUT_EVT + AVDT_CCB_MKR;
 +            break;
 +
 +        case BTU_TTYPE_AVDT_SCB_TC:
 +            event = AVDT_SCB_TC_TOUT_EVT;
 +            break;
 +
 +        default:
 +            break;
 +    }
 +
 +    if (event & AVDT_CCB_MKR)
 +    {
 +        avdt_ccb_event((tAVDT_CCB *) p_tle->param, (UINT8) (event & ~AVDT_CCB_MKR),
 +                       (tAVDT_CCB_EVT *) &err_code);
 +    }
 +    else
 +    {
 +        avdt_scb_event((tAVDT_SCB *) p_tle->param, event, NULL);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_Register
 +**
 +** Description      This is the system level registration function for the
 +**                  AVDTP protocol.  This function initializes AVDTP and
 +**                  prepares the protocol stack for its use.  This function
 +**                  must be called once by the system or platform using AVDTP
 +**                  before the other functions of the API an be used.
 +**
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback)
 +{
 +    /* register PSM with L2CAP */
 +    L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO *) &avdt_l2c_appl);
 +
 +    /* set security level */
 +    BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
 +        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
 +    BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
 +        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
 +
 +    /* do not use security on the media channel */
 +    BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
 +        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
 +    BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
 +        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
 +
 +#if AVDT_REPORTING == TRUE
 +    /* do not use security on the reporting channel */
 +    BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
 +        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
 +    BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
 +        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
 +#endif
 +
 +    /* initialize AVDTP data structures */
 +    avdt_scb_init();
 +    avdt_ccb_init();
 +    avdt_ad_init();
 +
 +    /* copy registration struct */
 +    memcpy(&avdt_cb.rcb, p_reg, sizeof(tAVDT_REG));
 +    avdt_cb.p_conn_cback = p_cback;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_Deregister
 +**
 +** Description      This function is called to deregister use AVDTP protocol.
 +**                  It is called when AVDTP is no longer being used by any
 +**                  application in the system.  Before this function can be
 +**                  called, all streams must be removed with AVDT_RemoveStream().
 +**
 +**
 +** Returns          void
 +**
 +*******************************************************************************/
 +void AVDT_Deregister(void)
 +{
 +    /* deregister PSM with L2CAP */
 +    L2CA_Deregister(AVDT_PSM);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_SINK_Activate
 +**
 +** Description      Activate SEP of A2DP Sink. In Use parameter is adjusted.
 +**                  In Use will be made false in case of activation. A2DP SRC
 +**                  will receive in_use as false and can open A2DP Sink
 +**                  connection
 +**
 +** Returns          void.
 +**
 +*******************************************************************************/
 +void AVDT_SINK_Activate()
 +{
 +    tAVDT_SCB           *p_scb = &avdt_cb.scb[0];
 +    int                 i;
 +    AVDT_TRACE_DEBUG("AVDT_SINK_Activate");
 +    /* for all allocated scbs */
 +    for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
 +    {
 +        if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK))
 +        {
 +            AVDT_TRACE_DEBUG("AVDT_SINK_Activate found scb");
 +            p_scb->sink_activated = TRUE;
 +            /* update in_use */
 +            p_scb->in_use = FALSE;
 +            break;
 +        }
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_SINK_Deactivate
 +**
 +** Description      Deactivate SEP of A2DP Sink. In Use parameter is adjusted.
 +**                  In Use will be made TRUE in case of activation. A2DP SRC
 +**                  will receive in_use as true and will not open A2DP Sink
 +**                  connection
 +**
 +** Returns          void.
 +**
 +*******************************************************************************/
 +void AVDT_SINK_Deactivate()
 +{
 +    tAVDT_SCB           *p_scb = &avdt_cb.scb[0];
 +    int                 i;
 +    AVDT_TRACE_DEBUG("AVDT_SINK_Deactivate");
 +    /* for all allocated scbs */
 +    for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
 +    {
 +        if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK))
 +        {
 +            AVDT_TRACE_DEBUG("AVDT_SINK_Deactivate, found scb");
 +            p_scb->sink_activated = FALSE;
 +            /* update in_use */
 +            p_scb->in_use = TRUE;
 +            break;
 +        }
 +    }
 +}
 +
 +void AVDT_AbortReq(UINT8 handle)
 +{
 +    AVDT_TRACE_ERROR("%s\n", __func__);
 +
 +    tAVDT_SCB *p_scb = avdt_scb_by_hdl(handle);
 +    if (p_scb != NULL)
 +    {
 +        avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_REQ_EVT, NULL);
 +    } else {
 +        AVDT_TRACE_ERROR("%s Improper SCB, can not abort the stream\n", __func__);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_CreateStream
 +**
 +** Description      Create a stream endpoint.  After a stream endpoint is
 +**                  created an application can initiate a connection between
 +**                  this endpoint and an endpoint on a peer device.  In
 +**                  addition, a peer device can discover, get the capabilities,
 +**                  and connect to this endpoint.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs)
 +{
 +    UINT16      result = AVDT_SUCCESS;
 +    tAVDT_SCB   *p_scb;
 +
 +    /* Verify parameters; if invalid, return failure */
 +    if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL))
 +    {
 +        result = AVDT_BAD_PARAMS;
 +    }
 +    /* Allocate scb; if no scbs, return failure */
 +    else if ((p_scb = avdt_scb_alloc(p_cs)) == NULL)
 +    {
 +        result = AVDT_NO_RESOURCES;
 +    }
 +    else
 +    {
 +        *p_handle = avdt_scb_to_hdl(p_scb);
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_RemoveStream
 +**
 +** Description      Remove a stream endpoint.  This function is called when
 +**                  the application is no longer using a stream endpoint.
 +**                  If this function is called when the endpoint is connected
 +**                  the connection is closed and then the stream endpoint
 +**                  is removed.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_RemoveStream(UINT8 handle)
 +{
 +    UINT16      result = AVDT_SUCCESS;
 +    tAVDT_SCB   *p_scb;
 +
 +    /* look up scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    else
 +    {
 +        /* send remove event to scb */
 +        avdt_scb_event(p_scb, AVDT_SCB_API_REMOVE_EVT, NULL);
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_DiscoverReq
 +**
 +** Description      This function initiates a connection to the AVDTP service
 +**                  on the peer device, if not already present, and discovers
 +**                  the stream endpoints on the peer device.  (Please note
 +**                  that AVDTP discovery is unrelated to SDP discovery).
 +**                  This function can be called at any time regardless of whether
 +**                  there is an AVDTP connection to the peer device.
 +**
 +**                  When discovery is complete, an AVDT_DISCOVER_CFM_EVT
 +**                  is sent to the application via its callback function.
 +**                  The application must not call AVDT_GetCapReq() or
 +**                  AVDT_DiscoverReq() again to the same device until
 +**                  discovery is complete.
 +**
 +**                  The memory addressed by sep_info is allocated by the
 +**                  application.  This memory is written to by AVDTP as part
 +**                  of the discovery procedure.  This memory must remain
 +**                  accessible until the application receives the
 +**                  AVDT_DISCOVER_CFM_EVT.
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO *p_sep_info,
 +                        UINT8 max_seps, tAVDT_CTRL_CBACK *p_cback)
 +{
 +    tAVDT_CCB       *p_ccb;
 +    UINT16          result = AVDT_SUCCESS;
 +    tAVDT_CCB_EVT   evt;
 +
 +    /* find channel control block for this bd addr; if none, allocate one */
 +    if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
 +    {
 +        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
 +        {
 +            /* could not allocate channel control block */
 +            result = AVDT_NO_RESOURCES;
 +        }
 +    }
 +
 +    if (result == AVDT_SUCCESS)
 +    {
 +        /* make sure no discovery or get capabilities req already in progress */
 +        if (p_ccb->proc_busy)
 +        {
 +            result = AVDT_BUSY;
 +        }
 +        /* send event to ccb */
 +        else
 +        {
 +            evt.discover.p_sep_info = p_sep_info;
 +            evt.discover.num_seps = max_seps;
 +            evt.discover.p_cback = p_cback;
 +            avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_REQ_EVT, &evt);
 +        }
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_get_cap_req
 +**
 +** Description      internal function to serve both AVDT_GetCapReq and
 +**                  AVDT_GetAllCapReq
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +static UINT16 avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP *p_evt)
 +{
 +    tAVDT_CCB       *p_ccb = NULL;
 +    UINT16          result = AVDT_SUCCESS;
 +
 +    /* verify SEID */
 +    if ((p_evt->single.seid < AVDT_SEID_MIN) || (p_evt->single.seid > AVDT_SEID_MAX))
 +    {
 +        AVDT_TRACE_ERROR("seid: %d\n", p_evt->single.seid);
 +        result = AVDT_BAD_PARAMS;
 +    }
 +    /* find channel control block for this bd addr; if none, allocate one */
 +    else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
 +    {
 +        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
 +        {
 +            /* could not allocate channel control block */
 +            result = AVDT_NO_RESOURCES;
 +        }
 +    }
 +
 +    if (result == AVDT_SUCCESS)
 +    {
 +        /* make sure no discovery or get capabilities req already in progress */
 +        if (p_ccb->proc_busy)
 +        {
 +            result = AVDT_BUSY;
 +        }
 +        /* send event to ccb */
 +        else
 +        {
 +            avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_REQ_EVT, (tAVDT_CCB_EVT *)p_evt);
 +        }
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_GetCapReq
 +**
 +** Description      This function initiates a connection to the AVDTP service
 +**                  on the peer device, if not already present, and gets the
 +**                  capabilities of a stream endpoint on the peer device.
 +**                  This function can be called at any time regardless of
 +**                  whether there is an AVDTP connection to the peer device.
 +**
 +**                  When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
 +**                  sent to the application via its callback function.  The
 +**                  application must not call AVDT_GetCapReq() or
 +**                  AVDT_DiscoverReq() again until the procedure is complete.
 +**
 +**                  The memory pointed to by p_cfg is allocated by the
 +**                  application.  This memory is written to by AVDTP as part
 +**                  of the get capabilities procedure.  This memory must
 +**                  remain accessible until the application receives
 +**                  the AVDT_GETCAP_CFM_EVT.
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_GetCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback)
 +{
 +    tAVDT_CCB_API_GETCAP    getcap;
 +
 +    getcap.single.seid = seid;
 +    getcap.single.sig_id = AVDT_SIG_GETCAP;
 +    getcap.p_cfg = p_cfg;
 +    getcap.p_cback = p_cback;
 +    return avdt_get_cap_req (bd_addr, &getcap);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_GetAllCapReq
 +**
 +** Description      This function initiates a connection to the AVDTP service
 +**                  on the peer device, if not already present, and gets the
 +**                  capabilities of a stream endpoint on the peer device.
 +**                  This function can be called at any time regardless of
 +**                  whether there is an AVDTP connection to the peer device.
 +**
 +**                  When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
 +**                  sent to the application via its callback function.  The
 +**                  application must not call AVDT_GetCapReq() or
 +**                  AVDT_DiscoverReq() again until the procedure is complete.
 +**
 +**                  The memory pointed to by p_cfg is allocated by the
 +**                  application.  This memory is written to by AVDTP as part
 +**                  of the get capabilities procedure.  This memory must
 +**                  remain accessible until the application receives
 +**                  the AVDT_GETCAP_CFM_EVT.
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_GetAllCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback)
 +{
 +    tAVDT_CCB_API_GETCAP    getcap;
 +
 +    getcap.single.seid = seid;
 +    getcap.single.sig_id = AVDT_SIG_GET_ALLCAP;
 +    getcap.p_cfg = p_cfg;
 +    getcap.p_cback = p_cback;
 +    return avdt_get_cap_req (bd_addr, &getcap);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_DelayReport
 +**
 +** Description      This functions sends a Delay Report to the peer device
 +**                  that is associated with a particular SEID.
 +**                  This function is called by SNK device.
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_DelayReport(UINT8 handle, UINT8 seid, UINT16 delay)
 +{
 +    tAVDT_SCB       *p_scb;
 +    UINT16          result = AVDT_SUCCESS;
 +    tAVDT_SCB_EVT   evt;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    else
 +    /* send event to scb */
 +    {
 +        evt.apidelay.hdr.seid   = seid;
 +        evt.apidelay.delay      = delay;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_DELAY_RPT_REQ_EVT, &evt);
 +    }
 +
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_OpenReq
 +**
 +** Description      This function initiates a connection to the AVDTP service
 +**                  on the peer device, if not already present, and connects
 +**                  to a stream endpoint on a peer device.  When the connection
 +**                  is completed, an AVDT_OPEN_CFM_EVT is sent to the
 +**                  application via the control callback function for this handle.
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_OpenReq(UINT8 handle, BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg)
 +{
 +    tAVDT_CCB       *p_ccb = NULL;
 +    tAVDT_SCB       *p_scb = NULL;
 +    UINT16          result = AVDT_SUCCESS;
 +    tAVDT_SCB_EVT   evt;
 +
 +    /* verify SEID */
 +    if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX))
 +    {
 +        result = AVDT_BAD_PARAMS;
 +    }
 +    /* map handle to scb */
 +    else if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    /* find channel control block for this bd addr; if none, allocate one */
 +    else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
 +    {
 +        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
 +        {
 +            /* could not allocate channel control block */
 +            result = AVDT_NO_RESOURCES;
 +        }
 +    }
 +
 +    /* send event to scb */
 +    if (result == AVDT_SUCCESS)
 +    {
 +        evt.msg.config_cmd.hdr.seid = seid;
 +        evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
 +        evt.msg.config_cmd.int_seid = handle;
 +        evt.msg.config_cmd.p_cfg = p_cfg;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_SETCONFIG_REQ_EVT, &evt);
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_ConfigRsp
 +**
 +** Description      Respond to a configure request from the peer device.  This
 +**                  function must be called if the application receives an
 +**                  AVDT_CONFIG_IND_EVT through its control callback.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_ConfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, UINT8 category)
 +{
 +    tAVDT_SCB       *p_scb;
 +    tAVDT_SCB_EVT   evt;
 +    UINT16          result = AVDT_SUCCESS;
 +    UINT8           event_code;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    /* handle special case when this function is called but peer has not send
 +    ** a configuration cmd; ignore and return error result
 +    */
 +    else if (!p_scb->in_use)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    /* send event to scb */
 +    else
 +    {
 +        evt.msg.hdr.err_code = error_code;
 +        evt.msg.hdr.err_param = category;
 +        evt.msg.hdr.label = label;
 +        if (error_code == 0)
 +        {
 +            event_code = AVDT_SCB_API_SETCONFIG_RSP_EVT;
 +        }
 +        else
 +        {
 +            event_code = AVDT_SCB_API_SETCONFIG_REJ_EVT;
 +        }
 +        avdt_scb_event(p_scb, event_code, &evt);
 +    }
 +
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_StartReq
 +**
 +** Description      Start one or more stream endpoints.  This initiates the
 +**                  transfer of media packets for the streams.  All stream
 +**                  endpoints must previously be opened.  When the streams
 +**                  are started, an AVDT_START_CFM_EVT is sent to the
 +**                  application via the control callback function for each stream.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_StartReq(UINT8 *p_handles, UINT8 num_handles)
 +{
 +    tAVDT_SCB       *p_scb = NULL;
 +    tAVDT_CCB_EVT   evt;
 +    UINT16          result = AVDT_SUCCESS;
 +    int             i;
 +
 +    if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS))
 +    {
 +        result = AVDT_BAD_PARAMS;
 +    }
 +    else
 +    {
 +        /* verify handles */
 +        for (i = 0; i < num_handles; i++)
 +        {
 +            if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == NULL)
 +            {
 +                result = AVDT_BAD_HANDLE;
 +                break;
 +            }
 +        }
 +    }
 +
 +    if (result == AVDT_SUCCESS)
 +    {
 +        if (p_scb->p_ccb == NULL)
 +        {
 +            result = AVDT_BAD_HANDLE;
 +        }
 +        else
 +        {
 +            /* send event to ccb */
 +            memcpy(evt.msg.multi.seid_list, p_handles, num_handles);
 +            evt.msg.multi.num_seps = num_handles;
 +            avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_START_REQ_EVT, &evt);
 +        }
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_SuspendReq
 +**
 +** Description      Suspend one or more stream endpoints. This suspends the
 +**                  transfer of media packets for the streams.  All stream
 +**                  endpoints must previously be open and started.  When the
 +**                  streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to
 +**                  the application via the control callback function for
 +**                  each stream.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_SuspendReq(UINT8 *p_handles, UINT8 num_handles)
 +{
 +    tAVDT_SCB       *p_scb = NULL;
 +    tAVDT_CCB_EVT   evt;
 +    UINT16          result = AVDT_SUCCESS;
 +    int             i;
 +
 +    if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS))
 +    {
 +        result = AVDT_BAD_PARAMS;
 +    }
 +    else
 +    {
 +        /* verify handles */
 +        for (i = 0; i < num_handles; i++)
 +        {
 +            if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == NULL)
 +            {
 +                result = AVDT_BAD_HANDLE;
 +                break;
 +            }
 +        }
 +    }
 +
 +    if (result == AVDT_SUCCESS)
 +    {
 +        if (p_scb->p_ccb == NULL)
 +        {
 +            result = AVDT_BAD_HANDLE;
 +        }
 +        else
 +        {
 +            /* send event to ccb */
 +            memcpy(evt.msg.multi.seid_list, p_handles, num_handles);
 +            evt.msg.multi.num_seps = num_handles;
 +            avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_SUSPEND_REQ_EVT, &evt);
 +        }
 +    }
 +
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_CloseReq
 +**
 +** Description      Close a stream endpoint.  This stops the transfer of media
 +**                  packets and closes the transport channel associated with
 +**                  this stream endpoint.  When the stream is closed, an
 +**                  AVDT_CLOSE_CFM_EVT is sent to the application via the
 +**                  control callback function for this handle.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_CloseReq(UINT8 handle)
 +{
 +    tAVDT_SCB       *p_scb;
 +    UINT16          result = AVDT_SUCCESS;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    else
 +    /* send event to scb */
 +    {
 +        avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_REQ_EVT, NULL);
 +    }
 +
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_ReconfigReq
 +**
 +** Description      Reconfigure a stream endpoint.  This allows the application
 +**                  to change the codec or content protection capabilities of
 +**                  a stream endpoint after it has been opened.  This function
 +**                  can only be called if the stream is opened but not started
 +**                  or if the stream has been suspended.  When the procedure
 +**                  is completed, an AVDT_RECONFIG_CFM_EVT is sent to the
 +**                  application via the control callback function for this handle.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_ReconfigReq(UINT8 handle, tAVDT_CFG *p_cfg)
 +{
 +    tAVDT_SCB       *p_scb;
 +    UINT16          result = AVDT_SUCCESS;
 +    tAVDT_SCB_EVT   evt;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    /* send event to scb */
 +    else
 +    {
 +        /* force psc_mask to zero */
 +        p_cfg->psc_mask = 0;
 +
 +        evt.msg.reconfig_cmd.p_cfg = p_cfg;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_REQ_EVT, &evt);
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_ReconfigRsp
 +**
 +** Description      Respond to a reconfigure request from the peer device.
 +**                  This function must be called if the application receives
 +**                  an AVDT_RECONFIG_IND_EVT through its control callback.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_ReconfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, UINT8 category)
 +{
 +    tAVDT_SCB       *p_scb;
 +    tAVDT_SCB_EVT   evt;
 +    UINT16          result = AVDT_SUCCESS;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    /* send event to scb */
 +    else
 +    {
 +        evt.msg.hdr.err_code = error_code;
 +        evt.msg.hdr.err_param = category;
 +        evt.msg.hdr.label = label;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, &evt);
 +    }
 +
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_SecurityReq
 +**
 +** Description      Send a security request to the peer device.  When the
 +**                  security procedure is completed, an AVDT_SECURITY_CFM_EVT
 +**                  is sent to the application via the control callback function
 +**                  for this handle.  (Please note that AVDTP security procedures
 +**                  are unrelated to Bluetooth link level security.)
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_SecurityReq(UINT8 handle, UINT8 *p_data, UINT16 len)
 +{
 +    tAVDT_SCB       *p_scb;
 +    UINT16          result = AVDT_SUCCESS;
 +    tAVDT_SCB_EVT   evt;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    /* send event to scb */
 +    else
 +    {
 +        evt.msg.security_rsp.p_data = p_data;
 +        evt.msg.security_rsp.len = len;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_REQ_EVT, &evt);
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_SecurityRsp
 +**
 +** Description      Respond to a security request from the peer device.
 +**                  This function must be called if the application receives
 +**                  an AVDT_SECURITY_IND_EVT through its control callback.
 +**                  (Please note that AVDTP security procedures are unrelated
 +**                  to Bluetooth link level security.)
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code,
 +                        UINT8 *p_data, UINT16 len)
 +{
 +    tAVDT_SCB       *p_scb;
 +    UINT16          result = AVDT_SUCCESS;
 +    tAVDT_SCB_EVT   evt;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    /* send event to scb */
 +    else
 +    {
 +        evt.msg.security_rsp.hdr.err_code = error_code;
 +        evt.msg.security_rsp.hdr.label = label;
 +        evt.msg.security_rsp.p_data = p_data;
 +        evt.msg.security_rsp.len = len;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, &evt);
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_WriteReqOpt
 +**
 +** Description      Send a media packet to the peer device.  The stream must
 +**                  be started before this function is called.  Also, this
 +**                  function can only be called if the stream is a SRC.
 +**
 +**                  When AVDTP has sent the media packet and is ready for the
 +**                  next packet, an AVDT_WRITE_CFM_EVT is sent to the
 +**                  application via the control callback.  The application must
 +**                  wait for the AVDT_WRITE_CFM_EVT before it makes the next
 +**                  call to AVDT_WriteReq().  If the applications calls
 +**                  AVDT_WriteReq() before it receives the event the packet
 +**                  will not be sent.  The application may make its first call
 +**                  to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
 +**                  or AVDT_START_IND_EVT.
 +**
 +**                  The application passes the packet using the BT_HDR structure.
 +**                  This structure is described in section 2.1.  The offset
 +**                  field must be equal to or greater than AVDT_MEDIA_OFFSET
 +**                  (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used).
 +**                  This allows enough space in the buffer for the L2CAP and
 +**                  AVDTP headers.
 +**
 +**                  The memory pointed to by p_pkt must be a GKI buffer
 +**                  allocated by the application.  This buffer will be freed
 +**                  by the protocol stack; the application must not free
 +**                  this buffer.
 +**
 +**                  The opt parameter allows passing specific options like:
 +**                  - NO_RTP : do not add the RTP header to buffer
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_WriteReqOpt(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt, tAVDT_DATA_OPT_MASK opt)
 +{
 +    tAVDT_SCB       *p_scb;
 +    tAVDT_SCB_EVT   evt;
 +    UINT16          result = AVDT_SUCCESS;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    else
 +    {
 +        evt.apiwrite.p_buf = p_pkt;
 +        evt.apiwrite.time_stamp = time_stamp;
 +        evt.apiwrite.m_pt = m_pt;
 +        evt.apiwrite.opt = opt;
 +#if AVDT_MULTIPLEXING == TRUE
 +        GKI_init_q (&evt.apiwrite.frag_q);
 +#endif
 +        avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt);
 +    }
 +
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_WriteReq
 +**
 +** Description      Send a media packet to the peer device.  The stream must
 +**                  be started before this function is called.  Also, this
 +**                  function can only be called if the stream is a SRC.
 +**
 +**                  When AVDTP has sent the media packet and is ready for the
 +**                  next packet, an AVDT_WRITE_CFM_EVT is sent to the
 +**                  application via the control callback.  The application must
 +**                  wait for the AVDT_WRITE_CFM_EVT before it makes the next
 +**                  call to AVDT_WriteReq().  If the applications calls
 +**                  AVDT_WriteReq() before it receives the event the packet
 +**                  will not be sent.  The application may make its first call
 +**                  to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
 +**                  or AVDT_START_IND_EVT.
 +**
 +**                  The application passes the packet using the BT_HDR structure.
 +**                  This structure is described in section 2.1.  The offset
 +**                  field must be equal to or greater than AVDT_MEDIA_OFFSET.
 +**                  This allows enough space in the buffer for the L2CAP and
 +**                  AVDTP headers.
 +**
 +**                  The memory pointed to by p_pkt must be a GKI buffer
 +**                  allocated by the application.  This buffer will be freed
 +**                  by the protocol stack; the application must not free
 +**                  this buffer.
 +**
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt)
 +{
 +    return AVDT_WriteReqOpt(handle, p_pkt, time_stamp, m_pt, AVDT_DATA_OPT_NONE);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_ConnectReq
 +**
 +** Description      This function initiates an AVDTP signaling connection
 +**                  to the peer device.  When the connection is completed, an
 +**                  AVDT_CONNECT_IND_EVT is sent to the application via its
 +**                  control callback function.  If the connection attempt fails
 +**                  an AVDT_DISCONNECT_IND_EVT is sent.  The security mask
 +**                  parameter overrides the outgoing security mask set in
 +**                  AVDT_Register().
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_ConnectReq(BD_ADDR bd_addr, UINT8 sec_mask, tAVDT_CTRL_CBACK *p_cback)
 +{
 +    tAVDT_CCB       *p_ccb = NULL;
 +    UINT16          result = AVDT_SUCCESS;
 +    tAVDT_CCB_EVT   evt;
 +
 +    /* find channel control block for this bd addr; if none, allocate one */
 +    if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
 +    {
 +        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
 +        {
 +            /* could not allocate channel control block */
 +            result = AVDT_NO_RESOURCES;
 +        }
 +    }
 +    else if (p_ccb->ll_opened == FALSE)
 +    {
 +        AVDT_TRACE_WARNING("AVDT_ConnectReq: CCB LL is in the middle of opening");
 +
 +        /* ccb was already allocated for the incoming signalling. */
 +        result = AVDT_BUSY;
 +    }
 +
 +    if (result == AVDT_SUCCESS)
 +    {
 +        /* send event to ccb */
 +        evt.connect.p_cback = p_cback;
 +        evt.connect.sec_mask = sec_mask;
 +        avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt);
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_DisconnectReq
 +**
 +** Description      This function disconnect an AVDTP signaling connection
 +**                  to the peer device.  When disconnected an
 +**                  AVDT_DISCONNECT_IND_EVT is sent to the application via its
 +**                  control callback function.
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK *p_cback)
 +{
 +    tAVDT_CCB       *p_ccb = NULL;
 +    UINT16          result = AVDT_SUCCESS;
 +    tAVDT_CCB_EVT   evt;
 +
 +    /* find channel control block for this bd addr; if none, error */
 +    if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
 +    {
 +        result = AVDT_BAD_PARAMS;
 +    }
 +
 +    if (result == AVDT_SUCCESS)
 +    {
 +        /* send event to ccb */
 +        evt.disconnect.p_cback = p_cback;
 +        avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCONNECT_REQ_EVT, &evt);
 +    }
 +    return result;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_GetL2CapChannel
 +**
 +** Description      Get the L2CAP CID used by the handle.
 +**
 +** Returns          CID if successful, otherwise 0.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_GetL2CapChannel(UINT8 handle)
 +{
 +    tAVDT_SCB       *p_scb;
 +    tAVDT_CCB       *p_ccb;
 +    UINT8           tcid;
 +    UINT16          lcid = 0;
 +
 +    /* map handle to scb */
 +    if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
 +     && ((p_ccb = p_scb->p_ccb) != NULL))
 +    {
 +        /* get tcid from type, scb */
 +        tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
 +
 +        lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
 +    }
 +
 +    return (lcid);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         AVDT_GetSignalChannel
 +**
 +** Description      Get the L2CAP CID used by the signal channel of the given handle.
 +**
 +** Returns          CID if successful, otherwise 0.
 +**
 +*******************************************************************************/
 +UINT16 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr)
 +{
 +    tAVDT_SCB       *p_scb;
 +    tAVDT_CCB       *p_ccb;
 +    UINT8           tcid = 0; /* tcid is always 0 for signal channel */
 +    UINT16          lcid = 0;
 +
 +    /* map handle to scb */
 +    if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
 +     && ((p_ccb = p_scb->p_ccb) != NULL))
 +    {
 +        lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
 +    }
 +    else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) != NULL)
 +    {
 +        lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
 +    }
 +
 +    return (lcid);
 +}
 +
 +#if AVDT_MULTIPLEXING == TRUE
 +/*******************************************************************************
 +**
 +** Function         AVDT_WriteDataReq
 +**
 +** Description      Send a media packet to the peer device.  The stream must
 +**                  be started before this function is called.  Also, this
 +**                  function can only be called if the stream is a SRC.
 +**
 +**                  When AVDTP has sent the media packet and is ready for the
 +**                  next packet, an AVDT_WRITE_CFM_EVT is sent to the
 +**                  application via the control callback.  The application must
 +**                  wait for the AVDT_WRITE_CFM_EVT before it makes the next
 +**                  call to AVDT_WriteDataReq().  If the applications calls
 +**                  AVDT_WriteDataReq() before it receives the event the packet
 +**                  will not be sent.  The application may make its first call
 +**                  to AVDT_WriteDataReq() after it receives an
 +**                  AVDT_START_CFM_EVT or AVDT_START_IND_EVT.
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +extern UINT16 AVDT_WriteDataReq(UINT8 handle, UINT8 *p_data, UINT32 data_len,
 +                                UINT32 time_stamp, UINT8 m_pt, UINT8 marker)
 +{
 +
 +    tAVDT_SCB       *p_scb;
 +    tAVDT_SCB_EVT   evt;
 +    UINT16          result = AVDT_SUCCESS;
 +
 +    do
 +    {
 +        /* check length of media frame */
 +        if(data_len > AVDT_MAX_MEDIA_SIZE)
 +        {
 +            result = AVDT_BAD_PARAMS;
 +            break;
 +        }
 +        /* map handle to scb */
 +        if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +        {
 +            result = AVDT_BAD_HANDLE;
 +            break;
 +        }
 +        AVDT_TRACE_WARNING("mux_tsid_media:%d\n", p_scb->curr_cfg.mux_tsid_media);
 +
 +        if (p_scb->p_pkt != NULL
 +            || p_scb->p_ccb == NULL
 +            || !GKI_queue_is_empty(&p_scb->frag_q)
 +            || p_scb->frag_off != 0
 +            || p_scb->curr_cfg.mux_tsid_media == 0)
 +        {
 +            result = AVDT_ERR_BAD_STATE;
++            AVDT_TRACE_WARNING("p_scb->p_pkt=%p, p_scb->p_ccb=%p, IsQueueEmpty=%x, p_scb->frag_off=%x\n",
 +                p_scb->p_pkt, p_scb->p_ccb, GKI_queue_is_empty(&p_scb->frag_q), p_scb->frag_off);
 +            break;
 +        }
 +        evt.apiwrite.p_buf = 0; /* it will indicate using of fragments queue frag_q */
 +        /* create queue of media fragments */
 +        GKI_init_q (&evt.apiwrite.frag_q);
 +
 +        /* compose fragments from media payload and put fragments into gueue */
 +        avdt_scb_queue_frags(p_scb, &p_data, &data_len, &evt.apiwrite.frag_q);
 +
 +        if(GKI_queue_is_empty(&evt.apiwrite.frag_q))
 +        {
 +            AVDT_TRACE_WARNING("AVDT_WriteDataReq out of GKI buffers");
 +            result = AVDT_ERR_RESOURCE;
 +            break;
 +        }
 +        evt.apiwrite.data_len = data_len;
 +        evt.apiwrite.p_data = p_data;
 +
 +        /* process the fragments queue */
 +        evt.apiwrite.time_stamp = time_stamp;
 +        evt.apiwrite.m_pt = m_pt | (marker<<7);
 +        avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt);
 +    } while (0);
 +
 +#if (BT_USE_TRACES == TRUE)
 +    if(result != AVDT_SUCCESS)
 +    {
 +        AVDT_TRACE_WARNING("*** AVDT_WriteDataReq failed result=%d\n",result);
 +    }
 +#endif
 +    return result;
 +}
 +#endif
 +
 +#if AVDT_MULTIPLEXING == TRUE
 +/*******************************************************************************
 +**
 +** Function         AVDT_SetMediaBuf
 +**
 +** Description      Assigns buffer for media packets or forbids using of assigned
 +**                  buffer if argument p_buf is NULL. This function can only
 +**                  be called if the stream is a SNK.
 +**
 +**                  AVDTP uses this buffer to reassemble fragmented media packets.
 +**                  When AVDTP receives a complete media packet, it calls the
 +**                  p_media_cback assigned by AVDT_CreateStream().
 +**                  This function can be called during callback to assign a
 +**                  different buffer for next media packet or can leave the current
 +**                  buffer for next packet.
 +**
 +** Returns          AVDT_SUCCESS if successful, otherwise error.
 +**
 +*******************************************************************************/
 +extern UINT16 AVDT_SetMediaBuf(UINT8 handle, UINT8 *p_buf, UINT32 buf_len)
 +{
 +    tAVDT_SCB       *p_scb;
 +    UINT16          result = AVDT_SUCCESS;
 +
 +    /* map handle to scb */
 +    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
 +    {
 +        result = AVDT_BAD_HANDLE;
 +    }
 +    else
 +    {
 +        if(p_buf && p_scb->cs.p_media_cback == NULL)
 +            result = AVDT_NO_RESOURCES;
 +        else
 +        {
 +            p_scb->p_media_buf = p_buf;
 +            p_scb->media_buf_len = buf_len;
 +        }
 +    }
 +
 +    return result;
 +}
 +#endif
 +
 +#if AVDT_REPORTING == TRUE
 +/*******************************************************************************
 +**
 +** Function         AVDT_SendReport
 +**
 +** Description
 +**
 +**
 +**
 +** Returns
 +**
 +*******************************************************************************/
 +UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type,
 +                       tAVDT_REPORT_DATA *p_data)
 +{
 +    tAVDT_SCB       *p_scb;
 +    UINT16          result = AVDT_BAD_PARAMS;
 +    BT_HDR          *p_pkt;
 +    tAVDT_TC_TBL    *p_tbl;
 +    UINT8           *p, *plen, *pm1, *p_end;
 +#if AVDT_MULTIPLEXING == TRUE
 +    UINT8           *p_al=NULL, u;
 +#endif
 +    UINT32  ssrc;
 +    UINT16  len;
 +
 +    /* map handle to scb && verify parameters */
 +    if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
 +     && (p_scb->p_ccb != NULL)
 +     && (((type == AVDT_RTCP_PT_SR) && (p_scb->cs.tsep == AVDT_TSEP_SRC)) ||
 +        ((type == AVDT_RTCP_PT_RR) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) ||
 +        (type == AVDT_RTCP_PT_SDES)) )
 +    {
 +        result = AVDT_NO_RESOURCES;
 +
 +        /* build SR - assume fit in one packet */
 +        p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
 +        if((p_tbl->state == AVDT_AD_ST_OPEN) &&
 +            (p_pkt = (BT_HDR *)GKI_getbuf(p_tbl->peer_mtu)) != NULL)
 +        {
 +            p_pkt->offset = L2CAP_MIN_OFFSET;
 +            p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
 +#if AVDT_MULTIPLEXING == TRUE
 +            if(p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX)
 +            {
 +                /* Adaptation Layer header later */
 +                p_al = p;
 +                p += 2;
 +            }
 +#endif
 +            pm1 = p;
 +            *p++ = AVDT_MEDIA_OCTET1 | 1;
 +            *p++ = type;
 +            /* save the location for length */
 +            plen = p;
 +            p+= 2;
 +            ssrc = avdt_scb_gen_ssrc(p_scb);
 +            UINT32_TO_BE_STREAM(p, ssrc);
 +
 +            switch(type)
 +            {
 +            case AVDT_RTCP_PT_SR:   /* Sender Report */
 +                *pm1 = AVDT_MEDIA_OCTET1;
 +                UINT32_TO_BE_STREAM(p, p_data->sr.ntp_sec);
 +                UINT32_TO_BE_STREAM(p, p_data->sr.ntp_frac);
 +                UINT32_TO_BE_STREAM(p, p_data->sr.rtp_time);
 +                UINT32_TO_BE_STREAM(p, p_data->sr.pkt_count);
 +                UINT32_TO_BE_STREAM(p, p_data->sr.octet_count);
 +                break;
 +
 +            case AVDT_RTCP_PT_RR:   /* Receiver Report */
 +                *p++ = p_data->rr.frag_lost;
 +                AVDT_TRACE_API("packet_lost: %d\n", p_data->rr.packet_lost);
 +                p_data->rr.packet_lost &= 0xFFFFFF;
 +                AVDT_TRACE_API("packet_lost: %d\n", p_data->rr.packet_lost);
 +                UINT24_TO_BE_STREAM(p, p_data->rr.packet_lost);
 +                UINT32_TO_BE_STREAM(p, p_data->rr.seq_num_rcvd);
 +                UINT32_TO_BE_STREAM(p, p_data->rr.jitter);
 +                UINT32_TO_BE_STREAM(p, p_data->rr.lsr);
 +                UINT32_TO_BE_STREAM(p, p_data->rr.dlsr);
 +                break;
 +
 +            case AVDT_RTCP_PT_SDES: /* Source Description */
 +                *p++ = AVDT_RTCP_SDES_CNAME;
 +                len = strlen((char *)p_data->cname);
 +                if(len > AVDT_MAX_CNAME_SIZE)
 +                    len = AVDT_MAX_CNAME_SIZE;
 +                *p++ = (UINT8)len;
 +                BCM_STRNCPY_S((char *)p, len+1, (char *)p_data->cname, len+1);
 +                p += len;
 +                break;
 +            }
 +            p_end = p;
 +            len = p - pm1 - 1;
 +            UINT16_TO_BE_STREAM(plen, len);
 +
 +#if AVDT_MULTIPLEXING == TRUE
 +            if(p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX)
 +            {
 +                /* Adaptation Layer header */
 +                p = p_al;
 +                len++;
 +                UINT16_TO_BE_STREAM(p_al, len );
 +                /* TSID, no-fragment bit and coding of length(9-bit length field) */
 +                u = *p;
 +                *p = (p_scb->curr_cfg.mux_tsid_report<<3) | AVDT_ALH_LCODE_9BITM0;
 +                if(u)
 +                    *p |= AVDT_ALH_LCODE_9BITM1;
 +            }
 +#endif
 +
 +            /* set the actual payload length */
 +            p_pkt->len = p_end - p;
 +            /* send the packet */
 +            if(L2CAP_DW_FAILED != avdt_ad_write_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, p_pkt))
 +                result = AVDT_SUCCESS;
 +        }
 +    }
 +
 +    return result;
 +}
 +#endif
 +
 +/******************************************************************************
 +**
 +** Function         AVDT_SetTraceLevel
 +**
 +** Description      Sets the trace level for AVDT. If 0xff is passed, the
 +**                  current trace level is returned.
 +**
 +**                  Input Parameters:
 +**                      new_level:  The level to set the AVDT tracing to:
 +**                      0xff-returns the current setting.
 +**                      0-turns off tracing.
 +**                      >= 1-Errors.
 +**                      >= 2-Warnings.
 +**                      >= 3-APIs.
 +**                      >= 4-Events.
 +**                      >= 5-Debug.
 +**
 +** Returns          The new trace level or current trace level if
 +**                  the input parameter is 0xff.
 +**
 +******************************************************************************/
 +UINT8 AVDT_SetTraceLevel (UINT8 new_level)
 +{
 +    if (new_level != 0xFF)
 +        avdt_cb.trace_level = new_level;
 +
 +    return (avdt_cb.trace_level);
 +}
index fa57f0f2a04acc6083e21654f4ffde9d90628eeb,0000000000000000000000000000000000000000..eb2227c6bed53b7ff5e8fb8c7e109bab3be3e321
mode 100755,000000..100755
--- /dev/null
@@@ -1,2175 -1,0 +1,2175 @@@
-             AVDT_TRACE_WARNING("p_end: 0x%x - p:0x%x < 4\n", p_end, p);
 +/******************************************************************************
 + *
 + *  Copyright (C) 2002-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.
 + *
 + ******************************************************************************/
 +
 +/******************************************************************************
 + *
 + *  This module contains the action functions associated with the stream
 + *  control block state machine.
 + *
 + ******************************************************************************/
 +
 +#include <string.h>
 +#include "bt_types.h"
 +#include "bt_target.h"
 +#include "bt_utils.h"
 +#include "avdt_api.h"
 +#include "avdtc_api.h"
 +#include "avdt_int.h"
 +#include "gki.h"
 +#include "btu.h"
 +
 +/* This table is used to lookup the callback event that matches a particular
 +** state machine API request event.  Note that state machine API request
 +** events are at the beginning of the event list starting at zero, thus
 +** allowing for this table.
 +*/
 +const UINT8 avdt_scb_cback_evt[] = {
 +    0,                          /* API_REMOVE_EVT (no event) */
 +    AVDT_WRITE_CFM_EVT,         /* API_WRITE_REQ_EVT */
 +    0,                          /* API_GETCONFIG_REQ_EVT (no event) */
 +    0,                          /* API_DELAY_RPT_REQ_EVT (no event) */
 +    AVDT_OPEN_CFM_EVT,          /* API_SETCONFIG_REQ_EVT */
 +    AVDT_OPEN_CFM_EVT,          /* API_OPEN_REQ_EVT */
 +    AVDT_CLOSE_CFM_EVT,         /* API_CLOSE_REQ_EVT */
 +    AVDT_RECONFIG_CFM_EVT,      /* API_RECONFIG_REQ_EVT */
 +    AVDT_SECURITY_CFM_EVT,      /* API_SECURITY_REQ_EVT */
 +    0                           /* API_ABORT_REQ_EVT (no event) */
 +};
 +
 +/* This table is used to look up the callback event based on the signaling
 +** role when the stream is closed.
 +*/
 +const UINT8 avdt_scb_role_evt[] = {
 +    AVDT_CLOSE_IND_EVT,         /* AVDT_CLOSE_ACP */
 +    AVDT_CLOSE_CFM_EVT,         /* AVDT_CLOSE_INT */
 +    AVDT_CLOSE_IND_EVT,         /* AVDT_OPEN_ACP */
 +    AVDT_OPEN_CFM_EVT           /* AVDT_OPEN_INT */
 +};
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_gen_ssrc
 +**
 +** Description      This function generates a SSRC number unique to the stream.
 +**
 +** Returns          SSRC value.
 +**
 +*******************************************************************************/
 +UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb)
 +{
 +    /* combine the value of the media type and codec type of the SCB */
 +    return ((UINT32)(p_scb->cs.cfg.codec_info[1] | p_scb->cs.cfg.codec_info[2]));
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_abort_cmd
 +**
 +** Description      This function sends the SCB an AVDT_SCB_API_ABORT_RSP_EVT
 +**                  to initiate sending of an abort response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    p_scb->role = AVDT_CLOSE_ACP;
 +    avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_RSP_EVT, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_abort_rsp
 +**
 +** Description      This function is an empty function; it serves as a
 +**                  placeholder for a conformance API action function.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_scb);
 +    UNUSED(p_data);
 +    return;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_close_cmd
 +**
 +** Description      This function sends the SCB an AVDT_SCB_API_CLOSE_RSP_EVT
 +**                  to initiate sending of a close response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    p_scb->role = AVDT_CLOSE_ACP;
 +    avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_RSP_EVT, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_close_rsp
 +**
 +** Description      This function sets the close_code variable to the error
 +**                  code returned in the close response.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    p_scb->close_code = p_data->msg.hdr.err_code;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_getconfig_cmd
 +**
 +** Description      This function retrieves the configuration parameters of
 +**                  the SCB and sends the SCB an AVDT_SCB_API_GETCONFIG_RSP_EVT
 +**                  to initiate sending of a get configuration response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb,tAVDT_SCB_EVT *p_data)
 +{
 +    p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
 +
 +    avdt_scb_event(p_scb, AVDT_SCB_API_GETCONFIG_RSP_EVT, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_getconfig_rsp
 +**
 +** Description      This function is an empty function; it serves as a
 +**                  placeholder for a conformance API action function.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_scb);
 +    UNUSED(p_data);
 +    return;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_open_cmd
 +**
 +** Description      This function sends the SCB an AVDT_SCB_API_OPEN_RSP_EVT
 +**                  to initiate sending of an open response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_RSP_EVT, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_open_rej
 +**
 +** Description      This function calls the application callback function
 +**                  indicating the open request has failed.  It initializes
 +**                  certain SCB variables and sends a AVDT_CCB_UL_CLOSE_EVT
 +**                  to the CCB.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    /* do exactly same as setconfig reject */
 +    avdt_scb_hdl_setconfig_rej(p_scb, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_open_rsp
 +**
 +** Description      This function calls avdt_ad_open_req() to initiate
 +**                  connection of the transport channel for this stream.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    /* initiate opening of trans channels for this SEID */
 +    p_scb->role = AVDT_OPEN_INT;
 +    avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_INT);
 +
 +    /* start tc connect timer */
 +    btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_CONN_TOUT);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_pkt_no_frag
 +**
 +** Description
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UINT8   *p, *p_start;
 +    UINT8   o_v, o_p, o_x, o_cc;
 +    UINT8   m_pt;
 +    UINT8   marker;
 +    UINT16  seq;
 +    UINT32  time_stamp;
 +    UINT16  offset;
 +    UINT16  ex_len;
 +    UINT8   pad_len = 0;
 +
 +    p = p_start = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
 +
 +    /* parse media packet header */
 +    AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc);
 +    AVDT_MSG_PRS_M_PT(p, m_pt, marker);
 +    BE_STREAM_TO_UINT16(seq, p);
 +    BE_STREAM_TO_UINT32(time_stamp, p);
 +    p += 4;
 +
 +    UNUSED(o_v);
 +
 +    /* skip over any csrc's in packet */
 +    p += o_cc * 4;
 +
 +    /* check for and skip over extension header */
 +    if (o_x)
 +    {
 +        p += 2;
 +        BE_STREAM_TO_UINT16(ex_len, p);
 +        p += ex_len * 4;
 +    }
 +
 +    /* save our new offset */
 +    offset = (UINT16) (p - p_start);
 +
 +    /* adjust length for any padding at end of packet */
 +    if (o_p)
 +    {
 +        /* padding length in last byte of packet */
 +        pad_len =  *(p_start + p_data->p_pkt->len);
 +    }
 +
 +    /* do sanity check */
 +    if ((offset > p_data->p_pkt->len) || ((pad_len + offset) > p_data->p_pkt->len))
 +    {
 +        AVDT_TRACE_WARNING("Got bad media packet");
 +        GKI_freebuf(p_data->p_pkt);
 +    }
 +    /* adjust offset and length and send it up */
 +    else
 +    {
 +        p_data->p_pkt->len -= (offset + pad_len);
 +        p_data->p_pkt->offset += offset;
 +
 +        if (p_scb->cs.p_data_cback != NULL)
 +        {
 +            /* report sequence number */
 +            p_data->p_pkt->layer_specific = seq;
 +            (*p_scb->cs.p_data_cback)(avdt_scb_to_hdl(p_scb), p_data->p_pkt,
 +                time_stamp, (UINT8)(m_pt | (marker<<7)));
 +        }
 +        else
 +        {
 +#if AVDT_MULTIPLEXING == TRUE
 +            if ((p_scb->cs.p_media_cback != NULL)
 +             && (p_scb->p_media_buf != NULL)
 +             && (p_scb->media_buf_len > p_data->p_pkt->len))
 +            {
 +                /* media buffer enough length is assigned by application. Lets use it*/
 +                memcpy(p_scb->p_media_buf,(UINT8*)(p_data->p_pkt + 1) + p_data->p_pkt->offset,
 +                    p_data->p_pkt->len);
 +                (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb),p_scb->p_media_buf,
 +                    p_scb->media_buf_len,time_stamp,seq,m_pt,marker);
 +            }
 +#endif
 +            GKI_freebuf(p_data->p_pkt);
 +        }
 +    }
 +}
 +
 +#if AVDT_REPORTING == TRUE
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_report
 +**
 +** Description
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +UINT8 * avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len)
 +{
 +    UINT16  result = AVDT_SUCCESS;
 +    UINT8   *p_start = p;
 +    UINT32  ssrc;
 +    UINT8   o_v, o_p, o_cc;
 +    AVDT_REPORT_TYPE    pt;
 +    tAVDT_REPORT_DATA   report, *p_rpt;
 +
 +    AVDT_TRACE_DEBUG( "avdt_scb_hdl_report");
 +    if(p_scb->cs.p_report_cback)
 +    {
 +        p_rpt = &report;
 +        /* parse report packet header */
 +        AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc);
 +        pt = *p++;
 +        p += 2;
 +        BE_STREAM_TO_UINT32(ssrc, p);
 +
 +        UNUSED(o_p);
 +        UNUSED(o_v);
 +
 +        switch(pt)
 +        {
 +        case AVDT_RTCP_PT_SR:   /* the packet type - SR (Sender Report) */
 +            BE_STREAM_TO_UINT32(report.sr.ntp_sec, p);
 +            BE_STREAM_TO_UINT32(report.sr.ntp_frac, p);
 +            BE_STREAM_TO_UINT32(report.sr.rtp_time, p);
 +            BE_STREAM_TO_UINT32(report.sr.pkt_count, p);
 +            BE_STREAM_TO_UINT32(report.sr.octet_count, p);
 +            break;
 +
 +        case AVDT_RTCP_PT_RR:   /* the packet type - RR (Receiver Report) */
 +            report.rr.frag_lost = *p;
 +            BE_STREAM_TO_UINT32(report.rr.packet_lost, p);
 +            report.rr.packet_lost &= 0xFFFFFF;
 +            BE_STREAM_TO_UINT32(report.rr.seq_num_rcvd, p);
 +            BE_STREAM_TO_UINT32(report.rr.jitter, p);
 +            BE_STREAM_TO_UINT32(report.rr.lsr, p);
 +            BE_STREAM_TO_UINT32(report.rr.dlsr, p);
 +            break;
 +
 +        case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */
 +            if(*p == AVDT_RTCP_SDES_CNAME)
 +            {
 +                p_rpt = (tAVDT_REPORT_DATA *)(p+2);
 +            }
 +            else
 +            {
 +                AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d %s\n",
 +                    ssrc, o_cc, *p, *(p+1), p+2);
 +                result = AVDT_BUSY;
 +            }
 +            break;
 +
 +        default:
 +            AVDT_TRACE_ERROR( "Bad Report pkt - packet type: %d\n", pt);
 +            result = AVDT_BAD_PARAMS;
 +        }
 +
 +        if(result == AVDT_SUCCESS)
 +            (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt);
 +
 +    }
 +    p_start += len;
 +    return p_start;
 +}
 +#endif
 +
 +#if AVDT_MULTIPLEXING == TRUE
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_pkt_frag
 +**
 +** Description
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_pkt_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    /* Fields of Adaptation Layer Header */
 +    UINT8   al_tsid,al_frag,al_lcode;
 +    UINT16  al_len;
 +    /* media header fields */
 +    UINT8   o_v, o_p, o_x, o_cc;
 +    UINT8   m_pt;
 +    UINT8   marker;
 +    UINT16  seq;
 +    UINT32  time_stamp;
 +    UINT32  ssrc;
 +    UINT16  ex_len;
 +    UINT8   pad_len;
 +    /* other variables */
 +    UINT8   *p; /* current pointer */
 +    UINT8   *p_end; /* end of all packet */
 +    UINT8   *p_payload; /* pointer to media fragment payload in the buffer */
 +    UINT32  payload_len; /* payload length */
 +    UINT16  frag_len; /* fragment length */
 +
 +    p = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
 +    p_end = p + p_data->p_pkt->len;
 +    /* parse all fragments */
 +    while(p < p_end)
 +    {
 +        if (p_end - p < 4) /* length check. maximum length of AL header = 4 */
 +        {
-                     AVDT_TRACE_WARNING("length check frag_off:%d p_media_buf:%d p_payload:%d\n",
++            AVDT_TRACE_WARNING("p_end: %p - p:%p < 4\n", p_end, p);
 +            break;
 +        }
 +
 +        /* parse first byte */
 +        al_tsid = (*p)>>3;
 +        al_frag = ( (*p) >> 2 ) & 0x01;
 +        al_lcode = (*p++) & AVDT_ALH_LCODE_MASK;
 +
 +        /* in case of TSID=00000, a second AL header byte, before the length field,
 +        ** is expected and contains the actual TSID, aligned with MSB */
 +        if(al_tsid == 0)
 +            al_tsid = *p++;
 +
 +        /* get remaining media length on base of lcode */
 +        switch(al_lcode)
 +        {
 +        case AVDT_ALH_LCODE_NONE:  /* No length field present. Take length from l2cap */
 +            al_len = (UINT16)(p_end - p);
 +            break;
 +        case AVDT_ALH_LCODE_16BIT:  /* 16 bit length field */
 +            BE_STREAM_TO_UINT16(al_len, p);
 +            break;
 +        case AVDT_ALH_LCODE_9BITM0:  /* 9 bit length field, MSB = 0, 8 LSBs in 1 octet following */
 +            al_len = *p++;
 +            break;
 +        default:    /* 9 bit length field, MSB = 1, 8 LSBs in 1 octet following */
 +            al_len =(UINT16)*p++ + 0x100;
 +        }
 +
 +        /* max fragment length */
 +        frag_len = (UINT16)(p_end - p);
 +        /* if it isn't last fragment */
 +        if(frag_len >= al_len)
 +            frag_len = al_len;
 +
 +        /* check TSID corresponds to config */
 +        if (al_tsid != p_scb->curr_cfg.mux_tsid_media)
 +        {
 +#if AVDT_REPORTING == TRUE
 +            if((p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) &&
 +                (al_tsid == p_scb->curr_cfg.mux_tsid_report))
 +            {
 +                /* parse reporting packet */
 +                p = avdt_scb_hdl_report(p_scb, p, frag_len);
 +                continue;
 +            }
 +            else
 +#endif
 +            {
 +                AVDT_TRACE_WARNING("bad tsid: %d, mux_tsid_media:%d\n", al_tsid, p_scb->curr_cfg.mux_tsid_media);
 +                break;
 +            }
 +        }
 +        /* check are buffer for assembling and related callback set */
 +        else if ((p_scb->p_media_buf == NULL) || (p_scb->cs.p_media_cback == NULL))
 +        {
 +            AVDT_TRACE_WARNING("NULL p_media_buf or p_media_cback");
 +            break;
 +        }
 +
 +
 +        /* it is media fragment beginning */
 +        if(!al_frag) /* is it first fragment of original media packet */
 +        {
 +            AVDT_TRACE_DEBUG("al:%d media:%d\n",
 +                al_len, p_scb->media_buf_len);
 +
 +            p_scb->frag_off = 0;
 +            p_scb->frag_org_len = al_len; /* total length of original media packet */
 +            /* length check: minimum length of media header is 12 */
 +            if (p_scb->frag_org_len < 12)
 +            {
 +                AVDT_TRACE_WARNING("bad al_len: %d(<12)\n", al_len);
 +                break;
 +            }
 +            /* check that data fit into buffer */
 +            if (al_len > p_scb->media_buf_len)
 +            {
 +                AVDT_TRACE_WARNING("bad al_len: %d(>%d)\n", al_len, p_scb->media_buf_len);
 +                break;
 +            }
 +            /* make sure it is the last fragment in l2cap packet */
 +            if (p + al_len < p_end)
 +            {
 +                AVDT_TRACE_WARNING("bad al_len: %d(>%d)\n", al_len, p_scb->media_buf_len);
 +                break;
 +            }
 +        }
 +        else
 +        {
 +            AVDT_TRACE_DEBUG("al:%d media:%d frag_org_len:%d frag_off:%d\n",
 +                al_len, p_scb->media_buf_len, p_scb->frag_org_len, p_scb->frag_off);
 +
 +            /* check that remaining length from AL header equals to original len - length of already received fragments */
 +            if(al_len != p_scb->frag_org_len - p_scb->frag_off)
 +            {
 +                AVDT_TRACE_WARNING("al_len:%d != (frag_org_len:%d - frag_off:%d) %d\n",
 +                    al_len, p_scb->frag_org_len, p_scb->frag_off,
 +                    (p_scb->frag_org_len- p_scb->frag_off));
 +                break;
 +            }
 +
 +            /* do sanity check */
 +            if (p_scb->frag_off == 0)
 +            {
 +                AVDT_TRACE_WARNING("frag_off=0");
 +                break;
 +            }
 +        }
 +        /* do common sanity check */
 +        if((p_scb->frag_org_len <= p_scb->frag_off) || (p_scb->frag_org_len >= p_scb->media_buf_len))
 +        {
 +            AVDT_TRACE_WARNING("common sanity frag_off:%d frag_org_len:%d media_buf_len:%d\n",
 +                p_scb->frag_off, p_scb->frag_org_len, p_scb->media_buf_len);
 +            break;
 +        }
 +
 +        AVDT_TRACE_DEBUG("Received fragment org_len=%d off=%d al_len=%d frag_len=%d\n",
 +            p_scb->frag_org_len, p_scb->frag_off, al_len, frag_len);
 +
 +        /* copy fragment into buffer */
 +        memcpy(p_scb->p_media_buf + p_scb->frag_off, p, frag_len);
 +        p_scb->frag_off += frag_len;
 +        /* move to the next fragment */
 +        p += frag_len;
 +        /* if it is last fragment in original media packet then process total media pocket */
 +        if(p_scb->frag_off == p_scb->frag_org_len)
 +        {
 +            p_payload = p_scb->p_media_buf;
 +
 +            /* media header */
 +            AVDT_MSG_PRS_OCTET1(p_payload, o_v, o_p, o_x, o_cc);
 +            AVDT_MSG_PRS_M_PT(p_payload, m_pt, marker);
 +            BE_STREAM_TO_UINT16(seq, p_payload);
 +            BE_STREAM_TO_UINT32(time_stamp, p_payload);
 +            BE_STREAM_TO_UINT32(ssrc, p_payload);
 +
 +            UNUSED(o_v);
 +            UNUSED(ssrc);
 +
 +            /* skip over any csrc's in packet */
 +            p_payload += o_cc * 4;
 +
 +            /* check for and skip over extension header */
 +            if (o_x)
 +            {
 +                if(p_scb->p_media_buf + p_scb->frag_off - p_payload < 4)
 +                {
-                 AVDT_TRACE_WARNING("length check2 frag_off:%d p_media_buf:%d p_payload:%d\n",
++                    AVDT_TRACE_WARNING("length check frag_off:%d p_media_buf:%p p_payload:%p\n",
 +                        p_scb->frag_off, p_scb->p_media_buf, p_payload);
 +                    break;/* length check */
 +                }
 +                p_payload += 2;
 +                BE_STREAM_TO_UINT16(ex_len, p_payload);
 +                p_payload += ex_len * 4;
 +            }
 +
 +            if(p_payload >= p_scb->p_media_buf + p_scb->frag_off)
 +            {
++                AVDT_TRACE_WARNING("length check2 frag_off:%d p_media_buf:%p p_payload:%p\n",
 +                    p_scb->frag_off, p_scb->p_media_buf, p_payload);
 +                break;/* length check */
 +            }
 +
 +            /* adjust length for any padding at end of packet */
 +            if (o_p)
 +            {
 +                /* padding length in last byte of packet */
 +                pad_len =  *(p_scb->p_media_buf + p_scb->frag_off - 1);
 +            }
 +            else
 +                pad_len =  0;
 +            /* payload length */
 +            payload_len = (UINT32)(p_scb->p_media_buf + p_scb->frag_off - pad_len - p_payload);
 +
 +            AVDT_TRACE_DEBUG("Received last fragment header=%d len=%d\n",
 +                p_payload - p_scb->p_media_buf,payload_len);
 +
 +            /* send total media packet up */
 +            if (p_scb->cs.p_media_cback != NULL)
 +            {
 +                (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb), p_payload,
 +                                           payload_len, time_stamp, seq, m_pt, marker);
 +            }
 +        }
 +    } /* while(p < p_end) */
 +
 +    if(p < p_end)
 +    {
 +        AVDT_TRACE_WARNING("*** Got bad media packet");
 +    }
 +    GKI_freebuf(p_data->p_pkt);
 +}
 +#endif
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_pkt
 +**
 +** Description
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +#if AVDT_REPORTING == TRUE
 +    UINT8 *p;
 +#endif
 +
 +#if AVDT_MULTIPLEXING == TRUE
 +    /* select right function in dependance of is fragmentation supported or not */
 +    if( 0 != (p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX))
 +    {
 +        avdt_scb_hdl_pkt_frag(p_scb, p_data);
 +    }
 +    else
 +#endif
 +#if AVDT_REPORTING == TRUE
 +    if(p_data->p_pkt->layer_specific == AVDT_CHAN_REPORT)
 +    {
 +        p = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
 +        avdt_scb_hdl_report(p_scb, p, p_data->p_pkt->len);
 +        GKI_freebuf(p_data->p_pkt);
 +    }
 +    else
 +#endif
 +        avdt_scb_hdl_pkt_no_frag(p_scb, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_drop_pkt
 +**
 +** Description      Drop an incoming media packet.  This function is called if
 +**                  a media packet is received in any state besides streaming.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_scb);
 +
 +    GKI_freebuf(p_data->p_pkt);
 +    AVDT_TRACE_ERROR(" avdt_scb_drop_pkt Dropped incoming media packet");
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_reconfig_cmd
 +**
 +** Description      This function calls the application callback function
 +**                  with a reconfiguration indication.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    /* if command not supported */
 +    if (p_scb->cs.nsc_mask & AVDT_NSC_RECONFIG)
 +    {
 +        /* send reject */
 +        p_data->msg.hdr.err_code = AVDT_ERR_NSC;
 +        p_data->msg.hdr.err_param = 0;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, p_data);
 +    }
 +    else
 +    {
 +        /* store requested configuration */
 +        memcpy(&p_scb->req_cfg, p_data->msg.reconfig_cmd.p_cfg, sizeof(tAVDT_CFG));
 +
 +        /* call application callback */
 +        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                                  NULL,
 +                                  AVDT_RECONFIG_IND_EVT,
 +                                  (tAVDT_CTRL *) &p_data->msg.reconfig_cmd);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_reconfig_rsp
 +**
 +** Description      This function calls the application callback function
 +**                  with a reconfiguration confirm.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    if (p_data->msg.hdr.err_code == 0)
 +    {
 +        /* store new configuration */
 +        if (p_scb->req_cfg.num_codec > 0)
 +        {
 +            p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
 +            memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE);
 +        }
 +        if (p_scb->req_cfg.num_protect > 0)
 +        {
 +            p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
 +            memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE);
 +        }
 +    }
 +
 +    p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
 +
 +    /* call application callback */
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              NULL,
 +                              AVDT_RECONFIG_CFM_EVT,
 +                              (tAVDT_CTRL *) &p_data->msg.svccap);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_security_cmd
 +**
 +** Description      This function calls the application callback with a
 +**                  security indication.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    /* if command not supported */
 +    if (p_scb->cs.nsc_mask & AVDT_NSC_SECURITY)
 +    {
 +        /* send reject */
 +        p_data->msg.hdr.err_code = AVDT_ERR_NSC;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, p_data);
 +    }
 +    else
 +    {
 +        /* call application callback */
 +        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                                  NULL,
 +                                  AVDT_SECURITY_IND_EVT,
 +                                  (tAVDT_CTRL *) &p_data->msg.security_cmd);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_security_rsp
 +**
 +** Description      This function calls the application callback with a
 +**                  security confirm.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    /* call application callback */
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              NULL,
 +                              AVDT_SECURITY_CFM_EVT,
 +                              (tAVDT_CTRL *) &p_data->msg.security_cmd);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_setconfig_cmd
 +**
 +** Description      This function marks the SCB as in use and copies the
 +**                  configuration and peer SEID to the SCB.  It then calls
 +**                  the application callback with a configuration indication.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_CFG *p_cfg;
 +
 +    if (!p_scb->in_use)
 +    {
 +        p_cfg = p_data->msg.config_cmd.p_cfg;
 +        if(p_scb->cs.cfg.codec_info[AVDT_CODEC_TYPE_INDEX] == p_cfg->codec_info[AVDT_CODEC_TYPE_INDEX])
 +        {
 +            /* set sep as in use */
 +            p_scb->in_use = TRUE;
 +
 +            /* copy info to scb */
 +            p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
 +            p_scb->peer_seid = p_data->msg.config_cmd.int_seid;
 +            memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG));
 +            /* call app callback */
 +            (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), /* handle of scb- which is same as sep handle of bta_av_cb.p_scb*/
 +                                      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                                      AVDT_CONFIG_IND_EVT,
 +                                      (tAVDT_CTRL *) &p_data->msg.config_cmd);
 +        }
 +        else
 +        {
 +            p_data->msg.hdr.err_code = AVDT_ERR_UNSUP_CFG;
 +            p_data->msg.hdr.err_param = 0;
 +            avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
 +                              p_data->msg.hdr.sig_id, &p_data->msg);
 +        }
 +    }
 +    else
 +    {
 +        avdt_scb_rej_in_use(p_scb, p_data);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_setconfig_rej
 +**
 +** Description      This function marks the SCB as not in use and calls the
 +**                  application callback with an open confirm indicating failure.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    /* clear scb variables */
 +    avdt_scb_clr_vars(p_scb, p_data);
 +
 +    /* tell ccb we're done with signaling channel */
 +    avdt_ccb_event(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_CCB_UL_CLOSE_EVT, NULL);
 +
 +    /* call application callback */
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              NULL,
 +                              AVDT_OPEN_CFM_EVT,
 +                              (tAVDT_CTRL *) &p_data->msg.hdr);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_setconfig_rsp
 +**
 +** Description      This function sends the SCB an AVDT_SCB_API_OPEN_REQ_EVT
 +**                  to initiate sending of an open command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_EVT_HDR   single;
 +    UNUSED(p_data);
 +
 +    if (p_scb->p_ccb != NULL)
 +    {
 +        /* save configuration */
 +        memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
 +
 +        /* initiate open */
 +        single.seid = p_scb->peer_seid;
 +        avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT *) &single);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_start_cmd
 +**
 +** Description      This function calls the application callback with a
 +**                  start indication.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                              AVDT_START_IND_EVT,
 +                              NULL);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_start_rsp
 +**
 +** Description      This function calls the application callback with a
 +**                  start confirm.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                              AVDT_START_CFM_EVT,
 +                              (tAVDT_CTRL *) &p_data->msg.hdr);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_suspend_cmd
 +**
 +** Description      This function calls the application callback with a suspend
 +**                  indication.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                              AVDT_SUSPEND_IND_EVT,
 +                              NULL);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_suspend_rsp
 +**
 +** Description      This function calls the application callback with a suspend
 +**                  confirm.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                              AVDT_SUSPEND_CFM_EVT,
 +                              (tAVDT_CTRL *) &p_data->msg.hdr);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_tc_close
 +**
 +** Description      This function is called when the transport channel is
 +**                  closed.  It marks the SCB as not in use and
 +**                  initializes certain SCB parameters.  It then sends
 +**                  an AVDT_CCB_UL_CLOSE_EVT to the CCB if the SCB
 +**                  initiated the close.  It then checks to see if the SCB
 +**                  is to be removed.  If it is it deallocates the SCB.  Finally,
 +**                  it calls the application callback with a close indication.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UINT8               hdl = avdt_scb_to_hdl(p_scb);
 +    tAVDT_CTRL_CBACK    *p_ctrl_cback = p_scb->cs.p_ctrl_cback;
 +    tAVDT_CTRL          avdt_ctrl;
 +    UINT8               event;
 +    tAVDT_CCB           *p_ccb = p_scb->p_ccb;
 +    BD_ADDR remote_addr;
 +
 +
 +    memcpy (remote_addr, p_ccb->peer_addr, BD_ADDR_LEN);
 +
 +    /* set up hdr */
 +    avdt_ctrl.hdr.err_code = p_scb->close_code;
 +
 +    /* clear sep variables */
 +    avdt_scb_clr_vars(p_scb, p_data);
 +    p_scb->media_seq = 0;
 +    p_scb->cong = FALSE;
 +
 +    /* free pkt we're holding, if any */
 +    if (p_scb->p_pkt != NULL)
 +    {
 +        GKI_freebuf(p_scb->p_pkt);
 +        p_scb->p_pkt = NULL;
 +    }
 +
 +    /* stop transport channel timer */
 +    btu_stop_timer(&p_scb->timer_entry);
 +
 +    if ((p_scb->role == AVDT_CLOSE_INT) || (p_scb->role == AVDT_OPEN_INT))
 +    {
 +        /* tell ccb we're done with signaling channel */
 +        avdt_ccb_event(p_ccb, AVDT_CCB_UL_CLOSE_EVT, NULL);
 +    }
 +    event = (p_scb->role == AVDT_CLOSE_INT) ? AVDT_CLOSE_CFM_EVT : AVDT_CLOSE_IND_EVT;
 +    p_scb->role = AVDT_CLOSE_ACP;
 +
 +    if (p_scb->remove)
 +    {
 +        avdt_scb_dealloc(p_scb, NULL);
 +    }
 +
 +    /* call app callback */
 +    (*p_ctrl_cback)(hdl, remote_addr, event, &avdt_ctrl);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_delay_rpt_req
 +**
 +** Description      This function calls the application callback with a delay
 +**                  report.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_delay_rpt_req (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT, (tAVDT_MSG *) &p_data->apidelay);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_delay_rpt_cmd
 +**
 +** Description      This function calls the application callback with a delay
 +**                  report.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_delay_rpt_cmd (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                              AVDT_DELAY_REPORT_EVT,
 +                              (tAVDT_CTRL *) &p_data->msg.hdr);
 +
 +    if (p_scb->p_ccb)
 +        avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_DELAY_RPT, &p_data->msg);
 +    else
 +        avdt_scb_rej_not_in_use(p_scb, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_delay_rpt_rsp
 +**
 +** Description      This function calls the application callback with a delay
 +**                  report.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_delay_rpt_rsp (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                              AVDT_DELAY_REPORT_CFM_EVT,
 +                              (tAVDT_CTRL *) &p_data->msg.hdr);
 +}
 +
 +#if AVDT_REPORTING == TRUE
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_tc_close_sto
 +**
 +** Description      This function is called when a channel is closed in OPEN
 +**                  state.  Check the channel type and process accordingly.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_CTRL          avdt_ctrl;
 +    /* AVDT_CHAN_SIG does not visit this action */
 +    if(p_data && p_data->close.type != AVDT_CHAN_MEDIA)
 +    {
 +        /* it's reporting or recovery channel,
 +         * the channel close in open state means the peer does not support it */
 +        if(p_data->close.old_tc_state == AVDT_AD_ST_OPEN)
 +        {
 +            avdt_ctrl.hdr.err_code = 0;
 +            avdt_ctrl.hdr.err_param = 0;
 +            /* call app callback */
 +            (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                                      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                                      AVDT_REPORT_DISCONN_EVT, &avdt_ctrl);
 +        }
 +    }
 +    else
 +    {
 +        /* must be in OPEN state. need to go back to idle */
 +        avdt_scb_event(p_scb, AVDT_SCB_MSG_ABORT_RSP_EVT, NULL);
 +        avdt_scb_hdl_tc_close(p_scb, p_data);
 +    }
 +}
 +#endif
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_tc_open
 +**
 +** Description      This function is called when the transport channel is
 +**                  opened while in the opening state.  It calls the
 +**                  application callback with an open indication or open
 +**                  confirm depending on who initiated the open procedure.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UINT8   event;
 +#if AVDT_REPORTING == TRUE
 +    UINT8   role;
 +#endif
 +
 +    /* stop transport channel connect timer */
 +    btu_stop_timer(&p_scb->timer_entry);
 +
 +    event = (p_scb->role == AVDT_OPEN_INT) ? AVDT_OPEN_CFM_EVT : AVDT_OPEN_IND_EVT;
 +    p_data->open.hdr.err_code = 0;
 +
 +    AVDT_TRACE_DEBUG("psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x\n",
 +        p_scb->cs.cfg.psc_mask, p_scb->req_cfg.psc_mask, p_scb->curr_cfg.psc_mask);
 +#if AVDT_REPORTING == TRUE
 +    if(p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
 +    {
 +        /* open the reporting channel, if both devices support it */
 +        role = (p_scb->role == AVDT_OPEN_INT) ? AVDT_INT : AVDT_ACP;
 +        avdt_ad_open_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, role);
 +    }
 +#endif
 +
 +    /* call app callback */
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                              event,
 +                              (tAVDT_CTRL *) &p_data->open);
 +}
 +
 +#if AVDT_REPORTING == TRUE
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_tc_open_sto
 +**
 +** Description      This function is called when the transport channel is
 +**                  opened while in the opening state.  It calls the
 +**                  application callback with an open indication or open
 +**                  confirm depending on who initiated the open procedure.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_CTRL          avdt_ctrl;
 +    /* open reporting channel here, when it is implemented */
 +
 +    /* call app callback */
 +    if(p_data->open.hdr.err_code == AVDT_CHAN_REPORT)
 +    {
 +        avdt_ctrl.hdr.err_code = 0;
 +        avdt_ctrl.hdr.err_param = 1;
 +        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
 +                              AVDT_REPORT_CONN_EVT, &avdt_ctrl);
 +    }
 +}
 +#endif
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_write_req_no_frag
 +**
 +** Description      This function frees the media packet currently stored in
 +**                  the SCB, if any.  Then it builds a new media packet from
 +**                  with the passed in buffer and stores it in the SCB.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_write_req_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UINT8   *p;
 +    UINT32  ssrc;
 +
 +    /* free packet we're holding, if any; to be replaced with new */
 +    if (p_scb->p_pkt != NULL)
 +    {
 +        GKI_freebuf(p_scb->p_pkt);
 +
 +        /* this shouldn't be happening */
 +        AVDT_TRACE_WARNING("Dropped media packet; congested");
 +    }
 +
 +    /* build a media packet */
 +    /* Add RTP header if required */
 +    if ( !(p_data->apiwrite.opt & AVDT_DATA_OPT_NO_RTP) )
 +    {
 +        ssrc = avdt_scb_gen_ssrc(p_scb);
 +
 +        p_data->apiwrite.p_buf->len += AVDT_MEDIA_HDR_SIZE;
 +        p_data->apiwrite.p_buf->offset -= AVDT_MEDIA_HDR_SIZE;
 +        p_scb->media_seq++;
 +        p = (UINT8 *)(p_data->apiwrite.p_buf + 1) + p_data->apiwrite.p_buf->offset;
 +
 +        UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1);
 +        UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt);
 +        UINT16_TO_BE_STREAM(p, p_scb->media_seq);
 +        UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp);
 +        UINT32_TO_BE_STREAM(p, ssrc);
 +    }
 +
 +    /* store it */
 +    p_scb->p_pkt = p_data->apiwrite.p_buf;
 +}
 +
 +#if AVDT_MULTIPLEXING == TRUE
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_write_req_frag
 +**
 +** Description      This function builds a new fragments of media packet from
 +**                  the passed in buffers and stores them in the SCB.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_write_req_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UINT8   *p;
 +    UINT32  ssrc;
 +    BT_HDR  *p_frag;
 +
 +    /* free fragments we're holding, if any; it shouldn't happen */
 +    if (!GKI_queue_is_empty(&p_scb->frag_q))
 +    {
 +        while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
 +            GKI_freebuf(p_frag);
 +
 +        /* this shouldn't be happening */
 +        AVDT_TRACE_WARNING("*** Dropped media packet; congested");
 +    }
 +
 +    /* build a media fragments */
 +    p_scb->frag_off = p_data->apiwrite.data_len;
 +    p_scb->p_next_frag = p_data->apiwrite.p_data;
 +
 +    ssrc = avdt_scb_gen_ssrc(p_scb);
 +
 +    /* get first packet */
 +    p_frag = (BT_HDR*)GKI_getfirst (&p_data->apiwrite.frag_q);
 +    /* posit on Adaptation Layer header */
 +    p_frag->len += AVDT_AL_HDR_SIZE + AVDT_MEDIA_HDR_SIZE;
 +    p_frag->offset -= AVDT_AL_HDR_SIZE + AVDT_MEDIA_HDR_SIZE;
 +    p = (UINT8 *)(p_frag + 1) + p_frag->offset;
 +
 +    /* Adaptation Layer header */
 +    /* TSID, no-fragment bit and coding of length(in 2 length octets following) */
 +    *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | AVDT_ALH_LCODE_16BIT;
 +
 +    /* length of all remaining transport packet */
 +    UINT16_TO_BE_STREAM(p, p_frag->layer_specific+AVDT_MEDIA_HDR_SIZE );
 +    /* media header */
 +    UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1);
 +    UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt);
 +    UINT16_TO_BE_STREAM(p, p_scb->media_seq);
 +    UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp);
 +    UINT32_TO_BE_STREAM(p, ssrc);
 +    p_scb->media_seq++;
 +
 +    while((p_frag = (BT_HDR*)GKI_getnext (p_frag)) != NULL)
 +    {
 +        /* posit on Adaptation Layer header */
 +        p_frag->len += AVDT_AL_HDR_SIZE;
 +        p_frag->offset -= AVDT_AL_HDR_SIZE;
 +        p = (UINT8 *)(p_frag + 1) + p_frag->offset;
 +        /* Adaptation Layer header */
 +        /* TSID, fragment bit and coding of length(in 2 length octets following) */
 +        *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | (AVDT_ALH_FRAG_MASK|AVDT_ALH_LCODE_16BIT);
 +
 +        /* length of all remaining transport packet */
 +        UINT16_TO_BE_STREAM(p, p_frag->layer_specific );
 +    }
 +
 +    /* store it */
 +    p_scb->frag_q = p_data->apiwrite.frag_q;
 +}
 +#endif
 +
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_hdl_write_req
 +**
 +** Description      This function calls one of the two versions of building functions
 +**                  for case with and without fragmentation
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +#if AVDT_MULTIPLEXING == TRUE
 +    if (GKI_queue_is_empty(&p_data->apiwrite.frag_q))
 +#endif
 +        avdt_scb_hdl_write_req_no_frag(p_scb, p_data);
 +#if AVDT_MULTIPLEXING == TRUE
 +    else
 +        avdt_scb_hdl_write_req_frag(p_scb, p_data);
 +#endif
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_abort_req
 +**
 +** Description      This function sends an abort command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_EVT_HDR   hdr;
 +    UNUSED(p_data);
 +
 +    if (p_scb->p_ccb != NULL)
 +    {
 +        p_scb->role = AVDT_CLOSE_INT;
 +
 +        hdr.seid = p_scb->peer_seid;
 +
 +        avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_ABORT, (tAVDT_MSG *) &hdr);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_abort_rsp
 +**
 +** Description      This function sends an abort response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_scb);
 +
 +    avdt_msg_send_rsp(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_SIG_ABORT,
 +                      &p_data->msg);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_close_req
 +**
 +** Description      This function sends a close command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_EVT_HDR   hdr;
 +    UNUSED(p_data);
 +
 +    p_scb->role = AVDT_CLOSE_INT;
 +
 +    hdr.seid = p_scb->peer_seid;
 +
 +    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_CLOSE, (tAVDT_MSG *) &hdr);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_stream_close
 +**
 +** Description      This function sends a close command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +#if AVDT_MULTIPLEXING == TRUE
 +    BT_HDR          *p_frag;
 +
 +    AVDT_TRACE_WARNING("avdt_scb_snd_stream_close c:%d, off:%d\n",
 +        GKI_queue_length(&p_scb->frag_q), p_scb->frag_off);
 +    /* clean fragments queue */
 +    while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
 +         GKI_freebuf(p_frag);
 +    p_scb->frag_off = 0;
 +#endif
 +    if (p_scb->p_pkt)
 +    {
 +        GKI_freebuf(p_scb->p_pkt);
 +        p_scb->p_pkt = NULL;
 +    }
 +
 +#if 0
 +    if(p_scb->cong)
 +        p_scb->cong = FALSE;
 +
 +    /* p_scb->curr_cfg.mux_tsid_media == 0 */
 +#endif
 +    avdt_scb_snd_close_req(p_scb, p_data);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_close_rsp
 +**
 +** Description      This function sends a close response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_CLOSE, &p_data->msg);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_getconfig_req
 +**
 +** Description      This function sends a get configuration command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_EVT_HDR   hdr;
 +    UNUSED(p_data);
 +
 +    hdr.seid = p_scb->peer_seid;
 +
 +    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_GETCONFIG, (tAVDT_MSG *) &hdr);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_getconfig_rsp
 +**
 +** Description      This function sends a get configuration response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_GETCONFIG, &p_data->msg);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_open_req
 +**
 +** Description      This function sends an open command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_EVT_HDR   hdr;
 +    UNUSED(p_data);
 +
 +    hdr.seid = p_scb->peer_seid;
 +
 +    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_OPEN, (tAVDT_MSG *) &hdr);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_open_rsp
 +**
 +** Description      This function sends an open response message.  It also
 +**                  calls avdt_ad_open_req() to accept a transport channel
 +**                  connection.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    /* notify adaption that we're waiting for transport channel open */
 +    p_scb->role = AVDT_OPEN_ACP;
 +    avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_ACP);
 +
 +    /* send response */
 +    avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_OPEN, &p_data->msg);
 +
 +    /* start tc connect timer */
 +    btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_CONN_TOUT);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_reconfig_req
 +**
 +** Description      This function stores the configuration parameters in the
 +**                  SCB and sends a reconfiguration command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
 +    p_data->msg.hdr.seid = p_scb->peer_seid;
 +    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_RECONFIG, &p_data->msg);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_reconfig_rsp
 +**
 +** Description      This function stores the configuration parameters in the
 +**                  SCB and sends a reconfiguration response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    if (p_data->msg.hdr.err_code == 0)
 +    {
 +        /* store new configuration */
 +        if (p_scb->req_cfg.num_codec > 0)
 +        {
 +            p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
 +            memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE);
 +        }
 +        if (p_scb->req_cfg.num_protect > 0)
 +        {
 +            p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
 +            memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE);
 +        }
 +
 +        /* send response */
 +        avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
 +    }
 +    else
 +    {
 +        /* send reject */
 +        avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_security_req
 +**
 +** Description      This function sends a security command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    p_data->msg.hdr.seid = p_scb->peer_seid;
 +    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SECURITY, &p_data->msg);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_security_rsp
 +**
 +** Description      This function sends a security response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    if (p_data->msg.hdr.err_code == 0)
 +    {
 +        avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
 +    }
 +    else
 +    {
 +        avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_setconfig_rej
 +**
 +** Description      This function marks the SCB as not in use and sends a
 +**                  set configuration reject message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    if (p_scb->p_ccb != NULL)
 +    {
 +        avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
 +
 +        /* clear scb variables */
 +        avdt_scb_clr_vars(p_scb, p_data);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_setconfig_req
 +**
 +** Description      This function marks the SCB as in use and copies the
 +**                  configuration parameters to the SCB.  Then the function
 +**                  sends a set configuration command message and initiates
 +**                  opening of the signaling channel.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_CFG *p_req, *p_cfg;
 +
 +    /* copy API parameters to scb, set scb as in use */
 +    p_scb->in_use = TRUE;
 +    p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
 +    p_scb->peer_seid = p_data->msg.config_cmd.hdr.seid;
 +    p_req = p_data->msg.config_cmd.p_cfg;
 +    p_cfg = &p_scb->cs.cfg;
 +#if AVDT_MULTIPLEXING == TRUE
 +    p_req->mux_tsid_media = p_cfg->mux_tsid_media;
 +    p_req->mux_tcid_media = p_cfg->mux_tcid_media;
 +    if(p_req->psc_mask & AVDT_PSC_REPORT)
 +    {
 +        p_req->mux_tsid_report = p_cfg->mux_tsid_report;
 +        p_req->mux_tcid_report = p_cfg->mux_tcid_report;
 +    }
 +#endif
 +    memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
 +
 +    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SETCONFIG, &p_data->msg);
 +
 +    /* tell ccb to open channel */
 +    avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_setconfig_rsp
 +**
 +** Description      This function copies the requested configuration into the
 +**                  current configuration and sends a set configuration
 +**                  response message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    if (p_scb->p_ccb != NULL)
 +    {
 +        memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
 +
 +        avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_snd_tc_close
 +**
 +** Description      This function calls avdt_ad_close_req() to close the
 +**                  transport channel for this SCB.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_data);
 +
 +#if AVDT_REPORTING == TRUE
 +    if(p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
 +        avdt_ad_close_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
 +#endif
 +    avdt_ad_close_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_cb_err
 +**
 +** Description      This function calls the application callback function
 +**                  indicating an error.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_CTRL          avdt_ctrl;
 +    UNUSED(p_data);
 +
 +    /* set error code and parameter */
 +    avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
 +    avdt_ctrl.hdr.err_param = 0;
 +
 +    /* call callback, using lookup table to get callback event */
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
 +                              NULL,
 +                              avdt_scb_cback_evt[p_scb->curr_evt],
 +                              &avdt_ctrl);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_cong_state
 +**
 +** Description      This function sets the congestion state of the SCB media
 +**                  transport channel.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    p_scb->cong = p_data->llcong;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_rej_state
 +**
 +** Description      This function sends a reject message to the peer indicating
 +**                  incorrect state for the received command message.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_scb);
 +
 +    p_data->msg.hdr.err_code = AVDT_ERR_BAD_STATE;
 +    p_data->msg.hdr.err_param = 0;
 +    avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
 +                      p_data->msg.hdr.sig_id, &p_data->msg);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_rej_in_use
 +**
 +** Description      This function sends a reject message to the peer indicating
 +**                  the stream is in use.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_scb);
 +
 +    p_data->msg.hdr.err_code = AVDT_ERR_IN_USE;
 +    p_data->msg.hdr.err_param = 0;
 +    avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
 +                      p_data->msg.hdr.sig_id, &p_data->msg);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_rej_not_in_use
 +**
 +** Description      This function sends a reject message to the peer indicating
 +**                  the stream is in use.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_scb);
 +
 +    p_data->msg.hdr.err_code = AVDT_ERR_NOT_IN_USE;
 +    p_data->msg.hdr.err_param = 0;
 +    avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
 +                      p_data->msg.hdr.sig_id, &p_data->msg);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_set_remove
 +**
 +** Description      This function marks an SCB to be removed.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    p_scb->remove = TRUE;
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_free_pkt
 +**
 +** Description      This function frees the media packet passed in.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_CTRL      avdt_ctrl;
 +#if AVDT_MULTIPLEXING == TRUE
 +    BT_HDR          *p_frag;
 +#endif
 +
 +    /* set error code and parameter */
 +    avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
 +    avdt_ctrl.hdr.err_param = 0;
 +
 +    /* p_buf can be NULL in case using of fragments queue frag_q */
 +    if(p_data->apiwrite.p_buf)
 +        GKI_freebuf(p_data->apiwrite.p_buf);
 +
 +#if AVDT_MULTIPLEXING == TRUE
 +    /* clean fragments queue */
 +    while((p_frag = (BT_HDR*)GKI_dequeue (&p_data->apiwrite.frag_q)) != NULL)
 +         GKI_freebuf(p_frag);
 +#endif
 +
 +    AVDT_TRACE_WARNING("Dropped media packet");
 +
 +    /* we need to call callback to keep data flow going */
 +    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
 +                              &avdt_ctrl);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_clr_pkt
 +**
 +** Description      This function frees the media packet stored in the SCB.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_CTRL      avdt_ctrl;
 +    tAVDT_CCB       *p_ccb;
 +    UINT8           tcid;
 +    UINT16          lcid;
 +#if AVDT_MULTIPLEXING == TRUE
 +    BT_HDR          *p_frag;
 +#endif
 +    UNUSED(p_data);
 +
 +    /* set error code and parameter */
 +    avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
 +    avdt_ctrl.hdr.err_param = 0;
 +    /* flush the media data queued at L2CAP */
 +    if((p_ccb = p_scb->p_ccb) != NULL)
 +    {
 +        /* get tcid from type, scb */
 +        tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
 +
 +        lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
 +        L2CA_FlushChannel (lcid, L2CAP_FLUSH_CHANS_ALL);
 +    }
 +
 +    if (p_scb->p_pkt != NULL)
 +    {
 +        GKI_freebuf(p_scb->p_pkt);
 +        p_scb->p_pkt = NULL;
 +
 +        AVDT_TRACE_DEBUG("Dropped stored media packet");
 +
 +        /* we need to call callback to keep data flow going */
 +        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
 +                                  &avdt_ctrl);
 +    }
 +#if AVDT_MULTIPLEXING == TRUE
 +    else if(!GKI_queue_is_empty (&p_scb->frag_q))
 +    {
 +        AVDT_TRACE_DEBUG("Dropped fragments queue");
 +        /* clean fragments queue */
 +        while((p_frag = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
 +             GKI_freebuf(p_frag);
 +
 +        p_scb->frag_off = 0;
 +
 +        /* we need to call callback to keep data flow going */
 +        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
 +                                  &avdt_ctrl);
 +    }
 +#endif
 +}
 +
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_chk_snd_pkt
 +**
 +** Description      This function checks if the SCB is congested, and if not
 +**                  congested it sends a stored media packet, if any.  After it
 +**                  sends the packet it calls the application callback function
 +**                  with a write confirm.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    tAVDT_CTRL      avdt_ctrl;
 +    BT_HDR          *p_pkt;
 +#if AVDT_MULTIPLEXING == TRUE
 +    BOOLEAN         sent = FALSE;
 +    UINT8   res = AVDT_AD_SUCCESS;
 +    tAVDT_SCB_EVT data;
 +#endif
 +    UNUSED(p_data);
 +
 +    avdt_ctrl.hdr.err_code = 0;
 +
 +    if (!p_scb->cong)
 +    {
 +        if (p_scb->p_pkt != NULL)
 +        {
 +            p_pkt = p_scb->p_pkt;
 +            p_scb->p_pkt = NULL;
 +            avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
 +
 +            (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl);
 +        }
 +#if AVDT_MULTIPLEXING == TRUE
 +        else
 +        {
 +#if 0
 +            AVDT_TRACE_DEBUG("num_q=%d\n",
 +                L2CA_FlushChannel(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb)].lcid),
 +                                  L2CAP_FLUSH_CHANS_GET);
 +#endif
 +            while((p_pkt = (BT_HDR*)GKI_dequeue (&p_scb->frag_q)) != NULL)
 +            {
 +                sent = TRUE;
 +                AVDT_TRACE_DEBUG("Send fragment len=%d\n",p_pkt->len);
 +                /* fragments queue contains fragment to send */
 +                res = avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
 +                if(AVDT_AD_CONGESTED == res)
 +                {
 +                    p_scb->cong = TRUE;
 +                    AVDT_TRACE_DEBUG("avdt/l2c congested!!");
 +                    break;/* exit loop if channel became congested */
 +            }
 +            }
 +            AVDT_TRACE_DEBUG("res=%d left=%d\n",res, p_scb->frag_off);
 +
 +            if(p_scb->frag_off)
 +            {
 +                if(AVDT_AD_SUCCESS == res || GKI_queue_is_empty (&p_scb->frag_q))
 +                {
 +                    /* all buffers were sent to L2CAP, compose more to queue */
 +                    avdt_scb_queue_frags(p_scb, &p_scb->p_next_frag, &p_scb->frag_off, &p_scb->frag_q);
 +                    if(!GKI_queue_is_empty (&p_scb->frag_q))
 +                    {
 +                        data.llcong = p_scb->cong;
 +                        avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, &data);
 +                    }
 +                }
 +            }
 +
 +            /* Send event AVDT_WRITE_CFM_EVT if it was last fragment */
 +            else if (sent && GKI_queue_is_empty (&p_scb->frag_q))
 +            {
 +                (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl);
 +            }
 +        }
 +#endif
 +    }
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_tc_timer
 +**
 +** Description      This function is called to start a timer when the peer
 +**                  initiates closing of the stream.  The timer verifies that
 +**                  the peer disconnects the transport channel.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_DISC_TOUT);
 +}
 +
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_clr_vars
 +**
 +** Description      This function initializes certain SCB variables.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
 +{
 +    UNUSED(p_data);
 +
 +    if ((p_scb->cs.tsep == AVDT_TSEP_SNK) && (!p_scb->sink_activated))
 +    {
 +        p_scb->in_use = TRUE;
 +    }
 +    else
 +    {
 +        p_scb->in_use = FALSE;
 +    }
 +    p_scb->p_ccb = NULL;
 +    p_scb->peer_seid = 0;
 +}
 +
 +#if AVDT_MULTIPLEXING == TRUE
 +/*******************************************************************************
 +**
 +** Function         avdt_scb_queue_frags
 +**
 +** Description      This function breaks media payload into fragments
 +**                  and put the fragments in the given queue.
 +**
 +** Returns          Nothing.
 +**
 +*******************************************************************************/
 +void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq)
 +{
 +    UINT16  lcid;
 +    UINT16  num_frag;
 +    UINT16  mtu_used;
 +    UINT8   *p;
 +    BOOLEAN al_hdr = FALSE;
 +    UINT8   tcid;
 +    tAVDT_TC_TBL    *p_tbl;
 +    UINT16          buf_size;
 +    UINT16          offset = AVDT_MEDIA_OFFSET + AVDT_AL_HDR_SIZE;
 +    UINT16          cont_offset = offset - AVDT_MEDIA_HDR_SIZE;
 +    BT_HDR          *p_frag;
 +
 +    tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
 +    lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][tcid].lcid;
 +
 +    if( p_scb->frag_off != 0)
 +    {
 +        /* continuing process is usually triggered by un-congest event.
 +         * the number of buffers at L2CAP is very small (if not 0).
 +         * we do not need to L2CA_FlushChannel() */
 +        offset = cont_offset;
 +        al_hdr = TRUE;
 +        num_frag = AVDT_MAX_FRAG_COUNT;
 +    }
 +    else
 +    {
 +        num_frag = L2CA_FlushChannel(lcid, L2CAP_FLUSH_CHANS_GET);
 +        AVDT_TRACE_DEBUG("num_q=%d lcid=%d\n", num_frag, lcid);
 +        if(num_frag >= AVDT_MAX_FRAG_COUNT)
 +        {
 +            num_frag = 0;
 +        }
 +        else
 +        {
 +            num_frag = AVDT_MAX_FRAG_COUNT - num_frag;
 +        }
 +    }
 +
 +    /* look up transport channel table entry to get peer mtu */
 +    p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
 +    buf_size = p_tbl->peer_mtu + BT_HDR_SIZE;
 +    AVDT_TRACE_DEBUG("peer_mtu: %d, buf_size: %d num_frag=%d\n",
 +        p_tbl->peer_mtu, buf_size, num_frag);
 +
 +    if(buf_size > AVDT_DATA_POOL_SIZE)
 +        buf_size = AVDT_DATA_POOL_SIZE;
 +
 +    mtu_used = buf_size - BT_HDR_SIZE;
 +
 +    while(*p_data_len && num_frag)
 +    {
 +        /* allocate buffer for fragment */
 +        if(NULL == (p_frag = (BT_HDR*)GKI_getbuf(buf_size)))
 +        {
 +            AVDT_TRACE_WARNING("avdt_scb_queue_frags len=%d(out of GKI buffers)\n",*p_data_len);
 +            break;
 +        }
 +        /* fill fragment by chunk of media payload */
 +        p_frag->layer_specific = *p_data_len;/* length of all remaining transport packet */
 +        p_frag->offset = offset;
 +        /* adjust packet offset for continuing packets */
 +        offset = cont_offset;
 +
 +        p_frag->len = mtu_used - p_frag->offset;
 +        if(p_frag->len > *p_data_len)
 +            p_frag->len = *p_data_len;
 +        memcpy((UINT8*)(p_frag+1) + p_frag->offset, *pp_data, p_frag->len);
 +        *pp_data += p_frag->len;
 +        *p_data_len -= p_frag->len;
 +        AVDT_TRACE_DEBUG("Prepared fragment len=%d\n", p_frag->len);
 +
 +        if(al_hdr)
 +        {
 +            /* Adaptation Layer header */
 +            p_frag->len += AVDT_AL_HDR_SIZE;
 +            p_frag->offset -= AVDT_AL_HDR_SIZE;
 +            p = (UINT8 *)(p_frag + 1) + p_frag->offset;
 +            /* TSID, fragment bit and coding of length(in 2 length octets following) */
 +            *p++ = (p_scb->curr_cfg.mux_tsid_media<<3) | (AVDT_ALH_FRAG_MASK|AVDT_ALH_LCODE_16BIT);
 +
 +            /* length of all remaining transport packet */
 +            UINT16_TO_BE_STREAM(p, p_frag->layer_specific );
 +        }
 +        /* put fragment into gueue */
 +        GKI_enqueue(pq, p_frag);
 +        num_frag--;
 +    }
 +}
 +#endif
 +
Simple merge
index 3439c1049b605e38290b599a2d2d152e0feb6167,0000000000000000000000000000000000000000..28f231b6a67d4e64c7895593b9f2af0228e6c0d4
mode 100644,000000..100644
--- /dev/null
@@@ -1,111 -1,0 +1,112 @@@
- #include "EspAudio.h"
- #include "EspAudioCom.h"
 +#include <stdint.h>
 +#include <stdbool.h>
 +#include <stdlib.h>
 +#include <string.h>
 +
 +#include "freertos/FreeRTOS.h"
 +#include "freertos/task.h"
 +
 +#include "esp_system.h"
-     EspAudioPlayerStreamWrite(data, len, 10);
++// #include "EspAudio.h"
++// #include "EspAudioCom.h"
 +
 +#include "bt_app_common.h"
 +#include "esp_bt_stack_manager.h"
 +#include "esp_gap_bt_api.h"
 +#include "bta_api.h"
 +#include "esp_a2dp_api.h"
 +
 +typedef enum {
 +    BT_APP_EVT_STACK_ON = 0xa0,
 +    BT_APP_EVT_MAX
 +} bt_app_evt_t;
 +
 +typedef union {
 +    esp_a2d_cb_param_t a2d;
 +} bt_app_evt_arg;
 +
 +static void bt_app_handle_evt(UINT16 event, void *p_param);
 +
 +static void bt_app_a2d_cb(uint32_t event, void *param)
 +{
 +    switch (event) {
 +    case ESP_A2D_CONNECTION_STATE_EVT:
 +    case ESP_A2D_AUDIO_STATE_EVT:
 +    case ESP_A2D_AUDIO_CFG_EVT:
 +    {
 +      bt_app_transfer_context(bt_app_handle_evt, event, param, sizeof(bt_app_evt_arg), NULL);
 +        break;
 +    }
 +    default:
 +        BT_APP_TRACE_ERROR("===a2dp invalid cb event: %d\n", event);
 +        break;
 +    }
 +}
 +
 +static void bt_app_a2d_data_cb(uint8_t *data, uint32_t len)
 +{
-             EspAudioPlayerStreamCfg(StreamSampleRate_44k, 2, StreamBitLen_16BIT);
-             EspAudio_SetupStream("stream.pcm", InputSrcType_Stream);
-             EspAudio_SetVolume(99);
++    // EspAudioPlayerStreamWrite(data, len, 10);
++    return;
 +}
 +                          
 +static void bt_app_handle_evt(UINT16 event, void *p_param)
 +{
 +    BT_APP_TRACE_EVENT("bt_app_handle_evt 0x%x\n", event);
 +    esp_a2d_cb_param_t *a2d = NULL;
 +    switch (event) {
 +    case BT_APP_EVT_STACK_ON: {
 +        char *dev_name = "ESP_SPEAKER";
 +        // BTM_SetTraceLevel(BT_TRACE_LEVEL_WARNING);
 +      esp_bt_gap_set_device_name(dev_name);
 +
 +        esp_a2d_register_callback(bt_app_a2d_cb);
 +        esp_a2d_register_data_callback(bt_app_a2d_data_cb);
 +
 +        esp_a2d_sink_init();
 +        esp_bt_gap_set_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
 +        break;
 +    }
 +    case ESP_A2D_CONNECTION_STATE_EVT: {
 +        a2d = (esp_a2d_cb_param_t *)(p_param);
 +        BT_APP_TRACE_ERROR("===a2dp conn_state_cb %d ===\n", a2d->conn_stat.state);
 +        break;
 +    }
 +    case ESP_A2D_AUDIO_STATE_EVT: {
 +        a2d = (esp_a2d_cb_param_t *)(p_param);
 +        BT_APP_TRACE_ERROR("===a2dp audio_state_cb %d ===\n", a2d->audio_stat.state);
 +        break;
 +    }
 +    case ESP_A2D_AUDIO_CFG_EVT: {
 +        a2d = (esp_a2d_cb_param_t *)(p_param);
 +        BT_APP_TRACE_ERROR("===a2dp audio_cfg_cb type %d ===\n", a2d->audio_cfg.mcc.type);
 +        if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC) {
 +            // temporarily hardcoded the PCM configuaration
 +            BT_APP_TRACE_ERROR("configure audio player\n");
++            // EspAudioPlayerStreamCfg(StreamSampleRate_44k, 2, StreamBitLen_16BIT);
++            // EspAudio_SetupStream("stream.pcm", InputSrcType_Stream);
++            // EspAudio_SetVolume(99);
 +        }
 +        break;
 +    }
 +    default:
 +        BT_APP_TRACE_ERROR("===application invalid event: %d\n", event);
 +        break;
 +    }
 +    
 +}
 +
 +void app_main_entry(void)
 +{
 +    bt_status_t init, enable;
 +    init = esp_bt_init_stack();
 +    if (init != ESP_OK) {
 +        return;
 +    }
 +
 +    enable = esp_bt_enable_stack();
 +    if (enable != ESP_OK) {
 +        return;
 +    }
 +
 +    bt_app_transfer_context(bt_app_handle_evt, BT_APP_EVT_STACK_ON, NULL, 0, NULL);
 +}
index fae8b983f1f7fc4e31bb39f04142d14eafb460ed,0000000000000000000000000000000000000000..7d7bf118b2e0bbc1a22a334a67e06e727df2ea91
mode 100755,000000..100755
--- /dev/null
@@@ -1,29 -1,0 +1,25 @@@
- #include "EspAudio.h"
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <unistd.h>
 +#include <string.h>
 +#include "bt.h"
 +#include "freertos/FreeRTOS.h"
 +#include "freertos/task.h"
 +
 +#include "nvs_flash.h"
 +#include "esp_system.h"
-     system_init();
-     #include "psramApi.h"
-     psram_cache_enable();    
-     
-     printf("Free memory: %d bytes\n", system_get_free_heap_size());
-     EspAudio_Init();
++// #include "EspAudio.h"
 +
 +extern void bte_main_boot_entry(void *);
 +extern void bt_app_task_start_up(void);
 +extern void bt_app_core_start(void);
 +
 +void app_main()
 +{
 +    nvs_flash_init();
-     // bte_main_boot_entry(bt_app_core_start);
++    // system_init();
++    // printf("Free memory: %d bytes\n", system_get_free_heap_size());
++    // EspAudio_Init();
 +    bt_controller_init();
 +    bt_app_task_start_up();
 +}