rtspprotocol.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:81k
- /* ***** BEGIN LICENSE BLOCK *****
- * Source last modified: $Id: rtspprotocol.cpp,v 1.27.2.3 2004/07/13 17:12:04 ping Exp $
- *
- * Portions Copyright (c) 1995-2004 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 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the current version of the RealNetworks Community
- * Source License (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.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL") in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your version of
- * this file only under the terms of the GPL, and not to allow others
- * to use your version of this file under the terms of either the RPSL
- * or RCSL, indicate your decision by deleting the provisions above
- * and replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient may
- * use your version of this file under the terms of any one of the
- * RPSL, the RCSL or the GPL.
- *
- * 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 ***** */
- #include "hxcom.h"
- #include "hlxclib/stdio.h"
- #include "hlxclib/stdlib.h"
- #include "hxver.h"
- #include "hxtypes.h"
- #include "hxresult.h"
- #include "hxstrutl.h"
- #include "hxcomm.h"
- #include "ihxpckts.h"
- #include "hxfiles.h"
- #include "hxengin.h"
- #include "hxasm.h"
- #include "hxsdesc.h"
- #include "chxpckts.h"
- #include "hxcore.h"
- #include "hxprefs.h"
- #include "hxpref.h"
- #include "hxsdesc.h"
- #include "hxpends.h"
- #include "hxrsdbf.h"
- #include "hxengin.h"
- #include "hxstring.h"
- #include "hxslist.h"
- #include "hxstat.h"
- #include "hxtick.h"
- #include "chxeven.h"
- #include "hxcleng.h"
- //#include "rtmlpars.h"
- #include "rtspclnt.h"
- #include "rtspclntext.h"
- #include "rtsputil.h"
- #include "mimehead.h"
- #include "rtspmsg.h"
- #include "rtsppars.h"
- #include "rtspmdsc.h"
- #include "statinfo.h"
- #include "hxntsrc.h"
- #include "hxprotocol.h"
- #include "hxauthn.h"
- #include "hxplgns.h"
- #include "hxauth.h"
- #include "hxdate.h"
- #include "hxurl.h"
- #include "platform.h"
- #include "clntcore.ver"
- #include "hxplugn.h"
- #include "dtrvtcon.h"
- #include "rmfftype.h"
- #include "rtspprotocol.h"
- #include "hxcomsp.h"
- #include "hxpktsp.h"
- #include "hxplnsp.h"
- #include "miscsp.h"
- #include "hxxrsmg.h"
- #include "hxresmgr.h"
- #include "dcoreres.h"
- #ifdef _MACINTOSH
- #include "hxmm.h"
- #endif
- #include "hxheap.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- #define PRAGMA "initiate-session"
- #define MINIMUM_STATS_INTERVAL 15000 // 15 seconds
- #define MAX_DEFAULT_STATS_SIZE 512
- #define MAX_TRANSPORT 10
- RTSPProtocol::RTSPProtocol(HXNetSource* owner, ULONG32 ulPlatformSpecific)
- : HXProtocol (owner, ulPlatformSpecific)
- , m_lRefCount(0)
- , m_uSecurityKey(0)
- , m_uStreamCount(0)
- , m_uCurrentStreamCount(0)
- , m_pProtocolLib(0)
- , m_pPendingStatus(0)
- , m_pStatistics(0)
- , m_bPlaying(FALSE)
- , m_bIsASMSource(FALSE)
- , m_bUseRTP(FALSE)
- , m_bReceivedData(FALSE)
- , m_bMulticastOnly(FALSE)
- , m_idleState(NULL_STATE)
- , m_pIDInfo(NULL)
- , m_pRequest(NULL)
- , m_bFirstAuthAttempt(TRUE)
- , mReceivedControl(FALSE)
- , m_bPendingSeek(FALSE)
- , m_ulSeekPos1(0)
- , m_ulSeekPos2(0)
- , m_bHandleWWWAuthentication(FALSE)
- , m_WWWResult(HXR_OK)
- , m_pWWWValues(NULL)
- #if defined(HELIX_FEATURE_REVERTER)
- , m_pDataRevert(0)
- #endif /* HELIX_FEATURE_REVERTER */
- {
- m_pStreamInfoList = new CHXMapLongToObj;
-
- if (owner)
- {
- IHXPlayer* pPlayer = NULL;
- IUnknown* pUnknown = NULL;
- owner->GetPlayer(pPlayer);
- if (pPlayer)
- {
- pUnknown = (IUnknown*)pPlayer;
- }
- // auto. config doesn't have the player object
- // use IHXClientEngine instead
- else
- {
- owner->GetContext(pUnknown);
- }
- #if defined(HELIX_FEATURE_REVERTER)
- m_pDataRevert = new DataRevertController(pUnknown);
- m_pDataRevert->AddRef();
- m_pDataRevert->SetControlResponse(this);
- #endif /* HELIX_FEATURE_REVERTER */
- HX_RELEASE(pUnknown);
- }
- /* Always allowed in RTSP - till we add some code to file format
- * plugins to set this value in file header - XXXRA
- */
- m_bPerfectPlayAllowed = TRUE;
- //
- // get proxy info for RTSP protocol
- //
- initialize_members();
- ReadPrefBOOL(m_pPreferences, "NonRS", m_bUseRTP);
- if (!m_bUseRTP)
- {
- ReadPrefBOOL(m_pPreferences, "UseRTP", m_bUseRTP);
- }
- }
- RTSPProtocol::~RTSPProtocol ()
- {
- if (m_pProtocolLib)
- {
- m_pProtocolLib->Done();
- HX_RELEASE(m_pProtocolLib);
- }
- HX_RELEASE(m_pRequest);
- HX_RELEASE(m_pPendingStatus);
- HX_RELEASE(m_pStatistics);
- HX_RELEASE(m_pIDInfo);
- HX_RELEASE(m_pWWWValues);
- #if defined(HELIX_FEATURE_REVERTER)
- HX_RELEASE(m_pDataRevert);
- #endif /* HELIX_FEATURE_REVERTER */
-
- HX_DELETE(m_pStreamInfoList);
- }
- /* IUnknown methods */
- STDMETHODIMP
- RTSPProtocol::QueryInterface(REFIID riid, void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IHXPendingStatus), (IHXPendingStatus*)this },
- { GET_IIDHANDLE(IID_IHXStatistics), (IHXStatistics*)this },
- { GET_IIDHANDLE(IID_IHXBackChannel), (IHXBackChannel*)this },
- { GET_IIDHANDLE(IID_IHXAtomicRuleChange), (IHXAtomicRuleChange*)this },
- { GET_IIDHANDLE(IID_IHXPreferredTransportSink), (IHXPreferredTransportSink*)this },
- { GET_IIDHANDLE(IID_IUnknown), this },
- };
-
- if (HXR_OK == ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj))
- {
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXASMSource) && m_bIsASMSource)
- {
- AddRef();
- *ppvObj = (IHXASMSource*)this;
- return HXR_OK;
- }
- else if (m_pProtocolLib &&
- (HXR_OK == m_pProtocolLib->QueryInterface(riid, ppvObj)))
- {
- return HXR_OK;
- }
- *ppvObj = NULL;
- return HXR_NOINTERFACE;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::AddRef
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) RTSPProtocol::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::Release
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) RTSPProtocol::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- /* IHXRTSPClientProtocolResponse methods */
- STDMETHODIMP
- RTSPProtocol::InitDone
- (
- HX_RESULT status
- )
- {
- if (status != HXR_OK)
- {
- /*
- * XXX...Need to get proper errors from protocol library
- */
- mOwner->ReportError(status); //ConvertHResultToHXError(status));
- }
- if (m_pProtocolLib->HttpOnly())
- {
- mCurrentTransport = TCPMode;
- }
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::HandleWWWAuthentication
- (
- HX_RESULT HX_RESULTStatus,
- IHXValues* pIHXValuesHeaders
- )
- {
- #if defined(HELIX_FEATURE_AUTHENTICATION)
- #ifdef _MACINTOSH
- /*
- * We load a plugin for authetication. Can't do this at interrupt
- * time on Mac
- */
- if (HXMM_ATINTERRUPT())
- {
- m_bHandleWWWAuthentication = TRUE;
- m_WWWResult = HX_RESULTStatus;
- HX_RELEASE(m_pWWWValues);
- m_pWWWValues = pIHXValuesHeaders;
- if (m_pWWWValues)
- {
- m_pWWWValues->AddRef();
- }
- if (mOwner)
- {
- mOwner->ScheduleProcessCallback();
- }
- return HXR_OK;
- }
- #endif
- return (handlePendingWWWAuthentication(HX_RESULTStatus, pIHXValuesHeaders));
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_AUTHENTICATION */
- }
- #if defined(HELIX_FEATURE_AUTHENTICATION)
- // IHXClientAuthResponse
- STDMETHODIMP
- RTSPProtocol::ResponseReady
- (
- HX_RESULT HX_RESULTStatus,
- IHXRequest* pIHXRequestResponse
- )
- {
- HX_RESULT HX_RESULTErr;
- IHXValues* pIHXValuesRequestHeaders = NULL;
- if(SUCCEEDED(HX_RESULTStatus))
- {
- if (!m_pProtocolLib)
- {
- return HXR_OUTOFMEMORY;
- }
- pIHXRequestResponse->GetRequestHeaders
- (
- pIHXValuesRequestHeaders
- );
- if(!m_uStreamCount)
- {
- // We haven't received a successful Describe..
- //
- CHXHeader::mergeHeaders
- (
- pIHXValuesRequestHeaders,
- m_spIHXValuesStoredHeaders
- );
- HX_RESULTErr = m_pProtocolLib->SendStreamDescriptionRequest
- (
- mPath,
- pIHXValuesRequestHeaders
- );
- }
- else if (m_uCurrentStreamCount == m_uStreamCount)
- {
- // We haven't received a successful Setup..
- //
- HX_RESULTErr = m_pProtocolLib->SendSetupRequest
- (
- NULL,
- 0,
- pIHXValuesRequestHeaders
- );
- }
- HX_RELEASE(pIHXValuesRequestHeaders);
- }
- else
- {
- if (HXR_FAIL == HX_RESULTStatus)
- {
- HX_RESULTStatus = HXR_NOT_AUTHORIZED;
- }
- mOwner->ReportError(HX_RESULTStatus);
- }
- return HXR_OK;
- }
- HX_RESULT
- RTSPProtocol::handlePendingWWWAuthentication
- (
- HX_RESULT HX_RESULTStatus,
- IHXValues* pIHXValuesHeaders
- )
- {
- HX_RESULT HX_RESULTRet = HXR_FAIL;
- if(HXR_NOT_AUTHORIZED == HX_RESULTStatus)
- {
- IUnknown* pIUnknownContext = NULL;
- IHXPlayer* pIHXPlayerPlayer = NULL;
- IHXAuthenticationManager* pIHXAuthenticationManager = NULL;
- // Don't transport switch while we are waiting for authentication
- mOwner->StopDataWait();
- if
- (
- m_spIHXClientAuthConversationAuthenticator.IsValid()
- &&
- m_spIHXClientAuthConversationAuthenticator->IsDone()
- )
- {
- // Well we tried to authenticate already,
- // so it must have failed
- m_spIHXClientAuthConversationAuthenticator->Authenticated(FALSE);
- // Cleanup so that we can re-auth
- m_spIHXClientAuthConversationAuthenticator.Release();
- }
- mOwner->GetPlayer(pIHXPlayerPlayer);
- if (NULL == pIHXPlayerPlayer)
- {
- // in case of the Auto. Config
- mOwner->GetContext(pIUnknownContext);
- }
- else
- {
- pIUnknownContext = (IUnknown*)pIHXPlayerPlayer;
- }
- if (!m_spIHXClientAuthConversationAuthenticator.IsValid())
- {
- DECLARE_SMART_POINTER_UNKNOWN spIUnknownAuthenticator;
- DECLARE_SMART_POINTER
- (
- IHXObjectConfiguration
- ) spIHXObjectConfigurationAuthenticator;
- DECLARE_SMART_POINTER
- (
- IHXCommonClassFactory
- ) spIHXCommonClassFactoryHXCore;
- spIHXCommonClassFactoryHXCore = pIUnknownContext;
- // Starting conversation
- HX_RESULTRet = spIHXCommonClassFactoryHXCore->CreateInstance
- (
- CLSID_CHXClientAuthenticator,
- (void**)&spIUnknownAuthenticator
- );
- if
- (
- SUCCEEDED(HX_RESULTRet)
- &&
- spIUnknownAuthenticator.IsValid()
- )
- {
- spIHXObjectConfigurationAuthenticator =
- (
- spIUnknownAuthenticator
- );
- spIHXObjectConfigurationAuthenticator->SetContext
- (
- pIUnknownContext
- );
- m_spIHXClientAuthConversationAuthenticator =
- (
- spIUnknownAuthenticator
- );
- }
- }
- if
- (
- m_spIHXClientAuthConversationAuthenticator.IsValid()
- &&
- !m_spIHXClientAuthConversationAuthenticator->IsDone()
- )
- {
- HX_ASSERT(m_pRequest);
- if (m_pRequest)
- {
- m_pRequest->SetResponseHeaders
- (
- pIHXValuesHeaders
- );
- HX_RESULTRet =
- (
- m_spIHXClientAuthConversationAuthenticator->MakeResponse
- (
- this,
- m_pRequest
- )
- );
- }
- else
- {
- // Auth Failed!
- m_spIHXClientAuthConversationAuthenticator->Authenticated(FALSE);
- mOwner->ReportError(HXR_NOT_AUTHORIZED);
- }
- // Flow continues in ResponseReady()
- }
- else
- {
- // Auth Failed!
- if (m_spIHXClientAuthConversationAuthenticator.IsValid())
- {
- m_spIHXClientAuthConversationAuthenticator->Authenticated(FALSE);
- }
- mOwner->ReportError(HXR_NOT_AUTHORIZED);
- }
- HX_RELEASE(pIUnknownContext);
- return HXR_OK;
- }
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::AuthenticationRequestDone(HX_RESULT result,
- const char* user,
- const char* password)
- {
- return HXR_NOTIMPL;
- }
- #endif /* HELIX_FEATURE_AUTHENTICATION */
- // XXXGo - IPTV_HACK
- void
- RTSPProtocol::hackCookie(IHXBuffer* pCookie)
- {
- HX_ASSERT(m_bUseRTP);
- // XXXGo - Interop Hack
- // IP/TV send a spec incomplient cookie...take care of it for now while
- // we get them to fix it.
- // we will assume Set-Cookie has just NAME=VALUE paris.
- IHXBuffer* pBuffer = new CHXBuffer();
- pBuffer->AddRef();
- pBuffer->Set((const BYTE*)pCookie->GetBuffer(),
- strlen((const char*)pCookie->GetBuffer()) +1);
- IHXBuffer* pBuf = NULL;
- char* pcOneCookie = (char*)pBuffer->GetBuffer();
- char* pc = pcOneCookie;
- char* pcKey = NULL;
- // go thorough each ';'
- for (;;)
- {
- pc = strchr(pc, ';');
- if (pc)
- {
- pBuf = new CHXBuffer();
- pBuf->AddRef();
- *pc = NULL;
- pBuf->Set((const BYTE*)pcOneCookie, strlen(pcOneCookie) + 1);
- mOwner->SetCookie(pBuf);
- HX_RELEASE(pBuf);
- pcOneCookie = ++pc;
- }
- else
- {
- // just set it
- pBuf = new CHXBuffer();
- pBuf->AddRef();
- pBuf->Set((const BYTE*)pcOneCookie, strlen(pcOneCookie) + 1);
- mOwner->SetCookie(pBuf);
- HX_RELEASE(pBuf);
- break;
- }
- }
- }
- HX_RESULT
- RTSPProtocol::SwitchToUnicast(void)
- {
- HX_RESULT rc = HXR_FAILED;
- IHXBuffer* pBuffer = NULL;
- if (mOwner && mOwner->m_pFileHeader)
- {
- // get a URL from the file header. No URL, no Unicast!
- if (HXR_OK == mOwner->m_pFileHeader->GetPropertyCString("UnicastURL", pBuffer) &&
- pBuffer)
- {
- rc = HandleRedirectRequest((const char*)pBuffer->GetBuffer(), 0);
- }
- HX_RELEASE(pBuffer);
- }
- return rc;
- }
- STDMETHODIMP
- RTSPProtocol::HandleOptionsResponse(HX_RESULT status,
- IHXValues* pHeader)
- {
- if (FAILED(status))
- {
- mOwner->ReportError(status);
- return status;
- }
- else if (HXR_REDIRECTION == status)
- {
- // expect a redirection message soon!
- m_idleState = NULL_STATE;
- BOOL bHackCookie = FALSE;
- IHXBuffer* pAgent = NULL;
- if (pHeader->GetPropertyCString("User-Agent", pAgent) == HXR_OK)
- {
- if (strncasecmp((const char*)pAgent->GetBuffer(), "Cisco IP/TV",
- 11) == 0)
- {
- bHackCookie = TRUE;
- }
- }
- HX_RELEASE(pAgent);
- // retrieve cookies from the response header
- IHXKeyValueList* pKeyValueList = NULL;
- if (HXR_OK == pHeader->QueryInterface(IID_IHXKeyValueList,
- (void**)&pKeyValueList))
- {
- IHXKeyValueListIterOneKey* pListIter = NULL;
- IHXBuffer* pCookie = NULL;
- pKeyValueList->GetIterOneKey("Set-Cookie",pListIter);
- while (pListIter->GetNextString(pCookie) == HXR_OK)
- {
- // XXXGo - IPTV_HACK
- if (bHackCookie)
- {
- hackCookie(pCookie);
- }
- else
- {
- mOwner->SetCookie(pCookie);
- }
- HX_RELEASE(pCookie);
- }
- HX_RELEASE(pListIter);
- }
- HX_RELEASE(pKeyValueList);
- return HXR_OK;
- }
- m_bConnectDone = TRUE;
- HX_RESULT result = HXR_OK;
- result = m_pProtocolLib->SendStreamDescriptionRequest
- (
- mPath,
- m_spIHXValuesStoredHeaders
- );
- return result;
- }
- STDMETHODIMP
- RTSPProtocol::HandleStreamDescriptionResponse(HX_RESULT status,
- IHXValues* pFileHeader,
- CHXSimpleList* pHeaderList,
- IHXValues* pResponseHeaders)
- {
- HX_RESULT hr = HXR_OK;
- if (FAILED(status))
- {
- if (!pFileHeader || !pHeaderList)
- {
- /*
- * XXX...Need to get proper errors from protocol library
- */
- mOwner->ReportError(status);//ConvertHResultToHXError(status));
- return (status != (UINT32)HXR_OK) ? status : (UINT32)HXR_FAIL;
- }
- }
- else if (!pFileHeader || !pHeaderList)
- {
- // Not a severe failure, need to try again.
- return m_pProtocolLib->SendStreamDescriptionRequest(mPath,
- m_spIHXValuesStoredHeaders);
- }
- #if defined(HELIX_FEATURE_REVERTER)
- // DESCRIBE Succeeded!
- //
- m_pDataRevert->RevertHeaders(pFileHeader, pHeaderList, pResponseHeaders);
- #else
- RevertHeadersDone(pFileHeader,
- pHeaderList,
- pResponseHeaders,
- FALSE);
- #endif /* HELIX_FEATURE_REVERTER */
- return HXR_OK;
- }
- /*
- * IHXPreferredTransportSink methods
- */
- STDMETHODIMP
- RTSPProtocol::TransportSucceeded(TransportMode /* IN */ prefTransportType,
- UINT16 /* IN */ uCloakPort)
- {
- if (m_bHTTPOnly)
- {
- return mOwner->TransportSucceeded(HTTPCloakMode, uCloakPort);
- }
- // we ignore the TCP control channel succeeded message if we are attempting
- // Multicast or UDP
- else if (mCurrentTransport == prefTransportType)
- {
- return mOwner->TransportSucceeded(prefTransportType, uCloakPort);
- }
- else
- {
- HX_ASSERT(mCurrentTransport == UDPMode || mCurrentTransport == MulticastMode);
- }
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::TransportFailed()
- {
- return mOwner->TransportFailed();
- }
- void
- RTSPProtocol::RevertHeadersDone(IHXValues* pFileHeader,
- CHXSimpleList* pHeaderList,
- IHXValues* pResponseHeaders,
- BOOL bUseReverter)
- {
- HX_RESULT status = HXR_OK;
- ULONG32 tempLiveStream = 0;
- pFileHeader->GetPropertyULONG32("LiveStream", tempLiveStream);
- mLiveStream = (tempLiveStream > 0)?TRUE:FALSE;
- #if defined(HELIX_FEATURE_REVERTER)
- if (bUseReverter && m_pDataRevert)
- {
- m_pProtocolLib->InitPacketFilter(m_pDataRevert);
- }
- #endif /* HELIX_FEATURE_REVERTER */
- ULONG32 ulFlags = 0;
- pFileHeader->GetPropertyULONG32("Flags", ulFlags);
- mSaveAsAllowed = ulFlags & HX_SAVE_ENABLED ? TRUE : FALSE;
- IHXBuffer* pBuffer = NULL;
- if (HXR_OK == pResponseHeaders->GetPropertyCString("StatsMask", pBuffer))
- {
- mSendStatsMask = atoi((const char*)pBuffer->GetBuffer());
- mOwner->SetOption(HX_STATS_MASK, &mSendStatsMask);
- }
- HX_RELEASE(pBuffer);
- if (HXR_OK == pResponseHeaders->GetPropertyCString("StatsInterval", pBuffer))
- {
- UINT32 ulStatsInterval = 1000* atoi((const char*)pBuffer->GetBuffer());
- // ulStatsInterval = 0 to disable the stats
- if (ulStatsInterval && ulStatsInterval < MINIMUM_STATS_INTERVAL)
- {
- ulStatsInterval = MINIMUM_STATS_INTERVAL;
- }
- mOwner->SetOption(HX_STATS_INTERVAL, &ulStatsInterval);
- }
- HX_RELEASE(pBuffer);
- if (HXR_OK == pResponseHeaders->GetPropertyCString("MaxBandwidth", pBuffer))
- {
- UINT32 ulMaxBandwidth = atoi((const char*)pBuffer->GetBuffer());
- // ulMaxBandwidth = 0 to disable the faststart
- mOwner->SetOption(HX_MAX_BANDWIDTH, &ulMaxBandwidth);
- }
- HX_RELEASE(pBuffer);
- if (HXR_OK == pResponseHeaders->GetPropertyCString("TurboPlay", pBuffer))
- {
- BOOL bTurboPlay = (BOOL)atoi((const char*)pBuffer->GetBuffer());
- mOwner->SetOption(HX_TURBO_PLAY, &bTurboPlay);
- }
- HX_RELEASE(pBuffer);
- // UseRTP was set from RTSPClientProtocol::handleDescribeResponse when
- // it detected we were not playing a stream from a RealServer.
- ULONG32 ulTemp = 0;
- if (HXR_OK == pResponseHeaders->GetPropertyULONG32("UseRTP", ulTemp))
- {
- m_bUseRTP = ulTemp;
- }
- // retrieve cookies from the response header
- IHXKeyValueList* pKeyValueList = NULL;
- if (HXR_OK == pResponseHeaders->QueryInterface(IID_IHXKeyValueList,
- (void**)&pKeyValueList))
- {
- IHXKeyValueListIterOneKey* pListIter = NULL;
- IHXBuffer* pCookie = NULL;
- pKeyValueList->GetIterOneKey("Set-Cookie",pListIter);
- while (pListIter->GetNextString(pCookie) == HXR_OK)
- {
- mOwner->SetCookie(pCookie);
- HX_RELEASE(pCookie);
- }
- HX_RELEASE(pListIter);
- }
- HX_RELEASE(pKeyValueList);
- m_pRequest->SetResponseHeaders(pResponseHeaders);
- // notify the source file header is ready
- mOwner->FileHeaderReady(pFileHeader);
- UINT32 ulNumHeaders = (UINT32) pHeaderList->GetCount();
- HX_ASSERT(m_pStreamInfoList->IsEmpty() == TRUE);
- if (m_pStreamInfoList->IsEmpty() && ulNumHeaders > 0 &&
- ulNumHeaders < m_pStreamInfoList->GetHashTableSize())
- {
- m_pStreamInfoList->InitHashTable(ulNumHeaders);
- }
- CHXSimpleList::Iterator i;
- for (i = pHeaderList->Begin(); i != pHeaderList->End(); ++i)
- {
- IHXValues* pHeader = (IHXValues*)(*i);
- mOwner->HeaderCallback(pHeader);
- if(!m_bIsASMSource)
- {
- // see if there's an ASMRuleBook in the stream header and set
- //flag for QI. only need to get one rulebook to make this TRUE
- IHXBuffer* pRuleBook = NULL;
- pHeader->GetPropertyCString("ASMRuleBook", pRuleBook);
- if(pRuleBook)
- {
- m_bIsASMSource = TRUE;
- pRuleBook->Release();
- }
- }
- /*
- * Need to maintain status for the streams
- */
- HX_RESULT result;
- UINT32 ulStreamNumber = 0;
- UINT32 ulClipBandwidth = 0;
- IHXBuffer* pMimeType = NULL;
- result = pHeader->GetPropertyULONG32("StreamNumber", ulStreamNumber);
- if (result != HXR_OK)
- {
- return;
- }
- pHeader->GetPropertyCString("MimeType", pMimeType);
- pHeader->GetPropertyULONG32("AvgBitRate", ulClipBandwidth);
- RTSP_STREAM_INFO* pStreamInfo = new RTSP_STREAM_INFO;
- pStreamInfo->m_uStreamNumber = (UINT16)ulStreamNumber;
- pStreamInfo->m_ulClipBandwidth = ulClipBandwidth;
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- pStreamInfo->m_pStreamStats = create_statistics((UINT16)ulStreamNumber);
- if (pStreamInfo->m_pStreamStats)
- {
- pStreamInfo->m_pStreamStats->m_pClipBandwidth->SetInt(0);
- if (pMimeType)
- {
- pStreamInfo->m_pStreamStats->m_pMimeType->SetStr((char*)pMimeType->GetBuffer());
- }
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- HX_RELEASE(pMimeType);
- (*m_pStreamInfoList)[ulStreamNumber] = pStreamInfo;
- m_uStreamCount++;
- }
- mReceivedControl = TRUE;
- m_uCurrentStreamCount = m_uStreamCount;
- m_idleState = INIT_SOCKETS_STATE;
- }
- void
- RTSPProtocol::SendControlBuffer(IHXBuffer* pBuffer)
- {
- char* p64Buf = new char[pBuffer->GetSize() * 2 + 4];
- BinTo64((const unsigned char*)pBuffer->GetBuffer(),
- pBuffer->GetSize(), p64Buf);
- m_pProtocolLib->SendSetParameterRequest("DataConvertBuffer", "1",
- "base64", p64Buf);
- delete[] p64Buf;
- }
- UINT16
- RTSPProtocol::GetRDTFeatureLevel(void)
- {
- #if defined(HELIX_FEATURE_RDT)
- if (m_pProtocolLib)
- {
- return ((RTSPClientProtocolExt*)m_pProtocolLib)->GetRDTFeatureLevel();
- }
- else
- #endif /* HELIX_FEATURE_RDT */
- {
- return 0;
- }
- }
- void
- RTSPProtocol::LeavePrefetch(void)
- {
- m_bPrefetch = FALSE;
- if (m_pProtocolLib)
- {
- ((RTSPClientProtocol*)m_pProtocolLib)->LeavePrefetch();
- }
- return;
- }
- void
- RTSPProtocol::EnterFastStart(void)
- {
- m_bFastStart = TRUE;
- if (m_pProtocolLib)
- {
- ((RTSPClientProtocol*)m_pProtocolLib)->EnterFastStart();
- }
- return;
- }
- void
- RTSPProtocol::LeaveFastStart(void)
- {
- m_bFastStart = FALSE;
- if (m_pProtocolLib)
- {
- ((RTSPClientProtocol*)m_pProtocolLib)->LeaveFastStart();
- }
- return;
- }
- /*
- * If this is multicast, make sure to send subscribe msg
- */
- HX_RESULT
- RTSPProtocol::handle_multicast(void)
- {
- #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
- HX_ASSERT(mCurrentTransport == MulticastMode);
- STREAM_INFO* pStreamInfo = NULL;
- IHXBuffer* pRuleBook = NULL;
- for (UINT16 uStrmNum = 0; uStrmNum < m_uStreamCount; uStrmNum++)
- {
- pStreamInfo = NULL;
- if (FAILED(mOwner->GetStreamInfo(uStrmNum, pStreamInfo)))
- {
- return HXR_OK;
- }
- HX_ASSERT(pStreamInfo);
- // If there is an ASMRuleBook, subscription will be done eventually
- // through RTSPClientProtocol::RuleChange()...
- pRuleBook = NULL;
- if (FAILED(pStreamInfo->m_pHeader->GetPropertyCString("ASMRuleBook", pRuleBook)))
- {
- HX_ASSERT(!pRuleBook);
- Subscribe(uStrmNum, 0);
- }
- HX_RELEASE(pRuleBook);
- }
- return HXR_OK;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
- }
- HX_RESULT
- RTSPProtocol::send_setup_request()
- {
- HX_RESULT rc = HXR_OK;
- RTSPTransportType* pTransport = new RTSPTransportType[MAX_TRANSPORT];
- int nTransports = 0;
- switch (mCurrentTransport)
- {
- /*
- * Port is omitted here, the transport layer will pick it.
- */
- #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
- case MulticastMode:
- if (!m_bUseRTP)
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_MCAST;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_UDP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_UDP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_UDP;
- pTransport[nTransports++].m_sPort = 0;
- if (m_ulTransportPrefMask & ATTEMPT_TCP)
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_TCP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_TCP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
- pTransport[nTransports++].m_sPort = 0;
- }
- }
- else
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_UDP;
- pTransport[nTransports++].m_sPort = 0;
- if (m_ulTransportPrefMask & ATTEMPT_TCP)
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
- pTransport[nTransports++].m_sPort = 0;
- }
- }
- // tell the owner that we are using multicast...
- // this is needed to display it on the stats dialog...
- mOwner->TransportStarted(MulticastMode);
- break;
- #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
- case UDPMode:
- if(!m_bUseRTP)
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_UDP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_UDP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_UDP;
- pTransport[nTransports++].m_sPort = 0;
- if (m_ulTransportPrefMask & ATTEMPT_TCP)
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_TCP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_TCP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
- pTransport[nTransports++].m_sPort = 0;
- }
- }
- else
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_UDP;
- pTransport[nTransports++].m_sPort = 0;
- if (m_ulTransportPrefMask & ATTEMPT_TCP)
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
- pTransport[nTransports++].m_sPort = 0;
- }
- }
- // tell the owner that we are using UDP...
- // this is needed to display it on the stats dialog...
- mOwner->TransportStarted(UDPMode);
- break;
- case TCPMode:
- if(!m_bUseRTP)
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_TCP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_TCP;
- pTransport[nTransports++].m_sPort = 0;
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
- pTransport[nTransports++].m_sPort = 0;
- }
- else
- {
- pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
- pTransport[nTransports++].m_sPort = 0;
- }
- // tell the owner that we are using TCPt...
- // this is needed to display it on the stats dialog...
- if (m_bHTTPOnly)
- {
- mOwner->TransportStarted(HTTPCloakMode);
- }
- else
- {
- mOwner->TransportStarted(TCPMode);
- }
- break;
- default:
- HX_VECTOR_DELETE(pTransport);
- #if defined(_DEBUG) && defined(DEBUG_LOG_INFO)
- HXStaticStatLog::StatPrintf("SetTransport::wrong mode %dn", mCurrentTransport);
- #endif
- return HXR_FAIL;
- }
- HX_ASSERT(nTransports <= MAX_TRANSPORT);
- // look for a cookie...
- // If we use pRequsetHeaders straight from m_pRequest, it will contain a
- // whole bunch of stuff that we don't need. SO, just extract the "Cookie"
- // and create a new header right here. If you need other headers, we might
- // need to come up with a better loginc.
- IHXValues* pRequestHeaders = NULL;
- IHXBuffer* pCookie = NULL;
- if (SUCCEEDED(m_pRequest->GetRequestHeaders(pRequestHeaders)))
- {
- pRequestHeaders->GetPropertyCString("Cookie", pCookie);
- HX_RELEASE(pRequestHeaders);
- if (pCookie)
- {
- pRequestHeaders = new CHXHeader();
- pRequestHeaders->AddRef();
- pRequestHeaders->SetPropertyCString("Cookie", pCookie);
- HX_RELEASE(pCookie);
- }
- }
- rc = m_pProtocolLib->SendSetupRequest(pTransport, nTransports, pRequestHeaders);
- HX_RELEASE(pRequestHeaders);
- HX_VECTOR_DELETE(pTransport);
- return rc;
- }
- STDMETHODIMP
- RTSPProtocol::HandleStreamRecordDescriptionResponse
- (
- HX_RESULT status,
- IHXValues* pResponseHeaders
- )
- {
- return HXR_NOTIMPL;
- }
- STDMETHODIMP
- RTSPProtocol::HandleSetupResponse
- (
- HX_RESULT status
- )
- {
- if (status != HXR_OK)
- {
- /*
- * XXX...Need to get proper errors from protocol library
- */
- mOwner->ReportError(status);
- return status;
- }
- switch(m_pProtocolLib->GetProtocolType())
- {
- case 1:
- mOwner->TransportStarted(MulticastMode);
- #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
- // OK, this is multicast for sure...Make sure to send subscription.
- handle_multicast();
- #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
- break;
- case 2:
- mOwner->TransportStarted(UDPMode);
- break;
- case 3:
- // notify that the server has selected TCP over UDP
- // when the player supports both
- if (!m_bHTTPOnly &&
- mCurrentTransport != TCPMode &&
- HXR_OK == mOwner->TransportStarted(TCPMode))
- {
- mOwner->TransportSucceeded(TCPMode, 0);
- }
- /* No need to report TCP success
- * We may be in TCP/HTTP Cloaking mode
- */
- break;
- default:
- HX_ASSERT(FALSE);
- break;
- }
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- /*
- * Must wait until transport is established before initializing
- * statistics
- */
- CHXMapLongToObj::Iterator i;
- for (i = m_pStreamInfoList->Begin(); i != m_pStreamInfoList->End(); ++i)
- {
- RTSP_STREAM_INFO* pStreamInfo = (RTSP_STREAM_INFO*)(*i);
- if (m_pProtocolLib)
- {
- ((RTSPClientProtocol*)m_pProtocolLib)->SetStatistics(pStreamInfo->m_uStreamNumber,
- pStreamInfo->m_pStreamStats);
- }
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- mOwner->Initialize();
- // return m_pProtocolLib->SendPlayRequest(RTSP_PLAY_RANGE_BLANK, RTSP_PLAY_RANGE_BLANK, 0);
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::HandlePlayResponse
- (
- HX_RESULT status
- )
- {
- if (status != HXR_OK)
- {
- /*
- * XXX...Need to get proper errors from protocol library
- */
- mOwner->ReportError(status); //ConvertHResultToHXError(status));
- return status;
- }
- /* Mark the current state as Playing ONLY if we have called resume */
- if (!m_bIsFirstResume)
- {
- m_bPlaying = TRUE;
- // Start Waiting for data..
- mOwner->StartDataWait();
- }
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::HandleRecordResponse
- (
- HX_RESULT status
- )
- {
- return HXR_NOTIMPL;
- }
- STDMETHODIMP
- RTSPProtocol::HandleTeardownResponse
- (
- HX_RESULT status
- )
- {
- AddRef();
- if (m_pProtocolLib)
- {
- m_pProtocolLib->Done();
- m_pProtocolLib->Release();
- m_pProtocolLib = 0;
- }
- Release();
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::HandleSetParameterRequest
- (
- UINT32 lParamType,
- const char* pParamName,
- IHXBuffer* pParamValue
- )
- {
- IHXPlayer* pPlayer;
- IHXBandwidthManager * pBWM;
- if(!strcmp(pParamName,"MaximumASMBandwidth") &&
- (HXR_OK == mOwner->GetPlayer(pPlayer)) &&
- (HXR_OK == pPlayer->QueryInterface(IID_IHXBandwidthManager,
- (void **)&pBWM)))
- {
- pBWM->ChangeBW((UINT32)atoi((const char *)pParamValue->GetBuffer()),
- mOwner);
- return HXR_OK;
- }
- #if defined(HELIX_FEATURE_REVERTER)
- else if (!strcmp(pParamName, "DataConvertBuffer"))
- {
- m_pDataRevert->ControlBufferReady(pParamValue);
- return HXR_OK;
- }
- #endif /* HELIX_FEATURE_REVERTER */
- return HXR_NOTIMPL;
- }
- STDMETHODIMP
- RTSPProtocol::HandleSetParameterRequest(const char* pParamName,
- const char* pParamValue, const char* pContent)
- {
- #if defined(HELIX_FEATURE_REVERTER)
- if (!strcmp(pParamName, "DataConvertBuffer"))
- {
- IHXBuffer* pBuffer = new CHXBuffer();
- int contentLen = strlen(pContent);
- pBuffer->SetSize(contentLen);
- int offset = BinFrom64(pContent, contentLen,
- (unsigned char*)pBuffer->GetBuffer());
- pBuffer->SetSize(offset);
- pBuffer->AddRef();
- m_pDataRevert->ControlBufferReady(pBuffer);
- pBuffer->Release();
- return HXR_OK;
- }
- #endif /* HELIX_FEATURE_REVERTER */
- return HXR_NOTIMPL;
- }
- STDMETHODIMP
- RTSPProtocol::HandleSetParameterResponse
- (
- HX_RESULT status
- )
- {
- return HXR_OK; // XXXSMP Just return OK for now.
- }
- STDMETHODIMP
- RTSPProtocol::HandleSetParameterResponseWithValues
- (
- HX_RESULT status,
- IHXValues* pValues
- )
- {
- if (status == HXR_OK && pValues)
- {
- UINT32 ulStatsInterval = 0;
- UINT32 ulValue = 0;
- if (pValues->GetPropertyULONG32("UpdateStatsInterval", ulStatsInterval) == HXR_OK)
- {
- ulStatsInterval = ulStatsInterval * 1000;
- // ulStatsInterval = 0 to disable the stats
- if (ulStatsInterval && ulStatsInterval < MINIMUM_STATS_INTERVAL)
- {
- ulStatsInterval = MINIMUM_STATS_INTERVAL;
- }
- mOwner->SetOption(HX_STATS_INTERVAL, &ulStatsInterval);
- }
- if (pValues->GetPropertyULONG32("Reconnect", ulValue) == HXR_OK)
- {
- mOwner->SetReconnectInfo(pValues);
- }
- }
- return HandleSetParameterResponse(status);
- }
- STDMETHODIMP
- RTSPProtocol::HandleGetParameterRequest
- (
- UINT32 lParamType,
- const char* pParamName,
- IHXBuffer** pParamValue
- )
- {
- /*
- * XXX...Need to implement
- */
- return HXR_NOTIMPL;
- }
- STDMETHODIMP
- RTSPProtocol::HandleGetParameterResponse
- (
- HX_RESULT status,
- IHXBuffer* pParamValue
- )
- {
- /*
- * XXX...Need to implement
- */
- return HXR_NOTIMPL;
- }
- STDMETHODIMP
- RTSPProtocol::HandleAlertRequest
- (
- HX_RESULT status,
- INT32 lAlertNumber,
- const char* pAlertText
- )
- {
- HX_RESULT theErr = HXR_OK;
- m_idleState = ALERT_STATE;
- m_ulLastAlert = (UINT32)lAlertNumber;
- HX_VECTOR_DELETE(m_pTextBuf);
- if (pAlertText)
- {
- m_pTextBuf = new char[::strlen(pAlertText) + 1];
- if(!m_pTextBuf)
- {
- theErr = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- strcpy(m_pTextBuf, pAlertText); /* Flawfinder: ignore */
- }
- cleanup:
- // Clear the authentication cache
- if (m_pRegistry)
- {
- m_pRegistry->DeleteByName("CredCache");
- }
- return theErr;
- }
- STDMETHODIMP
- RTSPProtocol::HandleUseProxyRequest
- (
- const char* pProxyURL
- )
- {
- HX_RESULT rc = HXR_OK;
- if(!pProxyURL)
- {
- mOwner->ReportError(HXR_DNR);
- }
- else
- {
- char* pProxyHost = NULL;
- UINT32 ulProxyPort = 0;
- // parse host name, port
- CHXURL proxyURL(pProxyURL);
- IHXValues* pProxyURLProps = proxyURL.GetProperties();
- IHXBuffer* pBuffer = NULL;
- if(HXR_OK == pProxyURLProps->GetPropertyBuffer(PROPERTY_HOST, pBuffer))
- {
- pProxyHost = new char[pBuffer->GetSize()+1];
- strcpy(pProxyHost, (char*)pBuffer->GetBuffer()); /* Flawfinder: ignore */
- HX_RELEASE(pBuffer);
- }
- pProxyURLProps->GetPropertyULONG32(PROPERTY_PORT, ulProxyPort);
- HX_RELEASE(pProxyURLProps);
- if(pProxyHost)
- {
- initialize_members();
- set_proxy(pProxyHost, (UINT16)ulProxyPort);
- // copy host/path so setup doesn't override
- char* pHost = new_string(mHost);
- char* pPath = new_string(mPath);
- rc = setup(pHost, pPath, mPort, mLossCorrection,
- m_bHTTPOnly, m_bSDPInitiated, mCloakPort);
- delete[] pHost;
- delete[] pPath;
- }
- delete[] pProxyHost;
- }
- return rc;
- }
- STDMETHODIMP
- RTSPProtocol::HandleRedirectRequest
- (
- const char* pURL,
- UINT32 msFromNow
- )
- {
- HX_RESULT rc = HXR_OK;
- char* pHostStr = NULL;
- char* pResource = NULL;
- UINT32 ulPort = 0;
- IHXValues* pHeader = NULL;
- if(pURL)
- {
- CHXURL urlObj(pURL);
- pHeader = urlObj.GetProperties();
- IHXBuffer* pBuffer = 0;
- if (HXR_OK != pHeader->GetPropertyBuffer(PROPERTY_HOST, pBuffer))
- {
- rc = HXR_FAILED;
- goto cleanup;
- }
- pHostStr = new char[pBuffer->GetSize()+1];
- strcpy(pHostStr, (char*)pBuffer->GetBuffer()); /* Flawfinder: ignore */
- pBuffer->Release();
- if (HXR_OK != pHeader->GetPropertyBuffer(PROPERTY_RESOURCE, pBuffer))
- {
- rc = HXR_FAILED;
- goto cleanup;
- }
- pResource = (char*)pBuffer->GetBuffer();
- ulPort = 0;
- pHeader->GetPropertyULONG32(PROPERTY_PORT, ulPort);
- mOwner->SetRedirectURL(pHostStr, (UINT16)ulPort, pResource, &urlObj);
- m_LastError = HXR_REDIRECTION;
- pBuffer->Release();
- delete[] pHostStr;
- }
- else
- {
- mOwner->ReportError(HXR_DNR);
- }
- cleanup:
- HX_RELEASE(pHeader);
- return rc;
- }
- STDMETHODIMP
- RTSPProtocol::HandlePacket
- (
- HX_RESULT status,
- const char* pSessionID,
- IHXPacket* pPacket
- )
- {
- if (HXR_OK == status)
- {
- /*
- * These are flushed pre-seek packets
- */
- if (pPacket)
- {
- CHXEvent* pEvent = new CHXEvent(pPacket);
- pEvent->SetPreSeekEvent();
- mOwner->EventReady(pEvent);
- }
- // HandlePacket is called with pPacket=NULL to indicate
- // the liveness of TCP/UDP data connection in order to
- // detect the server timeout
- else
- {
- m_ulLastPacketReceivedTime = HX_GET_TICKCOUNT();
- }
- }
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::HandleProtocolError
- (
- HX_RESULT status
- )
- {
- /*
- * XXX...Need to get proper errors from protocol library
- */
- mOwner->ReportError(status);//ConvertHResultToHXError(status));
- m_bPlaying = FALSE;
- return status;
- }
- STDMETHODIMP
- RTSPProtocol::HandleRTTResponse
- (
- HX_RESULT status,
- const char* pSessionID,
- UINT32 ulSecs,
- UINT32 ulUSecs
- )
- {
- // we handle RTT response in order to detect
- // whether the UDP channel is still alive during PAUSE/RESUME
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::HandleCongestion
- (
- HX_RESULT status,
- const char* pSessionID,
- INT32 xmitMultiplier,
- INT32 recvMultiplier
- )
- {
- return HXR_NOTIMPL;
- }
- STDMETHODIMP
- RTSPProtocol::HandleSourceDone(void)
- {
- mSourceEnd = TRUE;
- if (mOwner)
- {
- mOwner->SetEndOfClip();
- }
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::HandlePrerollChange(THIS_
- RTSPPrerollTypeEnum prerollType,
- UINT32 ulPreroll)
- {
- if (RTSP_PREROLL_PREDECBUFPERIOD == prerollType)
- {
- // Handle 3GPP 26.234 Annex G x-initpredecbufperiod field
- // This field only updates the preroll for video streams
- // Look through all the streams
- for (UINT16 uStrmNum = 0; uStrmNum < m_uStreamCount; uStrmNum++)
- {
- STREAM_INFO* pStreamInfo = NULL;
- IHXBuffer* pMimeType = NULL;
- // Look for video streams
- if ((HXR_OK == mOwner->GetStreamInfo(uStrmNum, pStreamInfo)) &&
- (pStreamInfo->m_pHeader) &&
- (HXR_OK == pStreamInfo->m_pHeader->GetPropertyCString("Mimetype",
- pMimeType)) &&
- (!strncasecmp("video/", (char*)pMimeType->GetBuffer(), 6)))
- {
- // Update the preroll value
- pStreamInfo->BufferingState().UpdatePreroll(ulPreroll);
- }
- HX_RELEASE(pMimeType);
- }
- }
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::HandleStreamDone
- (
- HX_RESULT status,
- UINT16 uStreamNumber
- )
- {
- STREAM_INFO* pStreamInfo;
- if (HXR_OK != mOwner->GetStreamInfo(uStreamNumber, pStreamInfo))
- {
- return HXR_FAIL;
- }
- HX_ASSERT(!pStreamInfo->m_bSrcStreamDone);
- if (!pStreamInfo->m_bSrcStreamDone)
- {
- pStreamInfo->m_bSrcStreamDone = TRUE;
- m_uCurrentStreamCount--;
- if (!m_uCurrentStreamCount)
- {
- mOwner->SetEndOfClip();
- }
- }
- return HXR_OK;
- }
- STDMETHODIMP
- RTSPProtocol::GetStatus
- (
- REF(UINT16) uStatusCode,
- REF(IHXBuffer*) pStatusDesc,
- REF(UINT16) ulPercentDone
- )
- {
- // XXX HP
- // we no longer care about the buffering at the transport layer
- // playback starts as soon as we get enough data at BufferManager
- #if 0
- /*
- * XXX...This needs to be properly implemented
- */
- CHXBuffer* pStatus = NULL;
- IUnknown* pContext = NULL;
- IHXClientEngine* pEngine = NULL;
- uStatusCode = HX_STATUS_READY;
- ulPercentDone = 100;
- pStatusDesc = NULL;
- if (!m_bConnectDone)
- {
- uStatusCode = HX_STATUS_CONTACTING;
- ulPercentDone = 0;
- mOwner->GetContext(pContext);
- #if defined(HELIX_FEATURE_RESOURCEMGR)
- if (pContext &&
- HXR_OK == pContext->QueryInterface(IID_IHXClientEngine, (void**)&pEngine))
- {
- pStatus = ((HXClientEngine *)pEngine)->GetResMgr()->GetMiscString(IDS_STATUS_CONTACTING);
- }
- pStatusDesc = new CHXBuffer;
- if (!pStatusDesc)
- {
- return HXR_OUTOFMEMORY;
- }
- pStatusDesc->AddRef();
- CHXString statusDesc = "";
- if (pStatus)
- {
- statusDesc += (const char*) pStatus->GetBuffer();
- statusDesc += " ";
- }
- statusDesc += mHost;
- statusDesc += "...";
- pStatusDesc->Set((UCHAR*)(const char*) statusDesc,
- strlen((const char*)statusDesc)+1);
- HX_RELEASE(pStatus);
- HX_RELEASE(pEngine);
- #endif /* HELIX_FEATURE_RESOURCEMGR */
- HX_RELEASE(pContext);
- return HXR_OK;
- }
- else if (m_pPendingStatus)
- {
- return m_pPendingStatus->GetStatus(uStatusCode,
- pStatusDesc,
- ulPercentDone);
- }
- else
- {
- uStatusCode = HX_STATUS_BUFFERING;
- ulPercentDone = 0;
- }
- return HXR_OK;
- #else
- return HXR_NOTIMPL;
- #endif
- }
- #if defined(HELIX_FEATURE_STATS)
- /************************************************************************
- * Method:
- * IHXStatistics::InitializeStatistics
- * Purpose:
- * Pass registry ID to the caller
- */
- STDMETHODIMP
- RTSPProtocol::InitializeStatistics
- (
- UINT32 /*IN*/ ulRegistryID
- )
- {
- m_ulRegistryID = ulRegistryID;
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXStatistics::UpdateStatistics
- * Purpose:
- * Notify the user to updates its statistics registry
- */
- STDMETHODIMP
- RTSPProtocol::UpdateStatistics()
- {
- if (!m_pStatistics)
- {
- return HXR_FAIL;
- }
- return m_pStatistics->UpdateStatistics();
- }
- #endif /* HELIX_FEATURE_STATS */
- HX_RESULT
- RTSPProtocol::GetStreamStatistics
- (
- ULONG32 ulStreamNumber,
- STREAM_STATS** ppStreamStats
- )
- {
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- RTSP_STREAM_INFO* pStreamInfo;
- if (!m_pStreamInfoList->Lookup(ulStreamNumber, (void*&)pStreamInfo))
- {
- *ppStreamStats = NULL;
- return HXR_FAIL;
- }
- *ppStreamStats = pStreamInfo->m_pStreamStats;
- return HXR_OK;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- }
- HX_RESULT
- RTSPProtocol::UpdateRegistry(UINT32 ulStreamNumber,
- UINT32 ulRegistryID)
- {
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- HX_RESULT result = HXR_OK;
- if (!m_pRegistry)
- {
- return HXR_FAIL;
- }
- CHXMapLongToObj::Iterator i;
- for (i = m_pStreamInfoList->Begin(); i != m_pStreamInfoList->End(); ++i)
- {
- RTSP_STREAM_INFO* pStreamInfo = (RTSP_STREAM_INFO*)(*i);
- if (pStreamInfo->m_uStreamNumber == (UINT16)ulStreamNumber)
- {
- STREAM_STATS* pTmpStreamStats = new STREAM_STATS(m_pRegistry, ulRegistryID);
- *pTmpStreamStats = *pStreamInfo->m_pStreamStats;
- HX_DELETE(pStreamInfo->m_pStreamStats);
- pStreamInfo->m_pStreamStats = pTmpStreamStats;
- if (m_pProtocolLib)
- {
- ((RTSPClientProtocol*)m_pProtocolLib)->SetStatistics(pStreamInfo->m_uStreamNumber,
- pStreamInfo->m_pStreamStats);
- }
- break;
- }
- }
- return result;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- }
- STDMETHODIMP
- RTSPProtocol::RuleChange(REF(CHXSimpleList) pList)
- {
- return m_pProtocolLib->RuleChange(&pList);
- }
- /*
- * IHXASMSource methods
- */
- /************************************************************************
- * 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
- * in rmartsp about this.
- */
- const UINT8 pRequireStr[] = "com.real.load-test-password-enabled";
- IHXBuffer* pReq = new CHXBuffer();
- pReq->AddRef();
- pReq->Set(pRequireStr, sizeof(pRequireStr) + 1);
- m_pIDInfo->SetPropertyCString("Require", pReq);
- pReq->Release();
- }
- #endif
- if (pRegionData)
- {
- m_pIDInfo->SetPropertyCString("RegionData", pRegionData);
- }
- HX_RELEASE(pGUID);
- HX_RELEASE(pClientID);
- HX_RELEASE(pRegionData);
- HX_RELEASE(pPragma);
- /*
- * XXX...This had better get fixed under full IRMA (should
- * be done with QueryInterface)
- */
- RTSPClientProtocol* pClientProtocol = NULL;
- #if defined(HELIX_FEATURE_RDT)
- pClientProtocol = new RTSPClientProtocolExt();
- #else
- pClientProtocol = new RTSPClientProtocol();
- #endif /* HELIX_FEATURE_RDT */
- m_pProtocolLib = (IHXRTSPClientProtocol*)pClientProtocol;
- if (!m_pProtocolLib)
- {
- return HXR_OUTOFMEMORY;
- }
- m_pProtocolLib->AddRef();
- if (m_bHTTPOnly)
- {
- IHXBuffer* pBuffer = NULL;
- const char* pszURL = NULL;
- pCloakValues = new CHXHeader();
- pCloakValues->AddRef();
- if (HXR_OK == m_pIDInfo->GetPropertyCString("ClientID", pBuffer))
- {
- pCloakValues->SetPropertyCString("ClientID", pBuffer);
- }
- HX_RELEASE(pBuffer);
- if (m_pRequest)
- {
- if (HXR_OK == m_pRequest->GetURL(pszURL))
- {
- pBuffer = new CHXBuffer();
- pBuffer->AddRef();
- pBuffer->Set((const UCHAR*)pszURL, strlen(pszURL)+1);
- pCloakValues->SetPropertyCString("url", pBuffer);
- HX_RELEASE(pBuffer);
- }
- if (HXR_OK == m_pRequest->GetRequestHeaders(pRequestHeaders))
- {
- if (HXR_OK == pRequestHeaders->GetPropertyCString("Cookie", pBuffer))
- {
- pCloakValues->SetPropertyCString("Cookie", pBuffer);
- }
- HX_RELEASE(pBuffer);
- }
- HX_RELEASE(pRequestHeaders);
- }
- pClientProtocol->InitCloak(m_pCloakPorts, m_nCloakPorts, pCloakValues);
- HX_RELEASE(pCloakValues);
- }
- if (m_bPrefetch)
- {
- pClientProtocol->EnterPrefetch();
- }
- //USER_AGENT_STRING defined in hxver.h
- CHXString buildVersion = USER_AGENT_STRING +
- CHXString(TARVER_STRING_VERSION) + " (" +
- CHXString(TARVER_STR_PLATFORM) + ")";
- m_pProtocolLib->SetBuildVersion((const char*)buildVersion);
- m_pPendingStatus = m_pProtocolLib->GetPendingStatus();
- m_pStatistics = m_pProtocolLib->GetStatistics();
- // start communication with server
- if(mUseProxy)
- {
- theErr = proxy_hello();
- }
- else
- {
- theErr = server_hello();
- }
- // Start Waiting for control channel..
- mOwner->StartDataWait(TRUE);
- return theErr;
- }
- // these get initialized every time we make a new connection with
- // the server
- void
- RTSPProtocol::initialize_members(void)
- {
- // intialize base class members
- HXProtocol::initialize_members();
- m_bPerfectPlayAllowed = TRUE;
- // release any allocated local resources
- HX_RELEASE(m_pPendingStatus);
- HX_RELEASE(m_pStatistics);
- HX_RELEASE(m_pIDInfo);
- if (m_pProtocolLib)
- {
- m_pProtocolLib->Done();
- HX_RELEASE(m_pProtocolLib);
- }
- CHXMapLongToObj::Iterator i;
- for (i = m_pStreamInfoList->Begin(); i != m_pStreamInfoList->End(); ++i)
- {
- RTSP_STREAM_INFO* pStreamInfo = (RTSP_STREAM_INFO*)(*i);
- HX_DELETE(pStreamInfo);
- }
- m_pStreamInfoList->RemoveAll();
- }
- HX_RESULT
- RTSPProtocol::seek
- (
- ULONG32 posArg,
- ULONG32 posArg2,
- UINT16 seekFrom
- )
- {
- if (IsLive())
- {
- return m_pProtocolLib->SeekFlush();
- }
- HX_RESULT theErr = HXR_OK;
- m_uCurrentStreamCount = m_uStreamCount;
- mSourceEnd = FALSE;
- m_bPendingSeek = TRUE;
- m_ulSeekPos1 = posArg;
- m_ulSeekPos2 = posArg2;
- return theErr;
- }
- HX_RESULT
- RTSPProtocol::resume(UINT32 ulEndTime)
- {
- if (m_bPendingSeek)
- {
- m_bPendingSeek = FALSE;
- m_bIsFirstResume = FALSE;
- m_bPaused = FALSE;
- if (mCurrentTransport == UDPMode)
- {
- m_bAreResuming = TRUE;
- mOwner->StartDataWait();
- }
- return m_pProtocolLib->SendPlayRequest(m_ulSeekPos1, (!mLiveStream && ulEndTime > 0) ? ulEndTime : m_ulSeekPos2, 0);
- }
- if (m_bIsFirstResume)
- {
- m_bIsFirstResume = FALSE;
- m_bPaused = FALSE;
- return m_pProtocolLib->SendPlayRequest(0, (!mLiveStream && ulEndTime > 0) ? ulEndTime : RTSP_PLAY_RANGE_BLANK, 0);
- }
- else if (mCurrentTransport == UDPMode)
- {
- m_bAreResuming = TRUE;
- mOwner->StartDataWait();
- }
- if (!m_bPaused)
- {
- return HXR_OK;
- }
- m_bPaused = FALSE;
- return m_pProtocolLib->SendResumeRequest();
- }
- HX_RESULT
- RTSPProtocol::stop(void)
- {
- if (m_pProtocolLib)
- {
- m_pProtocolLib->SendTeardownRequest();
- m_pProtocolLib->Done();
- m_pProtocolLib->Release();
- m_pProtocolLib = 0;
- }
- HXProtocol::stop();
- #if defined(HELIX_FEATURE_REVERTER)
- if (m_pDataRevert)
- {
- m_pDataRevert->Done();
- HX_RELEASE(m_pDataRevert);
- }
- #endif /* HELIX_FEATURE_REVERTER */
- CHXMapLongToObj::Iterator i;
- for (i = m_pStreamInfoList->Begin(); i != m_pStreamInfoList->End(); ++i)
- {
- RTSP_STREAM_INFO* pStreamInfo = (RTSP_STREAM_INFO*)(*i);
- HX_DELETE(pStreamInfo);
- }
- m_pStreamInfoList->RemoveAll();
- m_bReceivedData = FALSE;
- m_bPlaying = FALSE;
- m_uStreamCount = 0;
- return HXR_OK;
- }
- HX_RESULT
- RTSPProtocol::pause(void)
- {
- HX_RESULT rc = HXR_OK;
- // properly set the pause state for server timeout
- // calculation
- if (m_bIsFirstResume)
- {
- m_bPaused = TRUE;
- }
- else if (!m_bPaused)
- {
- m_bPaused = TRUE;
- rc = m_pProtocolLib->SendPauseRequest();
- }
- return rc;
- }
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- void
- RTSPProtocol::send_statistics
- (
- UINT32 ulStatsMask
- )
- {
- UINT32 ulStats123 = 0;
- UINT32 ulStats4 = 0;
- char* pszStats123 = NULL;
- char* pszStats4 = NULL;
- char* pszStats = NULL;
- prepare_statistics(ulStatsMask, pszStats123);
- if (pszStats123)
- {
- ulStats123 = strlen(pszStats123);
- }
- if (ulStatsMask & 8UL)
- {
- prepare_stats4(pszStats4, ulStats4);
- }
- if (pszStats123 && pszStats4)
- {
- pszStats = new char[ulStats123 + ulStats4 + 1];
- strcpy(pszStats, pszStats123); /* Flawfinder: ignore */
- strcat(pszStats, pszStats4); /* Flawfinder: ignore */
- HX_VECTOR_DELETE(pszStats123);
- HX_VECTOR_DELETE(pszStats4);
- }
- else if (pszStats123 && !pszStats4)
- {
- pszStats = pszStats123;
- }
- else if (!pszStats123 && pszStats4)
- {
- pszStats = pszStats4;
- }
- if (pszStats)
- {
- m_pProtocolLib->SendPlayerStats(pszStats);
- }
- HX_VECTOR_DELETE(pszStats);
- return;
- }
- HX_RESULT
- RTSPProtocol::prepare_stats4(char*& pszStats, UINT32& ulStats)
- {
- HX_RESULT rc = HXR_OK;
- UINT32 i = 0;
- UINT32 ulAllocatedBufferSize = MAX_DEFAULT_STATS_SIZE;
- UINT32 ulValue = 0;
- char szRegKeyName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
- char* pszValue = NULL;
- char* pszTempStats = NULL;
- RTSP_STREAM_INFO* pStreamInfo = NULL;
- STREAM_STATS* pStreamStats = NULL;
- IHXBuffer* pParentName = NULL;
- IHXBuffer* pValue = NULL;
- CHXMapLongToObj::Iterator j;
- pszStats = new char[ulAllocatedBufferSize];
- ulStats = 0;
- SafeStrCpy(pszStats, "[Stat4:", MAX_DISPLAY_NAME);
- ulStats += 7;
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, m_uStreamCount, " ", ulStats);
- // per stream stats
- if (m_pStreamInfoList->GetCount())
- {
- for (j = m_pStreamInfoList->Begin(); j != m_pStreamInfoList->End(); ++j)
- {
- pStreamInfo = (RTSP_STREAM_INFO*)(*j);
- pStreamStats = pStreamInfo->m_pStreamStats;
- if (!pStreamStats || !pStreamStats->m_bInitialized)
- {
- continue;
- }
- // mime type
- if (pStreamStats->m_pMimeType &&
- (pszValue = pStreamStats->m_pMimeType->GetStr()))
- {
- ulStats += strlen(pszValue);
- if (ulStats > (ulAllocatedBufferSize - MAX_DISPLAY_NAME))
- {
- ulAllocatedBufferSize += MAX_DEFAULT_STATS_SIZE;
- pszTempStats = new char[ulAllocatedBufferSize];
- SafeStrCpy(pszTempStats, pszStats, ulAllocatedBufferSize);
- HX_VECTOR_DELETE(pszStats);
- pszStats = pszTempStats;
- }
- SafeStrCat(pszStats, pszValue, ulAllocatedBufferSize);
- HX_VECTOR_DELETE(pszValue);
- }
- else
- {
- SafeStrCat(pszStats, "N/A", ulAllocatedBufferSize);
- ulStats += 3;
- }
- SafeStrCat(pszStats, "|", ulAllocatedBufferSize);
- ulStats++;
- // codec
- if (HXR_OK == m_pRegistry->GetPropName(pStreamStats->m_pRenderer->m_ulRegistryID, pParentName))
- {
- SafeSprintf(szRegKeyName, MAX_DISPLAY_NAME, "%s.Codec", pParentName->GetBuffer());
- if (HXR_OK == m_pRegistry->GetStrByName(szRegKeyName, pValue) && pValue)
- {
- ulValue = pValue->GetSize();
- pszValue = new char[ulValue+1];
- strcpy(pszValue, (const char*)pValue->GetBuffer()); /* Flawfinder: ignore */
- // replace space with underscore
- for (i = 0; i < ulValue; i++)
- {
- if (pszValue[i] == ' ')
- {
- pszValue[i] = '_';
- }
- }
- }
- HX_RELEASE(pValue);
- }
- HX_RELEASE(pParentName);
- if (pszValue)
- {
- ulStats += strlen(pszValue);
- if (ulStats > (ulAllocatedBufferSize - MAX_DISPLAY_NAME))
- {
- ulAllocatedBufferSize += MAX_DEFAULT_STATS_SIZE;
- pszTempStats = new char[ulAllocatedBufferSize];
- SafeStrCpy(pszTempStats, pszStats, ulAllocatedBufferSize);
- HX_VECTOR_DELETE(pszStats);
- pszStats = pszTempStats;
- }
- SafeStrCat(pszStats, pszValue, ulAllocatedBufferSize);
- HX_VECTOR_DELETE(pszValue);
- }
- else
- {
- SafeStrCat(pszStats, "N/A", ulAllocatedBufferSize);
- ulStats += 3;
- }
- SafeStrCat(pszStats, "|", ulAllocatedBufferSize);
- ulStats++;
- // bandwidth stats
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pReceived->GetInt(), "|", ulStats);
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pLost->GetInt(), "|", ulStats);
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pReceived->GetInt() - pStreamStats->m_pNormal->GetInt(), "|", ulStats);
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pAvgBandwidth->GetInt(), "|", ulStats);
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pCurBandwidth->GetInt(), "|", ulStats);
- SafeStrCat(pszStats, ";", ulAllocatedBufferSize);
- ulStats++;
- }
- }
- else
- {
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, 0, " ", ulStats);
- }
- pszStats[ulStats-1] = ' ';
- // Transport
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, mCurrentTransport, " ", ulStats);
- // TurboPlay
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, m_bFastStart, "|", ulStats);
- if (m_bFastStart)
- {
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->m_turboPlayStats.ulAcceleratedBW, "|", ulStats);
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->m_turboPlayStats.ulBufferedTime, "|", ulStats);
- }
- else
- {
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->m_turboPlayStats.tpOffReason, "|", ulStats);
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, 0, "|", ulStats);
- }
- SafeStrCat(pszStats, " ", ulAllocatedBufferSize);
- ulStats++;
- // Startup latency, first data packet arrives!
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->GetFirstDataArriveTime(), " ", ulStats);
- // Reason of clip end
- statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->m_srcEndCode, NULL, ulStats);
- SafeStrCat(pszStats, "]", ulAllocatedBufferSize);
- ulStats++;
- return rc;
- }
- STREAM_STATS*
- RTSPProtocol::create_statistics(UINT16 uStreamNumber)
- {
- HX_RESULT result = HXR_OK;
- STREAM_STATS* pStats = NULL;
- IHXBuffer* pParentName = NULL;
- CHAR RegKeyName[MAX_DISPLAY_NAME] = {0};
- if (!m_pRegistry)
- {
- goto cleanup;
- }
- if (HXR_OK == m_pRegistry->GetPropName(m_ulRegistryID, pParentName) && pParentName)
- {
- SafeSprintf(RegKeyName, MAX_DISPLAY_NAME, "%s.Stream%d", pParentName->GetBuffer(), uStreamNumber);
- /*
- * This the location where the first STREAM_STATS for the stream
- * is instantiated. The protocol library may make another to fill
- * the fields in the registry, but it must use the keys created
- * here
- */
- //ASSERT(!m_pRegistry->GetId(RegKeyName));
- UINT32 uStreamId = 0;
- if (!m_pRegistry->GetId(RegKeyName))
- {
- uStreamId = m_pRegistry->AddComp(RegKeyName);
- }
- else
- {
- uStreamId = m_pRegistry->GetId(RegKeyName);
- }
- pStats = new STREAM_STATS(m_pRegistry, uStreamId);
- }
- HX_RELEASE(pParentName);
- cleanup:
- return pStats;
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- BOOL
- RTSPProtocol::IsSourceDone(void)
- {
- return mSourceEnd;
- }
- HX_RESULT
- RTSPProtocol::GetCurrentBuffering(UINT16 uStreamNumber,
- INT64& llLowestTimestamp,
- INT64& llHighestTimestamp,
- UINT32& ulNumBytes,
- BOOL& bDone)
- {
- HX_RESULT theErr = HXR_OK;
- llLowestTimestamp = 0;
- llHighestTimestamp = 0;
- ulNumBytes = 0;
- bDone = FALSE;
- if (m_pProtocolLib)
- {
- theErr = m_pProtocolLib->GetCurrentBuffering(uStreamNumber,
- llLowestTimestamp,
- llHighestTimestamp,
- ulNumBytes,
- bDone);
- if (!theErr && ulNumBytes > 0)
- {
- m_bReceivedData = TRUE;
- }
- }
- return theErr;
- }