/*----------------------------------------------------------------------------
 * File:        RRCMMISC.C
 * Product:     RTP/RTCP implementation.
 * Description: Provides common RTP/RTCP support functionality.
 *
 *
 * INTEL Corporation Proprietary Information
 * This listing is supplied under the terms of a license agreement with
 * Intel Corporation and may not be copied nor disclosed except in
 * accordance with the terms of that agreement.
 * Copyright (c) 1995 Intel Corporation.
 *--------------------------------------------------------------------------*/


#include "rrcm.h"


/*---------------------------------------------------------------------------
/							Global Variables
/--------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------
/							External Variables
/--------------------------------------------------------------------------*/
#ifdef ENABLE_ISDM2
extern KEY_HANDLE hRRCMRootKey;
extern ISDM2	  Isdm2;
#endif

extern RRCM_WS	RRCMws;				

#ifdef _DEBUG
extern char		debug_string[];
#endif

#ifdef ISRDBG
extern WORD		ghISRInst;
#endif


/*--------------------------------------------------------------------------
 * Function   : searchForMySSRC
 * Description: Find the SSRC for this stream.
 *
 * Input :	pSSRC		:	-> to the SSRC entry
 *			RTPSocket	:	RTP socket descriptor
 *
 * Return: NULL 			==> Session not found.
 *         Buffer Address 	==> OK, Session ptr returned
 --------------------------------------------------------------------------*/
 PSSRC_ENTRY searchForMySSRC(PSSRC_ENTRY pSSRC,
							 SOCKET RTPSocket)
	{
	PSSRC_ENTRY	pRRCMSession;

	IN_OUT_STR ("RTP : Enter searchForMySSRC()\n");

	for (pRRCMSession = NULL;
		 (pSSRC != NULL);
		 pSSRC = (PSSRC_ENTRY)pSSRC->SSRCList.prev)
		{
		if (pSSRC->RTPsd == RTPSocket)
			{
			pRRCMSession = pSSRC;
			break;
			}
		}

	IN_OUT_STR ("RTP : Exit searchForMySSRC()\n");		

	return (pRRCMSession);
	}


/*--------------------------------------------------------------------------
 * Function   : searchforSSRCatHead
 * Description: Search through linked list of RTCP entries starting at the
 *					head of the list.
 *
 * Input :	pSSRC	:	-> to the SSRC entry
 *			ssrc	:	ssrc to look for
 *
 * Return: NULL 			==> Session not found.
 *         Non-NULL		 	==> OK, SSRC entry found
 --------------------------------------------------------------------------*/
 PSSRC_ENTRY searchforSSRCatHead(PSSRC_ENTRY pSSRC,
								 DWORD ssrc)					
	{
	PSSRC_ENTRY	pRRCMSession;

	IN_OUT_STR ("RTP : Enter searchForMySSRCatHead()\n");		
	
	for (pRRCMSession = NULL;
		 (pSSRC != NULL) &&
		 (pRRCMSession == NULL) && (ssrc <= pSSRC->SSRC);
		 pSSRC = (PSSRC_ENTRY)pSSRC->SSRCList.prev)
		{
		if (pSSRC->SSRC == ssrc)
			{
			pRRCMSession = pSSRC;
			}
		}

	IN_OUT_STR ("RTP : Exit searchForMySSRCatHead()\n");		 		

	return (pRRCMSession);
	}


/*--------------------------------------------------------------------------
 * Function   : searchforSSRCatTail
 * Description: Search through linked list of RTCP entries starting at the
 *					tail of the list.
 *
 * Input :	pSSRC	:	-> to the SSRC entry
 *			ssrc	:	SSRC to look for
 *
 * Return: NULL 			==> Session not found.
 *         Non-NULL		 	==> OK, SSRC entry found
 --------------------------------------------------------------------------*/
 PSSRC_ENTRY searchforSSRCatTail(PSSRC_ENTRY pSSRC,
								 DWORD ssrc)					
	{
	PSSRC_ENTRY	pRRCMSession;

	IN_OUT_STR ("RTP : Enter searchForMySSRCatTail()\n");		
	
	for (pRRCMSession = NULL;
		 (pSSRC != NULL) &&
		 (pRRCMSession == NULL) && (ssrc >= pSSRC->SSRC);
		 pSSRC = (PSSRC_ENTRY)pSSRC->SSRCList.next)
		{
		if (pSSRC->SSRC == ssrc)
			{
			pRRCMSession = pSSRC;
			}
		}

	IN_OUT_STR ("RTP : Exit searchForMySSRCatTail()\n");		
	
	return (pRRCMSession);
	}


/*---------------------------------------------------------------------------
 * Function   : saveNetworkAddress
 * Description: Saves the received or local network Address in the local
 *					context.
 *
 * Input :	pSSRCEntry	:	-> to the SSRC entry
 *			pNetAddr	:	-> to the network address
 *			addrLen		:	Address length
 *
 * Return:	OK: RRCM_NoError
 --------------------------------------------------------------------------*/
 DWORD saveNetworkAddress (PSSRC_ENTRY pSSRC,
 						   PSOCKADDR pNetAddr,
 						   int addrLen)
	{
	IN_OUT_STR ("RTP : Enter saveNetworkAddress()\n");		

	pSSRC->dwSSRCStatus |= NETWK_ADDR_UPDATED;
	pSSRC->fromLen = addrLen;
	memcpy (&pSSRC->from, pNetAddr, addrLen);

	IN_OUT_STR ("RTP : Exit saveNetworkAddress()\n");

	return RRCM_NoError;			
	}


/*---------------------------------------------------------------------------
 * Function   : updateRTCPDestinationAddress
 * Description: The applicatino updates the RTCP destination address
 *				
 * Input :	hRTPSess		:	RTP session
 *			pAddr		:	-> to address structure	of RTCP information
 *			addrLen		:	Address length
 *
 * Return: RRCM_NoError		= OK.
 *         Otherwise(!=0)	= Check RRCM.h file for references.
 --------------------------------------------------------------------------*/
 DWORD WINAPI updateRTCPDestinationAddress (HANDLE hRTPSess,
	 										 PSOCKADDR pRtcpAddr,
											 int addrLen)	
	{
	PRTP_SESSION	pRTPSession = (PRTP_SESSION) hRTPSess;
	PRTCP_SESSION	pRTCPses;

#ifdef ENABLE_ISDM2
	PSSRC_ENTRY		pSSRC;
#endif
	
	IN_OUT_STR ("RTP : Enter updateRTCPDestinationAddress()\n");

	if (pRTPSession == NULL)
		{
		RRCM_DBG_MSG ("RTP : ERROR - Invalid RTP session", 0,
					  __FILE__, __LINE__, DBG_CRITICAL);
		IN_OUT_STR ("RTP : Exit updateRTCPDestinationAddress()\n");

		return (MAKE_RRCM_ERROR(RRCMError_RTPInvalidSession));
		}

	// get the RTCP session
	pRTCPses = pRTPSession->pRTCPSession;
	if (pRTCPses == NULL)
		{
		RRCM_DBG_MSG ("RTP : ERROR - Invalid RTCP session", 0,
					  __FILE__, __LINE__, DBG_CRITICAL);
		IN_OUT_STR ("RTP : Exit updateRTCPDestinationAddress()\n");

		return (MAKE_RRCM_ERROR(RRCMError_RTCPInvalidSession));
		}

	if (!(pRTCPses->dwSessionStatus & RTCP_DEST_LEARNED))
		{
		pRTCPses->dwSessionStatus |= RTCP_DEST_LEARNED;
		pRTCPses->toLen = addrLen;
		memcpy (&pRTCPses->toBfr, pRtcpAddr, addrLen);

		// register our Xmt SSRC - Rcvd one will be found later
#ifdef ENABLE_ISDM2
		if (Isdm2.hISDMdll)
			{
			pSSRC = (PSSRC_ENTRY)pRTCPses->XmtSSRCList.prev;
			if (pSSRC != NULL)
				registerSessionToISDM (pSSRC, pRTCPses, &Isdm2);
			}
#endif
		}

	IN_OUT_STR ("RTP : Exit updateRTCPDestinationAddress()\n");

	return RRCM_NoError;
	}


/*---------------------------------------------------------------------------
 * Function   : updateSSRCentry
 * Description: The application updates some of the SSRC information
 *				
 * Input :	RTPsd		:	RTP socket descriptor
 *			updateType	:	Type of update desired
 *			updateInfo	:	Update information
 *			misc		:	Miscelleanous information
 *
 * Return: RRCM_NoError		= OK.
 *         Otherwise(!=0)	= Check RRCM.h file for references.
 --------------------------------------------------------------------------*/
 HRESULT WINAPI updateSSRCentry ( HANDLE hRTPSess,
 								  SOCKET RTPsd,
								  DWORD updateType,
	 						      DWORD_PTR updateInfo,
								  DWORD_PTR misc)	
	{
	PRTP_SESSION	pRTPSession = (PRTP_SESSION) hRTPSess;
	PRTCP_SESSION	pRTCPses;
	PSSRC_ENTRY		pSSRC;
	PLINK_LIST		pTmp;
	PSDES_DATA		pSdes;
	
	IN_OUT_STR ("RTP : Enter updateRTCPSdes ()\n");

	if (pRTPSession == NULL)
		{
		RRCM_DBG_MSG ("RTP : ERROR - Invalid RTP session", 0,
					  __FILE__, __LINE__, DBG_CRITICAL);
		IN_OUT_STR ("RTP : Exit updateRTCPSdes ()\n");

		return (MAKE_RRCM_ERROR(RRCMError_RTPInvalidSession));
		}

	// get the RTCP session
	pRTCPses = pRTPSession->pRTCPSession;
	if (pRTCPses == NULL)
		{
		RRCM_DBG_MSG ("RTP : ERROR - Invalid RTCP session", 0,
					  __FILE__, __LINE__, DBG_CRITICAL);
		IN_OUT_STR ("RTP : Exit updateRTCPSdes ()\n");

		return (MAKE_RRCM_ERROR(RRCMError_RTCPInvalidSession));
		}

	// search for the socket descriptor (unique per session)
	// walk through the list from the tail
	pTmp = (PLINK_LIST)pRTCPses->XmtSSRCList.prev;

	while (pTmp)
		{
		if (((PSSRC_ENTRY)pTmp)->RTPsd == RTPsd)
			{
			// lock access to this entry
			EnterCriticalSection (&((PSSRC_ENTRY)pTmp)->critSect);

			pSSRC = (PSSRC_ENTRY)pTmp;

			switch (updateType)
				{
				case RRCM_UPDATE_SDES:
					// update the SDES
					pSdes = (PSDES_DATA)updateInfo;

					switch (pSdes->dwSdesType)
						{
						case RTCP_SDES_CNAME:
							pSSRC->cnameInfo.dwSdesLength = pSdes->dwSdesLength;
							memcpy (pSSRC->cnameInfo.sdesBfr, pSdes->sdesBfr,
									pSdes->dwSdesLength);

							pSSRC->cnameInfo.dwSdesFrequency =
								frequencyToPckt (pSdes->dwSdesFrequency);
							pSSRC->cnameInfo.dwSdesEncrypted = pSdes->dwSdesEncrypted;
							break;

						case RTCP_SDES_NAME:
							pSSRC->nameInfo.dwSdesLength  = pSdes->dwSdesLength;
							memcpy (pSSRC->nameInfo.sdesBfr, pSdes->sdesBfr,
									pSdes->dwSdesLength);

							pSSRC->nameInfo.dwSdesFrequency =
								frequencyToPckt (pSdes->dwSdesFrequency);
							pSSRC->nameInfo.dwSdesEncrypted = pSdes->dwSdesEncrypted;
							break;

						case RTCP_SDES_EMAIL:
							pSSRC->emailInfo.dwSdesLength  = pSdes->dwSdesLength;
							memcpy (pSSRC->emailInfo.sdesBfr, pSdes->sdesBfr,
									pSdes->dwSdesLength);

							pSSRC->emailInfo.dwSdesFrequency =
								frequencyToPckt (pSdes->dwSdesFrequency);
							pSSRC->emailInfo.dwSdesEncrypted = pSdes->dwSdesEncrypted;
							break;

						case RTCP_SDES_PHONE:
							pSSRC->phoneInfo.dwSdesLength  = pSdes->dwSdesLength;
							memcpy (pSSRC->phoneInfo.sdesBfr, pSdes->sdesBfr,
									pSdes->dwSdesLength);

							pSSRC->phoneInfo.dwSdesFrequency =
								frequencyToPckt (pSdes->dwSdesFrequency);
							pSSRC->phoneInfo.dwSdesEncrypted = pSdes->dwSdesEncrypted;
							break;

						case RTCP_SDES_LOC:
							pSSRC->locInfo.dwSdesLength  = pSdes->dwSdesLength;
							memcpy (pSSRC->locInfo.sdesBfr, pSdes->sdesBfr,
									pSdes->dwSdesLength);

							pSSRC->locInfo.dwSdesFrequency =
								frequencyToPckt (pSdes->dwSdesFrequency);
							pSSRC->locInfo.dwSdesEncrypted = pSdes->dwSdesEncrypted;
							break;

						case RTCP_SDES_TOOL:
							pSSRC->toolInfo.dwSdesLength  = pSdes->dwSdesLength;
							memcpy (pSSRC->toolInfo.sdesBfr, pSdes->sdesBfr,
									pSdes->dwSdesLength);

							pSSRC->toolInfo.dwSdesFrequency =
								frequencyToPckt (pSdes->dwSdesFrequency);
							pSSRC->toolInfo.dwSdesEncrypted = pSdes->dwSdesEncrypted;
							break;

						case RTCP_SDES_TXT:
							pSSRC->txtInfo.dwSdesLength  = pSdes->dwSdesLength;
							memcpy (pSSRC->txtInfo.sdesBfr, pSdes->sdesBfr,
									pSdes->dwSdesLength);

							pSSRC->txtInfo.dwSdesFrequency =
								frequencyToPckt (pSdes->dwSdesFrequency);
							pSSRC->txtInfo.dwSdesEncrypted = pSdes->dwSdesEncrypted;
							break;

						case RTCP_SDES_PRIV:
							pSSRC->privInfo.dwSdesLength  = pSdes->dwSdesLength;
							memcpy (pSSRC->privInfo.sdesBfr, pSdes->sdesBfr,
									pSdes->dwSdesLength);

							pSSRC->privInfo.dwSdesFrequency =
								frequencyToPckt (pSdes->dwSdesFrequency);
							pSSRC->privInfo.dwSdesEncrypted = pSdes->dwSdesEncrypted;
							break;
						}
					break;

				case RRCM_UPDATE_STREAM_FREQUENCY:
					// upate the stream clocking frequency
					pSSRC->dwStreamClock = (DWORD)updateInfo;
					break;

				case RRCM_UPDATE_RTCP_STREAM_MIN_BW:
					// upate the stream clocking frequency
					pSSRC->xmtInfo.dwRtcpStreamMinBW = (DWORD)updateInfo;
					break;

				case RRCM_UPDATE_CALLBACK:
					// update the callback information
					EnterCriticalSection (&pRTCPses->critSect);
					pRTCPses->pRRCMcallback      = (PRRCM_EVENT_CALLBACK)updateInfo;
					pRTCPses->dwCallbackUserInfo = misc;
					LeaveCriticalSection (&pRTCPses->critSect);
					break;
				}

			// unlock access to this entry
			LeaveCriticalSection (&((PSSRC_ENTRY)pTmp)->critSect);
			}

		pTmp = pTmp->next;
		}	


	IN_OUT_STR ("RTP : Exit updateRTCPSdes ()\n");

	return RRCM_NoError;
	}



/*---------------------------------------------------------------------------
 * Function   : RRCMnotification
 * Description: Notify the application that one of the RTP/RTCP events that
 *				we keep track of has occured.
 *
 * Input :	RRCMevent	:	RRCM event to report
 *			pSSRC		:	-> to the SSRC entry
 *			ssrc		:	SSRC which generated the event
 *			misc		:	Miscelleanous value
 *
 * Return:	OK: RRCM_NoError
 --------------------------------------------------------------------------*/
 void RRCMnotification (RRCM_EVENT_T RRCMevent,
						PSSRC_ENTRY pSSRC,
						DWORD dwSSRC,
						DWORD misc)
	{
	IN_OUT_STR ("RRCM: Enter RRCMnotification()\n");		

	// check to see if the application is interested by the RRCM event
	if (pSSRC->pRTCPses->pRRCMcallback == NULL)				
		return;

	switch (RRCMevent)
		{
		case RRCM_NEW_SOURCE_EVENT:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, dwSSRC, misc,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		case RRCM_LOCAL_COLLISION_EVENT:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, pSSRC->SSRC, dwSSRC,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		case RRCM_REMOTE_COLLISION_EVENT:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, dwSSRC, 0,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		case RRCM_RECV_RTCP_SNDR_REPORT_EVENT:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, dwSSRC, pSSRC->RTCPsd,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		case RRCM_RECV_RTCP_RECV_REPORT_EVENT:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, dwSSRC, pSSRC->RTCPsd,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		case RRCM_TIMEOUT_EVENT:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, dwSSRC, 0,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		case RRCM_BYE_EVENT:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, dwSSRC, 0,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		case RRCM_RTCP_WS_RCV_ERROR:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, dwSSRC, misc,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		case RRCM_RTCP_WS_XMT_ERROR:
			pSSRC->pRTCPses->pRRCMcallback (RRCMevent, dwSSRC, misc,
											pSSRC->pRTCPses->dwCallbackUserInfo);
			break;

		default:
			break;
		}

	IN_OUT_STR ("RRCM: Exit RRCMnotification()\n");
	}



/*----------------------------------------------------------------------------
 * Function   : registerSessionToISDM
 * Description: Register an RTP/RTCP session with ISDM
 *
 * Input :      pSSRC	:	-> to the SSRC's entry
 *				pRTCP	:	-> to the RTCP session's information
 *				pIsdm	:	-> to the ISDM information
 *
 * Return: 		None
 ---------------------------------------------------------------------------*/
#ifdef ENABLE_ISDM2

#define SESSION_BFR_SIZE	30
void registerSessionToISDM (PSSRC_ENTRY pSSRC,
							PRTCP_SESSION pRTCPses,
							PISDM2 pIsdm2)
	{
	struct sockaddr_in	*pSSRCadr;
	unsigned short		port;
	unsigned long		netAddr;
	CHAR				SsrcBfr[10];
	CHAR				sessionBfr[SESSION_BFR_SIZE];
	unsigned char		*ptr;
	int					num;
	HRESULT				hError;
	ISDM2_ENTRY			Isdm2Stat;

	// get the destination address as the session identifier
	pSSRCadr = (struct sockaddr_in *)&pRTCPses->toBfr;
	RRCMws.htons (pSSRC->RTPsd, pSSRCadr->sin_port, &port);
	netAddr  = pSSRCadr->sin_addr.S_un.S_addr;

	ptr = (unsigned char *)&netAddr;
	memset (sessionBfr, 0x00, SESSION_BFR_SIZE);

	num = (int)*ptr++;
	RRCMitoa (num, sessionBfr, 10);
	strcat (sessionBfr, ".");
	num = (int)*ptr++;
	RRCMitoa (num, (sessionBfr + strlen(sessionBfr)), 10);
	strcat (sessionBfr, ".");
	num = (int)*ptr++;
	RRCMitoa (num, (sessionBfr + strlen(sessionBfr)), 10);
	strcat (sessionBfr, ".");
	num = (int)*ptr;
	RRCMitoa (num, (sessionBfr + strlen(sessionBfr)), 10);
	strcat (sessionBfr, ".");
	RRCMitoa (port, (sessionBfr + strlen(sessionBfr)), 10);

	// get the SSRC
	RRCMultoa (pSSRC->SSRC, SsrcBfr, 16);

	// register the session
	if (pRTCPses->hSessKey == NULL)
		{
		hError = Isdm2.ISDMEntry.ISD_CreateKey (hRRCMRootKey,
												sessionBfr,
												&pRTCPses->hSessKey);
		if(FAILED(hError))
			RRCM_DBG_MSG ("RTP: ISD_CreateKey Failed",0, NULL, 0, DBG_NOTIFY);
			
		}

	memset(&Isdm2Stat, 0x00, sizeof(ISDM2_ENTRY));

	hError = Isdm2.ISDMEntry.ISD_CreateValue (pRTCPses->hSessKey,
											  SsrcBfr,
											  BINARY_VALUE,
											  (BYTE *)&Isdm2Stat,
											  sizeof(ISDM2_ENTRY),
											  &pSSRC->hISDM);
	if(FAILED(hError))
		RRCM_DBG_MSG ("RTP: ISD_CreateValue Failed",0, NULL, 0, DBG_NOTIFY);				
	}


/*----------------------------------------------------------------------------
 * Function   : udpateISDMsta
 * Description: Update an ISDM data structure
 *
 * Input :      pSSRC	:	-> to the SSRC's entry
 *				pIsdm	:	-> to the ISDM entry
 *				flag	:	Sender/Receive flag
 *				LocalFB :	do or dont't update the local feedback
 *
 * Return: 		None
 ---------------------------------------------------------------------------*/
void updateISDMstat (PSSRC_ENTRY pSSRC,
					 PISDM2 pIsdm2,
					 DWORD flag,
					 BOOL LocalFB)
	{
	DWORD			curTime = timeGetTime();
	DWORD			dwTmp;
	DWORD			dwValue;
	ISDM2_ENTRY		Isdm2Stat;
	HRESULT			hError;

	unsigned short	idx = 0;
	
	EnterCriticalSection (&pIsdm2->critSect);
	
	Isdm2Stat.SSRC = pSSRC->SSRC;
	Isdm2Stat.PayLoadType = pSSRC->PayLoadType;

	if (flag == RECVR)
		{
		Isdm2Stat.dwSSRCStatus = RECVR;
		Isdm2Stat.rcvInfo.dwNumPcktRcvd = pSSRC->rcvInfo.dwNumPcktRcvd;
		Isdm2Stat.rcvInfo.dwPrvNumPcktRcvd = pSSRC->rcvInfo.dwPrvNumPcktRcvd;
		Isdm2Stat.rcvInfo.dwExpectedPrior  = pSSRC->rcvInfo.dwExpectedPrior;
		Isdm2Stat.rcvInfo.dwNumBytesRcvd   = pSSRC->rcvInfo.dwNumBytesRcvd;
		Isdm2Stat.rcvInfo.dwBaseRcvSeqNum  = pSSRC->rcvInfo.dwBaseRcvSeqNum;
		Isdm2Stat.rcvInfo.dwBadSeqNum      = pSSRC->rcvInfo.dwBadSeqNum;
		Isdm2Stat.rcvInfo.dwProbation      = pSSRC->rcvInfo.dwProbation;
		Isdm2Stat.rcvInfo.dwPropagationTime= pSSRC->rcvInfo.dwPropagationTime;
		Isdm2Stat.rcvInfo.interJitter      = pSSRC->rcvInfo.interJitter;
		Isdm2Stat.rcvInfo.XtendedSeqNum.seq_union.dwXtndedHighSeqNumRcvd =
			pSSRC->rcvInfo.XtendedSeqNum.seq_union.dwXtndedHighSeqNumRcvd;
		}
	else // (flag == ISDM_UPDATE_XMTSTAT)
		{
		Isdm2Stat.dwSSRCStatus = XMITR;

		Isdm2Stat.xmitinfo.dwNumPcktSent  = pSSRC->xmtInfo.dwNumPcktSent;
		Isdm2Stat.xmitinfo.dwNumBytesSent = pSSRC->xmtInfo.dwNumBytesSent;
		Isdm2Stat.xmitinfo.dwNTPmsw		  = pSSRC->xmtInfo.dwNTPmsw;
		Isdm2Stat.xmitinfo.dwNTPlsw		  = pSSRC->xmtInfo.dwNTPlsw;
		Isdm2Stat.xmitinfo.dwRTPts		  = pSSRC->xmtInfo.dwRTPts;
		Isdm2Stat.xmitinfo.dwCurXmtSeqNum = pSSRC->xmtInfo.dwCurXmtSeqNum;
		Isdm2Stat.xmitinfo.dwPrvXmtSeqNum = pSSRC->xmtInfo.dwPrvXmtSeqNum;
		Isdm2Stat.xmitinfo.sessionBW	  = pSSRC->xmtInfo.dwRtcpStreamMinBW;
		Isdm2Stat.xmitinfo.dwLastSR       = pSSRC->xmtInfo.dwLastSR;
		Isdm2Stat.xmitinfo.dwLastSRLocalTime =
			pSSRC->xmtInfo.dwLastSRLocalTime;
		Isdm2Stat.xmitinfo.dwLastSendRTPSystemTime =
			pSSRC->xmtInfo.dwLastSendRTPSystemTime;
		Isdm2Stat.xmitinfo.dwLastSendRTPTimeStamp =
			pSSRC->xmtInfo.dwLastSendRTPTimeStamp;
		}

	if(LocalFB)
		{
		memcpy(&Isdm2Stat.rrFeedback, &pSSRC->rrFeedback, sizeof(RTCP_FEEDBACK));
		}
	else
		{
		Isdm2Stat.rrFeedback.SSRC = pSSRC->rrFeedback.SSRC;
#ifdef ENABLE_FLOATING_POINT
		Isdm2Stat.rrFeedback.dwInterJitter = pSSRC->rcvInfo.interJitter;
#else
		// Check RFC for details of the round off
		Isdm2Stat.rrFeedback.dwInterJitter = pSSRC->rcvInfo.interJitter >> 4;
#endif
		Isdm2Stat.rrFeedback.XtendedSeqNum.seq_union.dwXtndedHighSeqNumRcvd =
			pSSRC->rcvInfo.XtendedSeqNum.seq_union.dwXtndedHighSeqNumRcvd;

		// fraction/cumulative number lost are in network order
		dwTmp = getSSRCpcktLoss (pSSRC, FALSE);
		Isdm2Stat.rrFeedback.fractionLost = (dwTmp & 0xFF);
		RRCMws.ntohl (pSSRC->RTPsd, dwTmp, &dwValue);
		Isdm2Stat.rrFeedback.cumNumPcktLost = (dwValue & 0x00FFFFFF);
		
		Isdm2Stat.rrFeedback.dwLastRcvRpt = pSSRC->rrFeedback.dwLastRcvRpt;
		Isdm2Stat.rrFeedback.dwLastSR = pSSRC->xmtInfo.dwLastSR;
		Isdm2Stat.rrFeedback.dwDelaySinceLastSR = getDLSR (pSSRC);
		}

	Isdm2Stat.dwLastReportRcvdTime = pSSRC->dwLastReportRcvdTime;

	memcpy(&Isdm2Stat.cnameInfo, &pSSRC->cnameInfo, sizeof(SDES_DATA));
	memcpy(&Isdm2Stat.nameInfo, &pSSRC->nameInfo, sizeof(SDES_DATA));
	memcpy(&Isdm2Stat.from, &pSSRC->from, sizeof(SOCKADDR));

	Isdm2Stat.fromLen = pSSRC->fromLen;
	Isdm2Stat.dwNumRptSent = pSSRC->dwNumRptSent;
	Isdm2Stat.dwNumRptRcvd = pSSRC->dwNumRptRcvd;
	Isdm2Stat.dwNumXmtIoPending = pSSRC->dwNumXmtIoPending;
	Isdm2Stat.dwStreamClock = pSSRC->dwStreamClock;

	hError = Isdm2.ISDMEntry.ISD_SetValue (NULL,
										   pSSRC->hISDM,
										   NULL,
										   BINARY_VALUE,
										   (BYTE *)&Isdm2Stat,
										   sizeof(ISDM2_ENTRY));
	
	if(FAILED(hError))
		RRCM_DBG_MSG ("RTP: ISD_SetValue Failed",0, NULL, 0, DBG_NOTIFY);				

	LeaveCriticalSection (&pIsdm2->critSect);

	}
#endif // #ifdef ENABLE_ISDM2


/*---------------------------------------------------------------------------
 * Function   : RRCMdebugMsg
 * Description: Output RRCM debug messages
 *
 * Input :      pMsg:		-> to message
 *				err:		Error code
 *				pFile:		-> to file where the error occured
 *				line:		Line number where the error occured
 *
 * Return:		None
 --------------------------------------------------------------------------*/
 void RRCMdebugMsg (PCHAR pMsg,
				    DWORD err,
				    PCHAR pFile,
				    DWORD line,
					DWORD type)
	{
#ifdef ISRDBG
	wsprintf (debug_string, "%s", pMsg);
	if (err)
		wsprintf (debug_string+strlen(debug_string), " Error:%d", err);
	if (pFile != NULL)
		wsprintf (debug_string+strlen(debug_string), " - %s, line:%d",
					pFile, line);
	switch (type)
		{
		case DBG_NOTIFY:
			ISRNOTIFY(ghISRInst, debug_string, 0);
			break;
		case DBG_TRACE:
			ISRTRACE(ghISRInst, debug_string, 0);
			break;
		case DBG_ERROR:
			ISRERROR(ghISRInst, debug_string, 0);
			break;
		case DBG_WARNING:
			ISRWARNING(ghISRInst, debug_string, 0);
			break;
		case DBG_TEMP:
			ISRTEMP(ghISRInst, debug_string, 0);
			break;
		case DBG_CRITICAL:
			ISRCRITICAL(ghISRInst, debug_string, 0);
			break;
		default:
			break;
		}
#elif DEBUG
extern HDBGZONE  ghDbgZoneRRCM ;
	wsprintf (debug_string, "%s", pMsg);
	if (err)
		wsprintf (debug_string+strlen(debug_string), " Error:%d", err);
	if (pFile != NULL)
		wsprintf (debug_string+strlen(debug_string), " - %s, line:%d",
					pFile, line);
	
	switch (type)
		{
		case DBG_NOTIFY:
		case DBG_TRACE:
		case DBG_WARNING:
		case DBG_TEMP:
			DBGMSG(ghDbgZoneRRCM,0,(debug_string)); // Trace Zone
			break;
		case DBG_ERROR:
		case DBG_CRITICAL:
			DBGMSG(ghDbgZoneRRCM,1,(debug_string));	// Error Zone
			break;
		default:
			break;
		}

#endif
	}


// [EOF]