📄 rtptran.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/****************************************************************************
* Defines
*/
#define ACCEPTABLE_SYNC_NOISE 3
#define STREAM_END_DELAY_RTP_TOLERANCE 500
/****************************************************************************
* Includes
*/
#include "hxtypes.h"
#include "hxassert.h"
#include "debug.h"
#include "hxcom.h"
#include "hxmarsh.h"
#include "hxstrutl.h"
#include "netbyte.h"
#include "hxengin.h"
#include "ihxpckts.h"
#include "hxsbuffer.h"
#include "hxcomm.h"
#include "hxmon.h"
#include "netbyte.h"
#include "hxstring.h"
#include "chxpckts.h"
#include "hxslist.h"
#include "hxmap.h"
#include "hxdeque.h"
#include "hxbitset.h"
#include "timebuff.h"
#include "timeval.h"
#include "tconverter.h"
#include "rtptypes.h"
#include "hxqosinfo.h"
#include "hxqossig.h"
#include "hxqos.h"
//#include "hxcorgui.h"
#include "ntptime.h"
#include "rtspif.h"
#include "rtsptran.h"
#include "rtptran.h"
#include "rtpwrap.h" // Wrappers for PMC generated base classes
#include "basepkt.h"
#include "hxtbuf.h"
#include "transbuf.h"
#include "hxtick.h"
#include "random32.h" // random32()
#include "pkthndlr.h" // in rtpmisc for RTCP routine
#include "rtcputil.h" // takes care of RTCP in RTP mode
#include "rtspmsg.h"
#include "hxprefs.h" // IHXPreferences
#include "hxmime.h"
#include "hxcore.h"
#include "hxheap.h"
#ifdef PAULM_IHXTCPSCAR
#include "objdbg.h"
#endif
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif
#include "bufnum.h"
#define MAX_STARTINFO_WAIT_TIME 20000 // in milliseconds
#define MIN_NUM_PACKETS_SCANNED_FOR_LIVE_START 5
#define MAX_NUM_PACKETS_GAPPED_FOR_LIVE_START 1
static const UINT32 NORMAL_ACK_INTERVAL = 1000; // 1/sec
static const UINT32 MINIMUM_ACK_INTERVAL = 200; // wait 200msecs
static const UINT32 NORMAL_REPORT_INTERVAL = 5000; // 1 per 5secs
static const UINT32 TRANSPORT_BUF_GROWTH_RATE = 1000;
static const UINT32 LATENCY_REPORT_INTERVAL_MS = 1000;
static const UINT32 RTP_NAT_TIMEOUT = 15000; // Default timeout period
static UINT32 GetNATTimeout(IUnknown* pContext)
{
UINT32 ret = RTP_NAT_TIMEOUT;
IHXPreferences* pPrefs = NULL;
if (pContext &&
(HXR_OK == pContext->QueryInterface(IID_IHXPreferences,
(void**)&pPrefs)))
{
IHXBuffer* pPrefBuf = NULL;
if ((HXR_OK == pPrefs->ReadPref("UDPNATTimeout", pPrefBuf)) &&
pPrefBuf)
{
int tmp = atoi((const char*)pPrefBuf->GetBuffer());
if (tmp >= 0)
{
ret = (UINT32)tmp;
}
HX_RELEASE(pPrefBuf);
}
HX_RELEASE(pPrefs);
}
return ret;
}
/******************************************************************************
* RTP RTP RTP RTP RTP
******************************************************************************/
RTPBaseTransport::RTPBaseTransport(BOOL bIsSource)
: RTSPTransport(bIsSource)
, m_lRefCount(0)
, m_pBwMgrInput(0)
, m_pSyncServer(NULL)
, m_streamNumber(0)
, m_uFirstSeqNum(0)
, m_ulFirstRTPTS(0)
, m_bFirstSet(FALSE)
, m_bWeakStartSync(FALSE)
, m_lTimeOffsetHX(0)
, m_lTimeOffsetRTP(0)
, m_lOffsetToMasterHX(0)
, m_lOffsetToMasterRTP(0)
, m_lSyncOffsetHX(0)
, m_lSyncOffsetRTP(0)
, m_lNTPtoHXOffset(0)
, m_bNTPtoHXOffsetSet(FALSE)
, m_ulLastRTPTS(0)
, m_ulLastHXTS(0)
, m_ulLastRawRTPTS(0)
, m_bLastTSSet(FALSE)
, m_pRTCPTran(0)
, m_pReportHandler(0)
, m_ulBaseTS(0)
, m_bHasMarkerRule(FALSE)
, m_bHasRTCPRule(FALSE)
, m_ulPayloadWirePacket(0)
, m_bIsLive(FALSE)
, m_ulExtensionSupport(0)
, m_bSeqNoSet(FALSE)
, m_bRTPTimeSet(FALSE)
, m_bActive(TRUE)
, m_pFirstPlayTime(NULL)
, m_bWaitForStartInfo(TRUE)
, m_bAbortWaitForStartInfo(FALSE)
, m_bEmulatePVSession(FALSE)
, m_pMBitHandler(NULL)
, m_pQoSInfo(NULL)
, m_bSSRCDetermined(FALSE)
, m_ulSSRCDetermined(0)
, m_cLSRRead(0)
, m_cLSRWrite(0)
#ifdef RTP_MESSAGE_DEBUG
, m_bMessageDebug(FALSE)
#endif // RTP_MESSAGE_DEBUG
{
m_wrapSequenceNumber = DEFAULT_WRAP_SEQ_NO;
}
RTPBaseTransport::~RTPBaseTransport()
{
resetStartInfoWaitQueue();
}
STDMETHODIMP
RTPBaseTransport::QueryInterface(REFIID riid, void** ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown))
{
AddRef();
*ppvObj = this;
return HXR_OK;
}
else if (IsEqualIID(riid, IID_IHXSourceBandwidthInfo))
{
AddRef();
*ppvObj = (IHXSourceBandwidthInfo*)this;
return HXR_OK;
}
*ppvObj = NULL;
return HXR_NOINTERFACE;
}
STDMETHODIMP_(UINT32)
RTPBaseTransport::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(UINT32)
RTPBaseTransport::Release()
{
if(InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
void
RTPBaseTransport::Done()
{
HX_RELEASE(m_pQoSInfo);
HX_RELEASE(m_pBwMgrInput);
HX_RELEASE(m_pRTCPTran);
HX_RELEASE(m_pPacketFilter);
HX_RELEASE(m_pSyncServer);
HX_DELETE(m_pFirstPlayTime);
}
HX_RESULT
RTPBaseTransport::init()
{
// m_pReportHandler will be freed in RTCPBaseTransport::Done()...
HX_ASSERT(!m_pReportHandler);
m_pReportHandler =
new ReportHandler(m_bIsSource, !m_bIsSource, random32(HX_GET_TICKCOUNT()));
HX_ASSERT(m_pReportHandler);
if(!m_pReportHandler)
{
return HXR_OUTOFMEMORY;
}
#ifdef RTP_MESSAGE_DEBUG
IHXPreferences* pPreferences = NULL;
if (m_pContext &&
(HXR_OK == m_pContext->QueryInterface(IID_IHXPreferences,
(void**) &pPreferences)))
{
IHXBuffer* pBuffer = NULL;
if (HXR_OK == pPreferences->ReadPref("RTPMessageDebug", pBuffer))
{
m_bMessageDebug = atoi((const char*)pBuffer->GetBuffer()) ? TRUE : FALSE;
HX_RELEASE(pBuffer);
if (m_bMessageDebug)
{
if (HXR_OK == pPreferences->ReadPref("RTPMessageDebugFile", pBuffer))
{
if (pBuffer->GetSize() <= 0)
{
// no file name, no log
m_bMessageDebug = FALSE;
}
else
{
m_messageDebugFileName = (const char*) pBuffer->GetBuffer();
}
}
HX_RELEASE(pBuffer);
}
}
}
HX_RELEASE(pPreferences);
#endif // RTP_MESSAGE_DEBUG
return HXR_OK;
}
void
RTPBaseTransport::addStreamInfo(RTSPStreamInfo* pStreamInfo, UINT32 ulBufferDepth)
{
RTSPTransport::addStreamInfo(pStreamInfo, ulBufferDepth);
// there better be only one stream
m_streamNumber = pStreamInfo->m_streamNumber;
// if pStreamInfo->m_rtpPayloadType is -1, it hasn't been set
// by user, so just assign RTP_PAYLOAD_RTSP
if (pStreamInfo->m_rtpPayloadType < 0)
{
m_rtpPayloadType = RTP_PAYLOAD_RTSP;
}
else
{
m_rtpPayloadType = (UINT8)pStreamInfo->m_rtpPayloadType;
}
if (pStreamInfo)
{
if (pStreamInfo->m_bHasMarkerRule)
{
m_bHasMarkerRule = pStreamInfo->m_bHasMarkerRule;
m_markerRuleNumber = pStreamInfo->m_markerRule;
// better be odd.
HX_ASSERT(m_markerRuleNumber & 0x1);
}
m_bIsLive = pStreamInfo->m_bIsLive;
m_ulExtensionSupport = pStreamInfo->m_bExtensionSupport;
m_bActive = pStreamInfo->m_bActive;
m_bIsSyncMaster = pStreamInfo->m_bIsSyncMaster;
// RTP transport always creates RTP packets on reception
if (!m_bIsSource)
{
RTSPStreamData* pStreamData = NULL;
pStreamData = m_pStreamHandler->getStreamData(pStreamInfo->m_streamNumber);
HX_ASSERT(pStreamData);
if (pStreamData)
{
pStreamData->m_bUsesRTPPackets = TRUE;
}
if (pStreamData->m_pTSConverter)
{
m_pRTCPTran->SetTSConverter(
pStreamData->m_pTSConverter->GetConversionFactors());
}
}
/*
* Reflection support
*/
m_bHasRTCPRule = pStreamInfo->m_bHasRTCPRule;
if (m_bHasRTCPRule)
{
m_RTCPRuleNumber = pStreamInfo->m_RTCPRule;
}
m_ulPayloadWirePacket = pStreamInfo->m_ulPayloadWirePacket;
if (m_pRTCPTran)
{
m_pRTCPTran->addStreamInfo(pStreamInfo, ulBufferDepth);
}
}
}
/*
* We need to set an initial SeqNo & timestamp for RTP
*/
HX_RESULT
RTPBaseTransport::setFirstSeqNum(UINT16 uStreamNumber, UINT16 uSeqNum)
{
HX_RESULT theErr = HXR_UNEXPECTED;
// On client we allow setting of sequence number only once not to cause
// havoc in transport buffer
if (m_bIsSource || (!m_bSeqNoSet))
{
theErr = RTSPTransport::setFirstSeqNum(uStreamNumber, uSeqNum);
#ifdef RTP_MESSAGE_DEBUG
messageFormatDebugFileOut("INIT: StartSeqNum=%u",
uSeqNum);
#endif // RTP_MESSAGE_DEBUG
if (SUCCEEDED(theErr))
{
m_bSeqNoSet = TRUE;
}
}
return theErr;
}
void
RTPBaseTransport::setFirstTimeStamp(UINT16 uStreamNumber, UINT32 ulTS,
BOOL bIsRaw)
{
RTSPStreamData* pStreamData =
m_pStreamHandler->getStreamData(uStreamNumber);
if (pStreamData)
{
if (m_bIsSource)
{
/* ulFrom is what we want to put in RTP-Info: rtptimestamp */
if (pStreamData->m_pTSConverter && !bIsRaw)
{
pStreamData->m_lastTimestamp = pStreamData->m_pTSConverter->hxa2rtp(ulTS);
}
else
{
pStreamData->m_lastTimestamp = ulTS;
}
}
else if (!m_bRTPTimeSet)
{
// ulTS is what's reported in rtptime of RTP-Info PLAY response
// header in RTP time. Unit is RTP.
/*
* HXTimeval = PktTime*Factor - (ulTS*Factor - m_ulPlayRangeFrom)
* RTPTimeval = PktTime - (ulTS - m_ulPlayRangeFrom / Factor)
*/
if (m_ulPlayRangeFrom != RTSP_PLAY_RANGE_BLANK)
{
if (pStreamData->m_pTSConverter)
{
m_lTimeOffsetRTP = ulTS -
pStreamData->
m_pTSConverter->hxa2rtp_raw(m_ulPlayRangeFrom);
pStreamData->m_pTSConverter->setAnchor(m_ulPlayRangeFrom, ulTS);
m_lTimeOffsetHX = 0;
}
else
{
m_lTimeOffsetHX = m_lTimeOffsetRTP = ulTS - m_ulPlayRangeFrom;
}
}
if ((m_ulPlayRangeFrom != RTSP_PLAY_RANGE_BLANK) &&
(m_ulPlayRangeTo != RTSP_PLAY_RANGE_BLANK))
{
pStreamData->m_pTransportBuffer->InformTimestampRange(
m_ulPlayRangeFrom,
m_ulPlayRangeTo,
STREAM_END_DELAY_RTP_TOLERANCE);
}
#ifdef RTP_MESSAGE_DEBUG
messageFormatDebugFileOut("INIT: RTPOffset=%u HXOffset=%u",
m_lTimeOffsetRTP,
m_lTimeOffsetHX);
#endif // RTP_MESSAGE_DEBUG
// Reset the time stamp ordering
HX_DELETE(pStreamData->m_pTSOrderHack);
}
m_bRTPTimeSet = TRUE;
}
}
void
RTPBaseTransport::notifyEmptyRTPInfo(void)
{
// If RTP-Info is empty there is no point in waiting for out-of-band
// start info (start seq number and time stamp) since this is the
// only out-of-band method of communicating start info. in RTP.
m_bAbortWaitForStartInfo = TRUE;
}
void
RTPBaseTransport::setPlayRange(UINT32 ulFrom, UINT32 ulTo)
{
// this is the Range values in PLAY request in RMA time (ms) called on PLAY
// request
RTSPTransport::setPlayRange(ulFrom, ulTo);
m_bSeqNoSet = FALSE;
m_bRTPTimeSet = FALSE;
m_bWaitForStartInfo = TRUE;
m_bAbortWaitForStartInfo = FALSE;
m_uFirstSeqNum = 0;
m_ulFirstRTPTS = 0;
m_bFirstSet = FALSE;
m_bWeakStartSync = FALSE;
m_lTimeOffsetHX = 0;
m_lTimeOffsetRTP = 0;
m_lOffsetToMasterHX = 0;
m_lOffsetToMasterRTP = 0;
m_lSyncOffsetHX = 0;
m_lSyncOffsetRTP = 0;
m_ulLastRTPTS = 0;
m_ulLastHXTS = 0;
m_ulLastRawRTPTS = 0;
m_bLastTSSet = FALSE;
m_lNTPtoHXOffset = 0;
m_bNTPtoHXOffsetSet = FALSE;
resetStartInfoWaitQueue();
#ifdef RTP_MESSAGE_DEBUG
messageFormatDebugFileOut("INIT: PlayRange=%u-%u",
ulFrom, ulTo);
#endif // RTP_MESSAGE_DEBUG
}
HX_RESULT
RTPBaseTransport::setFirstPlayTime(Timeval* pTv)
{
if (!m_pFirstPlayTime)
{
m_pFirstPlayTime = new Timeval();
if(!m_pFirstPlayTime)
{
return HXR_OUTOFMEMORY;
}
}
m_pFirstPlayTime->tv_sec = pTv->tv_sec;
m_pFirstPlayTime->tv_usec = pTv->tv_usec;
return HXR_OK;
}
HX_RESULT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -