#include "version.h"
#include "PalmType.h"
#include "p_util.h"
#include "p_tcpip.h"
#include "debug.h"
#include "p_rtp.h"
#include "v_task.h"
//#include "port.h"
#include "p_dsp.h"

CCHAR Rtp_cFrameTime[CODEC_NULL] = {G729_FRAME_TIME, G7231_FRAME_TIME, G711_FRAME_TIME, G711_FRAME_TIME, GSM610_FRAME_TIME, ILBC_FRAME_TIME};
CCHAR Rtp_cVoiceLen[CODEC_NULL] = {G729_R8_LEN, G7231_R53_LEN, G711_LEN, G711_LEN, GSM610_LEN, ILBC_LEN}; 

#ifdef GUI_RTP

#if defined CALL_SIP || defined CALL_MGCP
#define GUI_RFC2833
#endif

#define RTP_VERSION		0
#define RTP_PAYLOAD		1
#define RTP_SEQ			2
#define RTP_TIMESTAMP	4
#define RTP_SSRC		8
#define RTP_DATA		12

#define RTP_DTMF_DURATION	960

XCHAR Rtp_bOpened;
XCHAR Rtp_pLocalSSRC[RTP_SSRC_LEN];

// rtp settings
XSHORT	Rtp_iDstPort;
XCHAR	Rtp_iDtmfPayloadType;
XCHAR	Rtp_iPeerIlbcPType;
XLONG	Rtp_lSendPackets;
XLONG	Rtp_lSendBytes;
XLONG	Rtp_lRecvPackets;
XLONG	Rtp_lRecvBytes;

BOOLEAN Rtp_bPacketSent;
XLONG Rtp_lTimeStamp;

static PXCHAR _pHeadOut;
static PXCHAR _pDataOut;

static XSHORT _iSeq;
static XSHORT _iPrevSeq;
static BOOLEAN _bIgnoreSeq;
static XCHAR _iG711RemainLen;
static XSHORT _iPrevPacketLen;
static XSHORT _iPrevPacketLen2;

static BOOLEAN _bVoiceStart;
static XCHAR _iCurSendFrames;
static XSHORT _iCurSendLen;
static XCHAR _iTimeStamp;	

#ifdef GUI_RFC2833
static XCHAR _pKeyTimeStamp[4];
static BOOLEAN _bKeyReceived;
static BOOLEAN _bSendindKey;
static XSHORT _iSendKeyLen;
static XCHAR _iSendKey;
#endif

static XCHAR _bSend;
static XCHAR _bReceive;

/******************************************************************************
 **  Handle received RTP packets    *******************************************
 ******************************************************************************/

void _HandleRtpData()
{
	DCHAR iFrameLen, iType;
	PXCHAR_D pOrg;
	PXCHAR_D pCur;
#ifdef GUI_RFC2833
	XCHAR pKey[2];
#endif

	pCur = pOrg = (PXCHAR)Adapter_pReceiveUdpData;

	iType = pCur[1] & 0x7f;
	RtcpUpdateSeq(pCur);
	Adapter_iReceiveLen -= RTP_DATA;
	pCur += RTP_DATA;

#ifdef GUI_RFC2833
	if (iType == Rtp_iDtmfPayloadType && Sys_iDtmfType == DTMF_RFC2833)
	{
		if (_bKeyReceived)
		{
			if ((pCur[1] & 0x80) == 0x80)
			{
				_bKeyReceived = FALSE;
				TaskHandleData(DTMF_STOP_KEY, (PXCHAR)0, 0);
				return;
			}
			if (p_memcmp_x2x(_pKeyTimeStamp, (PXCHAR)(pOrg+RTP_TIMESTAMP), 4))
			{
				_bKeyReceived = FALSE;
				TaskHandleData(DTMF_STOP_KEY, (PXCHAR)0, 0);
			}
		}
		if (!_bKeyReceived)
		{
			p_memcpy_x2x(_pKeyTimeStamp, (PXCHAR)(pOrg+RTP_TIMESTAMP), 4);
			_bKeyReceived = TRUE;
			pKey[0] = p_getAsciiKey(*pCur);
			pKey[1] = 0;
//			TaskIncomingKeys(1, pKey);
			TaskHandleData(DTMF_START_KEY, pKey, 1);
		}
		return;
	}
#endif

	if (_iG711RemainLen)
	{
		if (Sys_iAudioType == CODEC_G711A || Sys_iAudioType == CODEC_G711U)
		{
			SdramReadData(OPTIONS_SDRAM_POS+RTP_G711_SDRAM_LO);
			iFrameLen = G711_LEN - _iG711RemainLen;
			p_memcpy_x2x((PXCHAR)(Sdram_pDataCache + _iG711RemainLen), pCur, iFrameLen);
			Rtp_lRecvPackets ++;
			Rtp_lRecvBytes += G711_LEN;
			TaskIncomingData(G711_LEN, (PXCHAR)Sdram_pDataCache);
			pCur += iFrameLen;
			if (Adapter_iReceiveLen >= iFrameLen)
			{
				Adapter_iReceiveLen -= iFrameLen;
			}
			else
			{
				Adapter_iReceiveLen = 0;
			}
		}
		_iG711RemainLen = 0;
	}

	while (Adapter_iReceiveLen)
	{
		switch (Sys_iAudioType)
		{
		case CODEC_G7231:
			iFrameLen = G7231GetFrameLen(pCur[0]);
			break;
		case CODEC_G729:
			iFrameLen = (Adapter_iReceiveLen > G729_R8_LEN) ? G729_R8_LEN : Adapter_iReceiveLen;
			break;
		case CODEC_G711A:
		case CODEC_G711U:
			iFrameLen = G711_LEN;
			break;
		case CODEC_GSM610:
			iFrameLen = GSM610_LEN;
			break;
		case CODEC_ILBC:
			iFrameLen = ILBC_LEN;
			break;
		}

		if (Adapter_iReceiveLen >= iFrameLen)
		{
			Adapter_iReceiveLen -= iFrameLen;
		}
		else
		{
			if (Adapter_iReceiveLen)
			{
				if (Sys_iAudioType == CODEC_G711A || Sys_iAudioType == CODEC_G711U)
				{
					_iG711RemainLen = (UCHAR)Adapter_iReceiveLen;
					SdramSaveData(OPTIONS_SDRAM_POS+RTP_G711_SDRAM_LO, pCur, (UCHAR)Adapter_iReceiveLen);
				}
			}
			return;
		}

		Rtp_lRecvPackets ++;
		Rtp_lRecvBytes += iFrameLen;
		TaskIncomingData(iFrameLen, pCur);
		pCur += iFrameLen;
	}
}

void _HandlePrevData()
{
	if (_iPrevPacketLen)
	{
		Adapter_iReceiveLen = _iPrevPacketLen;
		SdramCopyAll(OPTIONS_SDRAM_POS+RTP_PREV_SDRAM_LO, (PXCHAR)Adapter_pReceiveUdpData);
		_HandleRtpData();
		_iPrevPacketLen = 0;
	}
}

void _HandlePrevData2()
{
	if (_iPrevPacketLen2)
	{
		Adapter_iReceiveLen = _iPrevPacketLen2;
		SdramCopyAll(OPTIONS_SDRAM_POS+RTP_PREV2_SDRAM_LO, (PXCHAR)Adapter_pReceiveUdpData);
		_HandleRtpData();
		_iPrevPacketLen2 = 0;
	}
}

void _HandlePrevRtpData()
{
	DSHORT iCurPacketLen;

	if (_iPrevPacketLen2 || _iPrevPacketLen)
	{
		OutputVal(_iPrevSeq, IDS_RTP_PACKET_LOST);

		// back up current packet
		iCurPacketLen = Adapter_iReceiveLen;
		SdramSaveAll(OPTIONS_SDRAM_POS+RTP_CUR_SDRAM_LO, (PXCHAR)Adapter_pReceiveUdpData);

		_HandlePrevData2();
		_HandlePrevData();

		// restore
		Adapter_iReceiveLen = iCurPacketLen;
		SdramCopyAll(OPTIONS_SDRAM_POS+RTP_CUR_SDRAM_LO, (PXCHAR)Adapter_pReceiveUdpData);
	}
}

void _SavePrevData()
{
	SdramSaveAll(OPTIONS_SDRAM_POS+RTP_PREV_SDRAM_LO, (PXCHAR)Adapter_pReceiveUdpData);
	_iPrevPacketLen = Adapter_iReceiveLen;
}

void _SavePrevData2()
{
	SdramSaveAll(OPTIONS_SDRAM_POS+RTP_PREV2_SDRAM_LO, (PXCHAR)Adapter_pReceiveUdpData);
	_iPrevPacketLen2 = Adapter_iReceiveLen;
}

void RtpRun()
{
	DSHORT iCurSeq;
	DCHAR iType, iLen;
	PXCHAR_D pCur;

	if (!IsInCall() || !_bReceive || Sys_iAudioType == CODEC_NULL)
		return;

	if (Adapter_iReceiveLen <= RTP_DATA)	return;
	pCur = (PXCHAR)Adapter_pReceiveUdpData;

	iType = pCur[1] & 0x7f;
	if (iType != Rtp_iDtmfPayloadType && iType != RtpGetPeerRtpType(Sys_iAudioType))
	{
		return;
	}

	// Some device will add RTP padding, we handle it here
	if (pCur[0] & 0x20)
	{
		iLen = pCur[Adapter_iReceiveLen-1];
		Adapter_iReceiveLen -= iLen;
	}

	iCurSeq = PXCHAR2USHORT((PXCHAR)(pCur+2));
	if (_bIgnoreSeq)
	{
		_HandleRtpData();
		_bIgnoreSeq = FALSE;
		goto End;
	}
	if (iCurSeq == _iPrevSeq)
	{
		OutputVal(iCurSeq, IDS_RTP_PACKET_LATE);
		return;
	}
	else if (iCurSeq == _iPrevSeq + 1)
	{
		_HandlePrevRtpData();
		_HandleRtpData();
	}
	else if (iCurSeq == _iPrevSeq + 2)
	{
		_HandlePrevRtpData();
		_SavePrevData2();
	}
	else if (iCurSeq == _iPrevSeq + 3)
	{
		_HandlePrevRtpData();
		_SavePrevData();
	}
	else if (iCurSeq == _iPrevSeq - 1)
	{
		if (_iPrevPacketLen2)
		{
			_HandleRtpData();
			_HandlePrevData2();
		}
		else
		{
			_SavePrevData2();
		}
		return;
	}
	else if (iCurSeq == _iPrevSeq - 2)
	{
		_HandleRtpData();
		if (_iPrevPacketLen2)
		{
			_HandlePrevData2();
			_HandlePrevData();
		}
		else if (_iPrevPacketLen)
		{
			_iPrevPacketLen2 = _iPrevPacketLen;
			SdramReadAll(OPTIONS_SDRAM_POS+RTP_PREV_SDRAM_LO);
			SdramWriteAll(OPTIONS_SDRAM_POS+RTP_PREV2_SDRAM_LO);
			_iPrevPacketLen = 0;
		}
		return;
	}
	else
	{
		if (iCurSeq > _iPrevSeq)
		{
//			OutputVal(_iPrevSeq, IDS_CHECK_POINT_3);
//			OutputVal(iCurSeq, IDS_RTP_PACKET_LOST);
			_HandlePrevRtpData();
			_SavePrevData();
		}
		else
		{
//			OutputVal(_iPrevSeq, IDS_CHECK_POINT_3);
//			if (_iPrevSeq > 65530 || iCurSeq < 6)
			if (iCurSeq < (_iPrevSeq - 10))
			{
				_HandleRtpData();
			}
			else
			{
				OutputVal(iCurSeq, IDS_RTP_PACKET_LATE);
				return;
			}
		}
	}

End:
	_iPrevSeq = iCurSeq;
}


/******************************************************************************
 **  Handle sending RTP packets    *******************************************
 ******************************************************************************/

void _FillCommonHead()
{
	_pHeadOut[RTP_VERSION] = 0x80;
	p_memcpy_x2x((PXCHAR)(_pHeadOut+RTP_SSRC), Rtp_pLocalSSRC, RTP_SSRC_LEN);
	_iSeq ++;
	USHORT2PXCHAR(_iSeq, (PXCHAR)(_pHeadOut+RTP_SEQ));
	ULONG2PUCHAR(Rtp_lTimeStamp, (PUCHAR)((PXCHAR)(_pHeadOut+RTP_TIMESTAMP)));
}

void _SendRtpData(USHORT iLength)
{
	DSHORT iLen;

	_FillCommonHead();
	_pHeadOut[RTP_PAYLOAD] = RtpGetLocalRtpType(Sys_iAudioType);
	if (_bVoiceStart)
	{
		_pHeadOut[RTP_PAYLOAD] |= 0x80;
	}
	else
	{
		_pHeadOut[RTP_PAYLOAD] &= 0x7f;
	}

	iLen = iLength;
	iLen += RTP_DATA;
	UdpSend(iLen, RTP_SDRAM_LO);
}

#ifdef GUI_RFC2833
void _SendKeyPacket(BOOLEAN bHead, BOOLEAN bEnd)
{
	_FillCommonHead();
	_pHeadOut[RTP_PAYLOAD] = Rtp_iDtmfPayloadType;
	if (bHead)
	{
		_pHeadOut[RTP_PAYLOAD] |= 0x80;
	}
	_pDataOut[0] = _iSendKey;
	_pDataOut[1] = bEnd ? 0x80 : 0x00;
	USHORT2PXCHAR(_iSendKeyLen, (PXCHAR)(_pDataOut+2));
	UdpSend((UCHAR)(RTP_DATA + 4), RTP_SDRAM_LO);
}	
#endif

void RtpSend(UCHAR iLength, PXCHAR pData)
{
	BOOLEAN bVad;

	if (!_bSend || Sys_iAudioType == CODEC_NULL)			
		return;

	/* Handle DTMF Keys */
	// Net2phone MTA adapter's RFC2833 handling
#ifdef GUI_RFC2833
	if (_bSendindKey)
	{
		if (_iSendKeyLen < RTP_DTMF_DURATION)
		{
			if (_iSendKeyLen)	
			{
				_SendKeyPacket(FALSE, FALSE);
				_iSendKeyLen += _iTimeStamp;
			}
			else
			{
				_SendKeyPacket(TRUE, FALSE);
				_SendKeyPacket(TRUE, FALSE);
				_SendKeyPacket(TRUE, FALSE);
				_iSendKeyLen += _iTimeStamp;
				_SendKeyPacket(FALSE, FALSE);
				_iSendKeyLen += _iTimeStamp;
			}
		}
		else 
		{
			_SendKeyPacket(FALSE, TRUE);
			_SendKeyPacket(FALSE, TRUE);
			_SendKeyPacket(FALSE, TRUE);
			Rtp_lTimeStamp += _iSendKeyLen;
			_bSendindKey = FALSE;
		}
		return;
	}
#endif

	/* Handle voice packets */
	if (iLength < Dsp_iVadLen[Sys_iAudioType])	return;

	p_memcpy_x2x((PXCHAR)(_pDataOut+_iCurSendLen), pData, iLength);
	if (_iCurSendFrames)
	{
		SdramReadAll(OPTIONS_SDRAM_POS+RTP_DATA_SDRAM_LO);
		p_wmemcpy_x2x((PXCHAR)_pDataOut, (PXCHAR)(Sdram_pDataCache+RTP_DATA), _iCurSendLen);
	}
	_iCurSendFrames ++;
 	_iCurSendLen += iLength;
	Rtp_lTimeStamp += _iTimeStamp;
	bVad = (iLength >= Rtp_cVoiceLen[Sys_iAudioType]) ? FALSE : TRUE;
	if (_iCurSendFrames < Sys_iAudioFrames)
	{
		if (!bVad)	// if VAD frame, we will send out even the total number is not enough
		{
			p_wmemcpy_x2x((PXCHAR)(Sdram_pDataCache+RTP_DATA), (PXCHAR)_pDataOut, _iCurSendLen);
			SdramWriteAll(OPTIONS_SDRAM_POS+RTP_DATA_SDRAM_LO);
			return;
		}
	}

	_SendRtpData(_iCurSendLen);

	Rtp_lSendPackets ++;
	Rtp_lSendBytes += _iCurSendLen;
	Rtp_bPacketSent = TRUE;
	_iCurSendFrames = 0;
	_iCurSendLen = 0;
	_bVoiceStart = bVad;
}

void RtpInitialize()
{
	_pHeadOut = (PXCHAR)Adapter_pSendUdpData;
	_pDataOut = (PXCHAR)(Adapter_pSendUdpData+RTP_DATA);
	if (Sys_iIlbcPType < 96)
	{
		Sys_iIlbcPType = 97;
	}
	if (Sys_iDtmfType == DTMF_RFC2833)
	{

		if (Sys_iDtmfPayloadType < 96)
		{
			Sys_iDtmfPayloadType = RTP_TELEVENT;
		}
		Rtp_iDtmfPayloadType = Sys_iDtmfPayloadType;
		if (Sys_iIlbcPType == Sys_iDtmfPayloadType)
		{
			Sys_iIlbcPType ++;
		}
	}
	Rtp_iPeerIlbcPType = Sys_iIlbcPType;

	Rtp_lSendPackets = 0;
	Rtp_lSendBytes = 0;
	Rtp_lRecvPackets = 0;
	Rtp_lRecvBytes = 0;
	Rtp_bPacketSent = FALSE;

	RtpClose();
}

void RtpStartReceive(BOOLEAN bReceive)
{
	if (!_bReceive && bReceive)
	{
		_bIgnoreSeq = TRUE;
		_iG711RemainLen = 0;
		_iPrevPacketLen = 0;
		_iPrevPacketLen2 = 0;
		_iPrevSeq = 0;
#ifdef GUI_RFC2833
		_bKeyReceived = FALSE;
#endif
	}
	_bReceive = bReceive;
}

void RtpStartSend(BOOLEAN bSend)
{
	if (!_bSend && bSend)
	{
		_iCurSendFrames = 0;
		_iCurSendLen = 0;
		_bVoiceStart = TRUE;
#ifdef GUI_RFC2833
		_bSendindKey = FALSE;
#endif
	}
	_iTimeStamp = Rtp_cFrameTime[Sys_iAudioType];
	_iTimeStamp <<= 3;
	_bSend = bSend;
}

void RtpOpen(BOOLEAN bSend, BOOLEAN bReceive)
{
	if (!Rtp_bOpened)
	{
		_iSeq = p_rand();
		p_rand_array((PXCHAR)Sdram_pDataCache, 4);
		Rtp_lTimeStamp = PXCHAR2ULONG((PXCHAR)Sdram_pDataCache);
		p_rand_array(Rtp_pLocalSSRC, RTP_SSRC_LEN);
		Rtp_bOpened = TRUE;
	}

    // Fill udp layer data
	UdpOpen(Sys_pRemoteIP, Rtp_iDstPort, Sys_iRtpPort, RTP_SDRAM_LO);
	UdpSetTos(Rtp_iTos, RTP_SDRAM_LO);
	RtpStartSend(bSend);
	RtpStartReceive(bReceive);
}

void RtpClose()
{
	Rtp_bOpened = FALSE;
	_bSend = FALSE;
	_bReceive = FALSE;
}

#ifdef GUI_RFC2833
void RtpSendDtmfKey(UCHAR iKey)
{
	if (iKey == MAP_KEY_UNKNOWN)
		return;

	if (_bSendindKey)
	{
		_SendKeyPacket(FALSE, TRUE);
		_SendKeyPacket(FALSE, TRUE);
		_SendKeyPacket(FALSE, TRUE);
		Rtp_lTimeStamp += _iSendKeyLen;
	}

	_iSendKey = iKey;
	_iSendKeyLen = 0;
	_bSendindKey = TRUE;
}
#endif

/*
 void RtpSendNatHint()
{
	DCHAR i;

	if (!Rtp_bOpened)	return;

	for (i = 0; i < 3; i ++)
	{
		if (Sys_iProtocol == PROTOCOL_EPN)
		{
			_SendRtpData(8);
		}
		else
		{
			if (Sys_iServiceType == SERVICE_TYPE_HUAWEI)
			{
				p_memset_x((PXCHAR)Adapter_pSendUdpData, 0, 20);
				UdpSend(20, RTP_SDRAM_LO);
			}
			else
			{
				_SendRtpData(0);
			}
		}
//		TaskWaitPacket();
	}
}
*/

static CCHAR Rtp_cType[CODEC_NULL] = {RTP_G729, RTP_G7231, RTP_G711U, RTP_G711A, RTP_GSM}; 

#if defined CALL_SIP || defined CALL_MGCP
UCHAR RtpGetAudioType(UCHAR iRtpType)
{
	DCHAR i;

	for (i = 0; i < CODEC_NULL; i ++)
	{
		if (iRtpType == Rtp_cType[i])	return i;
	}
	return CODEC_NULL;
/*
	switch (iRtpType)
	{
	case 0:
		return CODEC_G711U;
	case 4:
		return CODEC_G7231;
	case 8:
		return CODEC_G711A;
	case 18:
		return CODEC_G729;
	default:
		return CODEC_NULL;
	}
*/
}
#endif

UCHAR RtpGetLocalRtpType(UCHAR iAudioType)
{
	if (iAudioType < CODEC_NULL)
	{
		if (iAudioType == CODEC_ILBC)
		{
			return Sys_iIlbcPType;
		}
		else
		{
			return Rtp_cType[iAudioType];
		}
	}
	else
		return 0;
}

UCHAR RtpGetPeerRtpType(UCHAR iAudioType)
{
	if (iAudioType < CODEC_NULL)
	{
		if (iAudioType == CODEC_ILBC)
		{
			return Rtp_iPeerIlbcPType;
		}
		else
		{
			return Rtp_cType[iAudioType];
		}
	}
	else
		return 0;
}

#endif
