#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"

#ifdef GUI_RTP

#define RTCP_SR		200
#define RTCP_RR		201
#define RTCP_SDES	202
#define RTCP_BYE	203
#define RTCP_APP	204

#define RTCP_SDES_END		0
#define RTCP_SDES_CNAME		1

#define RTP_SEQ_MOD		0x10000
// send out one RTCP packet every 10 seconds
#define RTCP_PACKET_INTERVAL	10 

 XSHORT Rtcp_iDstPort;

static XSHORT _iMaxSeq;
static XLONG _lCycles;
static XLONG _lReceived;
static XCHAR _pPeerSSRC[4];
static XCHAR _pLSR[4];
static XCHAR _iTimer;
static BOOLEAN _bReceivedSR;

extern XLONG Rtp_lTimeStamp;

static CCHAR _cSDES[3] = {0x81, RTCP_SDES, 0};
UCHAR _PackSDES(PXCHAR pData)
{
	DCHAR iTotal, iLen;
	PXCHAR_D pCur;

	pCur = pData;

//	pCur[0] = 0x81;
//	pCur[1] = RTCP_SDES;
//	pCur[2] = 0;
	p_memcpy_c2x(pCur, _cSDES, 3);
	pCur[8] = RTCP_SDES_CNAME;
	pCur += 4;
	p_memcpy_x2x(pCur, Rtp_pLocalSSRC, 4);

	pCur += 6;
	p_strcpy_x2x(pCur, Sys_pLocalNumber);
	iLen = p_strlen_x(pCur);
	pCur += iLen;
	pCur[0] = 0x40;
	pCur ++;
	iTotal = iLen + 11;

	p_IP2String(ProxyGetLocalIP(Sys_pRemoteIP), pCur);
	iLen = p_strlen_x(pCur);
	iTotal += iLen;
	pCur += iLen;

	pData[9] = iTotal-10;
	iLen = iTotal & 3;
	if (iLen)
	{
		iLen = 4 - iLen;
		p_memset_x(pCur, 0, iLen);
		iTotal += iLen;
	}
	pData[3] = (iTotal >> 2) - 1;
	return iTotal;
}

void _PackReportBlock(PXCHAR pData)
{
	PXCHAR_D pCur;

	pCur = pData;

	p_memset_x(pCur, 0, 24);
	p_memcpy_x2x(pCur, _pPeerSSRC, 4);
	//set Extended max seq
	ULONG2PUCHAR((ULONG)(_lCycles + _iMaxSeq), (PUCHAR)(pCur+8));
	// set jitter, should got from calculation
	pCur[14] = 1;
	pCur[15] = p_rand_char();
	if (_bReceivedSR)
	{
		//set last SR
		p_memcpy_x2x((PXCHAR)(pCur+16), _pLSR, 4);
		//Delay since Last SR, set to 1 second for simplicity
		pCur[21] = 1;
	} // else set to 0
}

static CCHAR _cRTCP_RR_1[4] = {0x81, RTCP_RR, 0x00, 0x07};
static CCHAR _cRTCP_RR_0[4] = {0x80, RTCP_RR, 0x00, 0x01};
UCHAR _PackRR(PXCHAR pData)
{
	PXCHAR_D pCur;
	BOOLEAN bReceived;

	pCur = pData;
	bReceived = (_lReceived) ? TRUE : FALSE;

	p_memcpy_c2x(pCur, (bReceived ? _cRTCP_RR_1 : _cRTCP_RR_0), 4);
	pCur += 4;
	p_memcpy_x2x(pCur, Rtp_pLocalSSRC, 4);
	if (bReceived)
	{
//		pCur[0] = 0x81;
//		pCur[1] = RTCP_RR;
//		pCur[2] = 0x00;
//		pCur[3] = 0x07;
		pCur += 4;
		_PackReportBlock(pCur);
		return 32;
	}

//		pCur[0] = 0x80;
//		pCur[1] = RTCP_RR;
//		pCur[2] = 0x00;
//		pCur[3] = 0x01;
	return 8;
}

