/****************************************************************************
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));
        }
    }
}
/* Disconnect an existing audio (Synchronous) connection */
static void audioDisconnectRequest(AGHFP *aghfp)
{
	if ( !aghfpCallManagerActiveNotComplete(aghfp) )
	{
		/* Send a disconnect request to the connection lib */
    	aghfp->audio_connection_state = aghfp_audio_disconnecting;
    	ConnectionSyncDisconnect(aghfp->audio_sink, hci_error_oetc_user);
	}
    else
    {
		/* Inform app that call manager is active, setting up or shutting down a call */
		sendAudioConnectCfmToApp(aghfp, aghfp_audio_disconnect_call_manager_active, hci_success);
    }
}
/*
	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);
	}
}
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);
	}
}
/* Attempt to create a new audio (Synchronous) connection */
static void audioConnectRequest(AGHFP *aghfp, sync_pkt_type packet_type, const aghfp_audio_params *audio_params)
{
	if ( !aghfpCallManagerActiveNotComplete(aghfp) )
	{
	    if ( aghfpStoreAudioParams(aghfp, packet_type, audio_params) )
	    {
		    startAudioConnectRequest(aghfp);
	    }
	    else
	    {
			/* Inform app that one or more parameters were invalid */
			sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_invalid_params, hci_success);
	    }
    }
    else
    {
		/* Inform app that call manager is active, setting up or shutting down a call */
		sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_call_manager_active, hci_success);
    }
}
/****************************************************************************
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));
    }
}
/*
	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 */
}