384 lines
10 KiB
C++
384 lines
10 KiB
C++
|
/*----------------------------------------------------------------------------
|
|||
|
* File: RTPIO.C
|
|||
|
* Product: RTP/RTCP implementation
|
|||
|
* Description: Provides Session Creation/Deletion Functionality.
|
|||
|
*
|
|||
|
*
|
|||
|
* This listing is supplied under the terms
|
|||
|
* of a license agreement with Intel Corporation and
|
|||
|
* many 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
|
|||
|
/--------------------------------------------------------------------------*/
|
|||
|
extern PRTP_CONTEXT pRTPContext;
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
extern char debug_string[];
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : CreateRTPSession
|
|||
|
* Description: Creates an RTP (and RTCP) session for a new stream.
|
|||
|
*
|
|||
|
* Input : RTPsocket : RTP socket descriptor
|
|||
|
* RTCPsd : RTCP socket descriptor
|
|||
|
* pRTCPTo : RTCP destination address
|
|||
|
* toRTCPLen : RTCP destination address length
|
|||
|
* pSdesInfo : -> to SDES information
|
|||
|
* dwStreamClock : Stream clocking frequency
|
|||
|
* ssrc : If set, user selected SSRC
|
|||
|
* pRRCMcallback : RRCM notification
|
|||
|
* dwCallbackInfo : User callback info
|
|||
|
* miscInfo : Miscelleanous information:
|
|||
|
* H.323Conf: 0x00000002
|
|||
|
* Encrypt SR/RR: 0x00000004
|
|||
|
* RTCPon: 0x00000008
|
|||
|
* dwRtpSessionBw : RTP session bandwidth used for RTCP BW
|
|||
|
* *pStatus : -> to status information
|
|||
|
*
|
|||
|
* Return: handle to created session if successful
|
|||
|
* Otherwise(0) *pStatus = Initialization Error (see RRCM.H)
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
HANDLE WINAPI CreateRTPSession (SOCKET RTPsocket,
|
|||
|
SOCKET RTCPsocket,
|
|||
|
LPVOID pRTCPTo,
|
|||
|
DWORD toRTCPLen,
|
|||
|
PSDES_DATA pSdesInfo,
|
|||
|
DWORD dwStreamClock,
|
|||
|
PENCRYPT_INFO pEncryptInfo,
|
|||
|
DWORD ssrc,
|
|||
|
PRRCM_EVENT_CALLBACK pRRCMcallback,
|
|||
|
DWORD_PTR dwCallbackInfo,
|
|||
|
DWORD miscInfo,
|
|||
|
DWORD dwRtpSessionBw,
|
|||
|
DWORD *pStatus)
|
|||
|
{
|
|||
|
DWORD numCells = NUM_FREE_CONTEXT_CELLS;
|
|||
|
DWORD dwStatus;
|
|||
|
DWORD dwRTCPstatus;
|
|||
|
PRTP_SESSION pSession = NULL;
|
|||
|
PSSRC_ENTRY pSSRC;
|
|||
|
|
|||
|
IN_OUT_STR ("RTP : Enter CreateRTPSession()\n");
|
|||
|
|
|||
|
// set status code
|
|||
|
*pStatus = dwStatus = RRCM_NoError;
|
|||
|
|
|||
|
// If RTP context doesn't exist, report error and return.
|
|||
|
if (pRTPContext == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTP : ERROR - No RTP Instance",
|
|||
|
0, __FILE__, __LINE__, DBG_CRITICAL);
|
|||
|
IN_OUT_STR ("RTP : Exit CreateRTPSession()\n");
|
|||
|
|
|||
|
*pStatus = MAKE_RRCM_ERROR(RRCMError_RTPNoContext);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
// look for an existing session - Sender/Receiver for the same session
|
|||
|
// will be on two different graph under ActiveMovie
|
|||
|
if (pSession = findSessionID (RTPsocket))
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTP : Session already created", 0,
|
|||
|
__FILE__, __LINE__, DBG_TRACE);
|
|||
|
|
|||
|
IN_OUT_STR ("RTP : Exit CreateRTPSession()\n");
|
|||
|
|
|||
|
// return the unique RTP session ID
|
|||
|
return ((HANDLE)pSession);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// Allocate a new session pointer.
|
|||
|
pSession = (PRTP_SESSION)GlobalAlloc (GMEM_FIXED | GMEM_ZEROINIT,
|
|||
|
sizeof(RTP_SESSION));
|
|||
|
|
|||
|
// Report error if could not allocate context
|
|||
|
if (pSession == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTP : ERROR - Resource allocation failed", 0,
|
|||
|
__FILE__, __LINE__, DBG_CRITICAL);
|
|||
|
IN_OUT_STR ("RTP : Exit CreateRTPSession()\n");
|
|||
|
|
|||
|
*pStatus = MAKE_RRCM_ERROR(RRCMError_RTPSessResources);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
// Initialize the RTP session's critical section
|
|||
|
InitializeCriticalSection(&pSession->critSect);
|
|||
|
|
|||
|
|
|||
|
// All seems OK, initialize RTCP for this session
|
|||
|
pSession->pRTCPSession = CreateRTCPSession(RTPsocket,
|
|||
|
RTCPsocket,
|
|||
|
pRTCPTo,
|
|||
|
toRTCPLen,
|
|||
|
pSdesInfo,
|
|||
|
dwStreamClock,
|
|||
|
pEncryptInfo,
|
|||
|
ssrc,
|
|||
|
pRRCMcallback,
|
|||
|
dwCallbackInfo,
|
|||
|
miscInfo,
|
|||
|
dwRtpSessionBw,
|
|||
|
&dwRTCPstatus);
|
|||
|
|
|||
|
if (pSession->pRTCPSession == NULL)
|
|||
|
{
|
|||
|
dwStatus = dwRTCPstatus;
|
|||
|
|
|||
|
|
|||
|
// Can't proceed, return session pointer
|
|||
|
if (pSession)
|
|||
|
{
|
|||
|
GlobalFree (pSession);
|
|||
|
pSession = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if 0
|
|||
|
// Associate the socket with the Session address
|
|||
|
dwStatus = createHashEntry (pSession, RTPsocket);
|
|||
|
#endif
|
|||
|
|
|||
|
if (dwStatus == RRCM_NoError)
|
|||
|
{
|
|||
|
pSSRC =
|
|||
|
(PSSRC_ENTRY)pSession->pRTCPSession->XmtSSRCList.prev;
|
|||
|
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTP : ERROR - No RTCP Xmt list", 0,
|
|||
|
__FILE__, __LINE__, DBG_CRITICAL);
|
|||
|
|
|||
|
dwStatus = RRCMError_RTCPNoXmtList;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Let's add this to our context
|
|||
|
addToHeadOfList(&(pRTPContext->pRTPSession),
|
|||
|
(PLINK_LIST)pSession,
|
|||
|
&pRTPContext->critSect);
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string, "RTP : Adding RTP Session. (Addr:0x%p)",
|
|||
|
pSession);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// set status code
|
|||
|
if (dwStatus != RRCM_NoError)
|
|||
|
*pStatus = MAKE_RRCM_ERROR(dwStatus);
|
|||
|
|
|||
|
IN_OUT_STR ("RTP : Exit CreateRTPSession()\n");
|
|||
|
|
|||
|
// return the unique RTP session ID
|
|||
|
return ((HANDLE)pSession);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function : CloseRTPSession
|
|||
|
* Description: Terminates a local stream session.
|
|||
|
*
|
|||
|
* Input : RTPSession = RTP session ID
|
|||
|
* byeReason = -> to BYE reason
|
|||
|
* closeRTCPSocket = TRUE/FALSE. RTCP will close or not the socket
|
|||
|
*
|
|||
|
* Return: RRCM_NoError = OK.
|
|||
|
* Otherwise(!=0) = Error (see RRCM.H)
|
|||
|
---------------------------------------------------------------------------*/
|
|||
|
HRESULT WINAPI CloseRTPSession (HANDLE RTPSession,
|
|||
|
PCHAR byeReason,
|
|||
|
DWORD closeRTCPSocket)
|
|||
|
{
|
|||
|
PRTP_SESSION pSession;
|
|||
|
PSSRC_ENTRY pSSRCList;
|
|||
|
PSSRC_ENTRY pSSRC;
|
|||
|
DWORD dwStatus;
|
|||
|
|
|||
|
IN_OUT_STR ("RTP : Enter CloseRTPSession()\n");
|
|||
|
|
|||
|
// If RTP context doesn't exist, report error and return.
|
|||
|
if (pRTPContext == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTP : ERROR - No RTP Instance", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
IN_OUT_STR ("RTP : Exit CloseRTPSession()\n");
|
|||
|
|
|||
|
return (MAKE_RRCM_ERROR(RRCMError_RTPNoContext));
|
|||
|
}
|
|||
|
|
|||
|
// Cast Session ID to obtain the session pointer.
|
|||
|
pSession = (PRTP_SESSION)RTPSession;
|
|||
|
if (pSession == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTP : ERROR - Invalid RTP session", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
IN_OUT_STR ("RTP : Exit CloseRTPSession()\n");
|
|||
|
|
|||
|
return (MAKE_RRCM_ERROR(RRCMError_RTPInvalidSession));
|
|||
|
}
|
|||
|
|
|||
|
// Remove the session from the linked list of sessions
|
|||
|
dwStatus = deleteRTPSession (pRTPContext, pSession);
|
|||
|
if (dwStatus != RRCM_NoError)
|
|||
|
{
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTP : ERROR - RTP session (Addr:0x%lX) not found",
|
|||
|
RTPSession);
|
|||
|
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_ERROR);
|
|||
|
#endif
|
|||
|
return (MAKE_RRCM_ERROR(dwStatus));
|
|||
|
}
|
|||
|
|
|||
|
// lock out the session - it's on a free list now
|
|||
|
EnterCriticalSection (&pSession->critSect);
|
|||
|
|
|||
|
#if 0
|
|||
|
// clean up the Hash table for any stream still left in the Session
|
|||
|
for (pSSRCList = (PSSRC_ENTRY)pSession->pRTCPSession->XmtSSRCList.prev;
|
|||
|
pSSRCList != NULL;
|
|||
|
pSSRCList = (PSSRC_ENTRY)pSSRCList->SSRCList.next)
|
|||
|
{
|
|||
|
deleteHashEntry (pSSRCList->RTPsd);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// All seems OK, close RTCP for each stream still open
|
|||
|
pSSRC = (PSSRC_ENTRY)pSession->pRTCPSession->XmtSSRCList.prev;
|
|||
|
if (pSSRC == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTP : ERROR - No SSRC entry on the Xmt list", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
IN_OUT_STR ("RTP : Exit CloseRTPSession()\n");
|
|||
|
|
|||
|
return (MAKE_RRCM_ERROR(RRCMError_RTCPInvalidSSRCentry));
|
|||
|
}
|
|||
|
|
|||
|
// reset the close socket flag
|
|||
|
if (closeRTCPSocket)
|
|||
|
pSSRC->dwSSRCStatus |= CLOSE_RTCP_SOCKET;
|
|||
|
|
|||
|
dwStatus = deleteRTCPSession (pSSRC->RTCPsd, byeReason);
|
|||
|
#ifdef _DEBUG
|
|||
|
if (dwStatus != RRCM_NoError)
|
|||
|
{
|
|||
|
wsprintf(debug_string,
|
|||
|
"RTP : ERROR - RTCP delete Session (Addr: x%p) error:%d",
|
|||
|
pSession, dwStatus);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
wsprintf(debug_string, "RTP : Deleting Session x%p", pSession);
|
|||
|
RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
|
|||
|
#endif
|
|||
|
|
|||
|
// lock out the session - it's on a free list now
|
|||
|
LeaveCriticalSection (&pSession->critSect);
|
|||
|
DeleteCriticalSection (&pSession->critSect);
|
|||
|
|
|||
|
GlobalFree (pSession);
|
|||
|
pSession = NULL;
|
|||
|
|
|||
|
IN_OUT_STR ("RTP : Exit CloseRTPSession()\n");
|
|||
|
|
|||
|
if (dwStatus != RRCM_NoError)
|
|||
|
dwStatus = MAKE_RRCM_ERROR(dwStatus);
|
|||
|
|
|||
|
return (dwStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*--------------------------------------------------------------------------
|
|||
|
** Function : deleteRTPSession
|
|||
|
** Description: Remove from RTP session queue and restore links for other
|
|||
|
** sessions.
|
|||
|
**
|
|||
|
** Input : pRTPContext: -> to the RTP context
|
|||
|
** pSession: -> to the RTP session
|
|||
|
**
|
|||
|
** Return: OK: RRCM_NoError
|
|||
|
** !0: Error code (see RRCM.H)
|
|||
|
--------------------------------------------------------------------------*/
|
|||
|
DWORD deleteRTPSession(PRTP_CONTEXT pRTPContext,
|
|||
|
PRTP_SESSION pSession)
|
|||
|
{
|
|||
|
PLINK_LIST pTmp;
|
|||
|
|
|||
|
IN_OUT_STR ("RTP : Enter deleteRTPSession()\n");
|
|||
|
|
|||
|
// make sure the session exist
|
|||
|
pTmp = pRTPContext->pRTPSession.prev;
|
|||
|
while (pTmp)
|
|||
|
{
|
|||
|
if (pTmp == (PLINK_LIST)pSession)
|
|||
|
break;
|
|||
|
|
|||
|
pTmp = pTmp->next;
|
|||
|
}
|
|||
|
|
|||
|
if (pTmp == NULL)
|
|||
|
{
|
|||
|
RRCM_DBG_MSG ("RTP : ERROR - Invalid RTP session", 0,
|
|||
|
__FILE__, __LINE__, DBG_ERROR);
|
|||
|
|
|||
|
IN_OUT_STR ("RTP : Exit deleteRTPSession()\n");
|
|||
|
|
|||
|
return (MAKE_RRCM_ERROR(RRCMError_RTPInvalidSession));
|
|||
|
}
|
|||
|
|
|||
|
// lock out queue access
|
|||
|
EnterCriticalSection (&pRTPContext->critSect);
|
|||
|
EnterCriticalSection (&pSession->critSect);
|
|||
|
|
|||
|
if (pSession->RTPList.prev == NULL)
|
|||
|
// this was the first entry in the queue
|
|||
|
pRTPContext->pRTPSession.prev = pSession->RTPList.next;
|
|||
|
else
|
|||
|
(pSession->RTPList.prev)->next = pSession->RTPList.next;
|
|||
|
|
|||
|
if (pSession->RTPList.next == NULL)
|
|||
|
// this was the last entry in the queue
|
|||
|
pRTPContext->pRTPSession.next = pSession->RTPList.prev;
|
|||
|
else
|
|||
|
(pSession->RTPList.next)->prev = pSession->RTPList.prev;
|
|||
|
|
|||
|
// unlock out queue access
|
|||
|
LeaveCriticalSection (&pSession->critSect);
|
|||
|
LeaveCriticalSection (&pRTPContext->critSect);
|
|||
|
|
|||
|
IN_OUT_STR ("RTP : Exit deleteRTPSession()\n");
|
|||
|
|
|||
|
return (RRCM_NoError);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// [EOF]
|
|||
|
|
|||
|
|