static CCHAR _cRTCP_SR_1[4] = {0x81, RTCP_SR, 0x00, 0x0c};
static CCHAR _cRTCP_SR_0[4] = {0x80, RTCP_SR, 0x00, 0x06};
UCHAR _PackSR(PXCHAR pData)
{
	PXCHAR_D pCur;
	BOOLEAN bReceived;

	pCur = pData;
	bReceived = (_lReceived) ? TRUE : FALSE;

	p_memcpy_c2x(pCur, (bReceived ? _cRTCP_SR_1 : _cRTCP_SR_0), 4);
	pCur += 4;
	p_memcpy_x2x(pCur, Rtp_pLocalSSRC, 4);

	// no way to get NTP time, set to 0
	pCur += 4;
	p_memset_x(pCur, 0, 8);
	pCur += 8;
	ULONG2PUCHAR(Rtp_lTimeStamp, (PUCHAR)pCur);
	pCur += 4;
	ULONG2PUCHAR(Rtp_lSendPackets, (PUCHAR)pCur);
	pCur += 4;
	ULONG2PUCHAR(Rtp_lSendBytes, (PUCHAR)pCur);
	if (bReceived)
	{
//		pCur[0] = 0x81;
//		pCur[1] = RTCP_SR;
//		pCur[2] = 0x00;
//		pCur[3] = 0x0c;
		pCur += 4;
		_PackReportBlock(pCur);
		return 52;
	}
//		pCur[0] = 0x80;
//		pCur[1] = RTCP_SR;
//		pCur[2] = 0x00;
//		pCur[3] = 0x06;
	return 28;
}

 void RtcpOpen()
{
	_bReceivedSR = FALSE;
	_lReceived = 0;

	_iTimer = 0;
	UdpOpen(Sys_pRemoteIP, Rtcp_iDstPort, (USHORT)(Sys_iRtpPort + 1), RTCP_SDRAM_LO);
}

void RtcpUpdateSeq(PXCHAR pRtpHead)
{
	DSHORT iSeq;
	PXCHAR_D pCur;

	pCur = pRtpHead;

	pCur += 2;
	iSeq = PXCHAR2USHORT(pCur);
	pCur += 6;
	p_memcpy_x2x(_pPeerSSRC, pCur, 4);
	if (_lReceived)
	{
		if (iSeq < _iMaxSeq)
		{
			_lCycles += RTP_SEQ_MOD;
		}
	}
	else 
	{
		_lCycles = 0;
	}
	_iMaxSeq = iSeq;
	_lReceived ++;
}

PXCHAR _GetRtcpSendBuf()
{
	return (PXCHAR)Adapter_pSendUdpData;
}

void _SendRtcpData(UCHAR iLength)
{
	DCHAR iLen;

	iLen = iLength;
	UdpSend(iLen, RTCP_SDRAM_LO);
}

void _SendRtcpPacket()
{
	DCHAR iLen;
	PXCHAR_D pCur;

	pCur = _GetRtcpSendBuf();
	if (Rtp_bPacketSent)
	{
		iLen = _PackSR(pCur);
		Rtp_bPacketSent = FALSE;
	}
	else
	{
		iLen = _PackRR(pCur);
	}
	iLen += _PackSDES((PXCHAR)(pCur+iLen));
	_SendRtcpData(iLen);
}

 void RtcpHandleTimer()
{
	_iTimer ++;
	if (_iTimer >= RTCP_PACKET_INTERVAL)
	{
		_SendRtcpPacket();	
		_iTimer = 0;
	}
}

 void RtcpRun()
{
	DCHAR iType, iLen;
	PXCHAR_D pReceive;
	PXCHAR_D pCur;

	if (!IsInCall())	return;
	if (!Adapter_iReceiveLen)	return;

	pReceive = (PXCHAR)Adapter_pReceiveUdpData;

	pCur = _GetRtcpSendBuf();
	iType = pReceive[1];
	if (iType == RTCP_SR)
	{
		_bReceivedSR = TRUE;
		p_memcpy_x2x(_pLSR, (PXCHAR)(pReceive+10), 4);
		iLen = _PackRR(pCur);
		iLen += _PackSDES((PXCHAR)(pCur+iLen));
		_SendRtcpData(iLen);
		_iTimer = RTCP_PACKET_INTERVAL >> 1;
		OutputString(IDS_RTCP_SENDER_REPORT);
	}
	else if (iType == RTCP_RR)
	{
		OutputString(IDS_RTCP_RECEIVER_REPORT);
	}
}

#endif
