📄 rtspprotocol.cpp
字号:
* Method:
* IHXASMSource::Subscribe
* Purpose:
* Subscribe to a stream
*/
STDMETHODIMP
RTSPProtocol::Subscribe
(
UINT16 streamNumber,
UINT16 ruleNumber
)
{
RTSPSubscription sub;
sub.m_streamNumber = streamNumber;
sub.m_ruleNumber = ruleNumber;
sub.m_bIsSubscribe = TRUE;
CHXSimpleList subList;
subList.AddTail(&sub);
return m_pProtocolLib->Subscribe(&subList);
}
/************************************************************************
* Method:
* IHXASMSource::Unsubscribe
* Purpose:
* Unsubscribe from a stream
*/
STDMETHODIMP
RTSPProtocol::Unsubscribe
(
UINT16 streamNumber,
UINT16 ruleNumber
)
{
RTSPSubscription sub;
sub.m_streamNumber = streamNumber;
sub.m_ruleNumber = ruleNumber;
sub.m_bIsSubscribe = FALSE;
CHXSimpleList subList;
subList.AddTail(&sub);
return m_pProtocolLib->Unsubscribe(&subList);
}
/*
* IHXBackChannel methods
*/
/************************************************************************
* Method:
* IHXBackChannel::PacketReady
* Purpose:
* Send a packet from renderer back to file format
*/
STDMETHODIMP
RTSPProtocol::PacketReady
(
IHXPacket* pPacket
)
{
/*
* XXXSMP - We'll use the transport when available eventually, but
* Control messages will do for now.
*/
if(m_pProtocolLib)
{
return m_pProtocolLib->BackChannelPacketReady(pPacket);
}
return HXR_FAIL;
}
/* HXProtocol methods */
HX_RESULT
RTSPProtocol::server_hello(void)
{
HX_RESULT theErr = HXR_OK;
IUnknown* pContext = NULL;
IHXBuffer* pBuffer = NULL;
IHXValues* pInfo = NULL;
pContext = (IUnknown*)(IHXStreamSource*)mOwner;
pContext->AddRef();
if (m_bSDPInitiated)
{
pInfo = new CHXHeader();
if (pInfo)
{
pInfo->AddRef();
pBuffer = new CHXBuffer();
if (pBuffer)
{
pBuffer->AddRef();
pBuffer->Set((UCHAR*)mPath, strlen(mPath) + 1);
pInfo->SetPropertyCString("helix-sdp", pBuffer);
pBuffer->Release();
}
}
}
theErr = m_pProtocolLib->Init((IUnknown*)pContext,
mHost,
mPort,
(IHXRTSPClientProtocolResponse*)this,
mUseProxy?RTSP_INIT_HXPRIVATE_AUTHORIZATION:0,
m_pIDInfo,
pInfo,
m_bHTTPOnly,
mCloakPort,
FALSE);
if (pInfo)
{
UINT32 ulMulticastOnly = 0;
// "MulticastOnly" is set by the RTSPClientProtocol when it's scalable
// multicast via SDP file.
//
// If "MulticastOnly" is set and the current transport is not multicast then
// we will returns error immediately and won't waste time in transport switching
pInfo->GetPropertyULONG32("MulticastOnly", ulMulticastOnly);
m_bMulticastOnly = (ulMulticastOnly > 0)?TRUE:FALSE;
if (m_bMulticastOnly && mCurrentTransport != MulticastMode)
{
theErr = HXR_SE_MULTICAST_DELIVERY_ONLY;
}
}
HX_RELEASE(pInfo);
HX_RELEASE(pContext);
return theErr;
}
HX_RESULT
RTSPProtocol::proxy_hello(void)
{
m_pProtocolLib->SetProxy(mProxy, mProxyPort);
return server_hello();
}
HX_RESULT
RTSPProtocol::process(void)
{
HX_RESULT theErr = HXR_OK;
if (m_LastError != HXR_OK)
{
return m_LastError;
}
#ifdef _MACINTOSH
#if defined(HELIX_FEATURE_AUTHENTICATION)
if (m_bHandleWWWAuthentication)
{
/* Need to wait for system time */
if (HXMM_ATINTERRUPT())
{
return HXR_OK;
}
m_bHandleWWWAuthentication = FALSE;
handlePendingWWWAuthentication(m_WWWResult, m_pWWWValues);
HX_RELEASE(m_pWWWValues);
}
#endif
#endif
switch(m_idleState)
{
case INIT_SOCKETS_STATE:
{
IUnknown* pContext = NULL;
IHXInterruptState* pInterruptState = NULL;
mOwner->GetContext(pContext);
if (pContext)
{
pContext->QueryInterface(IID_IHXInterruptState, (void**) &pInterruptState);
}
HX_RELEASE(pContext);
/* We want to initialize sockets ONLY at system time */
if (!pInterruptState ||
!pInterruptState->AtInterruptTime())
{
// XXX HP: we should find better way to handle this
// when the UseUDPPort option is selected
if (UDPMode == mCurrentTransport ||
MulticastMode == mCurrentTransport)
{
theErr = m_pProtocolLib->InitSockets();
}
m_idleState = SEND_SETUP_REQUEST_STATE;
}
HX_RELEASE(pInterruptState);
}
break;
case SEND_SETUP_REQUEST_STATE:
{
// Make sure we are finished with the file header
if (!mOwner->m_bContinueWithHeaders)
{
theErr = send_setup_request();
m_idleState = NULL_STATE;
}
}
break;
case ALERT_STATE:
{
// Set theErr to the correct ServerAlert HXR_ code.
theErr = MAKE_SA(m_ulLastAlert);
if (!IS_SERVER_ALERT(theErr))
{
theErr = HXR_SERVER_ALERT;
}
m_idleState = NULL_STATE;
}
break;
default:
break;
}
// check whether the connection has timed out
if (!theErr && !m_bPaused)
{
ULONG32 ulNow = HX_GET_TICKCOUNT();
if ((!mReceivedControl || (!m_bReceivedData && m_bPlaying))
&& mOwner->CheckTransportTimeout(ulNow))
{
/* Make sure that we have really not receioved any data.
* If it is a sparse stream, transport may hold onto initial
* data for around 2 seconds before releasing it to the next
* layer.
*/
if (!mReceivedControl)
{
theErr = HXR_NET_CONNECT;
}
else
{
if (m_pProtocolLib && m_pProtocolLib->IsDataReceived())
{
/* We haver received the data.. Transport will
* eventually give it to use (hopefully!)
*/
m_bReceivedData = TRUE;
}
else
{
switch (mCurrentTransport)
{
case MulticastMode:
theErr = HXR_MULTICAST_UDP;
break;
case UDPMode:
theErr = HXR_NET_UDP;
break;
case TCPMode:
if (!m_bHTTPOnly)
{
theErr = HXR_NET_TCP;
}
else
{
theErr = HXR_DNR;
}
break;
default:
break;
}
}
}
}
// The following logic is to force reconnect when in certain cases, the UDP
// channel would be closed after a long pause. This solves the 50% phenomenon.
if (HXR_OK == theErr && m_bReceivedData && m_bAreResuming && mCurrentTransport == UDPMode)
{
if (mSourceEnd || (m_pProtocolLib && m_pProtocolLib->IsDataReceived()))
{
m_bAreResuming = FALSE;
}
else if (mOwner->CheckTransportTimeout(ulNow))
{
m_bAreResuming = FALSE;
theErr = HXR_SERVER_TIMEOUT;
}
}
// fallback to unicast if scalable multicast fails
if (m_bSDPInitiated && HXR_MULTICAST_UDP == theErr && mLiveStream)
{
if (HXR_OK == SwitchToUnicast())
{
theErr = HXR_OK;
}
else
{
theErr = HXR_MULTICAST_JOIN;
}
}
}
// remember the last error so we won't proceed to the next
// RTSP state in subsequent process() calls
if (HXR_OK == m_LastError && HXR_OK != theErr)
{
m_LastError = theErr;
}
return theErr;
}
HX_RESULT
RTSPProtocol::abort(void)
{
HX_RESULT theErr = HXR_OK;
//XXX...Currently unimplemented
return theErr;
}
HX_RESULT
RTSPProtocol::GetEvent
(
UINT16 uStreamNumber,
CHXEvent*& pEvent
)
{
HX_TRACE("RTSPProtocol::GetPacket");
HX_RESULT result;
IHXPacket* pPacket = NULL;
pEvent = NULL;
result = m_pProtocolLib->GetPacket(uStreamNumber, pPacket);
#ifdef _DEBUG
if (result == HXR_AT_END)
{
STREAM_INFO* pStreamInfo;
if (HXR_OK != mOwner->GetStreamInfo(uStreamNumber, pStreamInfo))
{
return HXR_FAIL;
}
HX_ASSERT(pStreamInfo->m_bSrcStreamDone);
}
#endif
if (pPacket)
{
// signal the raw data is received
m_bReceivedData = TRUE;
pEvent = new CHXEvent(pPacket);
pPacket->Release();
}
return result;
}
HX_RESULT
RTSPProtocol::setup(const char* host, const char* path, UINT16 port,
BOOL LossCorrection, BOOL bHTTPCloak,
BOOL bSDPInitiated, UINT16 cloakPort)
{
HX_RESULT theErr = HXR_OK;
IHXValues* pRequestHeaders = NULL;
IHXValues* pCloakValues = NULL;
IHXBuffer* pRegionData = NULL;
m_bSDPInitiated = bSDPInitiated;
mOwner->GetRequest(m_pRequest);
// XXXkshoop store origional headers for use
// in replaying Describe's. This supports
// authentication.
HX_ASSERT(m_pRequest);
if (m_pRequest)
{
m_spIHXValuesStoredHeaders.Release();
theErr = m_pRequest->GetRequestHeaders(
m_spIHXValuesStoredHeaders.ptr_reference());
HX_VERIFY(SUCCEEDED(theErr) && m_spIHXValuesStoredHeaders.IsValid());
}
// setup base class members
theErr = HXProtocol::setup(host, path, port, LossCorrection, bHTTPCloak,
m_bSDPInitiated, cloakPort);
if (theErr)
{
return theErr;
}
if
(
m_pRequest
&&
SUCCEEDED(m_pRequest->GetRequestHeaders(pRequestHeaders))
&&
pRequestHeaders
)
{
pRequestHeaders->GetPropertyCString("RegionData", pRegionData);
}
HX_RELEASE(pRequestHeaders);
// construct the IHXValues
m_pIDInfo = new CHXHeader();
m_pIDInfo->AddRef();
IHXBuffer* pGUID = new CHXBuffer();
IHXBuffer* pClientID = new CHXBuffer();
IHXBuffer* pPragma = new CHXBuffer();
pGUID->AddRef();
pClientID->AddRef();
pPragma->AddRef();
pGUID->Set((const UCHAR*)m_pszGUID, strlen(m_pszGUID)+1);
pClientID->Set((const UCHAR*)m_pszClientID, strlen(m_pszClientID)+1);
pPragma->Set((const UCHAR*)PRAGMA, strlen(PRAGMA)+1);
m_pIDInfo->SetPropertyCString("GUID", pGUID);
m_pIDInfo->SetPropertyCString("ClientID", pClientID);
// server doesn't like this in SDP initiated playback
if (!m_bSDPInitiated)
{
m_pIDInfo->SetPropertyCString("Pragma", pPragma);
}
#if 0
IHXBuffer* pPasswordBuffer;
if (m_pPreferences && m_pPreferences->ReadPref("LoadTestPassword",
pPasswordBuffer) == HXR_OK)
{
char szLoadTestPasswordKey[HX_COMPANY_ID_KEY_SIZE] = {0}; /* Flawfinder: ignore */
// create the encrypted key
CalcCompanyIDKey((const char*)pPasswordBuffer->GetBuffer(),
(const char*)szStarttime,
(const char*)"LoadTestID",
(const char*)pRCMagic1,
(const char*)pMagic2,
(UCHAR*) &szLoadTestPasswordKey[0]);
char szEncodedLTP[HX_COMPANY_ID_KEY_SIZE * 2]; // probably overkill /* Flawfinder: ignore */
BinTo64((const BYTE*)szLoadTestPasswordKey, HX_COMPANY_ID_KEY_SIZE,
szEncodedLTP);
IHXBuffer* pEncodedLTPBuffer = new CHXBuffer();
pEncodedLTPBuffer->AddRef();
pEncodedLTPBuffer->Set((const UCHAR*)szEncodedLTP,
strlen(szEncodedLTP)+1);
m_pIDInfo->SetPropertyCString("LoadTestPassword", pEncodedLTPBuffer);
pEncodedLTPBuffer->Release();
HX_RELEASE(pPasswordBuffer);
/*
* XXXSMP Very poor way to set a requirement. This won't work
* as soon rmartsp needs to send other requirements. Comment
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -