Example #1
0
/*******************************************************************************
**
** Function         bta_hl_co_get_mdl_config
**
** Description     This function is called to get the MDL configuration
**                 from the persistent memory. This function shall only be called
*8                 once after the device is powered up
**
** Parameters      app_id - HDP application ID
**                 buffer_size - the unit of the buffer size is sizeof(tBTA_HL_MDL_CFG)
**                 p_mdl_buf - Point to the starting location of the buffer
**
** Returns         BOOLEAN
**
**
*******************************************************************************/
BOOLEAN bta_hl_co_load_mdl_config (UINT8 app_id, UINT8 buffer_size,
                                   tBTA_HL_MDL_CFG *p_mdl_buf )
{
    BOOLEAN result = TRUE;
    UINT8 i;
    tBTA_HL_MDL_CFG *p;

    BTIF_TRACE_DEBUG3("%s app_id=%d, num_items=%d",
                      __FUNCTION__, app_id, buffer_size);

    if (buffer_size > BTA_HL_NUM_MDL_CFGS)
    {
        result = FALSE;
        return result;
    }
    result = btif_hl_load_mdl_config(app_id, buffer_size, p_mdl_buf);

    if (result)
    {
        for (i=0, p=p_mdl_buf; i<buffer_size; i++, p++ )
        {
            if (p->active)
            {
                BTIF_TRACE_DEBUG6("i=%d mdl_id=0x%x dch_mode=%d local mdep_role=%d mdep_id=%d mtu=%d",
                                  i, p->mdl_id, p->dch_mode, p->local_mdep_role, p->local_mdep_role, p->mtu);
            }
        }
    }

    BTIF_TRACE_DEBUG3("%s success=%d num_items=%d", __FUNCTION__, result, buffer_size);

    return result;
}
Example #2
0
/*******************************************************************************
**
** Function        bta_hl_co_delete_mdl
**
** Description     This function is called to delete a MDL configuration item in persistent
**                 storage
**
** Parameters      app_id - HDP application ID
**                 item_idx - the MDL configuration storage index
**
** Returns          void
**
*******************************************************************************/
void bta_hl_co_delete_mdl(UINT8 app_id, UINT8 item_idx)
{


    BTIF_TRACE_DEBUG3("%s app_id=%d, item_idx=%d", __FUNCTION__, app_id, item_idx);

    btif_hl_delete_mdl_cfg(app_id, item_idx);


}
Example #3
0
void send_key (int fd, uint16_t key, int pressed)
{
    BTIF_TRACE_DEBUG4("%s fd:%d key:%u pressed:%d", __FUNCTION__,
        fd, key, pressed);

    if (fd < 0)
    {
        return;
    }

    BTIF_TRACE_DEBUG3("AVRCP: Send key %d (%d) fd=%d", key, pressed, fd);
    send_event(fd, EV_KEY, key, pressed);
    send_event(fd, EV_SYN, SYN_REPORT, 0);
}
Example #4
0
BOOLEAN btif_av_stream_started_ready(void)
{
    btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);

    BTIF_TRACE_DEBUG3("btif_av_stream_started : sm hdl %d, state %d, flags %x",
                btif_av_cb.sm_handle, state, btif_av_cb.flags);

    /* don't allow media task to start if we are suspending or
       remotely suspended (not yet changed state) */
    if (btif_av_cb.flags & (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING | BTIF_AV_FLAG_REMOTE_SUSPEND))
        return FALSE;

    return (state == BTIF_AV_STATE_STARTED);
}
Example #5
0
int init_uinput (void)
{
    char *name = "AVRCP";

    BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
    uinput_fd = uinput_create(name);
    if (uinput_fd < 0) {
        BTIF_TRACE_ERROR3("%s AVRCP: Failed to initialize uinput for %s (%d)",
                          __FUNCTION__, name, uinput_fd);
    } else {
        BTIF_TRACE_DEBUG3("%s AVRCP: Initialized uinput for %s (fd=%d)",
                          __FUNCTION__, name, uinput_fd);
    }
    return uinput_fd;
}
Example #6
0
/*******************************************************************************
**
** Function        bta_hl_co_get_num_of_mdep
**
** Description     This function is called to get the number of MDEPs for this
**                 application ID
**
** Parameters      app_id - application ID
**                 p_num_of_mdep (output) - number of MDEP configurations supported
**                                          by the application
**
** Returns         Bloolean - TRUE success
**
*******************************************************************************/
BOOLEAN bta_hl_co_get_num_of_mdep(UINT8 app_id, UINT8 *p_num_of_mdep)
{
    UINT8 app_idx;
    BOOLEAN success = FALSE;

    if (btif_hl_find_app_idx(app_id, &app_idx))
    {
        *p_num_of_mdep = p_btif_hl_cb->acb[app_idx].sup_feature.num_of_mdeps;
        success = TRUE;
    }


    BTIF_TRACE_DEBUG3("%s success=%d num_mdeps=%d",
                      __FUNCTION__, success, *p_num_of_mdep );
    return success;
}
Example #7
0
/***************************************************************************
 **
 ** Function       btif_rc_handler
 **
 ** Description    RC event handler
 **
 ***************************************************************************/
void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
{
    BTIF_TRACE_DEBUG2 ("%s event:%s", __FUNCTION__, dump_rc_event(event));
    switch (event)
    {
        case BTA_AV_RC_OPEN_EVT:
        {
            BTIF_TRACE_DEBUG1("Peer_features:%x", p_data->rc_open.peer_features);
            handle_rc_connect( &(p_data->rc_open) );
        }break;

        case BTA_AV_RC_CLOSE_EVT:
        {
            handle_rc_disconnect( &(p_data->rc_close) );
        }break;

        case BTA_AV_REMOTE_CMD_EVT:
        {
            BTIF_TRACE_DEBUG2("rc_id:0x%x key_state:%d", p_data->remote_cmd.rc_id,
                               p_data->remote_cmd.key_state);
            handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
        }
        break;
        case BTA_AV_RC_FEAT_EVT:
        {
            BTIF_TRACE_DEBUG1("Peer_features:%x", p_data->rc_feat.peer_features);
            btif_rc_cb.rc_features = p_data->rc_feat.peer_features;
            /* TODO  Handle RC_FEAT_EVT*/
        }
        break;
        case BTA_AV_META_MSG_EVT:
        {
            BTIF_TRACE_DEBUG2("BTA_AV_META_MSG_EVT  code:%d label:%d", p_data->meta_msg.code,
                p_data->meta_msg.label);
            BTIF_TRACE_DEBUG3("  company_id:0x%x len:%d handle:%d", p_data->meta_msg.company_id,
                p_data->meta_msg.len, p_data->meta_msg.rc_handle);
            /* handle the metamsg command */
            handle_rc_metamsg_cmd(&(p_data->meta_msg));
        }
        break;
        default:
            BTIF_TRACE_DEBUG1("Unhandled RC event : 0x%x", event);
    }
}
Example #8
0
btpan_conn_t* btpan_new_conn(int handle, const BD_ADDR addr, int local_role, int remote_role )
{
    int i;
    for(i = 0; i < MAX_PAN_CONNS; i++)
    {
        BTIF_TRACE_DEBUG2("conns[%d]:%d", i, btpan_cb.conns[i].handle);
        if(btpan_cb.conns[i].handle == -1)
        {
            BTIF_TRACE_DEBUG3("handle:%d, local_role:%d, remote_role:%d", handle, local_role, remote_role);

            btpan_cb.conns[i].handle = handle;
            bdcpy(btpan_cb.conns[i].peer, addr);
            btpan_cb.conns[i].local_role = local_role;
            btpan_cb.conns[i].remote_role = remote_role;
            return &btpan_cb.conns[i];
        }
    }
    BTIF_TRACE_DEBUG1("MAX_PAN_CONNS:%d exceeded, return NULL as failed", MAX_PAN_CONNS);
    return NULL;
}
Example #9
0
BOOLEAN btif_av_stream_ready(void)
{
    btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);

    BTIF_TRACE_DEBUG3("btif_av_stream_ready : sm hdl %d, state %d, flags %x",
                btif_av_cb.sm_handle, state, btif_av_cb.flags);

    /* also make sure main adapter is enabled */
    if (btif_is_enabled() == 0)
    {
        BTIF_TRACE_EVENT0("main adapter not enabled");
        return FALSE;
    }

    /* check if we are remotely suspended */
    if (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND)
        return FALSE;

    return (state == BTIF_AV_STATE_OPENED);
}
Example #10
0
/***************************************************************************
 *  Function       send_metamsg_rsp
 *
 *  - Argument:
 *                  rc_handle     RC handle corresponding to the connected RC
 *                  label            Label of the RC response
 *                  code            Response type
 *                  pmetamsg_resp    Vendor response
 *
 *  - Description: Remote control metamsg response handler (AVRCP 1.3)
 *
 ***************************************************************************/
static void send_metamsg_rsp (UINT8 rc_handle, UINT8 label, tBTA_AV_CODE code,
    tAVRC_RESPONSE *pmetamsg_resp)
{
    UINT8 ctype;
    tAVRC_STS status;

    if (!pmetamsg_resp)
    {
        BTIF_TRACE_WARNING1("%s: Invalid response received from application", __FUNCTION__);
        return;
    }

    BTIF_TRACE_EVENT5("+%s: rc_handle: %d, label: %d, code: 0x%02x, pdu: %s", __FUNCTION__,
        rc_handle, label, code, dump_rc_pdu(pmetamsg_resp->rsp.pdu));

    if (pmetamsg_resp->rsp.status != AVRC_STS_NO_ERROR)
    {
        ctype = AVRC_RSP_REJ;
    }
    else
    {
        if ( code < AVRC_RSP_NOT_IMPL)
        {
            if (code == AVRC_CMD_NOTIF)
            {
               ctype = AVRC_RSP_INTERIM;
            }
            else if (code == AVRC_CMD_STATUS)
            {
               ctype = AVRC_RSP_IMPL_STBL;
            }
            else
            {
               ctype = AVRC_RSP_ACCEPT;
            }
        }
        else
        {
            ctype = code;
        }
    }
    /* if response is for register_notification, make sure the rc has
    actually registered for this */
    if((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) && (code == AVRC_RSP_CHANGED))
    {
        BOOLEAN bSent = FALSE;
        UINT8   event_id = pmetamsg_resp->reg_notif.event_id;
        BOOLEAN bNotify = (btif_rc_cb.rc_connected) && (btif_rc_cb.rc_notif[event_id-1].bNotify);

        /* de-register this notification for a CHANGED response */
        btif_rc_cb.rc_notif[event_id-1].bNotify = FALSE;
        BTIF_TRACE_DEBUG4("%s rc_handle: %d. event_id: 0x%02d bNotify:%u", __FUNCTION__,
             btif_rc_cb.rc_handle, event_id, bNotify);
        if (bNotify)
        {
            BT_HDR *p_msg = NULL;
            tAVRC_STS status;

            if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(btif_rc_cb.rc_handle,
                pmetamsg_resp, &p_msg)) )
            {
                BTIF_TRACE_DEBUG3("%s Sending notification to rc_handle: %d. event_id: 0x%02d",
                     __FUNCTION__, btif_rc_cb.rc_handle, event_id);
                bSent = TRUE;
                BTA_AvMetaRsp(btif_rc_cb.rc_handle, btif_rc_cb.rc_notif[event_id-1].label,
                    ctype, p_msg);
            }
            else
            {
                BTIF_TRACE_WARNING2("%s failed to build metamsg response. status: 0x%02x",
                    __FUNCTION__, status);
            }

        }

        if (!bSent)
        {
            BTIF_TRACE_DEBUG2("%s: Notification not sent, as there are no RC connections or the \
                CT has not subscribed for event_id: %s", __FUNCTION__, dump_rc_notification_event_id(event_id));
        }
Example #11
0
/***************************************************************************
 *  Function       handle_rc_metamsg_cmd
 *
 *  - Argument:    tBTA_AV_VENDOR Structure containing the received
 *                          metamsg command
 *
 *  - Description: Remote control metamsg command handler (AVRCP 1.3)
 *
 ***************************************************************************/
void handle_rc_metamsg_cmd (tBTA_AV_META_MSG *pmeta_msg)
{
    /* Parse the metamsg command and pass it on to BTL-IFS */
    UINT8             scratch_buf[512] = {0};
    tAVRC_COMMAND    avrc_command = {0};
    tAVRC_STS status;
    int param_len;

    BTIF_TRACE_EVENT1("+ %s", __FUNCTION__);

    if (pmeta_msg->p_msg->hdr.opcode != AVRC_OP_VENDOR)
    {
        BTIF_TRACE_WARNING1("Invalid opcode: %x", pmeta_msg->p_msg->hdr.opcode);
        return;
    }
    if (pmeta_msg->len < 3)
    {
        BTIF_TRACE_WARNING2("Invalid length.Opcode: 0x%x, len: 0x%x", pmeta_msg->p_msg->hdr.opcode,
            pmeta_msg->len);
        return;
    }

    if (pmeta_msg->code >= AVRC_RSP_NOT_IMPL)
    {
        BTIF_TRACE_DEBUG3("%s:Received vendor dependent rsp. code: %d len: %d. Not processing it.",
            __FUNCTION__, pmeta_msg->code, pmeta_msg->len);
        return;
    }
    status = AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf, sizeof(scratch_buf));

    if (status != AVRC_STS_NO_ERROR)
    {
        /* return error */
        BTIF_TRACE_WARNING2("%s: Error in parsing received  metamsg command. status: 0x%02x",
            __FUNCTION__, status);
        send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_command.pdu, status);
    }
    else
    {
        /* if RegisterNotification, add it to our registered queue */

        if (avrc_command.cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION)
        {
            UINT8 event_id = avrc_command.reg_notif.event_id;
            param_len = sizeof(tAVRC_REG_NOTIF_CMD);
            BTIF_TRACE_EVENT3("%s: New register notification received. event_id:%s, label:0x%x",
                 __FUNCTION__, dump_rc_notification_event_id(event_id), pmeta_msg->label);
            btif_rc_cb.rc_notif[event_id-1].bNotify = TRUE;
            btif_rc_cb.rc_notif[event_id-1].label = pmeta_msg->label;

            if(event_id == AVRC_EVT_UIDS_CHANGE)
            {
                handle_uid_changed_notification(pmeta_msg, &avrc_command);
                return;
            }

        }

        BTIF_TRACE_EVENT2("%s: Passing received metamsg command to app. pdu: %s",
            __FUNCTION__, dump_rc_pdu(avrc_command.cmd.pdu));

        /* Since handle_rc_metamsg_cmd() itself is called from
            *btif context, no context switching is required. Invoke
            * btif_rc_upstreams_evt directly from here. */
        btif_rc_upstreams_evt((uint16_t)avrc_command.cmd.pdu, &avrc_command, pmeta_msg->code,
            pmeta_msg->label);
    }
}
Example #12
0
/***************************************************************************
 *  Function       handle_rc_passthrough_cmd
 *
 *  - Argument:    tBTA_AV_RC rc_id   remote control command ID
 *                 tBTA_AV_STATE key_state status of key press
 *
 *  - Description: Remote control command handler
 *
 ***************************************************************************/
void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
{
    const char *status;
    int pressed, i;

    /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up this PLAY */
    if (p_remote_cmd)
    {
        /* queue AVRC PLAY if GAVDTP Open notification to app is pending (2 second timer) */
        if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) && (!btif_av_is_connected()))
        {
            if (p_remote_cmd->key_state == AVRC_STATE_PRESS)
            {
                APPL_TRACE_WARNING1("%s: AVDT not open, queuing the PLAY command", __FUNCTION__);
                btif_rc_cb.rc_pending_play = TRUE;
            }
            return;
        }

        if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb.rc_pending_play))
        {
            APPL_TRACE_WARNING1("%s: Clear the pending PLAY on PAUSE received", __FUNCTION__);
            btif_rc_cb.rc_pending_play = FALSE;
            return;
        }
    }
    if (p_remote_cmd->key_state == AVRC_STATE_RELEASE) {
        status = "released";
        pressed = 0;
    } else {
        status = "pressed";
        pressed = 1;
    }

    /* If this is Play/Pause command (press or release)  before processing, check the following
     * a voice call has ended recently
     * the remote device is not of type headset
     * If the above conditions meet, drop the Play/Pause command
     * This fix is to interop with certain carkits which sends an automatic  PLAY  or PAUSE
     * commands right after call ends
     */
    if((p_remote_cmd->rc_id == BTA_AV_RC_PLAY || p_remote_cmd->rc_id == BTA_AV_RC_PAUSE)&&
       (btif_hf_call_terminated_recently() == TRUE) &&
       (check_cod( (const bt_bdaddr_t*)&(btif_rc_cb.rc_addr), COD_AV_HEADSETS) != TRUE))
    {
        BTIF_TRACE_DEBUG2("%s:Dropping the play/Pause command received right after call end cmd:%d",
                           __FUNCTION__,p_remote_cmd->rc_id);
        return;
    }

    for (i = 0; key_map[i].name != NULL; i++) {
        if (p_remote_cmd->rc_id == key_map[i].avrcp) {
            BTIF_TRACE_DEBUG3("%s: %s %s", __FUNCTION__, key_map[i].name, status);

           /* MusicPlayer uses a long_press_timeout of 1 second for PLAYPAUSE button
            * and maps that to autoshuffle. So if for some reason release for PLAY/PAUSE
            * comes 1 second after the press, the MediaPlayer UI goes into a bad state.
            * The reason for the delay could be sniff mode exit or some AVDTP procedure etc.
            * The fix is to generate a release right after the press and drown the 'actual'
            * release.
            */
            if ((key_map[i].release_quirk == 1) && (pressed == 0))
            {
                BTIF_TRACE_DEBUG2("%s: AVRC %s Release Faked earlier, drowned now",
                                  __FUNCTION__, key_map[i].name);
                return;
            }
            send_key(uinput_fd, key_map[i].mapped_id, pressed);
            if ((key_map[i].release_quirk == 1) && (pressed == 1))
            {
                GKI_delay(30); // 30ms
                BTIF_TRACE_DEBUG2("%s: AVRC %s Release quirk enabled, send release now",
                                  __FUNCTION__, key_map[i].name);
                send_key(uinput_fd, key_map[i].mapped_id, 0);
            }
            break;
        }
    }

    if (key_map[i].name == NULL)
        BTIF_TRACE_ERROR3("%s AVRCP: unknown button 0x%02X %s", __FUNCTION__,
                        p_remote_cmd->rc_id, status);
}
/***************************************************************************
 *  Function       handle_rc_passthrough_cmd
 *
 *  - Argument:    tBTA_AV_RC rc_id   remote control command ID
 *                 tBTA_AV_STATE key_state status of key press
 *
 *  - Description: Remote control command handler
 *
 ***************************************************************************/
void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
{
    const char *status;
    int pressed, i;

    /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up this PLAY */
    if (p_remote_cmd)
    {
        /* queue AVRC PLAY if GAVDTP Open notification to app is pending (2 second timer) */
        if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) && (!btif_av_is_connected()))
        {
            if (p_remote_cmd->key_state == AVRC_STATE_PRESS)
            {
                APPL_TRACE_WARNING1("%s: AVDT not open, queuing the PLAY command", __FUNCTION__);
                btif_rc_cb.rc_pending_play = TRUE;
            }
            return;
        }

        if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb.rc_pending_play))
        {
            APPL_TRACE_WARNING1("%s: Clear the pending PLAY on PAUSE received", __FUNCTION__);
            btif_rc_cb.rc_pending_play = FALSE;
            return;
        }
    }
    if (p_remote_cmd->key_state == AVRC_STATE_RELEASE) {
        status = "released";
        pressed = 0;
    } else {
        status = "pressed";
        pressed = 1;
    }


    for (i = 0; key_map[i].name != NULL; i++) {
        if (p_remote_cmd->rc_id == key_map[i].avrcp) {
            BTIF_TRACE_DEBUG3("%s: %s %s", __FUNCTION__, key_map[i].name, status);

           /* MusicPlayer uses a long_press_timeout of 1 second for PLAYPAUSE button
            * and maps that to autoshuffle. So if for some reason release for PLAY/PAUSE
            * comes 1 second after the press, the MediaPlayer UI goes into a bad state.
            * The reason for the delay could be sniff mode exit or some AVDTP procedure etc.
            * The fix is to generate a release right after the press and drown the 'actual'
            * release.
            */
            if ((key_map[i].release_quirk == 1) && (pressed == 0))
            {
                BTIF_TRACE_DEBUG2("%s: AVRC %s Release Faked earlier, drowned now",
                                  __FUNCTION__, key_map[i].name);
                return;
            }
            send_key(uinput_fd, key_map[i].mapped_id, pressed);
            if ((key_map[i].release_quirk == 1) && (pressed == 1))
            {
                GKI_delay(30); // 30ms
                BTIF_TRACE_DEBUG2("%s: AVRC %s Release quirk enabled, send release now",
                                  __FUNCTION__, key_map[i].name);
                send_key(uinput_fd, key_map[i].mapped_id, 0);
            }
            break;
        }
    }

    if (key_map[i].name == NULL)
        BTIF_TRACE_ERROR3("%s AVRCP: unknown button 0x%02X %s", __FUNCTION__,
                        p_remote_cmd->rc_id, status);
}
Example #14
0
static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_state_t call_setup_state,
                                            const char *number, bthf_call_addrtype_t type)
{
    tBTA_AG_RES res = 0xff;
    tBTA_AG_RES_DATA ag_res;
    bt_status_t status = BT_STATUS_SUCCESS;
    BOOLEAN activeCallUpdated = FALSE;

    CHECK_BTHF_SLC_CONNECTED();

    BTIF_TRACE_DEBUG6("phone_state_change: num_active=%d [prev: %d]  num_held=%d[prev: %d]"\
                      " call_setup=%s [prev: %s]", num_active, btif_hf_cb.num_active,
                       num_held, btif_hf_cb.num_held,
                       dump_hf_call_state(call_setup_state), dump_hf_call_state(btif_hf_cb.call_setup_state));

    /* if all indicators are 0, send end call and return */
    if (num_active == 0 && num_held == 0 && call_setup_state == BTHF_CALL_STATE_IDLE)
    {
        BTIF_TRACE_DEBUG1("%s: Phone on hook", __FUNCTION__);

        /* record call termination timestamp  if  there was an active/held call  or callsetup state > BTHF_CALL_STATE_IDLE */
        if ((btif_hf_cb.call_setup_state != BTHF_CALL_STATE_IDLE ) || (btif_hf_cb.num_active) ||(btif_hf_cb.num_held))
        {
            BTIF_TRACE_DEBUG1("%s: Record call termination timestamp", __FUNCTION__);
            clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb.call_end_timestamp);
        }
        BTA_AgResult (BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);

        /* if held call was present, reset that as well */
        if (btif_hf_cb.num_held)
            send_indicator_update(BTA_AG_IND_CALLHELD, 0);

        goto update_call_states;
    }

    /* active state can change when:
    ** 1. an outgoing/incoming call was answered
    ** 2. an held was resumed
    ** 3. without callsetup notifications, call became active
    ** (3) can happen if call is active and a headset connects to us
    **
    ** In the case of (3), we will have to notify the stack of an active
    ** call, instead of sending an indicator update. This will also
    ** force the SCO to be setup. Handle this special case here prior to
    ** call setup handling
    */
    if ( (num_active == 1) && (btif_hf_cb.num_active == 0) && (btif_hf_cb.num_held == 0) &&
         (btif_hf_cb.call_setup_state == BTHF_CALL_STATE_IDLE) )
    {
        BTIF_TRACE_DEBUG1("%s: Active call notification received without call setup update",
                          __FUNCTION__);

        memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
        ag_res.audio_handle = btif_hf_cb.handle;
        res = BTA_AG_OUT_CALL_CONN_RES;
        BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
        activeCallUpdated = TRUE;
    }

    /* Ringing call changed? */
    if (call_setup_state != btif_hf_cb.call_setup_state)
    {
        BTIF_TRACE_DEBUG3("%s: Call setup states changed. old: %s new: %s",
            __FUNCTION__, dump_hf_call_state(btif_hf_cb.call_setup_state),
            dump_hf_call_state(call_setup_state));
        memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));

        switch (call_setup_state)
        {
            case BTHF_CALL_STATE_IDLE:
            {
                switch (btif_hf_cb.call_setup_state)
                {
                    case BTHF_CALL_STATE_INCOMING:
                        if (num_active > btif_hf_cb.num_active)
                        {
                            res = BTA_AG_IN_CALL_CONN_RES;
                            ag_res.audio_handle = btif_hf_cb.handle;
                        }
                        else if (num_held > btif_hf_cb.num_held)
                            res = BTA_AG_IN_CALL_HELD_RES;
                        else
                            res = BTA_AG_CALL_CANCEL_RES;
                        break;
                    case BTHF_CALL_STATE_DIALING:
                    case BTHF_CALL_STATE_ALERTING:
                        if (num_active > btif_hf_cb.num_active)
                        {
                            ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
                            res = BTA_AG_OUT_CALL_CONN_RES;
                        }
                        else
                            res = BTA_AG_CALL_CANCEL_RES;
                        break;
                    default:
                        BTIF_TRACE_ERROR1("%s: Incorrect Call setup state transition", __FUNCTION__);
                        status = BT_STATUS_PARM_INVALID;
                        break;
                }
            } break;

            case BTHF_CALL_STATE_INCOMING:
                if (num_active || num_held)
                    res = BTA_AG_CALL_WAIT_RES;
                else
                    res = BTA_AG_IN_CALL_RES;
                if (number)
                {
                    int xx = 0;
                    if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
                        xx = sprintf (ag_res.str, "\"+%s\"", number);
                    else
                        xx = sprintf (ag_res.str, "\"%s\"", number);
                    ag_res.num = type;

                    if (res == BTA_AG_CALL_WAIT_RES)
                        sprintf(&ag_res.str[xx], ",%d", type);
                }
                break;
            case BTHF_CALL_STATE_DIALING:
                ag_res.audio_handle = btif_hf_cb.handle;
                res = BTA_AG_OUT_CALL_ORIG_RES;
                break;
            case BTHF_CALL_STATE_ALERTING:
                /* if we went from idle->alert, force SCO setup here. dialing usually triggers it */
                if (btif_hf_cb.call_setup_state == BTHF_CALL_STATE_IDLE)
                ag_res.audio_handle = btif_hf_cb.handle;
                res = BTA_AG_OUT_CALL_ALERT_RES;
                break;
            default:
                BTIF_TRACE_ERROR1("%s: Incorrect new ringing call state", __FUNCTION__);
                status = BT_STATUS_PARM_INVALID;
                break;
        }
        BTIF_TRACE_DEBUG3("%s: Call setup state changed. res=%d, audio_handle=%d", __FUNCTION__, res, ag_res.audio_handle);

        if (res)
            BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);

        /* if call setup is idle, we have already updated call indicator, jump out */
        if (call_setup_state == BTHF_CALL_STATE_IDLE)
        {
            /* check & update callheld */
            if ((num_held > 0) && (num_active > 0))
                send_indicator_update(BTA_AG_IND_CALLHELD, 1);
            goto update_call_states;
        }
    }

    memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));

    /* per the errata 2043, call=1 implies atleast one call is in progress (active/held)
    ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
    ** Handle call indicator change
    **/
    if (!activeCallUpdated && ((num_active + num_held) != (btif_hf_cb.num_active + btif_hf_cb.num_held)) )
    {
        BTIF_TRACE_DEBUG3("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.num_active, num_active);
        send_indicator_update(BTA_AG_IND_CALL, ((num_active + num_held) > 0) ? 1 : 0);
    }

    /* Held Changed? */
    if (num_held != btif_hf_cb.num_held)
    {
        BTIF_TRACE_DEBUG3("%s: Held call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.num_held, num_held);
        send_indicator_update(BTA_AG_IND_CALLHELD, ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
    }

    /* Calls Swapped? */
    if ( (call_setup_state == btif_hf_cb.call_setup_state) &&
         (num_active && num_held) &&
         (num_active == btif_hf_cb.num_active) &&
         (num_held == btif_hf_cb.num_held) )
    {
        BTIF_TRACE_DEBUG1("%s: Calls swapped", __FUNCTION__);
        send_indicator_update(BTA_AG_IND_CALLHELD, 1);
    }

update_call_states:
    btif_hf_cb.num_active = num_active;
    btif_hf_cb.num_held = num_held;
    btif_hf_cb.call_setup_state = call_setup_state;

    return status;
}