📄 rtspclnt.cpp
字号:
// create an RTCP transport for this stream
RTCPUDPTransport* pRTCPTran = new RTCPUDPTransport(m_bSetupRecord);
if(!pRTCPTran)
{
HX_DELETE(pHeader);
HX_RELEASE(pTrans);
m_pMutex->Unlock();
return HXR_OUTOFMEMORY;
}
pRTCPTran->AddRef();
pRTCPTran->init(m_pContext,
pRTCPSocket,
(RTPUDPTransport*)pTrans,
(IHXRTSPTransportResponse*) this,
streamNumber);
((RTPUDPTransport*)pTrans)->setRTCPTransport(pRTCPTran);
status = pRequest->addTransportInfo(pTrans, (RTCPBaseTransport*)pRTCPTran, streamNumber,
nUDPPort);
if (m_bIPTV && m_pSetupRequestHeader && status != HXR_OUTOFMEMORY)
{
addRFC822Headers(pMsg, m_pSetupRequestHeader);
// don't add it twice...
pIHXValuesRequestHeaders = NULL;
}
}
break;
case RTSP_TR_RTP_TCP:
{
RTSPTransport* pTrans = new RTPTCPTransport(m_bSetupRecord);
if(!pTrans)
{
HX_DELETE(pHeader);
return HXR_OUTOFMEMORY;
}
pTrans->AddRef();
if (m_bPrefetch)
{
pTrans->EnterPrefetch();
}
if (HXR_OK != ((RTPTCPTransport*)pTrans)->init(
m_pContext, m_pSocket, (IHXRTSPTransportResponse*)this))
{
status = HXR_BAD_TRANSPORT;
}
// create an RTCP transport for this stream
RTCPTCPTransport* pRTCPTran = new RTCPTCPTransport(m_bSetupRecord);
if(!pRTCPTran)
{
HX_DELETE(pHeader);
HX_DELETE(pTrans);
return HXR_OUTOFMEMORY;
}
pRTCPTran->AddRef();
pRTCPTran->init(m_pContext,
m_pSocket,
(RTPTCPTransport*)pTrans,
(IHXRTSPTransportResponse*)this,
streamNumber);
((RTPTCPTransport*)pTrans)->setRTCPTransport((RTCPBaseTransport*)pRTCPTran);
status = pRequest->addTransportInfo(pTrans, (RTCPBaseTransport*)pRTCPTran, streamNumber,
nUDPPort);
if (m_bIPTV && m_pSetupRequestHeader)
{
addRFC822Headers(pMsg, m_pSetupRequestHeader);
// don't add it twice...
pIHXValuesRequestHeaders = NULL;
}
}
break;
default:
{
}
break;
}
#endif /* HELIX_FEATURE_RTP */
char* pModifiedMimeType = NULL;
const char* pMimeType =
RTSPTransportMimeMapper::getTransportMimeType
(
pRequest->m_lTransportType
);
// Accomodate incompliant servers that understand only upper case
// transport mime-types
if (m_bForceUCaseTransportMimeType)
{
ULONG32 ulMimeTypeLength = strlen(pMimeType);
if (ulMimeTypeLength != 0)
{
pModifiedMimeType = new char [ulMimeTypeLength + 1];
if(!pModifiedMimeType)
{
HX_DELETE(pHeader);
return HXR_OUTOFMEMORY;
}
}
if (pModifiedMimeType)
{
strcpy(pModifiedMimeType, pMimeType); /* Flawfinder: ignore */
StrToUpper(pModifiedMimeType);
pMimeType = pModifiedMimeType;
}
}
#if defined(HELIX_FEATURE_RTP)
switch(pRequest->m_lTransportType)
{
case RTSP_TR_RTP_UDP:
case RTSP_TR_RTP_TCP:
{
char portValue[32]; /* Flawfinder: ignore */
MIMEHeaderValue* pHeaderValue = new MIMEHeaderValue(pMimeType);
if(!pHeaderValue)
{
HX_DELETE(pHeader);
HX_DELETE(pModifiedMimeType);
return HXR_OUTOFMEMORY;
}
if (RTSP_TR_RTP_UDP == pRequest->m_lTransportType)
{
SafeSprintf(portValue, 32, "%u-%u", nUDPPort, nUDPPort+1);
pHeaderValue->addParameter("client_port", (const char*)portValue);
#ifdef XXXtbradleyTEST_RTSP_DESTINATION
pHeaderValue->addParameter("destination", "127.0.0.1");
#endif /* XXXtbradleyTEST_RTSP_DESTINATION */
}
if(m_bSetupRecord)
{
pHeaderValue->addParameter("mode", "record");
}
else
{
pHeaderValue->addParameter("mode", "play");
}
pHeader->addHeaderValue(pHeaderValue);
}
break;
case RTSP_TR_RTP_MCAST:
default:
{
}
break;
}
#endif /* HELIX_FEATURE_RTP */
HX_VECTOR_DELETE(pModifiedMimeType);
}
pMsg->addHeader(pHeader);
return status;
}
STDMETHODIMP
RTSPClientProtocol::SendPlayRequest(UINT32 lFrom, UINT32 lTo,
CHXSimpleList* pASMRules)
{
/*
* Flush the data packets out of the transport buffers
*/
m_pMutex->Lock();
m_bPaused = FALSE;
#if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
if (m_bSDPInitiated && m_bMulticast)
{
m_pMutex->Unlock();
return m_pResp->HandlePlayResponse(HXR_OK);
}
#endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
/*
* XXXGH...I believe we should be iterating through m_transportRequestList
* here and for SendPauseRequest, SendResumeRequest, etc.
*/
// only used when m_bNonRSRTP is TRUE
m_bPlayJustSent = TRUE;
if (!m_transportRequestList.IsEmpty())
{
RTSPTransportRequest* pRequest =
(RTSPTransportRequest*)m_transportRequestList.GetHead();
RTSPTransportInfo* pTransInfo = pRequest->getFirstTransportInfo();
while(pTransInfo)
{
pTransInfo->m_pTransport->playReset();
// set the range in transport...only for RTP
pTransInfo->m_pTransport->setPlayRange(lFrom, lTo);
pTransInfo->m_pTransport->SetPlayRequestSent(TRUE);
pTransInfo->m_pTransport->resumeBuffers();
pTransInfo = pRequest->getNextTransportInfo();
}
}
HX_RESULT rc = HXR_OK;
RTSPPlayMessage* pMsg = new RTSPPlayMessage;
if(pMsg)
{
RTSPRange range(lFrom, lTo, RTSPRange::TR_NPT);
pMsg->setURL(m_url);
AddCommonHeaderToMsg(pMsg);
pMsg->addHeader("Range", (const char*)range.asString());
UINT32 seqNo = m_pSession->getNextSeqNo(this);
rc = sendRequest(pMsg, seqNo);
}
else
{
rc = HXR_OUTOFMEMORY;
}
m_pMutex->Unlock();
return rc;
}
STDMETHODIMP
RTSPClientProtocol::SendRecordRequest()
{
if (!m_pIsMethodSupported[RECORD] || !m_pSession)
{
return HXR_OK;
}
HX_RESULT rc = HXR_OK;
m_pMutex->Lock();
// Declaring these here so I can use a goto below!
CHXString streamSequenceNumbers;
BOOL bIsFirst = TRUE;
CHXMapLongToObj::Iterator i;
RTSPRecordMessage* pMsg = new RTSPRecordMessage;
if(!pMsg)
{
rc = HXR_OUTOFMEMORY;
goto overandout;
}
pMsg->setURL(m_url);
AddCommonHeaderToMsg(pMsg);
/*
* Add header for sequence numbers
*/
for(i=m_pTransportStreamMap->Begin(); i!=m_pTransportStreamMap->End(); ++i)
{
int lenTmpBuf = 100 + strlen(m_url);
char* tmpBuf = new char[lenTmpBuf];
if(!tmpBuf)
{
HX_DELETE(pMsg);
rc = HXR_OUTOFMEMORY;
goto overandout;
}
RTSPTransport* pTransport = (RTSPTransport*)(*i);
pTransport->m_bHackedRecordFlag = TRUE;
UINT16 streamNumber = (UINT16)i.get_key();
UINT16 seqNum = pTransport->getSeqNum(streamNumber);
UINT32 ulTimestamp = pTransport->getTimestamp(streamNumber);
SafeSprintf(tmpBuf, lenTmpBuf, "url=" + m_url +
"/streamid=%d;seq=%d;rtptime=%ld", streamNumber, seqNum,
ulTimestamp);
if(!bIsFirst)
{
streamSequenceNumbers += ", " + CHXString(tmpBuf);
}
else
{
bIsFirst = FALSE;
streamSequenceNumbers = tmpBuf;
}
delete[] tmpBuf;
}
pMsg->addHeader("RTP-Info", streamSequenceNumbers);
if( m_pSession )
{
UINT32 seqNo = m_pSession->getNextSeqNo(this);
rc = sendRequest(pMsg, seqNo);
}
overandout:
m_pMutex->Unlock();
return rc;
}
STDMETHODIMP
RTSPClientProtocol::SendPauseRequest()
{
m_bPaused = TRUE;
/*
* Stop the internal buffer timers
*/
if (!m_pIsMethodSupported[PAUSE] || m_transportRequestList.IsEmpty() ||
!m_pSession)
{
return HXR_OK;
}
m_pMutex->Lock();
// only used when m_bNonRSRTP is TRUE
m_bPlayJustSent = FALSE;
SendMsgToTransport(PAUSE_BUFFER);
HX_RESULT rc = SendMsgToServer(RTSP_PAUSE);
m_pMutex->Unlock();
return rc;
}
STDMETHODIMP
RTSPClientProtocol::SendResumeRequest()
{
m_bPaused = FALSE;
if (!m_pSession)
{
return HXR_OK;
}
/*
* Restart the internal buffer timers
*/
m_pMutex->Lock();
SendMsgToTransport(RESUME_BUFFER);
/*
* Man, iptv, teracast, and darwin server don't like this even though
* this is perfetly legal...
*/
if (m_bNonRSRTP && m_bPlayJustSent)
{
m_pResp->HandlePlayResponse(HXR_OK);
m_pMutex->Unlock();
return HXR_OK;
}
HX_RESULT rc = SendMsgToServer(RTSP_PLAY);
m_pMutex->Unlock();
return rc;
}
STDMETHODIMP
RTSPClientProtocol::SendTeardownRequest()
{
// make sure not to send a TEARDOWN unless SETUP succeeded
if (m_setupResponseCount <= 0 || !m_pSession)
{
// no successful SETUP response received...
return HXR_OK;
}
// it's ok if there is no session by spec.
m_pMutex->Lock();
HX_RESULT rc = SendMsgToServer(RTSP_TEARDOWN);
m_pMutex->Unlock();
return rc;
}
STDMETHODIMP
RTSPClientProtocol::SendPlayerStats(const char* pStats)
{
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
if (!m_pIsMethodSupported[SET_PARAM])
{
return HXR_OK;
}
if(m_pSession && !m_sessionID.IsEmpty())
{
HX_RESULT rc = HXR_OK;
m_pMutex->Lock();
RTSPSetParamMessage* pMsg = new RTSPSetParamMessage;
if(pMsg)
{
pMsg->setURL(m_url);
pMsg->addHeader("Session", m_sessionID);
pMsg->addHeader("PlayerStats", pStats);
UINT32 seqNo = m_pSession->getNextSeqNo(this);
rc = sendRequest(pMsg, seqNo);
}
else
{
rc = HXR_OUTOFMEMORY;
}
m_pMutex->Unlock();
return rc;
}
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
return HXR_OK;
}
STDMETHODIMP
RTSPClientProtocol::SendKeepAlive()
{
HX_RESULT rc = HXR_OK;
// XXXSMP - Not right! :-)
m_pMutex->Lock();
if (!m_pSession)
{
// just say alive!
m_pMutex->Unlock();
return HXR_OK;
}
// Handle server timeout
if (!m_bKeepLiveResponsed)
{
m_pResp->HandleOptionsResponse(HXR_SERVER_TIMEOUT, NULL);
m_pMutex->Unlock();
return rc;
}
m_bKeepLiveResponsed = FALSE;
// If using session timeout code, send an Options message,
// otherwise, send a SetParam. The SetParam approach is
// is for servers that do not specify a session timeout value.
if (!m_bUseLegacyTimeOutMsg ||
!m_pIsMethodSupported[SET_PARAM] ||
m_bNoKeepAlive)
{
m_bKeepAlivePending = TRUE;
rc = SendMsgToServer(RTSP_OPTIONS);
}
else
{
RTSPSetParamMessage* pMsg = new RTSPSetParamMessage;
if(pMsg)
{
pMsg->setURL("*");
MIMEHeader* pAlertHeader = new MIMEHeader("Ping");
if(pAlertHeader)
{
pAlertHeader->addHeaderValue("Pong");
pMsg->addHeader(pAlertHeader);
AddCommonHeaderToMsg(pMsg);
UINT32 seqNo = m_pSession->getNextSeqNo(this);
sendRequest(pMsg, seqNo);
}
else
{
rc = HXR_OUTOFMEMORY;
}
}
else
{
rc = HXR_OUTOFMEMORY;
}
}
m_pMutex->Unlock();
return rc;
}
STDMETHODIMP
RTSPClientProtocol::SendPacket(BasePacket* pPacket)
{
m_pMutex->Lock();
HX_RESULT rc = HXR_UNEXPECTED;
RTSPTransport* pTrans =
(RTSPTransport*)(*m_pTransportStreamMap)[pPacket->GetStreamNumber()];
if(pTrans)
{
rc = pTrans->sendPacket(pPacket);
}
m_pMutex->Unlock();
return rc;
}
STDMETHODIMP
RTSPClientProtocol::SendStreamDone(UINT16 streamNumber)
{
m_pMutex->Lock();
HX_RESULT rc = HXR_UNEXPECTED;
RTSPTransport* pTrans =
(RTSPTransport*)(*m_pTransportStreamMap)[streamNumber];
if(pTrans)
{
rc = pTrans->streamDone(streamNumber);
}
m_pMutex->Unlock();
return rc;
}
STDMETHODIMP
RTSPClientProtocol::GetPacket(UINT16 uStreamNumber, REF(IHXPacket*) pPacket)
{
m_pMutex->Lock();
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -