1209 lines
32 KiB
C++
1209 lines
32 KiB
C++
|
/*----------------------------------------------------------------------------
|
|||
|
* File: RTCPRECV.C
|
|||
|
* Product: RTP/RTCP implementation
|
|||
|
* Description: Provides the RTCP receive network I/O.
|
|||
|
*
|
|||
|
* 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"
|
|||
|
|
|||
|
|
|||
|
#define MIN(a, b) ((a < b) ? a : b)
|
|||
|
|
|||
|
|
|||
|
/*---------------------------------------------------------------------------
|
|||
|
/ Global Variables
|
|||
|
/--------------------------------------------------------------------------*/
|
|||
|
|
|||
|
|
|||
|
/*---------------------------------------------------------------------------
|
|||
|
/ External Variables
|
|||
|
/--------------------------------------------------------------------------*/
|
|||
|
extern PRTCP_CONTEXT pRTCPContext;
|
|||
|
extern PRTP_CONTEXT pRTPContext;
|
|||
|
extern RRCM_WS RRCMws;
|
|||
|
|
|||
|
#ifdef ENABLE_ISDM2
|
|||
|
extern ISDM2 Isdm2;
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
extern char debug_string[];
|
|||
|
#endif
|
|||
|
|
|||
|
#if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
|
|||
|
//INTEROP
|
|||
|
extern LPInteropLogger RTPLogger;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : RTCPrcvInit
|
|||
|
* Description: RTCP receive initialisation.
|
|||
|
*
|
|||
|
* Input : pRTCP : Pointer to the RTCP session information
|
|||
|
*
|
|||
|
* Return: TRUE/FALSE
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
DWORD RTCPrcvInit (PSSRC_ENTRY pSSRC)
|
|||
|
{
|
|||
|
PRTCP_BFR_LIST pRcvStruct;
|
|||
|
PRTCP_SESSION pRTCP;
|
|||
|
int dwStatus;
|
|||
|
int dwError;
|
|||
|
int errorCnt = 0;
|
|||
|
int bfrErrorCnt = 0;
|
|||
|
DWORD idx;
|
|||
|
int wsockSuccess = FALSE;
|
|||
|
|
|||
|
// save a pointer to the corresponding RTCP session
|
|||
|
pRTCP = pSSRC->pRTCPses;
|
|||
|
|
|||
|
// Post receive buffers for WS-2. As these buffers are posted per receive
|
|||
|
// thread, few of them should be plenty enough for RTCP.
|
|||
|
for (idx = 0; idx < pRTPContext->registry.NumRTCPPostedBfr; idx++)
|
|||
|
{
|
|||
|
// get a free RTCP buffer for a receive operation
|
|||
|
pRcvStruct =
|
|||
|
(PRTCP_BFR_LIST)removePcktFromTail(&pRTCP->RTCPrcvBfrList,
|
|||
|
&pRTCP->critSect);
|
|||
|
|
|||
|
// check buffer
|
|||
|
if (pRcvStruct == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR - Rcv Bfr Allocation Error", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
// make sure we have at least one buffer
|
|||
|
ASSERT (pRcvStruct);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// SSRC entry address of our own session
|
|||
|
pRcvStruct->pSSRC = pSSRC;
|
|||
|
|
|||
|
// received address length reset by the receive routine
|
|||
|
pRcvStruct->addrLen = sizeof(SOCKADDR);
|
|||
|
|
|||
|
// use hEvent to recover the buffer's address
|
|||
|
pRcvStruct->overlapped.hEvent = (WSAEVENT)pRcvStruct;
|
|||
|
|
|||
|
// post the receive buffer for this thread
|
|||
|
dwStatus = RRCMws.recvFrom (pSSRC->RTCPsd,
|
|||
|
&pRcvStruct->bfr,
|
|||
|
pRcvStruct->dwBufferCount,
|
|||
|
&pRcvStruct->dwNumBytesXfr,
|
|||
|
&pRcvStruct->dwFlags,
|
|||
|
(PSOCKADDR)pRcvStruct->addr,
|
|||
|
&pRcvStruct->addrLen,
|
|||
|
(LPWSAOVERLAPPED)&pRcvStruct->overlapped,
|
|||
|
RTCPrcvCallback);
|
|||
|
|
|||
|
// Check Winsock status
|
|||
|
if (dwStatus != 0)
|
|||
|
{
|
|||
|
// error, the receive request won't proceed
|
|||
|
dwError = GetLastError();
|
|||
|
if ((dwError != WSA_IO_PENDING) && (dwError != WSAEMSGSIZE))
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR WSARecvFrom()", GetLastError(),
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
// notify application if interested
|
|||
|
RRCMnotification (RRCM_RTCP_WS_RCV_ERROR, pSSRC,
|
|||
|
pSSRC->SSRC, dwError);
|
|||
|
|
|||
|
// Return the buffer to the free queue
|
|||
|
addToHeadOfList (&pRTCP->RTCPrcvBfrList,
|
|||
|
(PLINK_LIST)pRcvStruct,
|
|||
|
&pRTCP->critSect);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
wsockSuccess = TRUE;
|
|||
|
|
|||
|
// increment number of I/O pending
|
|||
|
InterlockedIncrement ((long *)&pRTCP->dwNumRcvIoPending);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
wsockSuccess = TRUE;
|
|||
|
|
|||
|
// increment number of I/O pending
|
|||
|
InterlockedIncrement ((long *)&pRTCP->dwNumRcvIoPending);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// make sure we posted at least some buffers
|
|||
|
if (wsockSuccess == FALSE)
|
|||
|
{
|
|||
|
// release all resources and kill the receive thread
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTCP: ERROR - Exit RCV init %s: Line:%d", __FILE__, __LINE__);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : RTCPrcvCallback
|
|||
|
* Description: Receive callback routine from Winsock2.
|
|||
|
*
|
|||
|
* Input : dwError: I/O completion status
|
|||
|
* cbTransferred: Number of bytes received
|
|||
|
* lpOverlapped: -> to overlapped structure
|
|||
|
* dwFlags: Flags
|
|||
|
*
|
|||
|
*
|
|||
|
* Return: None
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
void CALLBACK RTCPrcvCallback (DWORD dwError,
|
|||
|
DWORD cbTransferred,
|
|||
|
LPWSAOVERLAPPED lpOverlapped,
|
|||
|
DWORD dwFlags)
|
|||
|
{
|
|||
|
PRTCP_BFR_LIST pRcvStruct;
|
|||
|
RTCP_T *pRTCPpckt;
|
|||
|
PRTCP_SESSION pRTCPses;
|
|||
|
PSSRC_ENTRY pSSRC;
|
|||
|
PAPP_RTCP_BFR pAppBfr;
|
|||
|
DWORD dwStatus = 0;
|
|||
|
DWORD i;
|
|||
|
DWORD pcktLen;
|
|||
|
DWORD dwSSRC;
|
|||
|
USHORT wHost;
|
|||
|
SOCKET RTCPsd;
|
|||
|
unsigned char *pEndPckt;
|
|||
|
unsigned char *pEndBlock;
|
|||
|
int tmpSize;
|
|||
|
#if IO_CHECK
|
|||
|
DWORD initTime = timeGetTime();
|
|||
|
#endif
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Enter RTCPrcvCallback\n");
|
|||
|
|
|||
|
// hEvent in the WSAOVERLAPPED struct points to our buffer's information
|
|||
|
pRcvStruct = (PRTCP_BFR_LIST)lpOverlapped->hEvent;
|
|||
|
|
|||
|
// SSRC entry pointer
|
|||
|
pSSRC = pRcvStruct->pSSRC;
|
|||
|
|
|||
|
// check Winsock callback error status
|
|||
|
if (dwError)
|
|||
|
{
|
|||
|
// 65534 is probably a temporary bug in WS2
|
|||
|
if ((dwError == 65534) || (dwError == WSA_OPERATION_ABORTED))
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: I/O Aborted", dwError,
|
|||
|
__FILE__, __LINE__, DBG_NOTIFY);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR - Rcv Callback", dwError,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
// invalid RTCP packet header, re-queue the buffer
|
|||
|
RTCPpostRecvBfr (pSSRC, pRcvStruct);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit RTCPrcvCallback\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// read the RTCP packet
|
|||
|
pRTCPpckt = (RTCP_T *)pRcvStruct->bfr.buf;
|
|||
|
|
|||
|
#if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
|
|||
|
//INTEROP
|
|||
|
if (RTPLogger)
|
|||
|
{
|
|||
|
InteropOutput (RTPLogger,
|
|||
|
(BYTE FAR*)(pRcvStruct->bfr.buf),
|
|||
|
cbTransferred,
|
|||
|
RTPLOG_RECEIVED_PDU | RTCP_PDU);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// get the RTCP session ptr
|
|||
|
pRTCPses = pSSRC->pRTCPses;
|
|||
|
|
|||
|
// Check RTCP header validity of first packet in report.
|
|||
|
// Filter out junk. First thing in RTCP packet must be
|
|||
|
// either SR, RR or BYE
|
|||
|
if ((pRTCPpckt->common.type != RTP_TYPE) ||
|
|||
|
((pRTCPpckt->common.pt != RTCP_SR) &&
|
|||
|
(pRTCPpckt->common.pt != RTCP_RR) &&
|
|||
|
(pRTCPpckt->common.pt != RTCP_BYE)))
|
|||
|
{
|
|||
|
#ifdef MONITOR_STATS
|
|||
|
pRTCPses->dwNumRTCPhdrErr++;
|
|||
|
#endif
|
|||
|
|
|||
|
// invalid RTCP packet header, re-queue the buffer
|
|||
|
RTCPpostRecvBfr (pSSRC, pRcvStruct);
|
|||
|
|
|||
|
#if 0 // we could have shutdown so this code can fault
|
|||
|
if (pRTCPpckt->common.pt == FLUSH_RTP_PAYLOAD_TYPE)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: Flushing RCV I/O", 0, NULL, 0, DBG_NOTIFY);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTCP: ERROR - Pckt Header Error. Type:%d / Payload:%d",
|
|||
|
pRTCPpckt->common.type, pRTCPpckt->common.pt);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, __FILE__, __LINE__, DBG_TRACE);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit RTCPrcvCallback\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// get the socket descriptor
|
|||
|
RTCPsd = pSSRC->RTCPsd;
|
|||
|
|
|||
|
// get the sender's SSRC
|
|||
|
RRCMws.ntohl (RTCPsd, pRTCPpckt->r.sr.ssrc, &dwSSRC);
|
|||
|
|
|||
|
// skip our own loopback if we receive it
|
|||
|
if (ownLoopback (RTCPsd, dwSSRC, pRTCPses))
|
|||
|
{
|
|||
|
RTCPpostRecvBfr (pSSRC, pRcvStruct);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// at this point we think the RTCP packet's valid. Get the sender's
|
|||
|
// address, if not already known
|
|||
|
if (!(pRTCPses->dwSessionStatus & RTCP_DEST_LEARNED))
|
|||
|
{
|
|||
|
pRTCPses->dwSessionStatus |= RTCP_DEST_LEARNED;
|
|||
|
pRTCPses->toLen = pRcvStruct->addrLen;
|
|||
|
memcpy (&pRTCPses->toBfr, &pRcvStruct->addr, pRcvStruct->addrLen);
|
|||
|
|
|||
|
#ifdef ENABLE_ISDM2
|
|||
|
// register our Xmt SSRC - Rcvd one will be found later
|
|||
|
if (Isdm2.hISDMdll)
|
|||
|
registerSessionToISDM (pSSRC, pRTCPses, &Isdm2);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
// Update our RTCP average packet size estimator
|
|||
|
EnterCriticalSection (&pRTCPses->critSect);
|
|||
|
tmpSize = (cbTransferred + NTWRK_HDR_SIZE) - pRTCPses->avgRTCPpktSizeRcvd;
|
|||
|
|
|||
|
#ifdef ENABLE_FLOATING_POINT
|
|||
|
// As per RFC
|
|||
|
tmpSize = (int)(tmpSize * RTCP_SIZE_GAIN);
|
|||
|
#else
|
|||
|
// Need to remove floating point operation
|
|||
|
tmpSize = tmpSize / 16;
|
|||
|
#endif
|
|||
|
|
|||
|
pRTCPses->avgRTCPpktSizeRcvd += tmpSize;
|
|||
|
LeaveCriticalSection (&pRTCPses->critSect);
|
|||
|
|
|||
|
// check if the raw RTCP packet needs to be copied into an application
|
|||
|
// buffer - Mainly used by ActiveMovieRTP to propagate the reports up
|
|||
|
// the filter graph to the Receive Payload Handler
|
|||
|
pAppBfr = (PAPP_RTCP_BFR)removePcktFromHead (&(pRTCPses->appRtcpBfrList),
|
|||
|
&pRTCPses->critSect);
|
|||
|
if (pAppBfr && !(pAppBfr->dwBfrStatus & RTCP_SR_ONLY))
|
|||
|
{
|
|||
|
// copy the full RTCP packet
|
|||
|
memcpy (pAppBfr->bfr,
|
|||
|
pRTCPpckt,
|
|||
|
MIN(pAppBfr->dwBfrLen, cbTransferred));
|
|||
|
|
|||
|
// number of bytes received
|
|||
|
pAppBfr->dwBytesRcvd = MIN(pAppBfr->dwBfrLen, cbTransferred);
|
|||
|
|
|||
|
// set the event associated with this buffer
|
|||
|
SetEvent (pAppBfr->hBfrEvent);
|
|||
|
}
|
|||
|
|
|||
|
// end of the received packet
|
|||
|
pEndPckt = (unsigned char *)pRTCPpckt + cbTransferred;
|
|||
|
|
|||
|
while ((unsigned char *)pRTCPpckt < pEndPckt)
|
|||
|
{
|
|||
|
// get the length
|
|||
|
dwStatus = RRCMws.ntohs (RTCPsd, pRTCPpckt->common.length, &wHost);
|
|||
|
if (dwStatus)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR - WSANtohs()", GetLastError(),
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
// get this report block length
|
|||
|
pcktLen = (wHost + 1) << 2;
|
|||
|
pEndBlock = (unsigned char *)pRTCPpckt + pcktLen;
|
|||
|
|
|||
|
// sanity check
|
|||
|
if (pEndBlock > pEndPckt)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR - Rcv packet length error", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
#ifdef MONITOR_STATS
|
|||
|
pRTCPses->dwNumRTCPlenErr++;
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// make sure the version is correct for all packets
|
|||
|
if (pRTCPpckt->common.type != RTP_TYPE)
|
|||
|
{
|
|||
|
#ifdef MONITOR_STATS
|
|||
|
pRTCPses->dwNumRTCPhdrErr++;
|
|||
|
#endif
|
|||
|
// invalid RTCP packet header, packet will be re-queued
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
switch (pRTCPpckt->common.pt)
|
|||
|
{
|
|||
|
case RTCP_SR:
|
|||
|
// check if only the SR needs to be propagated up to the app
|
|||
|
if (pAppBfr && (pAppBfr->dwBfrStatus & RTCP_SR_ONLY))
|
|||
|
{
|
|||
|
// copy the RTCP SR
|
|||
|
memcpy (pAppBfr->bfr,
|
|||
|
pRTCPpckt,
|
|||
|
MIN(pAppBfr->dwBfrLen, 24));
|
|||
|
|
|||
|
// number of bytes received
|
|||
|
pAppBfr->dwBytesRcvd = MIN(pAppBfr->dwBfrLen, 24);
|
|||
|
|
|||
|
// set the event associated with this buffer
|
|||
|
SetEvent (pAppBfr->hBfrEvent);
|
|||
|
}
|
|||
|
|
|||
|
// get the sender's SSRC
|
|||
|
RRCMws.ntohl (RTCPsd, pRTCPpckt->r.sr.ssrc, &dwSSRC);
|
|||
|
|
|||
|
// parse the sender report
|
|||
|
parseRTCPsr (RTCPsd, pRTCPpckt, pRTCPses, pRcvStruct);
|
|||
|
|
|||
|
// parse additional receiver reports if any
|
|||
|
for (i = 0; i < pRTCPpckt->common.count; i++)
|
|||
|
{
|
|||
|
parseRTCPrr (RTCPsd, &pRTCPpckt->r.sr.rr[i],
|
|||
|
pRTCPses, pRcvStruct,
|
|||
|
dwSSRC);
|
|||
|
}
|
|||
|
|
|||
|
// notify application if interested
|
|||
|
RRCMnotification (RRCM_RECV_RTCP_SNDR_REPORT_EVENT, pSSRC,
|
|||
|
dwSSRC, 0);
|
|||
|
break;
|
|||
|
|
|||
|
case RTCP_RR:
|
|||
|
// get the sender's SSRC
|
|||
|
RRCMws.ntohl (RTCPsd, pRTCPpckt->r.rr.ssrc, &dwSSRC);
|
|||
|
|
|||
|
// parse receiver reports
|
|||
|
for (i = 0; i < pRTCPpckt->common.count; i++)
|
|||
|
{
|
|||
|
parseRTCPrr (RTCPsd, &pRTCPpckt->r.rr.rr[i],
|
|||
|
pRTCPses, pRcvStruct,
|
|||
|
dwSSRC);
|
|||
|
}
|
|||
|
|
|||
|
// notify application if interested
|
|||
|
RRCMnotification (RRCM_RECV_RTCP_RECV_REPORT_EVENT, pSSRC,
|
|||
|
dwSSRC, 0);
|
|||
|
break;
|
|||
|
|
|||
|
case RTCP_SDES:
|
|||
|
{
|
|||
|
PCHAR buf;
|
|||
|
|
|||
|
buf = (PCHAR)&pRTCPpckt->r.sdes;
|
|||
|
|
|||
|
for (i = 0; i < pRTCPpckt->common.count; i++)
|
|||
|
{
|
|||
|
buf = parseRTCPsdes (RTCPsd, buf, pRTCPses, pRcvStruct);
|
|||
|
if (buf == NULL)
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case RTCP_BYE:
|
|||
|
for (i = 0; i < pRTCPpckt->common.count; i++)
|
|||
|
parseRTCPbye (RTCPsd, pRTCPpckt->r.bye.src[i],
|
|||
|
pRTCPses, pRcvStruct);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// go to next report block
|
|||
|
pRTCPpckt = (RTCP_T *)(pEndBlock);
|
|||
|
}
|
|||
|
|
|||
|
// post back the buffer to WS-2
|
|||
|
RTCPpostRecvBfr (pSSRC, pRcvStruct);
|
|||
|
|
|||
|
#if IO_CHECK
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTCP: Leaving Rcv Callback after: %ld msec\n",
|
|||
|
timeGetTime() - initTime);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit RTCPrcvCallback\n");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : parseRTCPsr
|
|||
|
* Description: Parse an RTCP sender reports and update the corresponding
|
|||
|
* statistics.
|
|||
|
*
|
|||
|
* Input : sd: RTCP Socket descriptor
|
|||
|
* pRTCPpckt: -> to the RTCP packet
|
|||
|
* pRTCPses: -> to the RTCP session information
|
|||
|
* pRcvStruct: -> to the receive structure information
|
|||
|
*
|
|||
|
* Return: OK: RRCM_NoError
|
|||
|
* !0: Error code (see RRCM.H)
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
DWORD parseRTCPsr (SOCKET sd,
|
|||
|
RTCP_T *pRTCPpckt,
|
|||
|
PRTCP_SESSION pRTCPses,
|
|||
|
PRTCP_BFR_LIST pRcvStruct)
|
|||
|
{
|
|||
|
PSSRC_ENTRY pSSRC;
|
|||
|
DWORD dwSSRC;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Enter parseRTCPsr\n");
|
|||
|
|
|||
|
// get the sender's SSRC
|
|||
|
RRCMws.ntohl (sd, pRTCPpckt->r.sr.ssrc, &dwSSRC);
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string, "RTCP: Receive SR from SSRC:x%lX", dwSSRC);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
|
|||
|
// look for the SSRC entry in the list for this RTCP session
|
|||
|
pSSRC = searchforSSRCatTail((PSSRC_ENTRY)pRTCPses->RcvSSRCList.prev,
|
|||
|
dwSSRC);
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
// new SSRC, create an entry in this RTCP session
|
|||
|
pSSRC = createSSRCEntry(dwSSRC,
|
|||
|
pRTCPses,
|
|||
|
(PSOCKADDR)pRcvStruct->addr,
|
|||
|
(DWORD)pRcvStruct->addrLen,
|
|||
|
FALSE);
|
|||
|
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
// cannot create a new entry, out of resources
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR - Resource allocation", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPsr\n");
|
|||
|
|
|||
|
return (RRCMError_RTCPResources);
|
|||
|
}
|
|||
|
|
|||
|
// notify application if it desired so
|
|||
|
RRCMnotification (RRCM_NEW_SOURCE_EVENT, pSSRC, dwSSRC,
|
|||
|
UNKNOWN_PAYLOAD_TYPE);
|
|||
|
}
|
|||
|
|
|||
|
// get the RTP timestamp
|
|||
|
RRCMws.ntohl (sd, pRTCPpckt->r.sr.rtp_ts, &pSSRC->xmtInfo.dwRTPts);
|
|||
|
|
|||
|
// number of packets send
|
|||
|
RRCMws.ntohl (sd, pRTCPpckt->r.sr.psent, &pSSRC->xmtInfo.dwNumPcktSent);
|
|||
|
|
|||
|
// number of bytes sent
|
|||
|
RRCMws.ntohl (sd, pRTCPpckt->r.sr.osent, &pSSRC->xmtInfo.dwNumBytesSent);
|
|||
|
|
|||
|
// get the NTP most significant word
|
|||
|
RRCMws.ntohl (sd, pRTCPpckt->r.sr.ntp_sec, &pSSRC->xmtInfo.dwNTPmsw);
|
|||
|
|
|||
|
// get the NTP least significant word
|
|||
|
RRCMws.ntohl (sd, pRTCPpckt->r.sr.ntp_frac, &pSSRC->xmtInfo.dwNTPlsw);
|
|||
|
|
|||
|
// last SR timestamp (middle 32 bits of the NTP timestamp)
|
|||
|
pSSRC->xmtInfo.dwLastSR = ((pSSRC->xmtInfo.dwNTPmsw & 0x0000FFFF) << 16);
|
|||
|
pSSRC->xmtInfo.dwLastSR |= ((pSSRC->xmtInfo.dwNTPlsw & 0xFFFF0000) >> 16);
|
|||
|
|
|||
|
// last time this SSRC's heard
|
|||
|
pSSRC->dwLastReportRcvdTime = pSSRC->xmtInfo.dwLastSRLocalTime =
|
|||
|
timeGetTime();
|
|||
|
|
|||
|
// get the source address information
|
|||
|
if (!(pSSRC->dwSSRCStatus & NETWK_ADDR_UPDATED))
|
|||
|
{
|
|||
|
saveNetworkAddress(pSSRC,
|
|||
|
(PSOCKADDR)pRcvStruct->addr,
|
|||
|
pRcvStruct->addrLen);
|
|||
|
}
|
|||
|
|
|||
|
// increment the number of report received from this SSRC
|
|||
|
InterlockedIncrement ((long *)&pSSRC->dwNumRptRcvd);
|
|||
|
|
|||
|
#ifdef ENABLE_ISDM2
|
|||
|
// update ISDM
|
|||
|
if (Isdm2.hISDMdll && pRTCPses->hSessKey)
|
|||
|
{
|
|||
|
if (pSSRC->hISDM)
|
|||
|
updateISDMstat (pSSRC, &Isdm2, RECVR, FALSE);
|
|||
|
else
|
|||
|
registerSessionToISDM (pSSRC, pRTCPses, &Isdm2);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPsr\n");
|
|||
|
|
|||
|
return (RRCM_NoError);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : parseRTCPrr
|
|||
|
* Description: Parse an RTCP receiver reports and update the corresponding
|
|||
|
* statistics.
|
|||
|
*
|
|||
|
* Input : sd: RTCP socket descriptor
|
|||
|
* pRR: -> to receiver report buffer
|
|||
|
* pRTCPses: -> to the RTCP session information
|
|||
|
* pRcvStruct: -> to the receive structure information
|
|||
|
* senderSSRC: Sender's SSRC
|
|||
|
*
|
|||
|
* Return: OK: RRCM_NoError
|
|||
|
* !0: Error code (see RRCM.H)
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
DWORD parseRTCPrr (SOCKET sd,
|
|||
|
RTCP_RR_T *pRR,
|
|||
|
PRTCP_SESSION pRTCPses,
|
|||
|
PRTCP_BFR_LIST pRcvStruct,
|
|||
|
DWORD senderSSRC)
|
|||
|
{
|
|||
|
PSSRC_ENTRY pSSRC;
|
|||
|
DWORD dwSSRC;
|
|||
|
DWORD dwGetFeedback = FALSE;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Enter parseRTCPrr\n");
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTCP: Receive RR from sender SSRC:x%lX", senderSSRC);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
|
|||
|
// get the receiver report SSRC
|
|||
|
RRCMws.ntohl (sd, pRR->ssrc, &dwSSRC);
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string, "RTCP: RR for SSRC:x%lX", dwSSRC);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// NOTE:
|
|||
|
// For now we just keep track of feedback information about ourselve. Later
|
|||
|
// the link list can be used to keep track about everybody feedback
|
|||
|
// information.
|
|||
|
//
|
|||
|
// Check to see if we're interested in this report, ie, does this SSRC report
|
|||
|
// information about one of our active sender.
|
|||
|
dwGetFeedback =
|
|||
|
searchforSSRCatTail((PSSRC_ENTRY)pRTCPses->XmtSSRCList.prev,
|
|||
|
dwSSRC) != NULL;
|
|||
|
|
|||
|
// look for the sender SSRC entry in the list for this RTCP session
|
|||
|
pSSRC =
|
|||
|
searchforSSRCatTail((PSSRC_ENTRY)pRTCPses->RcvSSRCList.prev,
|
|||
|
senderSSRC);
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
// new SSRC, create an entry in this RTCP session
|
|||
|
pSSRC = createSSRCEntry(senderSSRC,
|
|||
|
pRTCPses,
|
|||
|
(PSOCKADDR)pRcvStruct->addr,
|
|||
|
(DWORD)pRcvStruct->addrLen,
|
|||
|
FALSE);
|
|||
|
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
// cannot create a new entry, out of resources
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR - Resource allocation", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPrr\n");
|
|||
|
return (RRCMError_RTCPResources);
|
|||
|
}
|
|||
|
|
|||
|
// notify application if it desired so
|
|||
|
RRCMnotification (RRCM_NEW_SOURCE_EVENT, pSSRC, senderSSRC,
|
|||
|
UNKNOWN_PAYLOAD_TYPE);
|
|||
|
}
|
|||
|
|
|||
|
// update RR feedback information
|
|||
|
if (dwGetFeedback)
|
|||
|
updateRRfeedback (sd, senderSSRC, dwSSRC, pRR, pSSRC);
|
|||
|
|
|||
|
// last time this SSRC's heard
|
|||
|
pSSRC->dwLastReportRcvdTime = timeGetTime();
|
|||
|
|
|||
|
// get the source address information
|
|||
|
if (!(pSSRC->dwSSRCStatus & NETWK_ADDR_UPDATED))
|
|||
|
{
|
|||
|
saveNetworkAddress(pSSRC,
|
|||
|
(PSOCKADDR)pRcvStruct->addr,
|
|||
|
pRcvStruct->addrLen);
|
|||
|
}
|
|||
|
|
|||
|
// increment the number of report received from this SSRC
|
|||
|
InterlockedIncrement ((long *)&pSSRC->dwNumRptRcvd);
|
|||
|
|
|||
|
#ifdef ENABLE_ISDM2
|
|||
|
// update ISDM
|
|||
|
if (Isdm2.hISDMdll && pRTCPses->hSessKey)
|
|||
|
{
|
|||
|
if (pSSRC->hISDM)
|
|||
|
updateISDMstat (pSSRC, &Isdm2, RECVR, TRUE);
|
|||
|
else
|
|||
|
registerSessionToISDM (pSSRC, pRTCPses, &Isdm2);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPrr\n");
|
|||
|
|
|||
|
return (RRCM_NoError);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : parseRTCPsdes
|
|||
|
* Description: Parse an RTCP SDES packet
|
|||
|
*
|
|||
|
* Input : sd: RTCP socket descriptor
|
|||
|
* bfr: -> to SDES buffer
|
|||
|
* pRTCPses: -> to the RTCP session information
|
|||
|
* pRcvStruct: -> to the receive structure information
|
|||
|
*
|
|||
|
* Return: OK: RRCM_NoError
|
|||
|
* !0: Error code (see RRCM.H)
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
PCHAR parseRTCPsdes (SOCKET sd,
|
|||
|
PCHAR bfr,
|
|||
|
PRTCP_SESSION pRTCPses,
|
|||
|
PRTCP_BFR_LIST pRcvStruct)
|
|||
|
{
|
|||
|
DWORD dwHost;
|
|||
|
DWORD ssrc = *(DWORD *)bfr;
|
|||
|
RTCP_SDES_ITEM_T *pSdes;
|
|||
|
PSSRC_ENTRY pSSRC;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Enter parseRTCPsdes\n");
|
|||
|
|
|||
|
// get the SSRC
|
|||
|
RRCMws.ntohl (sd, ssrc, &dwHost);
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string, "RTCP: Receive SDES from SSRC: x%lX", dwHost);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
|
|||
|
// look for the SSRC entry in the list for this RTCP session
|
|||
|
pSSRC = searchforSSRCatTail ((PSSRC_ENTRY)pRTCPses->RcvSSRCList.prev,
|
|||
|
dwHost);
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTCP: SDES and SSRC (x%lX) not found for session (Addr x%lX)",
|
|||
|
dwHost, pRTCPses);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
|
|||
|
// new SSRC, create an entry in this RTCP session
|
|||
|
pSSRC = createSSRCEntry(dwHost,
|
|||
|
pRTCPses,
|
|||
|
(PSOCKADDR)pRcvStruct->addr,
|
|||
|
(DWORD)pRcvStruct->addrLen,
|
|||
|
FALSE);
|
|||
|
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
// cannot create a new entry, out of resources
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR - Resource allocation", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPsdes\n");
|
|||
|
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
// notify application if it desired so
|
|||
|
RRCMnotification (RRCM_NEW_SOURCE_EVENT, pSSRC, dwHost,
|
|||
|
UNKNOWN_PAYLOAD_TYPE);
|
|||
|
}
|
|||
|
|
|||
|
// read the SDES chunk
|
|||
|
pSdes = (RTCP_SDES_ITEM_T *)(bfr + sizeof(DWORD));
|
|||
|
|
|||
|
// go through until a 'type = 0' is found
|
|||
|
for (; pSdes->dwSdesType;
|
|||
|
pSdes = (RTCP_SDES_ITEM_T *)((char *)pSdes + pSdes->dwSdesLength + 2))
|
|||
|
{
|
|||
|
switch (pSdes->dwSdesType)
|
|||
|
{
|
|||
|
case RTCP_SDES_CNAME:
|
|||
|
if (pSSRC->cnameInfo.dwSdesLength == 0)
|
|||
|
{
|
|||
|
pSSRC->cnameInfo.dwSdesLength = pSdes->dwSdesLength;
|
|||
|
|
|||
|
// get the Cname
|
|||
|
memcpy (pSSRC->cnameInfo.sdesBfr, pSdes->sdesData,
|
|||
|
min (pSdes->dwSdesLength, MAX_SDES_LEN-1));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// check to see for a loop/collision of the SSRC
|
|||
|
if (memcmp (pSdes->sdesData, pSSRC->cnameInfo.sdesBfr,
|
|||
|
min (pSdes->dwSdesLength, MAX_SDES_LEN-1)) != 0)
|
|||
|
{
|
|||
|
// loop/collision of a third-party detected
|
|||
|
pSSRC->dwSSRCStatus |= THIRD_PARTY_COLLISION;
|
|||
|
|
|||
|
// notify application if interested
|
|||
|
RRCMnotification (RRCM_REMOTE_COLLISION_EVENT, pSSRC,
|
|||
|
pSSRC->SSRC, 0);
|
|||
|
|
|||
|
// RTP & RTCP packet from this SSRC will be rejected
|
|||
|
// until the senders resolve the collision
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPsdes\n");
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case RTCP_SDES_NAME:
|
|||
|
// the name can change, not like the Cname, so update it
|
|||
|
// every time.
|
|||
|
pSSRC->nameInfo.dwSdesLength = pSdes->dwSdesLength;
|
|||
|
|
|||
|
// get the name
|
|||
|
memcpy (pSSRC->nameInfo.sdesBfr, pSdes->sdesData,
|
|||
|
min (pSdes->dwSdesLength, MAX_SDES_LEN-1));
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// last time this SSRC's heard
|
|||
|
pSSRC->dwLastReportRcvdTime = timeGetTime();
|
|||
|
|
|||
|
// get the source address information
|
|||
|
if (!(pSSRC->dwSSRCStatus & NETWK_ADDR_UPDATED))
|
|||
|
{
|
|||
|
saveNetworkAddress(pSSRC,
|
|||
|
(PSOCKADDR)pRcvStruct->addr,
|
|||
|
pRcvStruct->addrLen);
|
|||
|
}
|
|||
|
|
|||
|
// adjust pointer
|
|||
|
bfr = (char *)pSdes;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPsdes\n");
|
|||
|
|
|||
|
// go the next 32 bits boundary
|
|||
|
return bfr + ((4 - ((LONG_PTR)bfr & 0x3)) & 0x3);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : parseRTCPbye
|
|||
|
* Description: Parse an RTCP BYE packet
|
|||
|
*
|
|||
|
* Input : sd: RTCP socket descriptor
|
|||
|
* ssrc: SSRC
|
|||
|
* pRTCPses: -> to the RTCP session information
|
|||
|
* pRcvStruct: -> to the receive structure
|
|||
|
*
|
|||
|
* Return: OK: RRCM_NoError
|
|||
|
* !0: Error code (see RRCM.H)
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
DWORD parseRTCPbye (SOCKET sd,
|
|||
|
DWORD ssrc,
|
|||
|
PRTCP_SESSION pRTCPses,
|
|||
|
PRTCP_BFR_LIST pRcvStruct)
|
|||
|
{
|
|||
|
DWORD dwStatus;
|
|||
|
DWORD dwHost;
|
|||
|
PSSRC_ENTRY pSSRC;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Enter parseRTCPbye\n");
|
|||
|
|
|||
|
RRCMws.ntohl (sd, ssrc, &dwHost);
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string, "RTCP: BYE from SSRC: x%lX", dwHost);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
|
|||
|
// find the SSRC entry
|
|||
|
pSSRC = searchforSSRCatTail((PSSRC_ENTRY)pRTCPses->RcvSSRCList.prev,
|
|||
|
dwHost);
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTCP: SSRC: x%lX not found in session: x%lX",
|
|||
|
dwHost, pRTCPses);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, __FILE__, __LINE__, DBG_TRACE);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPbye\n");
|
|||
|
#endif
|
|||
|
return (RRCM_NoError);
|
|||
|
}
|
|||
|
|
|||
|
// make sure the BYE is coming from the expected source and not intruder
|
|||
|
if ((pRcvStruct->addrLen != pSSRC->fromLen) ||
|
|||
|
#if 0
|
|||
|
// There is a bug NT's Winsock2 implememtation. The unused bytes of
|
|||
|
// SOCKADDR are not reset to 0 as they should be. Work fine on W95
|
|||
|
// Temporarily just check the first 8 bytes, i.e. address family, port
|
|||
|
// and IP address.
|
|||
|
(memcmp (&pRcvStruct->addr, &pSSRC->from, pSSRC->fromLen)))
|
|||
|
#else
|
|||
|
(memcmp (&pRcvStruct->addr, &pSSRC->from, 8)))
|
|||
|
#endif
|
|||
|
return (RRCM_NoError);
|
|||
|
|
|||
|
// notify application if interested
|
|||
|
RRCMnotification (RRCM_BYE_EVENT, pSSRC, dwHost, 0);
|
|||
|
|
|||
|
// delete this SSRC from the list
|
|||
|
dwStatus = deleteSSRCEntry (dwHost, pRTCPses);
|
|||
|
#ifdef _DEBUG
|
|||
|
if (dwStatus == FALSE)
|
|||
|
{
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTCP: SSRC: x%lX not found in session: x%lX",
|
|||
|
dwHost, pRTCPses);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, __FILE__, __LINE__, DBG_TRACE);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit parseRTCPbye\n");
|
|||
|
return (RRCM_NoError);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : ownLoopback
|
|||
|
* Description: Determine if we receive our own loopback. We don't want to
|
|||
|
* create an entry for ourselve, as we're already in the list.
|
|||
|
*
|
|||
|
* Input : sd: RTCP socket descriptor
|
|||
|
* ssrc: SSRC
|
|||
|
* pRTCPses: -> to the RTCP session's information
|
|||
|
*
|
|||
|
* Return: TRUE: Our loopback
|
|||
|
* FALSE: No loopback
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
DWORD ownLoopback (SOCKET sd,
|
|||
|
DWORD ssrc,
|
|||
|
PRTCP_SESSION pRTCPses)
|
|||
|
{
|
|||
|
PSSRC_ENTRY pSSRC;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Enter ownLoopback\n");
|
|||
|
|
|||
|
// don't create an entry if received our own xmit back
|
|||
|
pSSRC = searchforSSRCatTail((PSSRC_ENTRY)pRTCPses->XmtSSRCList.prev,
|
|||
|
ssrc);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit ownLoopback\n");
|
|||
|
|
|||
|
if (pSSRC)
|
|||
|
return TRUE;
|
|||
|
else
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : updateRRfeedback
|
|||
|
* Description: Update the Receiver Report feedback for an active source
|
|||
|
*
|
|||
|
* Input : sd: RTCP socket descriptor
|
|||
|
* dwSndSSRC: Sender's SSRC
|
|||
|
* pRR: -> to receiver report entry
|
|||
|
* pSSRC: -> to the SSRC entry
|
|||
|
*
|
|||
|
* Return: TRUE
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
DWORD updateRRfeedback (SOCKET sd,
|
|||
|
DWORD dwSndSSRC,
|
|||
|
DWORD dwSSRCfedback,
|
|||
|
RTCP_RR_T *pRR,
|
|||
|
PSSRC_ENTRY pSSRC)
|
|||
|
{
|
|||
|
DWORD dwHost;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Enter updateRRfeedback\n");
|
|||
|
|
|||
|
// Note when we last heard from the receiver
|
|||
|
pSSRC->rrFeedback.dwLastRcvRpt = timeGetTime();
|
|||
|
|
|||
|
// SSRC who's feedback is for (ourselve for now)
|
|||
|
pSSRC->rrFeedback.SSRC = dwSSRCfedback;
|
|||
|
|
|||
|
// get delay since last SR
|
|||
|
RRCMws.ntohl (sd, pRR->dlsr, &pSSRC->rrFeedback.dwDelaySinceLastSR);
|
|||
|
|
|||
|
// get last SR
|
|||
|
RRCMws.ntohl (sd, pRR->lsr, &pSSRC->rrFeedback.dwLastSR);
|
|||
|
|
|||
|
// get the jitter
|
|||
|
RRCMws.ntohl (sd, pRR->jitter, &pSSRC->rrFeedback.dwInterJitter);
|
|||
|
|
|||
|
// highest sequence number received
|
|||
|
RRCMws.ntohl (sd, pRR->expected,
|
|||
|
&pSSRC->rrFeedback.XtendedSeqNum.seq_union.dwXtndedHighSeqNumRcvd);
|
|||
|
|
|||
|
// fraction lost
|
|||
|
pSSRC->rrFeedback.fractionLost = (pRR->received & 0xFF);
|
|||
|
|
|||
|
// cumulative number of packet lost
|
|||
|
RRCMws.ntohl (sd, pRR->received, &dwHost);
|
|||
|
dwHost &= 0x00FFFFFF;
|
|||
|
pSSRC->rrFeedback.cumNumPcktLost = dwHost;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit updateRRfeedback\n");
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : RTCPpostRecvBfr
|
|||
|
* Description: RTCP post a receive buffer to Winsock-2
|
|||
|
*
|
|||
|
* Input : sd: RTCP socket descriptor
|
|||
|
* pSSRC: -> to the SSRC entry
|
|||
|
*
|
|||
|
* Return: TRUE
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
void RTCPpostRecvBfr (PSSRC_ENTRY pSSRC,
|
|||
|
PRTCP_BFR_LIST pRcvStruct)
|
|||
|
{
|
|||
|
DWORD dwStatus;
|
|||
|
DWORD dwError;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Enter RTCPpostRecvBfr\n");
|
|||
|
|
|||
|
// decrement number of I/O pending
|
|||
|
InterlockedDecrement ((long *)&pSSRC->pRTCPses->dwNumRcvIoPending);
|
|||
|
|
|||
|
// don't repost any buffer if within the shutdown procedure
|
|||
|
if ((pSSRC->pRTCPses->dwSessionStatus & SHUTDOWN_IN_PROGRESS) &&
|
|||
|
(pSSRC->pRTCPses->dwNumRcvIoPending == 0))
|
|||
|
{
|
|||
|
// shutdown done - set event
|
|||
|
if (SetEvent (pSSRC->pRTCPses->hShutdownDone) == FALSE)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: SetEvent() Error\n", GetLastError(),
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit RTCPpostRecvBfr\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
else if (pSSRC->pRTCPses->dwSessionStatus & SHUTDOWN_IN_PROGRESS)
|
|||
|
{
|
|||
|
IN_OUT_STR ("RTCP: Exit RTCPpostRecvBfr\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// clear number of bytes transferred
|
|||
|
pRcvStruct->dwNumBytesXfr = 0;
|
|||
|
|
|||
|
dwStatus = RRCMws.recvFrom (pSSRC->RTCPsd,
|
|||
|
&pRcvStruct->bfr,
|
|||
|
pRcvStruct->dwBufferCount,
|
|||
|
&pRcvStruct->dwNumBytesXfr,
|
|||
|
&pRcvStruct->dwFlags,
|
|||
|
(PSOCKADDR)pRcvStruct->addr,
|
|||
|
&pRcvStruct->addrLen,
|
|||
|
(LPWSAOVERLAPPED)&pRcvStruct->overlapped,
|
|||
|
RTCPrcvCallback);
|
|||
|
|
|||
|
// Check Winsock status
|
|||
|
if (dwStatus != 0)
|
|||
|
{
|
|||
|
// error, the receive request won't proceed
|
|||
|
dwError = GetLastError();
|
|||
|
if ((dwError != WSA_IO_PENDING) && (dwError != WSAEMSGSIZE))
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP: ERROR - WSARecvFrom()", dwError,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
// notify application if interested
|
|||
|
RRCMnotification (RRCM_RTCP_WS_RCV_ERROR, pSSRC,
|
|||
|
pSSRC->SSRC, dwError);
|
|||
|
|
|||
|
// Return the buffer to the free queue
|
|||
|
addToHeadOfList (&pSSRC->pRTCPses->RTCPrcvBfrList,
|
|||
|
(PLINK_LIST)pRcvStruct,
|
|||
|
&pSSRC->pRTCPses->critSect);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// increment number of I/O pending
|
|||
|
InterlockedIncrement ((long *)&pSSRC->pRTCPses->dwNumRcvIoPending);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// synchronous completion - callback has been scheduled
|
|||
|
// increment number of I/O pending
|
|||
|
InterlockedIncrement ((long *)&pSSRC->pRTCPses->dwNumRcvIoPending);
|
|||
|
}
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP: Exit RTCPpostRecvBfr\n");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : addApplicationRtcpBfr
|
|||
|
* Description: Add an application provided buffer for RTCP to copy the
|
|||
|
* raw received reports to be used by the application if it
|
|||
|
* desired so.
|
|||
|
*
|
|||
|
* Input : RTPsession: Handle to the RTP session
|
|||
|
* pAppBfr: -> an application buffer data structure
|
|||
|
*
|
|||
|
* Return: TRUE
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
HRESULT WINAPI addApplicationRtcpBfr (DWORD_PTR RTPsession,
|
|||
|
PAPP_RTCP_BFR pAppBfr)
|
|||
|
{
|
|||
|
IN_OUT_STR ("RTCP : Enter addApplicationRtcpBfr()\n");
|
|||
|
|
|||
|
PRTP_SESSION pSession = (PRTP_SESSION)RTPsession;
|
|||
|
PRTCP_SESSION pRTCPSess;
|
|||
|
|
|||
|
if (pSession == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP : ERROR - Invalid RTP session", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP : Exit addApplicationRtcpBfr()\n");
|
|||
|
|
|||
|
return (MAKE_RRCM_ERROR(RRCMError_RTPSessResources));
|
|||
|
}
|
|||
|
|
|||
|
pRTCPSess = (PRTCP_SESSION)pSession->pRTCPSession;
|
|||
|
if (pRTCPSess == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP : ERROR - Invalid RTCP session", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP : Exit addApplicationRtcpBfr()\n");
|
|||
|
|
|||
|
return (MAKE_RRCM_ERROR(RRCMError_RTCPInvalidSession));
|
|||
|
}
|
|||
|
|
|||
|
// Let's add this buffer to our list
|
|||
|
addToTailOfList(&(pRTCPSess->appRtcpBfrList),
|
|||
|
(PLINK_LIST)pAppBfr,
|
|||
|
&pRTCPSess->critSect);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP : Exit addApplicationRtcpBfr()\n");
|
|||
|
|
|||
|
return NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : removeApplicationRtcpBfr
|
|||
|
* Description: Remove an application provided buffer to this RTCP session.
|
|||
|
*
|
|||
|
* Input : RTPsession: RTP session handle
|
|||
|
*
|
|||
|
* Return: Application buffer address / NULL
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
PAPP_RTCP_BFR WINAPI removeApplicationRtcpBfr (DWORD_PTR RTPsession)
|
|||
|
{
|
|||
|
PRTP_SESSION pSession = (PRTP_SESSION)RTPsession;
|
|||
|
PRTCP_SESSION pRTCPSess;
|
|||
|
PAPP_RTCP_BFR pAppBfr;
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP : Enter removeApplicationRtcpBfr()\n");
|
|||
|
|
|||
|
if (pSession == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP : ERROR - Invalid RTP session", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP : Exit removeApplicationRtcpBfr()\n");
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
pRTCPSess = (PRTCP_SESSION)pSession->pRTCPSession;
|
|||
|
if (pRTCPSess == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTCP : ERROR - Invalid RTCP session", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP : Exit removeApplicationRtcpBfr()\n");
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
pAppBfr = (PAPP_RTCP_BFR)removePcktFromHead (&(pRTCPSess->appRtcpBfrList),
|
|||
|
&pRTCPSess->critSect);
|
|||
|
|
|||
|
IN_OUT_STR ("RTCP : Exit removeApplicationRtcpBfr()\n");
|
|||
|
|
|||
|
return pAppBfr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// [EOF]
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|