#include "p_apps.h"
#include "p_sip.h"
#include "v_task.h"
#include "p_dsp.h"
#include "my_sip.h"

#define SIP_SDP_INFO_IP			0
#define SIP_SDP_INFO_RTPPORT	4
#define SIP_SDP_INFO_RTCPPORT	6
#define SIP_SDP_INFO_MODE		8
#define SIP_SDP_INFO_CODEC		9
#define SIP_SDP_INFO_DTMF		10
#define SIP_SDP_INFO_ILBC		11
#define SIP_SDP_INFO_LEN		12

#define MODE_LABEL_LEN	10
static CCHAR _cTxMode[SIP_MODE_NUMBER][MODE_LABEL_LEN+1] = {
	"a=inactive", "a=recvonly", "a=sendonly", "a=sendrecv"
};

CCHAR _cConnMode[SIP_MODE_NUMBER] = {
	SIP_MODE_INACTIVE, SIP_MODE_SENDONLY, SIP_MODE_RECVONLY, SIP_MODE_SENDRECV
};

 DCHAR Sip_iConnMode;

void _FillMode(UCHAR iVal)
{
	DCHAR iMode;

	iMode = iVal;
	if (iMode != SIP_MODE_SENDRECV)
	{
		p_line_add_c(_cTxMode[iMode]);
		p_line_add_newline();
	}
}

void _FillRandomNumber(UCHAR iLen)
{
	DCHAR i, iVal;

	for (i = 0; i < iLen; i ++)
	{
		iVal = (UCHAR)(p_rand() % 10) + '0';
		p_line_add_char(iVal);
	}
}
/*******************************************************************
 **** SDP message **************************************************
 *******************************************************************/
void SipInitSdp()
{
	Rtp_iDstPort = 0;
	Rtcp_iDstPort = 0;
	p_memset_ip_0(Sys_pRemoteIP);
	RtpInitialize();
}

void SipSaveSdp(UCHAR iDstIndex)
{
	p_memcpy_ip((PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_IP), Sys_pRemoteIP);
	USHORT2PXCHAR(Rtp_iDstPort, (PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_RTPPORT));
	USHORT2PXCHAR(Rtcp_iDstPort, (PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_RTCPPORT));
	X_VAL(Sdram_pDataCache, SIP_SDP_INFO_MODE) = Sip_iConnMode;
	X_VAL(Sdram_pDataCache, SIP_SDP_INFO_CODEC) = Sys_iAudioType;
	X_VAL(Sdram_pDataCache, SIP_SDP_INFO_DTMF) = Rtp_iDtmfPayloadType;
	X_VAL(Sdram_pDataCache, SIP_SDP_INFO_ILBC) = Rtp_iPeerIlbcPType;
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex), SIP_SDP_INFO_LEN);
}

void SipLoadSdp(UCHAR iSrcIndex)
{
	if (!SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))	return;
	p_memcpy_ip(Sys_pRemoteIP, (PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_IP));
	Rtp_iDstPort = PXCHAR2USHORT((PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_RTPPORT));
	Rtcp_iDstPort = PXCHAR2USHORT((PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_RTCPPORT));
	Sip_iConnMode = X_VAL(Sdram_pDataCache, SIP_SDP_INFO_MODE);
	Sys_iAudioType = X_VAL(Sdram_pDataCache, SIP_SDP_INFO_CODEC);
	Rtp_iDtmfPayloadType = X_VAL(Sdram_pDataCache, SIP_SDP_INFO_DTMF);
	Rtp_iPeerIlbcPType = X_VAL(Sdram_pDataCache, SIP_SDP_INFO_ILBC);
}

USHORT SipNewSdp(UCHAR iIndexLow, BOOLEAN bOffer)
{
	p_line_start((PXCHAR)Sdram_pDataCache);
	p_line_add_c(Sdp_cV0);
	p_line_add_newline();

	// YuNeng's German customer requires random session id
//	p_line_add_c((PCCHAR)"o=- 0 0 IN IP4");
	p_line_add_c((PCCHAR)"o=- ");
//	p_line_add_val(p_rand());
	_FillRandomNumber(8);
	p_line_add_space();
//	p_line_add_val(p_rand());
	_FillRandomNumber(8);
	p_line_add_c((PCCHAR)" IN IP4");
	p_line_add_space();
	p_line_add_ip(SipGetLocalIP());
	p_line_add_newline();

	p_line_add_c((PCCHAR)"s=SIP CALL");
	p_line_add_newline();
	p_line_add_c((PCCHAR)"c=IN IP4");
	p_line_add_space();
	if (Sip_iConnMode & SIP_MODE_RECVONLY)
	{
		p_line_add_ip(SipGetLocalIP());
	}
	else
	{
		p_line_add_c((PCCHAR)"0.0.0.0");
	}
	p_line_add_newline();

	p_line_add_c((PCCHAR)"t=0 0");
	p_line_add_newline();

	p_line_add_c(Sdp_cMAudio);
	p_line_add_space();
	p_line_add_val(Sip_iRtpPort);
	p_line_add_space();
	p_line_add_c((PCCHAR)"RTP/AVP");
	p_line_add_space();

	if (bOffer)
	{
		SdpAddAudioCode();
	}
	else
	{
		p_line_add_val(RtpGetLocalRtpType(Sys_iAudioType));
	}

	if (Sys_iDtmfType == DTMF_RFC2833)
	{
		p_line_add_space();
		p_line_add_val(Rtp_iDtmfPayloadType);
	}
	p_line_add_newline();

	if (bOffer)
	{
		SdpAddRtpMapList();
	}
	else
	{
		SdpAddRtpMap(Sys_iAudioType);
	}
	if (Sys_iDtmfType == DTMF_RFC2833)
	{
		SdpAddDtmfType(Rtp_iDtmfPayloadType);
		SdpAddDtmfFmtp(Rtp_iDtmfPayloadType);
	}
	_FillMode(Sip_iConnMode);

	SdramWriteAll((USHORT)(PROTOCOL_SDRAM_POS+iIndexLow));
	return p_line_get_len();
}

BOOLEAN SipSdpParse(UCHAR iDstIndex)
{
	DCHAR i, iTemp, iAudioType, iDtmfPType, iConnMode;
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	XCHAR pDstIP[IP_ALEN];
	DSHORT iDstPort, iRtcpPort;
	XCHAR iIlbcPType;
	BOOLEAN bValidIP;
	BOOLEAN bMediaAudio;

	iAudioType = CODEC_NULL;
	if (Sys_iServiceType == SERVICE_TYPE_ZTE)
	{
		iDtmfPType = 97;
	}
	else
	{
		iDtmfPType = Rtp_iDtmfPayloadType;
	}
	iConnMode = SIP_MODE_SENDRECV;
	iIlbcPType = Rtp_iPeerIlbcPType;
	iDstPort = 0;
	iRtcpPort = 0;
	bValidIP = FALSE;
	bMediaAudio = FALSE;
	p_memset_x(pDstIP, 0, IP_ALEN);

	for (i = 0; i < Sip_iBodyLines; i ++)
	{
		SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+i + SIP_RECV_BODY));
		pCur = (PXCHAR)Sdram_pDataCache;
		switch (pCur[0])
		{
		case 'v':
			if (p_memcmp_c2x(pCur, Sdp_cV0, V0_LABEL_LEN))
			{
				OutputString(IDS_SIP_SDP_VER_MISMATCH);
				return FALSE;
			}
			break;
		case 'o':	// o=<username> <session id> <version> <network type> <address type> <address> 
			if (!bValidIP)
			{
				// o=<username>
				pTemp = p_strchr_x(pCur, ' ');
				if (!pTemp)		return FALSE;
				pCur = pTemp;
				pCur ++;
				// <session id>
				pTemp = p_strchr_x(pCur, ' ');
				if (!pTemp)		return FALSE;
				pCur = pTemp;
				pCur ++;
				// <version>
				pTemp = p_strchr_x(pCur, ' ');
				if (!pTemp)		return FALSE;
				pCur = pTemp;
				pCur ++;
				// <network type>
				pTemp = p_strchr_x(pCur, ' ');
				if (!pTemp)		return FALSE;
				pCur = pTemp;
				pCur ++;
				// <address type>
				pTemp = p_strchr_x(pCur, ' ');
				if (!pTemp)		return FALSE;
				pCur = pTemp;
				pCur ++;
				// <address>
				if (!p_String2IP(pCur, pDstIP))
				{
					// address is a domain name;
					DebugString(pCur);
					return FALSE;
				}
			}
			break;
		case 'c':	// c=<network type> <address type> <connection address>
			// c=<network type>
			if (!bValidIP)
			{
				pTemp = p_strchr_x(pCur, ' ');
				if (!pTemp)		return FALSE;
				pCur = pTemp;
				pCur ++;
				// <address type>
				pTemp = p_strchr_x(pCur, ' ');
				if (!pTemp)		return FALSE;
				pCur = pTemp;
				pCur ++;
				// <connection address>
				if (!p_String2IP(pCur, pDstIP))
				{
					// address is a domain name;
					DebugString(pCur);
					return FALSE;
				}
				else
				{
					bValidIP = TRUE;
				}
			}
			break;
		case 'm':	// m=<media> <port> <transport> <fmt list>
			// m=<media>
			pTemp = p_strchr_x(pCur, ' ');
			if (!pTemp)		return FALSE;
			pTemp[0] = 0;
			if (!p_strcmp_c2x(pCur, Sdp_cMAudio))
			{
				bMediaAudio = TRUE;
			}
			else
			{
				bMediaAudio = FALSE;
				break;
			}
			pCur = pTemp;
			pCur ++;
			// <port>
			pTemp = p_strchr_x(pCur, ' ');
			if (!pTemp)		return FALSE;
			pTemp[0] = 0;
			iDstPort = p_atoi(pCur, 10);
			pCur = pTemp;
			pCur ++;
			// <transport>
			pTemp = p_strchr_x(pCur, ' ');
			if (!pTemp)		return FALSE;
			pCur = pTemp;
			pCur ++;
			// <fmt list>
			do
			{
				pTemp = p_strchr_x(pCur, ' ');
				if (pTemp)	pTemp[0] = 0;
				iTemp = (UCHAR)p_atoi(pCur, 10);
				iTemp = RtpGetAudioType(iTemp);
				iTemp = SdpAudioMatch(iTemp);
				if (iTemp != CODEC_NULL)
				{
					iAudioType = iTemp;
					break;
				}
				if (pTemp)
				{
					pCur = pTemp;
					pCur ++;
				}
			}while (pTemp);			
			break;
		case 'a':
			if (bMediaAudio)
			{
				if (p_memcmp_nocase_c2x(pCur, Sdp_cRtpmap, RTPMAP_LABEL_LEN))
				{
					pCur += RTPMAP_LABEL_LEN;
					iTemp = (UCHAR)p_atoi(pCur, 10);
					pTemp = p_strchr_x(pCur, ' ');
					if (!pTemp)		break;
					pCur = pTemp;
					pCur ++;
					if (p_memcmp_nocase_c2x(pCur, Sdp_cTelEvent, TELEVENT_LABEL_LEN))
					{
						iDtmfPType = iTemp;
					}
					else if (p_memcmp_nocase_c2x(pCur, Sdp_cAudioMap[CODEC_ILBC], p_strlen_c(Sdp_cAudioMap[CODEC_ILBC])))
					{
						iIlbcPType = iTemp;
						if (iAudioType == CODEC_NULL)
						{
							iTemp = SdpAudioMatch(CODEC_ILBC);
							if (iTemp != CODEC_NULL)		iAudioType = iTemp;
						}
					}
					break;
				}
				if (p_memcmp_nocase_c2x(pCur, Sdp_cRtcp, RTCP_LABEL_LEN))
				{
					pCur += RTCP_LABEL_LEN;
					iRtcpPort = (UCHAR)p_atoi(pCur, 10);
					break;
				}
				for (iTemp = 0; iTemp < SIP_MODE_NUMBER; iTemp ++)
				{
					if (p_memcmp_nocase_c2x(pCur, _cTxMode[iTemp], MODE_LABEL_LEN))
					{
						iConnMode = _cConnMode[iTemp];
						break;
					}
				}			
			}
			break;
		}
	}

	if (iAudioType == CODEC_NULL)	
	{
		OutputString(IDS_SIP_SDP_AUDIO_MISMATCH);
		return FALSE;
	}

	if (!iRtcpPort)
	{
		iRtcpPort = iDstPort + 1;
	}

	if (!IsValidIP(pDstIP))
	{
		iConnMode &= ~SIP_MODE_SENDONLY;
	}
	p_memcpy_ip((PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_IP), pDstIP);
	USHORT2PXCHAR(iDstPort, (PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_RTPPORT));
	USHORT2PXCHAR(iRtcpPort, (PXCHAR)(Sdram_pDataCache + SIP_SDP_INFO_RTCPPORT));
	X_VAL(Sdram_pDataCache, SIP_SDP_INFO_MODE) = iConnMode;
	X_VAL(Sdram_pDataCache, SIP_SDP_INFO_CODEC) = iAudioType;
	X_VAL(Sdram_pDataCache, SIP_SDP_INFO_DTMF) = iDtmfPType;
	X_VAL(Sdram_pDataCache, SIP_SDP_INFO_ILBC) = iIlbcPType;
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex), SIP_SDP_INFO_LEN);
	return TRUE;
}
