/*******************************************************************************
**
** Function         bta_av_chk_mtu
**
** Description      if this is audio channel, check if more than one audio
**                  channel is connected.
**
** Returns          The smallest mtu of the connected audio channels
**
*******************************************************************************/
UINT16 bta_av_chk_mtu(tBTA_AV_SCB *p_scb, UINT16 mtu)
{
    UINT16 ret_mtu = BTA_AV_MAX_A2DP_MTU;
    tBTA_AV_SCB *p_scbi;
    int i;
    UINT8   mask;

    /* TODO_MV mess with the mtu according to the number of EDR/non-EDR headsets */
    if(p_scb->chnl == BTA_AV_CHNL_AUDIO)
    {
        if(bta_av_cb.audio_open_cnt >= 2)
        {
            /* more than one audio channel is connected */
            for(i=0; i<BTA_AV_NUM_STRS; i++)
            {
                p_scbi = bta_av_cb.p_scb[i];
                if((p_scb != p_scbi) && p_scbi && (p_scbi->chnl == BTA_AV_CHNL_AUDIO) )
                {
                    mask = BTA_AV_HNDL_TO_MSK(i);
                    APPL_TRACE_DEBUG3("[%d] mtu: %d, mask:0x%x",
                        i, p_scbi->stream_mtu, mask);
                    if(bta_av_cb.conn_audio & mask)
                    {
                        if(ret_mtu > p_scbi->stream_mtu)
                            ret_mtu = p_scbi->stream_mtu;
                    }
                }
            }
        }
        APPL_TRACE_DEBUG3("bta_av_chk_mtu audio count:%d, conn_audio:0x%x, ret:%d",
            bta_av_cb.audio_open_cnt, bta_av_cb.conn_audio, ret_mtu);
    }
    return ret_mtu;
}
/*******************************************************************************
**
** Function         bta_hf_client_remove_sco
**
** Description      Removes the specified SCO from the system.
**                  If only_active is TRUE, then SCO is only removed if connected
**
** Returns          BOOLEAN   - TRUE if Sco removal was started
**
*******************************************************************************/
static BOOLEAN bta_hf_client_sco_remove(BOOLEAN only_active)
{
    BOOLEAN     removed_started = FALSE;
    tBTM_STATUS status;

    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, only_active);

    if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX)
    {
        status = BTM_RemoveSco(bta_hf_client_cb.scb.sco_idx);

        APPL_TRACE_DEBUG3("%s idx 0x%04x, status:0x%x", __FUNCTION__, bta_hf_client_cb.scb.sco_idx, status);

        if (status == BTM_CMD_STARTED)
        {
            removed_started = TRUE;
        }
        /* If no connection reset the sco handle */
        else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) )
        {
            bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
        }
    }
    return removed_started;
}
static char *bta_hf_client_skip_unknown(char *buffer)
{
    char *start;
    char *tmp;

    tmp = strstr(buffer, "\r\n");
    if (tmp == NULL)
    {
        return NULL;
    }

    buffer += 2;
    start = buffer;

    tmp = strstr(buffer, "\r\n");
    if (tmp == NULL)
    {
        return NULL;
    }

    buffer = tmp + 2;

    APPL_TRACE_DEBUG3("%s %.*s", __FUNCTION__, buffer - start - 2, start);

    return buffer;
}
int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size, uint32_t user_id)
{
    if(h < 0 || h >= MAX_THREAD)
    {
        APPL_TRACE_ERROR1("invalid bt thread handle:%d", h);
        return FALSE;
    }
    if(ts[h].cmd_fdw == -1)
    {
        APPL_TRACE_ERROR0("cmd socket is not created. socket thread may not initialized");
        return FALSE;
    }
    sock_cmd_t cmd = {CMD_USER_PRIVATE, 0, type, size, user_id};
    APPL_TRACE_DEBUG3("post cmd type:%d, size:%d, h:%d, ", type, size, h);
    sock_cmd_t* cmd_send = &cmd;
    int size_send = sizeof(cmd);
    if(data && size)
    {
        size_send = sizeof(cmd) + size;
        cmd_send = (sock_cmd_t*)alloca(size_send);
        if(cmd_send)
        {
            *cmd_send = cmd;
            memcpy(cmd_send + 1, data, size);
        }
        else
        {
            APPL_TRACE_ERROR3("alloca failed at h:%d, cmd type:%d, size:%d", h, type, size_send);
            return FALSE;
        }
    }
    return send(ts[h].cmd_fdw, cmd_send, size_send, 0) == size_send;
}
static void bta_hf_client_handle_ciev(UINT32 index, UINT32 value)
{
    INT8 realind = -1;

    APPL_TRACE_DEBUG3("%s index: %u value: %u", __FUNCTION__, index, value);

    if(index == 0 || index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT)
    {
        return;
    }

    realind = bta_hf_client_cb.scb.at_cb.indicator_lookup[index - 1];

    if(realind >= 0 && realind < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT)
    {
        /* get the real in-array index from lookup table by index it comes at */
        /* if there is no bug it should automatically be correctly calculated    */
        if(value > bta_hf_client_indicators[realind].max || value < bta_hf_client_indicators[realind].min)
        {
            return;
        }

        /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
        bta_hf_client_ind(realind, value);
    }
}
Exemple #6
0
/*******************************************************************************
 **
 ** Function         bta_av_co_audio_disc_res
 **
 ** Description      This callout function is executed by AV to report the
 **                  number of stream end points (SEP) were found during the
 **                  AVDT stream discovery process.
 **
 **
 ** Returns          void.
 **
 *******************************************************************************/
BTA_API void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk,
        BD_ADDR addr)
{
    tBTA_AV_CO_PEER *p_peer;

    FUNC_TRACE();

    APPL_TRACE_DEBUG3("bta_av_co_audio_disc_res h:x%x num_seps:%d num_snk:%d",
            hndl, num_seps, num_snk);

    /* Find the peer info */
    p_peer = bta_av_co_get_peer(hndl);
    if (p_peer == NULL)
    {
        APPL_TRACE_ERROR0("bta_av_co_audio_disc_res could not find peer entry");
        return;
    }

    /* Sanity check : this should never happen */
    if (p_peer->opened)
    {
        APPL_TRACE_ERROR0("bta_av_co_audio_disc_res peer already opened");
    }

    /* Copy the discovery results */
    bdcpy(p_peer->addr, addr);
    p_peer->num_snks = num_snk;
    p_peer->num_seps = num_seps;
    p_peer->num_rx_snks = 0;
    p_peer->num_sup_snks = 0;
}
/******************************************************************************
**
**          MAIN PARSING FUNCTION
**
**
*******************************************************************************/
void bta_hf_client_at_parse(char *buf, unsigned int len)
{
    APPL_TRACE_DEBUG3("%s offset: %u len: %u", __FUNCTION__, bta_hf_client_cb.scb.at_cb.offset, len);

    if (len + bta_hf_client_cb.scb.at_cb.offset > BTA_HF_CLIENT_AT_PARSER_MAX_LEN)
    {
        char tmp_buff[BTA_HF_CLIENT_AT_PARSER_MAX_LEN];
        unsigned int tmp = bta_hf_client_cb.scb.at_cb.offset;
        unsigned int space_left = BTA_HF_CLIENT_AT_PARSER_MAX_LEN - bta_hf_client_cb.scb.at_cb.offset;

        APPL_TRACE_DEBUG1("%s overrun, trying to recover", __FUNCTION__);

        /* fill up parser buffer */
        memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, space_left);
        len -= space_left;
        buf += space_left;
        bta_hf_client_cb.scb.at_cb.offset += space_left;

        /* find end of last complete command before proceeding */
        while(bta_hf_client_check_at_complete() == FALSE)
        {
            if (bta_hf_client_cb.scb.at_cb.offset == 0) {
                APPL_TRACE_ERROR0("HFPClient: AT parser buffer overrun, disconnecting");

                bta_hf_client_at_reset();
                bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
                return;
            }

            bta_hf_client_cb.scb.at_cb.offset--;
        }

        /* cut buffer to complete AT event and keep cut data */
        tmp += space_left - bta_hf_client_cb.scb.at_cb.offset;
        memcpy(tmp_buff, bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, tmp);
        bta_hf_client_cb.scb.at_cb.buf[bta_hf_client_cb.scb.at_cb.offset] = '\0';

        /* parse */
        bta_hf_client_at_parse_start();
        bta_hf_client_at_clear_buf();

        /* recover cut data */
        memcpy(bta_hf_client_cb.scb.at_cb.buf, tmp_buff, tmp);
        bta_hf_client_cb.scb.at_cb.offset += tmp;
    }

    memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, len);
    bta_hf_client_cb.scb.at_cb.offset += len;

    /* If last event is complete, parsing can be started */
    if (bta_hf_client_check_at_complete() == TRUE)
    {
        bta_hf_client_at_parse_start();
        bta_hf_client_at_clear_buf();
    }
}
static void bta_hf_client_handle_clcc(UINT16 idx, UINT16 dir, UINT16 status, UINT16 mode, UINT16 mpty, char *numstr, UINT16 type)
{
    APPL_TRACE_DEBUG6("%s idx: %u dir: %u status: %u mode: %u mpty: %u",
                        __FUNCTION__, idx, dir, status, mode, mpty);

    if (numstr)
    {
        APPL_TRACE_DEBUG3("%s number: %s  type: %u", __FUNCTION__, numstr, type);
    }

    bta_hf_client_clcc(idx, dir, status, mpty, numstr);
}
/* create dummy socket pair used to wake up select loop */
static inline void init_cmd_fd(int h)
{
    asrt(ts[h].cmd_fdr == -1 && ts[h].cmd_fdw == -1);
    if(socketpair(AF_UNIX, SOCK_STREAM, 0, &ts[h].cmd_fdr) < 0)
    {
        APPL_TRACE_ERROR1("socketpair failed: %s", strerror(errno));
        return;
    }
    APPL_TRACE_DEBUG3("h:%d, cmd_fdr:%d, cmd_fdw:%d", h, ts[h].cmd_fdr, ts[h].cmd_fdw);
    //add the cmd fd for read & write
    add_poll(h, ts[h].cmd_fdr, 0, SOCK_THREAD_FD_RD, 0);
}
/*******************************************************************************
**
** Function         bta_gattc_sm_execute
**
** Description      State machine event handling function for GATTC
**
**
** Returns          void
**
*******************************************************************************/
void bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
{
    tBTA_GATTC_ST_TBL     state_table;
    UINT8               action;
    int                 i;
#if BTA_GATT_DEBUG == TRUE
    tBTA_GATTC_STATE in_state = p_clcb->state;
    UINT16         in_event = event;
    APPL_TRACE_DEBUG4("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state,
                      gattc_state_code(in_state),
                      in_event,
                      gattc_evt_code(in_event));
#endif


    /* look up the state table for the current state */
    state_table = bta_gattc_st_tbl[p_clcb->state];

    event &= 0x00FF;

    /* set next state */
    p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];

    /* execute action functions */
    for (i = 0; i < BTA_GATTC_ACTIONS; i++)
    {
        if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
        {
            (*bta_gattc_action[action])(p_clcb, p_data);
        }
        else
        {
            break;
        }
    }

#if BTA_GATT_DEBUG == TRUE
    if (in_state != p_clcb->state)
    {
        APPL_TRACE_DEBUG3("GATTC State Change: [%s] -> [%s] after Event [%s]",
                          gattc_state_code(in_state),
                          gattc_state_code(p_clcb->state),
                          gattc_evt_code(in_event));
    }
#endif
}
static void bta_hf_client_send_at(tBTA_HF_CLIENT_AT_CMD cmd, char *buf, UINT16 buf_len)
{
    if ((bta_hf_client_cb.scb.at_cb.current_cmd == BTA_HF_CLIENT_AT_NONE ||
            bta_hf_client_cb.scb.svc_conn == FALSE) &&
            bta_hf_client_cb.scb.at_cb.hold_timer_on == FALSE)
    {
        UINT16  len;

#ifdef BTA_HF_CLIENT_AT_DUMP
        APPL_TRACE_DEBUG3("%s %.*s", __FUNCTION__, buf_len - 1, buf);
#endif

        bta_hf_client_cb.scb.at_cb.current_cmd = cmd;
        PORT_WriteData(bta_hf_client_cb.scb.conn_handle, buf, buf_len, &len);

        bta_hf_client_start_at_resp_timer();

        return;
    }

    bta_hf_client_queue_at(cmd, buf, buf_len);
}
static void bta_hf_client_handle_error(tBTA_HF_CLIENT_AT_RESULT_TYPE type, UINT16 cme)
{
    APPL_TRACE_DEBUG3("%s %u %u", __FUNCTION__, type, cme);

    bta_hf_client_stop_at_resp_timer();

    if (!bta_hf_client_cb.scb.svc_conn)
    {
        bta_hf_client_slc_seq(TRUE);
        return;
    }

    switch(bta_hf_client_cb.scb.at_cb.current_cmd)
    {
        case BTA_HF_CLIENT_AT_BIA:
            break;
        case BTA_HF_CLIENT_AT_BCC:
        case BTA_HF_CLIENT_AT_BCS:
            bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
            break;
        case BTA_HF_CLIENT_AT_CLIP: //last cmd is post slc seq
            if (bta_hf_client_cb.scb.send_at_reply == FALSE)
            {
                bta_hf_client_cb.scb.send_at_reply = TRUE;
            }
            break;
        default:
            if (bta_hf_client_cb.scb.send_at_reply)
            {
                bta_hf_client_at_result(type, cme);
            }
            break;
    }

    bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;

    bta_hf_client_send_queued_at();
}
static void bta_hf_client_handle_cind_value(UINT32 index, UINT32 value)
{
    APPL_TRACE_DEBUG3("%s index: %u value: %u", __FUNCTION__, index, value);

    if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT)
    {
        return;
    }

    if (service_index == index)
    {
        if (value == 0)
        {
            service_availability = FALSE;
        }
        else
        {
            service_availability = TRUE;
        }
    }
    if (bta_hf_client_cb.scb.at_cb.indicator_lookup[index] == -1)
    {
        return;
    }

    /* get the real array index from lookup table */
    index = bta_hf_client_cb.scb.at_cb.indicator_lookup[index];

    /* Ignore out of range values */
    if(value > bta_hf_client_indicators[index].max ||
       value < bta_hf_client_indicators[index].min)
    {
        return;
    }

    /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
    bta_hf_client_ind(index, value);
}
static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN *p_open, uint32_t id)
{
    lock_slot(&slot_lock);
    rfc_slot_t* rs = find_rfc_slot_by_id(id);
    if(rs && p_open->status == BTA_JV_SUCCESS)
    {
        rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
        bd_copy(rs->addr.address, p_open->rem_bda, 0);
        //notify app rfc is connected
        APPL_TRACE_DEBUG4("call send_app_connect_signal, slot id:%d, fd:%d, rfc scn:%d, server:%d",
                         rs->id, rs->fd, rs->scn, rs->f.server);
        if(send_app_connect_signal(rs->fd, &rs->addr, rs->scn, 0, -1))
        {
            //start monitoring the socketpair to get call back when app writing data
            APPL_TRACE_DEBUG3("on_rfc_connect_ind, connect signal sent, slot id:%d, rfc scn:%d, server:%d",
                             rs->id, rs->scn, rs->f.server);
            rs->f.connected = TRUE;
        }
        else APPL_TRACE_ERROR0("send_app_connect_signal failed");
    }
    else if(rs)
        cleanup_rfc_slot(rs);
    unlock_slot(&slot_lock);
}
static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
{
    uint32_t id = (uint32_t)user_data;
    APPL_TRACE_DEBUG2("jv_dm_cback: event:%d, slot id:%d", event, id);
    switch(event)
    {
        case BTA_JV_CREATE_RECORD_EVT:
            {
                lock_slot(&slot_lock);
                rfc_slot_t* rs = find_rfc_slot_by_id(id);
                if(rs && create_server_sdp_record(rs))
                {
                    //now start the rfcomm server after sdp & channel # assigned
                    BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION, rfcomm_cback,
                                            (void*)rs->id);
                }
                else if(rs)
                {
                    APPL_TRACE_ERROR1("jv_dm_cback: cannot start server, slot found:%p", rs);
                    cleanup_rfc_slot(rs);
                }
                unlock_slot(&slot_lock);
                break;
            }
        case BTA_JV_DISCOVERY_COMP_EVT:
            {
                rfc_slot_t* rs = NULL;
                lock_slot(&slot_lock);
                if(p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn)
                {
                    APPL_TRACE_DEBUG3("BTA_JV_DISCOVERY_COMP_EVT, slot id:%d, status:%d, scn:%d",
                                      id, p_data->disc_comp.status, p_data->disc_comp.scn);

                    rs = find_rfc_slot_by_id(id);
                    if(rs && rs->f.doing_sdp_request)
                    {
                        if(BTA_JvRfcommConnect(rs->security, rs->role, p_data->disc_comp.scn, rs->addr.address,
                                    rfcomm_cback, (void*)rs->id) == BTA_JV_SUCCESS)
                        {
                            rs->scn = p_data->disc_comp.scn;
                            rs->f.doing_sdp_request = FALSE;
                            if(!send_app_scn(rs))
                                cleanup_rfc_slot(rs);
                        }
                        else cleanup_rfc_slot(rs);
                    }
                    else if(rs)
                    {
                        APPL_TRACE_ERROR3("DISCOVERY_COMP_EVT no pending sdp request, slot id:%d, \
                                flag sdp pending:%d, flag sdp doing:%d",
                                id, rs->f.pending_sdp_request, rs->f.doing_sdp_request);
                    }
                }
                else
                {
                    APPL_TRACE_ERROR3("DISCOVERY_COMP_EVT slot id:%d, failed to find channle, \
                                      status:%d, scn:%d", id, p_data->disc_comp.status,
                                      p_data->disc_comp.scn);
                    rs = find_rfc_slot_by_id(id);
                    if(rs)
                        cleanup_rfc_slot(rs);
                }
                rs = find_rfc_slot_by_pending_sdp();
                if(rs)
                {
                    APPL_TRACE_DEBUG0("BTA_JV_DISCOVERY_COMP_EVT, start another pending scn sdp request");
                    tSDP_UUID sdp_uuid;
                    sdp_uuid.len = 16;
                    memcpy(sdp_uuid.uu.uuid128, rs->service_uuid, sizeof(sdp_uuid.uu.uuid128));
                    BTA_JvStartDiscovery((UINT8*)rs->addr.address, 1, &sdp_uuid, (void*)rs->id);
                    rs->f.pending_sdp_request = FALSE;
                    rs->f.doing_sdp_request = TRUE;
                }
                unlock_slot(&slot_lock);
                break;
            }
static void bta_hf_client_handle_ccwa(char *numstr, UINT32 type)
{
    APPL_TRACE_DEBUG3("%s %u %s", __FUNCTION__, type, numstr);

    bta_hf_client_ccwa(numstr);
}
static void bta_hf_client_handle_cops(char *opstr, UINT32 mode)
{
    APPL_TRACE_DEBUG3("%s %u %s", __FUNCTION__, mode, opstr);

    bta_hf_client_operator_name(opstr);
}
/*******************************************************************************
**
** Function         bta_av_sys_rs_cback
**
** Description      Receives the role change event from dm
**
** Returns          (BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda)
**
*******************************************************************************/
static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
{
    int         i;
    tBTA_AV_SCB *p_scb;
    tBTA_AV_ROLE_RES  *p_buf;
    UINT8       cur_role;
    UINT8       peer_idx = 0;

    APPL_TRACE_DEBUG1("bta_av_sys_rs_cback: %d", bta_av_cb.rs_idx);
    for(i=0; i<BTA_AV_NUM_STRS; i++)
    {
        /* loop through all the SCBs to find matching peer addresses and report the role change event */
        /* note that more than one SCB (a2dp & vdp) maybe waiting for this event */
        p_scb = bta_av_cb.p_scb[i];
        if (p_scb && (bdcmp (peer_addr, p_scb->peer_addr) == 0) &&
            (p_buf = (tBTA_AV_ROLE_RES *) GKI_getbuf(sizeof(tBTA_AV_ROLE_RES))) != NULL)
        {
            APPL_TRACE_DEBUG3("new_role:%d, hci_status:x%x hndl: x%x", id, app_id, p_scb->hndl);
            /*
            if ((id != BTM_ROLE_MASTER) && (app_id != HCI_SUCCESS))
            {
                bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_MASTER_SLAVE_SWITCH|HCI_ENABLE_SNIFF_MODE), p_scb->peer_addr);
            }
            */
            p_buf->hdr.event = BTA_AV_ROLE_CHANGE_EVT;
            p_buf->hdr.layer_specific = p_scb->hndl;
            p_buf->new_role = id;
            p_buf->hci_status = app_id;
            bta_sys_sendmsg(p_buf);

            peer_idx = p_scb->hdi + 1;  /* Handle index for the peer_addr */
        }
    }

    /* restore role switch policy, if role switch failed */
    if ((HCI_SUCCESS != app_id) &&
        (BTM_GetRole (peer_addr, &cur_role) == BTM_SUCCESS) &&
        (cur_role == BTM_ROLE_SLAVE) )
    {
        bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, peer_addr);
    }

    /* if BTA_AvOpen() was called for other device, which caused the role switch of the peer_addr,  */
    /* we need to continue opening process for the BTA_AvOpen().                                    */
    if ((bta_av_cb.rs_idx != 0) && (bta_av_cb.rs_idx != peer_idx))
    {
        p_scb = bta_av_cb.p_scb[bta_av_cb.rs_idx - 1];
        if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN)
        {
            APPL_TRACE_DEBUG3 ("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d",
                bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag);

            if(HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id)
                p_scb->q_info.open.switch_res = BTA_AV_RS_OK;
            else
                p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL;

            /* Continue av open process */
            bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open));
        }

        bta_av_cb.rs_idx = 0;
    }
}
/*******************************************************************************
**
** Function         bta_av_api_register
**
** Description      allocate stream control block,
**                  register the service to stack
**                  create SDP record
**
** Returns          void
**
*******************************************************************************/
static void bta_av_api_register(tBTA_AV_DATA *p_data)
{
    tBTA_AV_REGISTER    registr;
    tBTA_AV_SCB         *p_scb;    /* stream control block */
    tAVDT_REG       reg;
    tAVDT_CS        cs;
    char            *p_service_name;
    tBTA_AV_CODEC   codec_type;
    tBTA_UTL_COD    cod;
    UINT8           index = 0;

    memset(&cs,0,sizeof(tAVDT_CS));

    registr.status = BTA_AV_FAIL_RESOURCES;
    registr.app_id = p_data->api_reg.app_id;
    registr.chnl   = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
    do
    {
        p_scb = bta_av_alloc_scb(registr.chnl);
        if(p_scb == NULL)
        {
            APPL_TRACE_ERROR0("failed to alloc SCB");
            break;
        }

        registr.hndl    = p_scb->hndl;
        p_scb->app_id   = registr.app_id;

        /* initialize the stream control block */
        p_scb->timer.p_cback = (TIMER_CBACK*)&bta_av_timer_cback;
        registr.status = BTA_AV_SUCCESS;

        if((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0)
        {
            /* the first channel registered. register to AVDTP */
            reg.ctrl_mtu = p_bta_av_cfg->sig_mtu;
            reg.ret_tout = BTA_AV_RET_TOUT;
            reg.sig_tout = BTA_AV_SIG_TOUT;
            reg.idle_tout = BTA_AV_IDLE_TOUT;
            reg.sec_mask = bta_av_cb.sec_mask;
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
            bta_ar_reg_avdt(&reg, bta_av_conn_cback, BTA_ID_AV);
#endif
            bta_sys_role_chg_register(&bta_av_sys_rs_cback);

            /* create remote control TG service if required */
            if (bta_av_cb.features & (BTA_AV_FEAT_RCTG))
            {
                /* register with no authorization; let AVDTP use authorization instead */
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
                bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                bta_av_cb.sec_mask, BTA_ID_AV);
#else
                bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
#endif

                bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL,
                                p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV);
#endif
            }

            /* Set the Capturing service class bit */
            cod.service = BTM_COD_SERVICE_CAPTURING;
            utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
        } /* if 1st channel */

        /* get stream configuration and create stream */
        /* memset(&cs.cfg,0,sizeof(tAVDT_CFG)); */
        cs.cfg.num_codec = 1;
#ifdef A2DP_SINK
        cs.tsep = AVDT_TSEP_SNK;
#else
        cs.tsep = AVDT_TSEP_SRC;
#endif

        /*
         * memset of cs takes care setting call back pointers to null.
        cs.p_data_cback = NULL;
        cs.p_report_cback = NULL;
        */
#ifdef A2DP_SINK
        cs.p_data_cback = bta_av_a2dp_data_cback;
#endif
        cs.nsc_mask = AVDT_NSC_RECONFIG |
              ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY);
        APPL_TRACE_DEBUG1("nsc_mask: 0x%x", cs.nsc_mask);

        if (p_data->api_reg.p_service_name[0] == 0)
        {
            p_service_name = NULL;
        }
        else
        {
            p_service_name = p_data->api_reg.p_service_name;
        }

        p_scb->suspend_sup  = TRUE;
        p_scb->recfg_sup    = TRUE;

        cs.p_ctrl_cback  = bta_av_dt_cback[p_scb->hdi];
        if(registr.chnl == BTA_AV_CHNL_AUDIO)
        {
            /* set up the audio stream control block */
            p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action;
            p_scb->p_cos     = &bta_av_a2d_cos;
            p_scb->media_type= AVDT_MEDIA_AUDIO;
            cs.cfg.psc_mask  = AVDT_PSC_TRANS;
            cs.media_type    = AVDT_MEDIA_AUDIO;
            cs.mtu           = p_bta_av_cfg->audio_mtu;
            cs.flush_to      = L2CAP_DEFAULT_FLUSH_TO;
#if AVDT_REPORTING == TRUE
            if(bta_av_cb.features & BTA_AV_FEAT_REPORT)
            {
                cs.cfg.psc_mask |= AVDT_PSC_REPORT;
                cs.p_report_cback = bta_av_a2dp_report_cback;
#if AVDT_MULTIPLEXING == TRUE
                cs.cfg.mux_tsid_report = 2;
#endif
            }
#endif
            if(bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
                cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;

            /* keep the configuration in the stream control block */
            memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
            while(index < BTA_AV_MAX_SEPS &&
                (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info,
                &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE)
            {
                if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS)
                {
                    p_scb->seps[index].codec_type = codec_type;
                    APPL_TRACE_DEBUG3("audio[%d] av_handle: %d codec_type: %d",
                        index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type);
                    index++;
                }
                else
                    break;
            }

            if(!bta_av_cb.reg_audio)
            {
                /* create the SDP records on the 1st audio channel */
                bta_av_cb.sdp_a2d_handle = SDP_CreateRecord();
#ifdef A2DP_SINK
                A2D_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL,
                                  A2D_SUPF_SPEAKER, bta_av_cb.sdp_a2d_handle);
                bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
#else
                A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
                                  A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle);
                bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
#endif

                /* start listening when A2DP is registered */
                if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
                    bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);

                /* if the AV and AVK are both supported, it cannot support the CT role */
                if (bta_av_cb.features & (BTA_AV_FEAT_RCCT))
                {
                    /* if TG is not supported, we need to register to AVCT now */
                    if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0)
                    {
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
                        bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                        bta_av_cb.sec_mask, BTA_ID_AV);
#else
                        bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
                                        (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV);
#endif
#endif
                    }
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
                    /* create an SDP record as AVRC CT. */
                    bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
                           p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV);
#endif
                }
            }
            bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
            APPL_TRACE_DEBUG1("reg_audio: 0x%x",bta_av_cb.reg_audio);
        }
        else
        {
            bta_av_cb.reg_video = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
            bta_av_cb.sdp_vdp_handle = SDP_CreateRecord();
            /* register the video channel */
            /* no need to verify the function pointer here. it's verified prior */
            (*p_bta_av_cfg->p_reg)(&cs, p_service_name, p_scb);
        }
    } while (0);

    /* call callback with register event */
    (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV *)&registr);
}
Exemple #20
0
/*******************************************************************************
 **
 ** Function         bta_av_co_audio_getconfig
 **
 ** Description      This callout function is executed by AV to retrieve the
 **                  desired codec and content protection configuration for the
 **                  audio stream.
 **
 **
 ** Returns          Stream codec and content protection configuration info.
 **
 *******************************************************************************/
BTA_API UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
        UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect,
        UINT8 *p_protect_info)

{
    UINT8 result = A2D_FAIL;
    BOOLEAN supported;
    tBTA_AV_CO_PEER *p_peer;
    tBTA_AV_CO_SINK *p_sink;
    UINT8 codec_cfg[AVDT_CODEC_SIZE];
    UINT8 index;

    FUNC_TRACE();

    APPL_TRACE_DEBUG3("bta_av_co_audio_getconfig handle:0x%x codec_type:%d seid:%d", hndl, codec_type, seid);
    APPL_TRACE_DEBUG4("num_protect:0x%02x protect_info:0x%02x%02x%02x",
        *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]);

    /* Retrieve the peer info */
    p_peer = bta_av_co_get_peer(hndl);
    if (p_peer == NULL)
    {
        APPL_TRACE_ERROR0("bta_av_co_audio_getconfig could not find peer entry");
        return A2D_FAIL;
    }

    APPL_TRACE_DEBUG4("bta_av_co_audio_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)",
            p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks);

    /* Increment the number of received sinks capabilities */
    p_peer->num_rx_snks++;

    /* Check if this is a supported configuration */
    supported = FALSE;
    switch (codec_type)
    {
    case BTA_AV_CODEC_SBC:
        supported = TRUE;
        break;

    default:
        break;
    }

    if (supported)
    {
        /* If there is room for a new one */
        if (p_peer->num_sup_snks < BTA_AV_CO_NUM_ELEMENTS(p_peer->snks))
        {
            p_sink = &p_peer->snks[p_peer->num_sup_snks++];

            APPL_TRACE_DEBUG6("bta_av_co_audio_getconfig saved caps[%x:%x:%x:%x:%x:%x]",
                    p_codec_info[1], p_codec_info[2], p_codec_info[3],
                    p_codec_info[4], p_codec_info[5], p_codec_info[6]);

            memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
            p_sink->codec_type = codec_type;
            p_sink->sep_info_idx = *p_sep_info_idx;
            p_sink->seid = seid;
            p_sink->num_protect = *p_num_protect;
            memcpy(p_sink->protect_info, p_protect_info, BTA_AV_CP_INFO_LEN);
        }
        else
        {
            APPL_TRACE_ERROR0("bta_av_co_audio_getconfig no more room for SNK info");
        }
    }

    /* If last SNK get capabilities or all supported codec capa retrieved */
    if ((p_peer->num_rx_snks == p_peer->num_snks) ||
        (p_peer->num_sup_snks == BTA_AV_CO_NUM_ELEMENTS(p_peer->snks)))
    {
        APPL_TRACE_DEBUG0("bta_av_co_audio_getconfig last sink reached");

        /* Protect access to bta_av_co_cb.codec_cfg */
        GKI_disable();

        /* Find a sink that matches the codec config */
        if (bta_av_co_audio_peer_supports_codec(p_peer, &index))
        {
            /* stop fetching caps once we retrieved a supported codec */
            if (p_peer->acp)
            {
                *p_sep_info_idx = p_peer->num_seps;
                APPL_TRACE_EVENT0("no need to fetch more SEPs");
            }

            p_sink = &p_peer->snks[index];

            /* Build the codec configuration for this sink */
            if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg))
            {
                APPL_TRACE_DEBUG6("bta_av_co_audio_getconfig reconfig p_codec_info[%x:%x:%x:%x:%x:%x]",
                        codec_cfg[1], codec_cfg[2], codec_cfg[3],
                        codec_cfg[4], codec_cfg[5], codec_cfg[6]);

                /* Save the new configuration */
                p_peer->p_snk = p_sink;
                memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE);

                /* By default, no content protection */
                *p_num_protect = 0;

#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
                /* Check if this sink supports SCMS */
                if (bta_av_co_audio_sink_has_scmst(p_sink))
                {
                    p_peer->cp_active = TRUE;
                    bta_av_co_cb.cp.active = TRUE;
                    *p_num_protect = BTA_AV_CP_INFO_LEN;
                    memcpy(p_protect_info, bta_av_co_cp_scmst, BTA_AV_CP_INFO_LEN);
                }
                else
                {
                    p_peer->cp_active = FALSE;
                    bta_av_co_cb.cp.active = FALSE;
                }
#endif

                /* If acceptor -> reconfig otherwise reply for configuration */
                if (p_peer->acp)
                {
                    if (p_peer->recfg_needed)
                    {
                        APPL_TRACE_DEBUG1("bta_av_co_audio_getconfig call BTA_AvReconfig(x%x)", hndl);
                        BTA_AvReconfig(hndl, TRUE, p_sink->sep_info_idx, p_peer->codec_cfg, *p_num_protect, (UINT8 *)bta_av_co_cp_scmst);
                    }
                }
                else
                {
                    *p_sep_info_idx = p_sink->sep_info_idx;
                    memcpy(p_codec_info, p_peer->codec_cfg, AVDT_CODEC_SIZE);
                }
                result =  A2D_SUCCESS;
            }
        }
        /* Protect access to bta_av_co_cb.codec_cfg */
        GKI_enable();
    }
    return result;
}
/*******************************************************************************
**
** Function         bta_hh_sm_execute
**
** Description      State machine event handling function for HID Host
**
**
** Returns          void
**
*******************************************************************************/
void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
{
    tBTA_HH_ST_TBL  state_table;
    UINT8           action;
    tBTA_HH         cback_data;
    tBTA_HH_EVT     cback_event = 0;
#if BTA_HH_DEBUG == TRUE
    tBTA_HH_STATE   in_state ;
    UINT16          debug_event = event;
#endif

    memset(&cback_data, 0, sizeof(tBTA_HH));

    /* handle exception, no valid control block was found */
    if (!p_cb)
    {
        /* BTA HH enabled already? otherwise ignore the event although it's bad*/
        if (bta_hh_cb.p_cback != NULL)
        {
            switch (event)
            {
            /* no control block available for new connection */
            case BTA_HH_API_OPEN_EVT:
                cback_event = BTA_HH_OPEN_EVT;
                /* build cback data */
                bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
                cback_data.conn.status  = BTA_HH_ERR_DB_FULL;
                cback_data.conn.handle  = BTA_HH_INVALID_HANDLE;
                break;
            /* DB full, BTA_HhAddDev */
            case BTA_HH_API_MAINT_DEV_EVT:
                cback_event = p_data->api_maintdev.sub_event;

                if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT)
                {
                    bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
                    cback_data.dev_info.status    = BTA_HH_ERR_DB_FULL;
                    cback_data.dev_info.handle    = BTA_HH_INVALID_HANDLE;
                }
                else
                {
                    cback_data.dev_info.status    = BTA_HH_ERR_HDL;
                    cback_data.dev_info.handle    = (UINT8)p_data->api_maintdev.hdr.layer_specific;
                }
                break;
            case BTA_HH_API_WRITE_DEV_EVT:
                cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
                        BTA_HH_FST_TRANS_CB_EVT;
                if (p_data->api_sndcmd.p_data != NULL)
                {
                    GKI_freebuf(p_data->api_sndcmd.p_data);
                }
                if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
                    p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
                    p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE)
                {
                    cback_data.dev_status.status = BTA_HH_ERR_HDL;
                    cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                }
                else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
                    p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
                {
                    cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                    cback_data.hs_data.status = BTA_HH_ERR_HDL;
                    /* hs_data.rsp_data will be all zero, which is not valid value */
                }
                else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL &&
                         p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
                {
                    cback_data.status = BTA_HH_ERR_HDL;
                    cback_event = BTA_HH_VC_UNPLUG_EVT;
                }
                else
                    cback_event = 0;
                break;

            case BTA_HH_API_CLOSE_EVT:
                cback_event = BTA_HH_CLOSE_EVT;

                cback_data.dev_status.status = BTA_HH_ERR_HDL;
                cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                break;

            default:
                /* invalid handle, call bad API event */
                APPL_TRACE_ERROR1("wrong device handle: [%d]", p_data->hdr.layer_specific);
                break;
            }
           if (cback_event)
               (* bta_hh_cb.p_cback)(cback_event, &cback_data);
        }
    }
    /* corresponding CB is found, go to state machine */
    else
    {
#if BTA_HH_DEBUG == TRUE
        in_state = p_cb->state;
        APPL_TRACE_EVENT3("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
                          in_state, bta_hh_state_code(in_state),
                          bta_hh_evt_code(debug_event));
#endif

        if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST))
        {
            APPL_TRACE_ERROR2("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d",
                              p_cb->state,event);
            return;
        }
        state_table = bta_hh_st_tbl[p_cb->state - 1];

        event &= 0xff;

        p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;

        if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
        {
            (*bta_hh_action[action])(p_cb, p_data);
        }

#if BTA_HH_DEBUG == TRUE
        if (in_state != p_cb->state)
        {
            APPL_TRACE_DEBUG3("HH State Change: [%s] -> [%s] after Event [%s]",
                          bta_hh_state_code(in_state),
                          bta_hh_state_code(p_cb->state),
                          bta_hh_evt_code(debug_event));
        }
#endif
    }

    return;
}
/*******************************************************************************
**
** Function         bta_hf_client_sco_event
**
** Description      Handle SCO events
**
**
** Returns          void
**
*******************************************************************************/
static void bta_hf_client_sco_event(UINT8 event)
{
    APPL_TRACE_DEBUG3("%s state: %d event: %d", __FUNCTION__,
                        bta_hf_client_cb.scb.sco_state, event);

    switch (bta_hf_client_cb.scb.sco_state)
    {
        case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
            switch (event)
            {
                case BTA_HF_CLIENT_SCO_LISTEN_E:
                    /* create sco listen connection */
                    bta_hf_client_sco_create(FALSE);
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
                    break;

                default:
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d", event);
                    break;
            }
            break;

        case BTA_HF_CLIENT_SCO_LISTEN_ST:
            switch (event)
            {
                case BTA_HF_CLIENT_SCO_LISTEN_E:
                    /* create sco listen connection (Additional channel) */
                    bta_hf_client_sco_create(FALSE);
                    break;

                case BTA_HF_CLIENT_SCO_OPEN_E:
                    /* remove listening connection */
                    bta_hf_client_sco_remove(FALSE);

                    /* create sco connection to peer */
                    bta_hf_client_sco_create(TRUE);
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
                    /* remove listening connection */
                    bta_hf_client_sco_remove(FALSE);

                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
                    break;

                case BTA_HF_CLIENT_SCO_CLOSE_E:
                    /* remove listening connection */
                    /* Ignore the event. We need to keep listening SCO for the active SLC */
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event);
                    break;

                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
                    /* sco failed; create sco listen connection */
                    bta_hf_client_sco_create(FALSE);
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
                    break;

                default:
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event);
                    break;
            }
            break;

        case BTA_HF_CLIENT_SCO_OPENING_ST:
            switch (event)
            {
                case BTA_HF_CLIENT_SCO_CLOSE_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
                    break;

                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
                    break;

                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
                    /* sco failed; create sco listen connection */
                    bta_hf_client_sco_create(FALSE);
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
                    break;

                default:
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d", event);
                    break;
            }
            break;

        case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
            switch (event)
            {
                case BTA_HF_CLIENT_SCO_OPEN_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
                    /* close sco connection */
                    bta_hf_client_sco_remove(TRUE);

                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
                    /* sco failed; create sco listen connection */

                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
                    break;

                default:
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d", event);
                    break;
            }
            break;

        case BTA_HF_CLIENT_SCO_OPEN_ST:
            switch (event)
            {
                case BTA_HF_CLIENT_SCO_CLOSE_E:
                    /* close sco connection if active */
                    if (bta_hf_client_sco_remove(TRUE))
                    {
                        bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
                    }
                    break;

                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
                    /* remove all listening connections */
                    bta_hf_client_sco_remove(FALSE);

                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
                    /* peer closed sco; create sco listen connection */
                    bta_hf_client_sco_create(FALSE);
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
                    break;

                default:
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d", event);
                    break;
            }
            break;

        case BTA_HF_CLIENT_SCO_CLOSING_ST:
            switch (event)
            {
                case BTA_HF_CLIENT_SCO_OPEN_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
                    break;

                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
                    /* peer closed sco; create sco listen connection */
                    bta_hf_client_sco_create(FALSE);

                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
                    break;

                default:
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d", event);
                    break;
            }
            break;

        case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
            switch (event)
            {
                case BTA_HF_CLIENT_SCO_CLOSE_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
                    break;

                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
                    /* open sco connection */
                    bta_hf_client_sco_create(TRUE);
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
                    break;

                default:
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d", event);
                    break;
            }
            break;

        case BTA_HF_CLIENT_SCO_SHUTTING_ST:
            switch (event)
            {
                case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
                    /* close sco connection; wait for conn close event */
                    bta_hf_client_sco_remove(TRUE);
                    break;

                case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
                    break;

                case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
                    bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
                    break;

                default:
                    APPL_TRACE_WARNING1("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d", event);
                    break;
            }
            break;

        default:
            break;
    }
}