/****************************************************************************
NAME	
	aghfpHandleAudioConnectReq

DESCRIPTION
	Transfer the audio from the AG to the HF or vice versa depending on which
	device currently has it.

RETURNS
	void
*/
void aghfpHandleAudioConnectReq(AGHFP *aghfp, const AGHFP_INTERNAL_AUDIO_CONNECT_REQ_T *req)
{
    AGHFP_DEBUG(("aghfpHandleAudioConnectReq\n"));
	/* If we don't have a valid audio handle, open a Synchronous connection */
    switch ( aghfp->audio_connection_state )
    {
    case aghfp_audio_disconnected:
	case aghfp_audio_codec_connect:
		audioConnectRequest(aghfp, req->packet_type, &req->audio_params);
        break;
    case aghfp_audio_connecting_esco:
    case aghfp_audio_connecting_sco:
    case aghfp_audio_accepting:
		/* Already attempting to create an audio connection - indicate a fail for this attempt */
		sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_in_progress, hci_success);
        break;
    case aghfp_audio_disconnecting:   /* Until disconnect is complete, assume we have a connection */
    case aghfp_audio_connected:
		/* Already have an audio connection - indicate a fail for this attempt */
		sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_have_audio, hci_success);
		break;
	default:
        AGHFP_DEBUG(("aghfpHandleAudioConnectReq invalid state %d\n",aghfp->audio_connection_state));
        break;
    }
}
void aghfpHandleAvailableCodecs(Task task, const struct aghfpHandleAvailableCodecs *availableCodecs)
{
	/* Immediately extract the data. Once we return from this
	   function the data is lost, so parse now. */
	uint16 num_of_entries = availableCodecs->codecs.count;
	uint16 counter1;
	struct value_aghfpHandleAvailableCodecs_codecs value;

	MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_CODEC_NEGOTIATION_REQ);
	
	AGHFP_DEBUG(("aghfpHandleCodecNegotiationReq\n"));

	if(num_of_entries > AGHFP_MAX_NUM_CODECS)
	{
		AGHFP_DEBUG(("Warning HF specified more codecs than AG can handle. Only considering the first %d\n", AGHFP_MAX_NUM_CODECS));
		num_of_entries = AGHFP_MAX_NUM_CODECS;
	}

	message->num_codecs = num_of_entries;

	for (counter1 = 0; counter1 < num_of_entries; counter1++)
	{
		/* Get the next Codec ID. */
		value = get_aghfpHandleAvailableCodecs_codecs(&availableCodecs->codecs, counter1);

		message->codec_uuids[counter1] = value.codec;
	}

	MessageSend(task, AGHFP_INTERNAL_CODEC_NEGOTIATION_REQ, message);
}
void aghfpEnableWbs(AGHFP *aghfp)
{
	if (aghfp->codecs_info.ag_codecs)
	{ /* WB-Speech Supported */
		AGHFP_DEBUG(("WB-Speech Local Codecs [0x%x]\n", aghfp->codecs_info.ag_codecs));
		aghfp->use_wbs = TRUE;
	}
	else
	{
		AGHFP_DEBUG(("Wbs - Not Supported, Disabling WB-Speech\n"));
		aghfp->use_wbs = FALSE;
	}
}
/****************************************************************************
NAME	
	aghfpHandleAudioTransferReqError

DESCRIPTION
	The app has requested that the audio be transferred (either to or from the AG).
	If the profile instance was in the wrong state for this operation to be 
	performed we need to send an immediate response to the app indicating an
	error has ocurred. We send the a audio status message with the status code 
	set to hfp_fail. We determine which message to send by looking at the action
	the app has requested and the current state of the HFP instance.

RETURNS
	void
*/
void aghfpHandleAudioTransferReqError(AGHFP *aghfp, const AGHFP_INTERNAL_AUDIO_TRANSFER_REQ_T *req)
{
	switch (req->direction)
	{
	case aghfp_audio_to_hfp:
        /* Send error message to inform the app we didn't open a Synchronous connection */
        sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_error, hci_success);
		break;

	case aghfp_audio_to_ag:
        /* Send error message to inform the app we didn't close the Synchronous connection */
        sendAudioDisconnectIndToApp(aghfp, aghfp_audio_disconnect_error);
		break;

	case aghfp_audio_transfer:
        /* Need to inform the app that the request failed. */
        if (aghfp->audio_sink)
        {
			sendAudioDisconnectIndToApp(aghfp, aghfp_audio_disconnect_error);
        }
		else
        {
			sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_error, hci_success);
        }
		break;

	default:
		AGHFP_DEBUG(("Unknown audio transfer direction\n"));
	}
}
/*
	Start Codec negotiation with HF
*/
bool aghfpWbsStartCodecNegotiation(AGHFP *aghfp, aghfp_wbs_negotiate_action wbs_negotiate_action)
{
	char bcs[15];
	uint16 codec; 		/* Codec bitmap used internally */
	uint16 codecUUID16; /* Used to store the actual codec UUID16 */
	
	/*	find highest codec supported by both ends*/
	codec = aghfp->codecs_info.ag_codecs & aghfp->hf_codecs;

	AGHFP_DEBUG(("aghfpWbsStartCodecNegotiation\n"));
	
	if ((codec & aghfp->codec_to_negotiate) == 0)
		return FALSE;

	/* If we get here then the selected codec to negotiate is ok. */
 	
	/* Remember the codec we wish to use */
	aghfp->use_codec = aghfp->codec_to_negotiate;
	
	/* Translate from the internal bitmap format (only one bit should be set in 'aghfp->use_codec') into codec UUID16. */
	codecUUID16 = WbsCodecToUuid16((codecs_info*)(&aghfp->codecs_info), aghfp->use_codec);

	/* Create the AT cmd we're sending */
	aghfpAtCmdBegin(aghfp);
	aghfpAtCmdString(aghfp, "+BCS=");

	sprintf(bcs, "%d", codecUUID16);

	aghfpAtCmdString(aghfp, bcs);
	aghfpAtCmdEnd(aghfp);
	
	aghfp->wbs_negotiate_action = wbs_negotiate_action;
	
	return TRUE;
}
void aghfpDisableWbs(AGHFP *aghfp)
{
	AGHFP_DEBUG(("Wbs - Disabling WB-Speech\n"));
	aghfp->use_wbs = FALSE;

	/* Clear any negotiated codec. */
	aghfp->use_codec = 0;
}
/****************************************************************************
NAME	
	aghfpHandleSyncDisconnectInd

DESCRIPTION
	Audio (Synchronous) connection has been disconnected 

RETURNS
	void
*/
void aghfpHandleSyncDisconnectInd(AGHFP *aghfp, const CL_DM_SYNC_DISCONNECT_IND_T *ind)
{
    /* If it's not our sink, silently ignore this indication */
    if ( ind->audio_sink == aghfp->audio_sink )
    {
        if ( aghfp->audio_connection_state==aghfp_audio_connected ||
             aghfp->audio_connection_state==aghfp_audio_disconnecting )
        { 
    	    /* Inform the app */ 
    	    if (ind->status == hci_success)
            {
		   	    resetAudioParams(aghfp);
		        aghfp->audio_connection_state = aghfp_audio_disconnected;
		        
				if ( aghfpCallManagerActiveNotComplete(aghfp) )
				{
					aghfpManageCall(aghfp, CallEventAudioDisconnected, CallFlagSuccess);
				}
				else
				{
					sendAudioDisconnectIndToApp(aghfp, aghfp_success);
				}
            }
    	    else
            {
                /* Disconnect has failed, we are still connected - inform the app */
				if ( aghfpCallManagerActiveNotComplete(aghfp) )
				{
					aghfpManageCall(aghfp, CallEventAudioDisconnected, CallFlagFail);
				}
				else
				{
					sendAudioDisconnectIndToApp(aghfp, aghfp_fail);
				}
            }
            
			/* Update the local state. Check current state in case SLC disconnect has beaten the SCO/eSCO disconnect */
			if (!aghfpCallManagerActive(aghfp) && supportedProfileIsHsp(aghfp->supported_profile) && (aghfp->state != aghfp_ready))
			{
				aghfpSetState(aghfp, aghfp_slc_connected);
			}
        }
        else
        {
            /* Should never get here */
            AGHFP_DEBUG(("aghfpHandleSyncDisconnectInd invalid state %d\n",aghfp->audio_connection_state));
        }
    }
}
/*
	Handle Codec Connection request from the HF (AT+BCC).
	This function performs the the actual actions of handling the AT+BCC (once the audio params have been
	obtained from the app, i.e. after aghfpHandleWbsCodecConReq() and ).
*/
static void aghfpHandleWbsCodecConReqProcessing(AGHFP *aghfp)
{
	/* Are we supporting WBS */
	if (aghfp->use_wbs)
	{
		/* OK to initiate WBS Codec Negotiation. */
	
		/* Send OK */
		aghfpSendOk(aghfp);
	
		/* If we haven't negotiatied a codec we need to do so.
		   If we have, we're gonna go ahead and use it here. */
		if (aghfp->use_codec == 0)
		{
			/* Start codec negotiation with HF. */
			if (aghfpWbsStartCodecNegotiation(aghfp, aghfp_negotiate_audio_at_hf))
			{
				aghfp->audio_connection_state = aghfp_audio_codec_connect;
			}
		}
		else
		{
			if (!aghfpCallManagerActiveNotComplete(aghfp))
			{
				MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_AUDIO_CONNECT_REQ);
				AGHFP_DEBUG(("	  Normal Audio Connection\n"));
				
				message->audio_params = aghfp->audio_params;
				message->packet_type = aghfp->audio_packet_type;
				MessageSend(&aghfp->task, AGHFP_INTERNAL_AUDIO_CONNECT_REQ, message);
			}
			else
			{
				/* Save the audio packet type for Call Manager */
				aghfpStoreAudioParams(aghfp, aghfp->audio_packet_type, &aghfp->audio_params);
				
				/* Answer the call again now that the WBS negotiation is complete. */
				aghfpManageCall(aghfp, CallEventAnswer, CallFlagOpenAudio);
			}
		}
	}
	else
	{
		/* WBS not supported, send ERROR. */
		aghfpSendError(aghfp);
	}
}
/*
	Get WB-Speech packet type
*/
sync_pkt_type aghfpGetWbsPacketType(AGHFP *aghfp)
{
	switch(aghfp->use_codec)
	{
		case(wbs_codec_mask_sbc):
		case(wbs_codec_mask_amr_wb):
			return(WBS_PACKET_TYPE);
			break;
		case(wbs_codec_mask_cvsd):
			/* This relies on audio parameters having been stored previously using aghfpStoreAudioParams() */
			return(aghfp->audio_packet_type);
		default:
		case(wbs_codec_mask_evrc_wb):
			AGHFP_DEBUG(("Codec not supported.\n"));
			Panic();
			return(0);
			break;
	}
}
void AghfpStartAudioAfterAppCodecNegotiation(AGHFP * aghfp)
{
	if (!aghfpCallManagerActiveNotComplete(aghfp))
	{
		MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_AUDIO_CONNECT_REQ);
		AGHFP_DEBUG(("	  Normal Audio Connection\n"));
		
		/* Assume that the audio parameters have been previously stored using aghfpStoreAudioParams() */
		message->audio_params = aghfp->audio_params;
		message->packet_type = aghfp->audio_packet_type;
		
		MessageSend(&aghfp->task, AGHFP_INTERNAL_AUDIO_CONNECT_REQ, message);
	}
	else
	{
		/* Answer the call again now that the WBS negotiation is complete. */
		aghfpManageCall(aghfp, CallEventAnswer, CallFlagOpenAudio);
	}
}
/*
	Get pointer to WB-Speech eSCO Parameters
*/
aghfp_audio_params *aghfpGetWbsParameters(AGHFP *aghfp)
{
	switch(aghfp->use_codec)
	{
		case(wbs_codec_mask_sbc):
			return((aghfp_audio_params*)&wb_speech_esco_audio_params_sbc);
			break;
		case(wbs_codec_mask_amr_wb):
			return((aghfp_audio_params*)&wb_speech_esco_audio_params_amr);
			break;
		case(wbs_codec_mask_cvsd):
			/* This relies on audio parameters having been stored previously using aghfpStoreAudioParams() */
			return(&aghfp->audio_params);
		default:
		case(wbs_codec_mask_evrc_wb):
			AGHFP_DEBUG(("Codec not supported.\n"));
			Panic();
			return(NULL);
			break;
	}
}
/*
	Handle set audio parameters request from the app.
*/
void aghfpHandleSetAudioParamsReq(AGHFP *aghfp, const AGHFP_INTERNAL_SET_AUDIO_PARAMS_REQ_T *req)
{
	/* Only act upon the apps request if in the correct state. */
	switch ( aghfp->audio_connection_state )
	{
	case aghfp_audio_disconnected:
	case aghfp_audio_codec_connect:
		aghfpStoreAudioParams(aghfp, req->packet_type, &req->audio_params);

		/* Continue the Codec Connection */
		aghfpHandleWbsCodecConReqProcessing(aghfp);
		break;
	case aghfp_audio_connecting_esco:
	case aghfp_audio_connecting_sco:
	case aghfp_audio_accepting:
	case aghfp_audio_disconnecting:
	case aghfp_audio_connected:
	default:
		AGHFP_DEBUG(("aghfpHandleAudioConnectReq invalid state %d\n",aghfp->audio_connection_state));
		break;
	}
}
/****************************************************************************
NAME	
	aghfpHandleAudioDisconnectReq

DESCRIPTION
	Attempt to disconnect the audio (Synchronous) connection.

RETURNS
	void
*/
void aghfpHandleAudioDisconnectReq(AGHFP *aghfp)
{
    switch ( aghfp->audio_connection_state )
    {
    case aghfp_audio_disconnected:
    case aghfp_audio_connecting_esco:  /* Until connect is complete, assume we don't have a connection */
    case aghfp_audio_connecting_sco:
    case aghfp_audio_accepting:
		/* Audio already with AG - indicate a fail for this attempt */
		sendAudioDisconnectIndToApp(aghfp, aghfp_audio_disconnect_no_audio);
        break;
    case aghfp_audio_disconnecting:   
		/* Already attempting to close an audio connection - indicate a fail for this attempt */
		sendAudioDisconnectIndToApp(aghfp, aghfp_audio_disconnect_in_progress);
        break;
    case aghfp_audio_connected:
		audioDisconnectRequest(aghfp);
		break;
	default:
        AGHFP_DEBUG(("aghfpHandleAudioDisconnectReq invalid state %d\n",aghfp->audio_connection_state));
        break;
    }
}
/****************************************************************************
NAME	
	aghfpHandleAudioConnectRes

DESCRIPTION
    Accept or reject to an incoming audio connection request from remote device.

RETURNS
	void
*/
void aghfpHandleAudioConnectRes(AGHFP *aghfp, const AGHFP_INTERNAL_AUDIO_CONNECT_RES_T *res)
{
    switch ( aghfp->audio_connection_state )
    {
    case aghfp_audio_disconnected:
    case aghfp_audio_accepting:
        audioConnectResponse(aghfp, res->response, res->packet_type, &res->audio_params);
        break;
    case aghfp_audio_connecting_esco:
    case aghfp_audio_connecting_sco:
		/* Already attempting to create an audio connection - indicate a fail for this attempt */
		sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_in_progress, hci_success);
        break;
    case aghfp_audio_disconnecting:   /* Until disconnect is complete, assume we have a connection */
    case aghfp_audio_connected:
		/* Already have an audio connection - indicate a fail for this attempt */
		sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_have_audio, hci_success);
		break;
	default:
        AGHFP_DEBUG(("aghfpHandleAudioConnectRes invalid state %d\n",aghfp->audio_connection_state));
        break;
    }
}
/* Accept/reject an incoming audio connect request */
static void audioConnectResponse(AGHFP *aghfp, bool response, sync_pkt_type packet_type, const aghfp_audio_params *audio_params)
{    
    tp_bdaddr tpaddr;
    sync_config_params config_params;
    
    AGHFP_DEBUG(("audioConnectResponse\n"));
    
    /* If connection request is being rejected, don't worry about validating params being returned */
    if ( !response )
    {
        AGHFP_DEBUG(("if !response\n"));
    
        /* To send the response we need the bd addr of the underlying connection. */
        if(SinkGetBdAddr(aghfp->rfcomm_sink, &tpaddr))
        {
            AGHFP_DEBUG(("SinkGetBdAddr\n"));
    
            ConnectionSyncConnectResponse(&aghfp->task, &tpaddr.taddr.addr, FALSE, 0);
        }
        /* 
            If we can't get the addr from the sink then quietly don't respond. 
            If the underlying ACL has gone down there's not much we can do. 
        */
    }
    else
    {
        AGHFP_DEBUG(("setting audio params\n"));
        
        if((aghfp->use_wbs) && !(aghfp->hf_supported_features & aghfp_hf_codec_negotiation))
        {
            AGHFP_DEBUG(("using default CVSD Sco parameters \n"));
            config_params.tx_bandwidth = 8000;
            config_params.rx_bandwidth = 8000;
            config_params.max_latency = 16;
            config_params.voice_settings = 0;
            config_params.retx_effort = sync_retx_power_usage;
            config_params.packet_type = 0x2BF;
        }
        
        else
        {
            config_params.tx_bandwidth = audio_params->bandwidth;
            config_params.rx_bandwidth = audio_params->bandwidth;
            config_params.max_latency = audio_params->max_latency;
            config_params.voice_settings = audio_params->voice_settings;
            config_params.retx_effort = audio_params->retx_effort;
            config_params.packet_type = packet_type;
        }

        /* 
            To send the response we need the bd addr of the underlying connection. 
            If we can't get the addr from the sink then quietly don't respond. 
            If the underlying ACL has gone down there's not much we can do.
        */
        if(SinkGetBdAddr(aghfp->rfcomm_sink, &tpaddr))
        {
            AGHFP_DEBUG(("ConnectionSyncConnectResponse\n"));
            ConnectionSyncConnectResponse(&aghfp->task, &tpaddr.taddr.addr, TRUE, &config_params);
        }
    }
}
void aghfpHandleBiaParse(Task task, const struct aghfpHandleBiaParse *data)
{
    struct sequence indicators = data->indicators;
    uint16 i, indicator_idx=0;    
    bool success = TRUE;
    
    MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_INDICATORS_ACTIVATION_REQ);
    
    /* By default we don't update the indicator state */
    message->service=indicator_ignore;
    message->signal=indicator_ignore;
    message->roam=indicator_ignore;
    message->battchg=indicator_ignore;
    
    AGHFP_DEBUG(("aghfpHandleBiaParse - Parsing\n"));
    
    for(i=0; i<indicators.length; i++)
    {
        AGHFP_DEBUG(("%c", (char)indicators.data[i]));
        if(indicators.data[i] == ',' || indicators.data[i] == ';')
        {
            /* If this is a comma move on (break if more indicators specified than we support) */
            AGHFP_DEBUG(("+ "));
            if(++indicator_idx > 6)
                break;
        }
        else if(indicators.data[i] == ' ' || indicators.data[i] =='\t')
        {
            /* Ignore whitespace */
            AGHFP_DEBUG(("- "));
        }
        else if(indicators.data[i] == '0' || indicators.data[i] == '1')
        {
            AGHFP_DEBUG(("m "));
            
            /* Matched a valid value */
            switch(indicator_idx)
            {
                /* This corresponds to the order we list our indicators to the HF */
                case 0:
                    message->service = indicators.data[i]-0x30;
                break;
                case 4:
                    message->signal = indicators.data[i]-0x30;
                break;
                case 5:
                    message->roam = indicators.data[i]-0x30;
                break;
                case 6:
                    message->battchg = indicators.data[i]-0x30;
                break;
                default:
                    /* Ignore call, call_setup and call_held - always on */
                break;
            }
        }
        else
        {
            /* Improperly formatted command - ERROR */
            success = FALSE;
            break;
        }
    }
    
    if(success)
    {
        AGHFP_DEBUG(("\nOK\n"));
        MessageSend(task, AGHFP_INTERNAL_INDICATORS_ACTIVATION_REQ, message);
    }
    else
    {
        AGHFP_DEBUG(("\nERROR\n"));
        free(message);
        aghfpSendError((AGHFP *)task);
    }
}
/****************************************************************************
NAME	
	aghfpHandleAudioTransferReq

DESCRIPTION
	Transfer the audio from the AG to the HF or vice versa depending on which
	device currently has it.

RETURNS
	void
*/
void aghfpHandleAudioTransferReq(AGHFP *aghfp, const AGHFP_INTERNAL_AUDIO_TRANSFER_REQ_T *req)
{
	switch (req->direction)
	{
	case aghfp_audio_to_hfp:
        switch ( aghfp->audio_connection_state )
        {
        case aghfp_audio_disconnected:
		case aghfp_audio_codec_connect:

    		audioConnectRequest(aghfp, req->packet_type, &req->audio_params);
            break;
        case aghfp_audio_connecting_esco:
        case aghfp_audio_connecting_sco:
        case aghfp_audio_accepting:
    		/* Already attempting to create an audio connection - indicate a fail for this attempt */
    		sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_in_progress, hci_success);
            break;
        case aghfp_audio_disconnecting:   /* Until disconnect is complete, assume we have a connection */
        case aghfp_audio_connected:
    		/* Already have an audio connection - indicate a fail for this attempt */
    		sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_have_audio, hci_success);
    		break;
    	default:
            AGHFP_DEBUG(("aghfpHandleAudioTransferReq invalid state %d\n",aghfp->audio_connection_state));
            break;
        }
		break;

	case aghfp_audio_to_ag:
        switch ( aghfp->audio_connection_state )
        {
        case aghfp_audio_disconnected:
        case aghfp_audio_connecting_esco:  /* Until connect is complete, assume we don't have a connection */
        case aghfp_audio_connecting_sco:
        case aghfp_audio_accepting:
        	/* Audio already with AG - indicate a fail for this attempt */
    		sendAudioDisconnectIndToApp(aghfp, aghfp_audio_disconnect_no_audio);
            break;
        case aghfp_audio_disconnecting:   
    		/* Already attempting to close an audio connection - indicate a fail for this attempt */
    		sendAudioDisconnectIndToApp(aghfp, aghfp_audio_disconnect_in_progress);
            break;
        case aghfp_audio_connected:
    		audioDisconnectRequest(aghfp);
            break;
    	default:
            AGHFP_DEBUG(("aghfpHandleAudioTransferReq invalid state %d\n",aghfp->audio_connection_state));
            break;
        }
		break;

	case aghfp_audio_transfer:
        switch ( aghfp->audio_connection_state )
        {
        case aghfp_audio_disconnected:
		case aghfp_audio_codec_connect:
    		audioConnectRequest(aghfp, req->packet_type, &req->audio_params);
            break;
        case aghfp_audio_connecting_esco:
        case aghfp_audio_connecting_sco:
        case aghfp_audio_accepting:
    		/* Already attempting to create an audio connection - indicate a fail for this attempt */
    		sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_in_progress, hci_success);
            break;
        case aghfp_audio_disconnecting:   
    		/* Already attempting to close an audio connection - indicate a fail for this attempt */
    		sendAudioDisconnectIndToApp(aghfp, aghfp_audio_disconnect_in_progress);
            break;
        case aghfp_audio_connected:
    		audioDisconnectRequest(aghfp);
            break;
    	default:
            AGHFP_DEBUG(("aghfpHandleAudioTransferReq invalid state %d\n",aghfp->audio_connection_state));
            break;
        }
		break;

	default:
		AGHFP_DEBUG(("Unknown audio transfer direction\n"));
	}
}
/*
	Handle Codec Negotiation resopnse from the HF (AT+BCS)
*/
void aghfpHandleWbsCodecNegReq(AGHFP *aghfp, uint16 codecUUID16)
{
    sync_pkt_type		audio_packet_type = aghfp->audio_packet_type;
    aghfp_audio_params	audio_params = aghfp->audio_params;
	uint16 codec; 		/* Codec bitmap used internally */
	
    AGHFP_DEBUG(("aghfpHandleWbsCodecNegReq : "));
    
	/* Translate from codec UUID16 format to internal bitmap. */
	codec = WbsUuid16ToCodec((codecs_info*)&(aghfp->codecs_info), codecUUID16);

	/* Note that one bit should be set in the bitmaps and it must be the same bit for success. */
	if(aghfp->use_wbs && (aghfp->use_codec == codec))
	{
		AGHFP_DEBUG(("Starting WB-Speech eSCO\n"));
		
		/* Send OK */
		aghfpSendOk(aghfp);

		/* audio_packet_type and audio_params already set to WBS values. */
		
		/* Force connection create.
		   WBS SCO connection are always initiated by the AG. */
		if(aghfp->wbs_negotiate_action != aghfp_negotiate_no_audio)
		{
			aghfp->wbs_negotiate_action = aghfp_negotiate_audio_at_ag;
		}
	}
	else
	{
		AGHFP_DEBUG(("Falling back to request eSCO type\n"));
		/* send Error */
		aghfpSendError(aghfp);

		/* Reset any saved codecs; Codec Negotiation aborted. */
		aghfp->use_codec = 0;
		
		/* For normal SCO we only set up the SCO here if the AG initiated the connection. */
		if (aghfp->wbs_negotiate_action == aghfp_negotiate_audio_at_ag)
		{ /* Start eSCO Connection */
	        audio_packet_type = aghfp->audio_packet_type;
	        audio_params = aghfp->audio_params;
	        audio_params.override_wbs = TRUE;
        }
	}
	
	if (aghfp->wbs_negotiate_action == aghfp_negotiate_audio_at_ag)
	{ /* Start eSCO Connection. We get here if we are setting up a WBS link or an AG initiated normal SCO. */
		if (!aghfpCallManagerActiveNotComplete(aghfp))
		{
		    MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_AUDIO_CONNECT_REQ);
		    AGHFP_DEBUG(("    Normal Audio Connection\n"));
		    
			message->audio_params = audio_params;
			message->packet_type = audio_packet_type;
	        MessageSend(&aghfp->task, AGHFP_INTERNAL_AUDIO_CONNECT_REQ, message);
		}
		else
		{
			/* Save the audio packet type for Call Manager */
			aghfpStoreAudioParams(aghfp, audio_packet_type, &audio_params);
			
			/* Answer the call again now that the WBS negotiation is complete. */
			aghfpManageCall(aghfp, CallEventAnswer, CallFlagOpenAudio);
        }
	}
	
	aghfp->wbs_negotiate_action = aghfp_negotiate_undefined; /* Reset flag to ensure it is correct next time */
}
/****************************************************************************
NAME	
	aghfpHandleSyncConnectCfm

DESCRIPTION
	Confirmation in response to an audio (SCO/eSCO) open request indicating 
    the outcome of the Synchronous connect attempt.

RETURNS
	void
*/
void aghfpHandleSyncConnectCfm(AGHFP *aghfp, const CL_DM_SYNC_CONNECT_CFM_T *cfm)
{
   	if ( aghfp->audio_connection_state==aghfp_audio_connecting_esco ||
   	     aghfp->audio_connection_state==aghfp_audio_connecting_sco ||
         aghfp->audio_connection_state==aghfp_audio_accepting )
    {
    	/* Informs us of the outcome of the Synchronous connect attempt */
    	if (cfm->status == hci_success)
    	{
    	    /* store the audio parameters */
    	    aghfp->audio_sink = cfm->audio_sink;
    	    aghfp->rx_bandwidth = cfm->rx_bandwidth;
    	    aghfp->tx_bandwidth = cfm->tx_bandwidth;
    	    aghfp->link_type = cfm->link_type;
	    	    aghfp->audio_connection_state = aghfp_audio_connected;
	    
			/* Tell the app about this */
			if ( aghfpCallManagerActiveNotComplete(aghfp) )
			{	/* Audio connection request will have come from call manager */
				aghfpManageCall(aghfp, CallEventAudioConnected, CallFlagSuccess);
			}
			else
			{	/* Audio connection request will have come fom app */
				sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_success, cfm->status);
			}
    	}
    	else 
    	{
        	/* Give up if we are either attempting to accept in incoming connection or error code
        	   indicates it is pointless to continue. */
        	if ( cfm->status<=hci_error_host_timeout || 
        	     (cfm->status>=hci_error_oetc_user && cfm->status<=hci_error_unknown_lmp_pdu) ||
        	     aghfp->audio_connection_state==aghfp_audio_accepting )
        	{
                aghfp->audio_connection_state = aghfp_audio_disconnected;

           	    resetAudioParams(aghfp);

				/* SCO/eSCO connect failed */
				if ( aghfpCallManagerActiveNotComplete(aghfp) )
				{	/* Audio connection request will have come from call manager */
					aghfpManageCall(aghfp, CallEventAudioConnected, CallFlagFail);
				}
				else
				{	/* Audio connection request will have come fom app */
					sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_failure, cfm->status);
				}
        	}
        	else
        	{
        	    /* This step failed, move onto next stage of connection attempt */
    		    continueAudioConnectRequest(aghfp);
    	    }
    	}
	}
    else
    {
        /* Should never get here */
        AGHFP_DEBUG(("aghfpHandleSyncConnectCfm invalid state %d",aghfp->audio_connection_state));
    }
}
/* Attempt to create an audio (Synchronous) connection.  Due to firmware operation, eSCO and SCO must be requested
   separately. */
static void startAudioConnectRequest(AGHFP *aghfp)
{
    sync_config_params config_params;
    
    AGHFP_DEBUG(("startAudioConnectRequest\n"));
    AGHFP_DEBUG(("aghfp->hf_supported_features %d\n",aghfp->hf_supported_features));    
    AGHFP_DEBUG(("aghfp_hf_codec_negotiation %d\n",aghfp_hf_codec_negotiation));    

	/* Start Codec Negotiaion if:
			Audio id disconnected AND
			WBS is not being overridden AND
			We wish to use WBS AND
			The AG indicates that it supports Codec Negotiation AND
			No codec has already previously been successfully negotiated
	*/
    if ((aghfp->audio_connection_state == aghfp_audio_disconnected) && (!(aghfp->audio_params.override_wbs)) && 
    							(aghfp->use_wbs) && (aghfp->hf_supported_features & aghfp_hf_codec_negotiation) &&
    							(aghfp->use_codec == 0) && (aghfp->negotiation_type == aghfp_codec_negotiation_type_wbs))
    {
        AGHFP_DEBUG(("aghfpWbsStartCodecNegotiation\n"));
        if (aghfpWbsStartCodecNegotiation(aghfp, aghfp_negotiate_audio_at_ag))
	    {
		    aghfp->audio_connection_state = aghfp_audio_codec_connect;
	    	return;
    	}
    }
    
    /* added to meet wbs test spec 
       if we currently use wbs but the HF does not support it then change the audio
       params so that a CVSD SCO can be negotiatiated */
    if((aghfp->use_wbs) && !(aghfp->hf_supported_features & aghfp_hf_codec_negotiation))
    {
        AGHFP_DEBUG(("using default CVSD Sco parameters \n"));
        aghfp->audio_packet_type = 0x2BF;
        aghfp->audio_params.bandwidth = 8000;
        aghfp->audio_params.max_latency = 16;
        aghfp->audio_params.voice_settings = 0;
    }
    
    
	if((aghfp->negotiation_type == aghfp_codec_negotiation_type_csr) && (aghfp->app_pending_codec_negotiation))
	{
		AGHFP_DEBUG(("aghfpSendCsrFeaturesNegotiationReqInd\n"));
        /* Prompt the app to negotiate the codec */
		aghfpSendCsrFeatureNegotiationReqInd(aghfp);
		aghfp->audio_connection_state = aghfp_audio_codec_connect;
		return;
	}

    AGHFP_DEBUG(("aghfp->audio_packet_type %d\n", aghfp->audio_packet_type));
    /* Save the packet type for use later if this connection fails. */
    aghfp->audio_packet_type_to_try = aghfp->audio_packet_type;

    if ( aghfp->audio_packet_type & sync_all_esco )
    {   /* Attempt to open an eSCO connection */
        AGHFP_DEBUG(("attempt to open an eSCO connection\n"));
        aghfp->audio_connection_state = aghfp_audio_connecting_esco;
        config_params.retx_effort = aghfp->audio_params.retx_effort;
    }
    else
    {   /* Attempt to open a SCO connection */
        AGHFP_DEBUG(("attempt to open a SCO connection\n"));
        aghfp->audio_connection_state = aghfp_audio_connecting_sco;
            /* No re-transmissions for SCO */
        config_params.retx_effort = sync_retx_disabled;
    }
            /* set packet type - pass through without checking anything*/
    config_params.packet_type = aghfp->audio_packet_type ;
    

    config_params.tx_bandwidth = aghfp->audio_params.bandwidth;
    config_params.rx_bandwidth = aghfp->audio_params.bandwidth;
    config_params.max_latency = aghfp->audio_params.max_latency;
    config_params.voice_settings = aghfp->audio_params.voice_settings;
    
    AGHFP_DEBUG(("config_params.packet_type %d\n", config_params.packet_type));
    AGHFP_DEBUG(("config_params.tx_bandwidth %d\n", (int)config_params.tx_bandwidth));
    AGHFP_DEBUG(("config_params.rx_bandwidth %d\n", (int)config_params.rx_bandwidth));
    AGHFP_DEBUG(("config_params.max_latency %d\n", config_params.max_latency));
    AGHFP_DEBUG(("config_params.voice_settings %d\n", config_params.voice_settings));

    
    /* Issue a Synchronous connect request to the connection lib */
    ConnectionSyncConnectRequest(&aghfp->task, aghfp->rfcomm_sink, &config_params);
}