hxntsrc.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:179k
- /* ***** 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 ***** */
- #include "hxcom.h"
- #include "hlxclib/stdio.h"
- #if defined (_UNIX) || defined (_WIN16)
- #include <stdlib.h>
- #endif
- #include "hxcomm.h"
- #include "hxplugn.h"
- #include "ihxpckts.h"
- #include "hxpends.h"
- #include "hxfiles.h"
- #include "hxengin.h"
- #include "hxcore.h"
- #include "hxprefs.h"
- #include "hxpref.h"
- #include "hxausvc.h"
- #include "hxasm.h"
- #include "hxauthn.h"
- #include "hxgroup.h"
- #include "hxsmbw.h"
- #include "hxrsdbf.h"
- #include "hxmime.h"
- #include "hxslist.h"
- #include "hxstring.h"
- #include "portaddr.h"
- #include "chxeven.h"
- #include "chxelst.h"
- #include "strminfo.h"
- #include "hxbsrc.h"
- #include "hxsrc.h"
- #include "hxntsrc.h"
- #include "hxstrm.h"
- #include "hxplay.h"
- #include "rtspif.h"
- #include "hxprotocol.h"
- #include "dtrvtcon.h"
- #include "rtspprotocol.h"
- #if defined(HELIX_FEATURE_PNA)
- #include "hxpnapro.h"
- #endif /* HELIX_FEATURE_PNA */
- #include "rmfftype.h"
- #include "prefdefs.h"
- #include "plprefk.h"
- #include "hxtick.h"
- #include "netbyte.h"
- #include "hxcom.h"
- #include "hxstrutl.h"
- #include "ihxpckts.h"
- #include "chxpckts.h"
- #include "hxmap.h"
- #include "hxstat.h"
- #include "hxmangle.h"
- #include "srcinfo.h"
- #include "srcerrs.h"
- #include "errdbg.h"
- #include "ihxcookies.h"
- #include "pacutil.h"
- #if defined(HELIX_FEATURE_NETCHECK)
- #include "netchck.h"
- #endif /* defined(HELIX_FEATURE_NETCHECK) */
- #include "hxrasyn.h"
- #include "hxaudstr.h"
- #include "hxaudses.h"
- #include "verutil.h"
- #include "hxrendr.h"
- #include "hxcleng.h"
- #include "wmbufctl.h"
- #include "fbbufctl.h"
- #include "clntcore.ver"
- #include "hxver.h"
- #include "hxwinver.h"
- #include "hxheap.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- // maximum level of statistics that we wanna send back to the server
- #define MAX_STATS_MASK 15 // value from server is a bit field
- #define MAX_LOGINFO_LENGTH 2048 // maximum of 2K bytes of statistics
- /* RTSP Setup may take a lot ot time */
- #define NEW_DEF_SETTINGS_TIMEOUT 3000
- #define MINIMUM_TIMEOUT 5
- const short int MAX_CLOAK_PORTS = 4;
- const UINT16 g_uCloakPorts[MAX_CLOAK_PORTS] = {80, 8080, 554, 7070};
- #define CLOAKPORT_URL_OPTION "cloakport"
- HXNetSource::HXNetSource() :
- m_bLossCorrection (FALSE)
- , m_pHost (0)
- , m_pPath (NULL)
- , m_pResource (0)
- , m_uPort (0)
- , m_bRTSPProtocol (FALSE)
- , m_pProxy (0)
- , m_uProxyPort (0)
- , m_bUseProxy (FALSE)
- , m_pCloakPortList(NULL)
- , m_nNumberOfCloakPorts(0)
- , m_nCurrPortIdx (0)
- , m_uCurrCloakedPort(0)
- , m_bUseUDPPort (FALSE)
- , m_pProto (0)
- , m_ulStartBuffering (0)
- , m_bSendStatistics (TRUE)
- , m_ulServerTimeOut (90)
- , m_ulConnectionTimeout(DEFAULT_CONN_TIMEOUT)
- , m_bAtInterrupt (FALSE)
- , m_fReBufferPercent ((float)0.)
- , m_pProtocolStatus (0)
- , m_ulMulticastTimeout (NEW_DEF_SETTINGS_TIMEOUT)
- , m_ulUDPTimeout (NEW_DEF_SETTINGS_TIMEOUT)
- , m_ulTCPTimeout(NEW_DEF_SETTINGS_TIMEOUT)
- , m_ulStartDataWait (0)
- , m_ulServerVersion(0)
- , m_ulTransportPrefMask(0)
- , m_bDataWaitStarted(FALSE)
- , m_bConnectionWait(TRUE)
- , m_ulFirstDataArrives (0)
- , m_uProtocolType(unknownProtocol)
- , m_bPerfectPlayPreferenceRead(FALSE)
- , m_bPerfectPlayErrorChecked(FALSE)
- , m_CurrentTransport(UnknownMode)
- , m_PreferredTransport(UnknownMode)
- , m_bServerHasPerfectPlay(FALSE)
- , m_ulSendStatsMask(0)
- , m_ulStatsInterval(0)
- , m_bServerHasTransportSwitching (FALSE)
- , m_bForcePerfectPlay (FALSE)
- , mServerSelRecordSupport(FALSE)
- , mInterframeControlSupport(FALSE)
- , mServerHasBandwidthReport(FALSE)
- , mServerHasFrameControl(FALSE)
- , m_bInRetryMode(FALSE)
- , m_bPushDownSet(FALSE)
- , m_pushDownStatus(PUSHDOWN_NONE)
- , m_bRARVSource(FALSE)
- , m_bRARVSourceVerified(FALSE)
- , m_bBruteForceReconnected(FALSE)
- , m_bBruteForceConnectToBeDone(FALSE)
- , m_lRAStreamNumber(-1)
- , m_pLogInfoList(NULL)
- , m_ulLogInfoLength(0)
- , m_bResendAuthenticationInfo(FALSE)
- , m_bUserHasCalledResume(FALSE)
- , m_bUserHasCalledStartInit(FALSE)
- , m_bTimeBased(FALSE)
- , m_uLastBuffering(0)
- , m_uLastStatusCode(HX_STATUS_BUFFERING)
- , m_bAltURL(FALSE)
- , m_bNoLatency(FALSE)
- , m_bNoLatencySet(FALSE)
- , m_pCookies(NULL)
- , m_pCookies2(NULL)
- , m_ulSeekPendingTime(0)
- , m_bSeekPending(FALSE)
- , m_prefTransportState(PTS_UNKNOWN)
- , m_pPreferredTransport(NULL)
- , m_pPreferredTransportManager(NULL)
- , m_pReconnectCallback(NULL)
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- , m_pStatsCallback(NULL)
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- , m_bAttemptReconnect(TRUE)
- , m_pszReconnectServer(NULL)
- , m_pszReconnectProxy(NULL)
- , m_pszReconnectURL(NULL)
- , m_ulReconnectServerPort(0)
- , m_ulReconnectProxyPort(0)
- , m_pszRedirectServer(NULL)
- , m_pszRedirectResource(NULL)
- , m_pszRedirectURL(NULL)
- , m_ulRedirectServerPort(0)
- , m_pPAC(NULL)
- , m_pPACInfoList(NULL)
- , m_PACInfoPosition(0)
- , m_state(NETSRC_READY)
- , m_pBufferCtl(NULL)
- , m_pWMBufferCtl(NULL)
- {
- HX_TRACE("HXNetSource::HXNetSource");
- memset(m_szUserName, 0, MAX_DISPLAY_NAME);
- memset(m_szPassword, 0, MAX_DISPLAY_NAME);
- }
- HXNetSource::~HXNetSource()
- {
- DoCleanup();
- HX_DELETE(m_pPACInfoList);
- HX_VECTOR_DELETE(m_pHost);
- HX_VECTOR_DELETE(m_pPath);
- HX_VECTOR_DELETE(m_pResource);
- HX_VECTOR_DELETE(m_pCloakPortList);
- HX_VECTOR_DELETE(m_pszReconnectServer);
- HX_VECTOR_DELETE(m_pszReconnectProxy);
- HX_VECTOR_DELETE(m_pszReconnectURL);
- HX_VECTOR_DELETE(m_pszRedirectServer);
- HX_VECTOR_DELETE(m_pszRedirectResource);
- HX_VECTOR_DELETE(m_pszRedirectURL);
- HX_RELEASE(m_pProtocolStatus);
- HX_RELEASE(m_pCookies);
- HX_RELEASE(m_pCookies2);
- HX_RELEASE(m_pPreferredTransport);
- HX_RELEASE(m_pPreferredTransportManager);
- HX_RELEASE(m_pPAC);
- HX_TRACE("HXNetSource::~HXNetSource");
- }
- HX_RESULT
- HXNetSource::DoCleanup(EndCode endCode)
- {
- HX_TRACE("HXNetSource::DoCleanup");
- if (m_pBufferCtl)
- {
- m_pBufferCtl->Close();
- }
- HX_RELEASE(m_pBufferCtl);
- HX_RELEASE(m_pWMBufferCtl);
- m_srcEndCode = endCode;
- #if defined(HELIX_FEATURE_PAC)
- if (NETSRC_PACPENDING == m_state)
- {
- m_state = NETSRC_READY;
- m_pPAC->AbortProxyInfo(this);
- }
- #endif /* HELIX_FEATURE_PAC */
- #if defined(HELIX_FEATURE_SMARTERNETWORK)
- // notify the failure of transport detection
- if (m_pPreferredTransport)
- {
- m_pPreferredTransport->RemoveTransportSink(this);
- if (m_pPlayer && m_pHost && m_prefTransportState != PTS_READY)
- {
- m_pPreferredTransport->RemoveTransport();
- HX_RELEASE(m_pPreferredTransport);
- }
- }
- #endif /* HELIX_FEATURE_SMARTERNETWORK */
- // sends the stats
- if (m_pProto)
- {
- // log stop action
- LogInformation("STOP", NULL);
- if (m_bSendStatistics)
- {
- m_pProto->send_statistics(m_ulSendStatsMask);
- }
- }
- HXSource::DoCleanup(endCode);
- cleanup_proxy();
- /* UnRegister any previously registered source */
- if (m_pSourceInfo)
- {
- m_pSourceInfo->UnRegister();
- }
- // Close down the net connection
- if (m_pProto)
- {
- m_pProto->stop();
- HX_RELEASE (m_pProto);
- }
- // cleanup the log list
- if (m_pLogInfoList)
- {
- while (m_pLogInfoList->GetCount() > 0)
- {
- char* pszInfo = (char*) m_pLogInfoList->RemoveHead();
- delete [] pszInfo;
- }
- HX_DELETE(m_pLogInfoList);
- }
- if (m_pReconnectCallback)
- {
- m_pReconnectCallback->CancelCallback();
- HX_RELEASE(m_pReconnectCallback);
- }
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- if (m_pStatsCallback)
- {
- m_pStatsCallback->CancelCallback();
- HX_RELEASE(m_pStatsCallback);
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- #if defined(HELIX_FEATURE_PAC)
- while (m_pPACInfoList && m_pPACInfoList->GetCount())
- {
- PACInfo* pPACInfo = (PACInfo*)m_pPACInfoList->RemoveHead();
- HX_DELETE(pPACInfo);
- }
- #endif /* HELIX_FEATURE_PAC */
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::QueryInterface
- // Purpose:
- // Implement this to export the interfaces supported by your
- // object.
- //
- STDMETHODIMP
- HXNetSource::QueryInterface(REFIID riid, void** ppvObj)
- {
- if (HXSource::QueryInterface(riid, ppvObj) == HXR_OK)
- {
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXRegistryID))
- {
- AddRef();
- *ppvObj = (IHXRegistryID*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXPreferredTransportSink))
- {
- AddRef();
- *ppvObj = (IHXPreferredTransportSink*)this;
- return HXR_OK;
- }
- else if (m_pBufferCtl &&
- m_pBufferCtl->QueryInterface(riid, ppvObj) == HXR_OK)
- {
- return HXR_OK;
- }
- else if (m_pProto &&
- m_pProto->QueryInterface(riid, ppvObj) == HXR_OK)
- {
- return HXR_OK;
- }
- else if (m_pPlayer &&
- m_pPlayer->QueryInterface(riid, ppvObj) == HXR_OK)
- {
- return HXR_OK;
- }
- // we don't have m_pPlayer during AutoConfig
- else if (m_pEngine &&
- m_pEngine->QueryInterface(riid, ppvObj) == HXR_OK)
- {
- 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)
- HXNetSource::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::Release
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32)
- HXNetSource::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- HX_RESULT
- HXNetSource::Setup(const char* host,
- const char* resource,
- UINT16 port,
- BOOL LossCorrection,
- const CHXURL* pURL,
- BOOL bAltURL)
- {
- HX_TRACE("HXNetSource::Setup");
- HX_RESULT theErr = HXR_OK;
- IHXValues* pValues = NULL;
- IHXValues* pRequestHeaders = NULL;
- IHXBuffer* pBuffer = NULL;
- IHXBuffer* pPlayerCookies = NULL;
- if (!m_bBruteForceReconnected &&
- !m_bReSetup)
- {
- theErr = SetupRegistry();
- if (HXR_OK != theErr)
- {
- goto cleanup;
- }
- }
- if (!m_bReSetup)
- {
- m_ulOriginalDelay = m_ulDelay;
- }
- // Remember whether or not we ask for loss correction!
- m_bLossCorrection = LossCorrection;
- // delete protocol object if one exists
- HX_RELEASE (m_pProto);
- m_uProtocolType = pURL->GetProtocol();
- if (rtspProtocol == m_uProtocolType || helixSDPProtocol == m_uProtocolType)
- {
- m_bRTSPProtocol = TRUE;
- m_ulSendStatsMask = MAX_STATS_MASK;
- /* Perfect Play Always supported iin RTSP,
- * till we add some preference to disable it.
- */
- BOOL bSupported = TRUE;
- SetOption(HX_PERFECTPLAY_SUPPORTED, &bSupported);
- }
- if (helixSDPProtocol != m_uProtocolType)
- {
- // get out immediately if we have bogus parameters
- if(!host || !*host)
- {
- theErr = HXR_INVALID_URL_HOST;
- goto cleanup;
- }
- if(!theErr && (!resource || !*resource))
- {
- theErr = HXR_INVALID_URL_PATH;
- goto cleanup;
- }
- if (m_pHost != host)
- {
- HX_VECTOR_DELETE(m_pHost);
- m_pHost = new char[::strlen(host) + 1];
- if (!m_pHost)
- {
- theErr = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- ::strcpy(m_pHost, host); /* Flawfinder: ignore */
- }
- if(m_pResource != resource)
- {
- HX_VECTOR_DELETE(m_pResource);
- m_pResource = new char[::strlen(resource) + 1];
- if (!m_pResource)
- {
- theErr = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- ::strcpy(m_pResource, resource); /* Flawfinder: ignore */
- }
- }
- // save parameters for use with different protocols.
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- // save URL to the registry
- if (m_pStats)
- {
- m_pStats->m_pSourceName->SetStr((char*)pURL);
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- if (m_pURL != pURL)
- {
- HX_DELETE(m_pURL);
- m_pURL = new CHXURL(*pURL);
- if (!m_pURL)
- {
- theErr = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- HX_VECTOR_DELETE(m_pszURL);
- m_pszURL = new char[::strlen(m_pURL->GetURL()) + 1];
- if (!m_pszURL)
- {
- theErr = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- ::strcpy(m_pszURL, m_pURL->GetURL()); /* Flawfinder: ignore */
- }
- m_uPort = port;
- HX_VECTOR_DELETE(m_pPath);
- pValues = m_pURL->GetProperties();
- if (pValues &&
- HXR_OK == pValues->GetPropertyBuffer(PROPERTY_PATH, pBuffer) && pBuffer)
- {
- StrAllocCopy(m_pPath, (char*)pBuffer->GetBuffer());
- }
- HX_RELEASE(pBuffer);
- HX_RELEASE(pValues);
- // set request
- m_bAltURL = bAltURL;
- SetRequest(m_pURL, bAltURL);
- if (!m_pCookies && HXR_OK != m_pEngine->QueryInterface(IID_IHXCookies, (void**)&m_pCookies))
- {
- m_pCookies = NULL;
- }
- if (!m_pCookies2 && HXR_OK != m_pEngine->QueryInterface(IID_IHXCookies2, (void**)&m_pCookies2))
- {
- m_pCookies2 = NULL;
- }
- if (m_pCookies || m_pCookies2)
- {
- if (HXR_OK == m_pRequest->GetRequestHeaders(pRequestHeaders) && pRequestHeaders)
- {
- HX_RESULT res = HXR_FAIL;
- if(m_pCookies2)
- res = m_pCookies2->GetCookies(m_pHost, m_pPath, pBuffer, pPlayerCookies);
- else if(m_pCookies)
- res = m_pCookies->GetCookies(m_pHost, m_pPath, pBuffer);
- if (HXR_OK == res && pBuffer)
- {
- pRequestHeaders->SetPropertyCString("Cookie", pBuffer);
- if(pPlayerCookies)
- {
- pRequestHeaders->SetPropertyCString("PlayerCookie", pPlayerCookies);
- }
- }
- HX_RELEASE(pBuffer);
- HX_RELEASE(pPlayerCookies);
- }
- }
- HX_RELEASE(pRequestHeaders);
- #if defined(HELIX_FEATURE_SMARTERNETWORK)
- if (!m_pPreferredTransportManager &&
- HXR_OK != m_pEngine->QueryInterface(IID_IHXPreferredTransportManager,
- (void**)&m_pPreferredTransportManager))
- {
- theErr = HXR_FAILED;
- goto cleanup;
- }
- #endif /* HELIX_FEATURE_SMARTERNETWORK */
- // Read all relevant preferences...
- theErr = ReadPreferences();
- // either we will wait for the first source to negotiate the transport
- // then connect the remaining sources
- // or we are initiating PAC(ProxyAutoConfig)
- if (HXR_WOULD_BLOCK == theErr)
- {
- theErr = HXR_OK;
- }
- else if (HXR_OK == theErr)
- {
- theErr = FinishSetup();
- }
- cleanup:
- return theErr;
- }
- HX_RESULT
- HXNetSource::FinishSetup()
- {
- HX_RESULT rc = HXR_OK;
- BOOL bSDPInitiated = FALSE;
- CHXString pString;
- // start off with the preferred protocol
- rc = CreateProtocol();
- if (HXR_OK != rc)
- {
- goto cleanup;
- }
- rc = InitializeProtocol();
- if (HXR_OK != rc)
- {
- goto cleanup;
- }
- if (helixSDPProtocol == m_uProtocolType)
- {
- bSDPInitiated = TRUE;
- CHXURL::decodeURL(m_pURL->GetEscapedURL(), pString);
-
- HX_VECTOR_DELETE(m_pResource);
- m_pResource = new char[pString.GetLength() - 9];
- ::strcpy(m_pResource, (const char*)pString + 10);
- }
-
- rc = m_pProto->setup(m_pHost,
- m_pResource,
- m_uPort,
- m_bLossCorrection,
- (HTTPCloakMode == m_CurrentTransport)?TRUE:FALSE,
- bSDPInitiated,
- m_uCurrCloakedPort);
- // Mask this error
- // Let the _ProcessIdle() determine whether ReportError() or
- // TransportSwitching for HXR_BAD_TRANSPORT
- if(rc == HXR_BLOCK_CANCELED || rc == HXR_BAD_TRANSPORT)
- {
- rc = HXR_OK;
- }
- if (HXR_OK != rc)
- {
- mLastError = rc;
- goto cleanup;
- }
- // create log info list
- m_pLogInfoList = new CHXSimpleList;
- m_ulLogInfoLength = 0;
- // start time of this source
- m_ulSourceStartTime = HX_GET_TICKCOUNT();
- if (m_pBufferCtl)
- {
- m_pBufferCtl->Close();
- }
- HX_RELEASE(m_pBufferCtl);
- HX_RELEASE(m_pWMBufferCtl);
-
- #ifdef HELIX_FEATURE_FEEDBACK_BUFFER_CONTROL
- m_pBufferCtl = new HXFeedbackBufferControl();
- #else
- m_pBufferCtl = new HXWatermarkBufferControl();
- #endif /* HELIX_FEATURE_FEEDBACK_BUFFER_CONTROL */
- if (m_pBufferCtl)
- {
- m_pBufferCtl->AddRef();
- m_pBufferCtl->QueryInterface(IID_IHXWatermarkBufferControl,
- (void**)&m_pWMBufferCtl);
- m_pBufferCtl->Init((IUnknown*)(IHXStreamSource*)this);
- if (m_pWMBufferCtl)
- {
- m_pWMBufferCtl->SetSource(this);
- }
- }
- cleanup:
- if (HXR_OK != rc)
- {
- HX_RELEASE(m_pProto);
- }
- return rc;
- }
- HX_RESULT
- HXNetSource::DoSeek(ULONG32 seekTime)
- {
- HX_TRACE("HXNetSource::DoSeek");
- BOOL bSeekInsideRecordControl = FALSE;
- if ((!m_pProto && m_state != NETSRC_RECONNECTPENDING) ||
- (mLiveStream && !m_bPlayFromRecordControl && m_bSourceEnd))
- {
- return HXR_OK;
- }
- // log seek action
- LogInformation("SEEK", NULL);
- if (seekTime >= m_ulDelay)
- {
- seekTime -= m_ulDelay;
- m_bDelayed = FALSE;
- }
- else
- {
- seekTime = 0;
- /* This source has not been even started yet...
- * Do not attempt to seek it if the start time = 0
- */
- if (m_bDelayed && m_ulStartTime == 0 && !m_bSourceEnd)
- {
- // will start pre-fetch again in TryResume()
- if (!m_bIsPreBufferingDone)
- {
- m_bIsPreBufferingStarted = FALSE;
- // will be registered again in DoResume() or TryResume()
- if (m_pSourceInfo)
- {
- m_pSourceInfo->UnRegister();
- }
- }
- return HXR_OK;
- }
- m_bDelayed = TRUE;
- }
- /* Add any start time to seek time */
- seekTime += m_ulStartTime;
- /* Are we seeking past the last expected packet time?
- * If so, don't bother... and mark this source as done
- */
- HX_ASSERT(m_llLastExpectedPacketTime <= MAX_UINT32);
- // XXX HP make sure the source has been initialized otherwise
- // m_llLastExpectedPacketTime could be 0 and we could falsely
- // mark the source ended
- if (m_bInitialized && !mLiveStream && seekTime >= m_llLastExpectedPacketTime)
- {
- if (m_pSourceInfo && m_pSourceInfo->m_bSeekToLastFrame)
- {
- seekTime = INT64_TO_ULONG32(m_llLastExpectedPacketTime);
- }
- else
- {
- m_bSourceEnd = TRUE;
- m_bForcedSourceEnd = TRUE;
- AdjustClipBandwidthStats(FALSE);
- #if defined(HELIX_FEATURE_RECORDCONTROL)
- if (m_pRecordControl)
- {
- m_pRecordControl->Seek(seekTime);
- }
- #endif /* HELIX_FEATURE_RECORDCONTROL*/
- goto cleanup;
- }
- }
- // workaround for b#42118 for older servers(<= RealServer8.0 Gold)
- // server sends no more streamdone when reaching the endtime if seek
- // is occurred after streamdone has been sent. fix has been made in the latest server
- if (m_bSourceEnd && m_bCustomEndTime && m_pProto && m_pProto->GetRDTFeatureLevel() < 2)
- {
- m_bRTSPRuleFlagWorkAround = TRUE;
- }
- if (mLiveStream)
- {
- seekTime += m_ulFirstPacketTime;
- }
- #if defined(HELIX_FEATURE_RECORDCONTROL)
- if (m_pRecordControl && m_pRecordControl->Seek(seekTime) == HXR_OK &&
- m_bPlayFromRecordControl)
- {
- bSeekInsideRecordControl = TRUE;
- }
- else
- #endif /* HELIX_FEATURE_RECORDCONTROL */
- {
- m_ulSeekPendingTime = seekTime;
- m_bSeekPending = TRUE;
- if(m_pProto)
- m_pProto->seek(seekTime, seekTime, FALSE);
- if (mLiveStream)
- {
- seekTime = 0;
- }
- m_bSourceEnd = FALSE;
- m_bForcedSourceEnd = FALSE;
- STREAM_INFO* pStreamInfo = NULL;
- CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
- for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
- {
- pStreamInfo = (STREAM_INFO*) (*lStreamIterator);
- pStreamInfo->ResetPreReconnectEventList();
- }
- }
- // initiating reconnect NOW ...
- if (NETSRC_RECONNECTPENDING == m_state)
- {
- m_state = NETSRC_RECONNECTFORCED;
- if (m_pReconnectCallback)
- {
- m_pReconnectCallback->CancelCallback();
- }
- StartReconnect();
- }
- m_uLastBuffering = 0;
- m_bInitialBuffering = TRUE;
- m_bIsPreBufferingStarted = FALSE;
- m_bIsPreBufferingDone = FALSE;
- m_pushDownStatus = PUSHDOWN_NONE;
- if (m_pBufferCtl)
- {
- m_pBufferCtl->OnSeek();
- }
- // Buffer manager needs to know whether we seek inside the RecordControl
- // to not reset variables related to stream completeness.
- m_pBufferManager->DoSeek(seekTime, bSeekInsideRecordControl);
- cleanup:
- return HXR_OK;
- }
- HX_RESULT
- HXNetSource::DoPause(void)
- {
- HX_TRACE("HXNetSource::DoPause");
- if (!m_pProto || m_bPaused)
- {
- return HXR_OK;
- }
- // log pause action
- LogInformation("PAUSE", NULL);
- m_pBufferManager->DoPause();
- if (m_pBufferCtl)
- {
- m_pBufferCtl->OnPause();
- }
- m_bPaused = TRUE;
- if (m_bPlayFromRecordControl && !m_bDelayed)
- {
- return HXR_OK;
- }
- /* Do not call pause if the source has ended. In RTSP, if the transport
- * is paused, it does not give us any packets. We would never issue a
- * resume since the source has ended and this would result in starting
- * the playback without giving any packets to the renderer if the preroll
- * of the renderer happens to be zero.(like RealText).
- */
- /* Call Pause even after source is done. This is to keep track
- * of Accounting information on the server side for PPV content
- * The only time we do not issue a pause is if we have internally
- * stopped the stream because of a end/dur tag.
- *
- * RTSP transport has been fixed so that it returns packets even
- * in a paused state. So the bug reported above should not occur.
- * Moreover, we now call protocol Resume even if the source is done.
- * So the transport should never be really in a Paused state when
- * we need to read packets.
- */
- if (!m_bForcedSourceEnd)
- {
- m_pProto->pause();
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- if (m_pStatsCallback)
- {
- m_pStatsCallback->PauseCallback();
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- }
- return HXR_OK;
- }
- HX_RESULT
- HXNetSource::StartInitialization(void)
- {
- if (m_pProto)
- {
- m_bUserHasCalledStartInit = TRUE;
- m_pBufferManager->DoResume();
- if (m_pSourceInfo)
- {
- m_pSourceInfo->Resumed();
- /* This is temporary. The source MUST be registered by this point.
- * Fix it after B1.
- * For now, added a work around
- * - Rahul
- */
- if (!m_pSourceInfo->IsRegistered() && m_pSourceInfo->IsActive())
- {
- m_pSourceInfo->Register();
- if (m_pPlayer)
- {
- m_pPlayer->RegisterSourcesDone();
- }
- }
- }
- SetNoLatency();
- HX_ASSERT(m_llLastExpectedPacketTime <= MAX_UINT32);
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- if (m_bSendStatistics && m_ulStatsInterval > 0)
- {
- if (!m_pStatsCallback)
- {
- m_pStatsCallback = new ReconnectCallback(this, TRUE);
- m_pStatsCallback->AddRef();
- }
- if (m_pStatsCallback->IsPaused())
- {
- m_pStatsCallback->ResumeCallback();
- }
- else
- {
- m_pStatsCallback->ScheduleCallback(m_ulStatsInterval);
- }
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- return m_pProto->resume(INT64_TO_UINT32(m_llLastExpectedPacketTime));
- }
- return HXR_OK;
- }
- HX_RESULT
- HXNetSource::DoResume(void)
- {
- HX_TRACE("HXNetSource::DoResume");
- HX_RESULT theErr = HXR_OK;
- /* This may happen if a new source is added from SMIL renderer during
- * initialization of exisitng sources. We will eventually call Resume
- * on this source once it is initialized in SourceInfo::ProcessIdle
- */
- if (!m_bInitialized)
- {
- return HXR_OK;
- }
- m_bUserHasCalledResume = TRUE;
- // log resume action
- LogInformation("Resume", NULL);
- if(m_pBufferManager && !m_bSourceEnd && CanBeResumed())
- {
- m_pBufferManager->DoResume();
- }
- /* Call Resume even after source is done. This is to keep track
- * of Accounting information on the server side for PPV content
- * Only if we have forced a source end because of end/dur tag
- * or because of seeking past source's duration in SMIL,
- * we do not send Pause/Resume to the server
- */
- if (!m_pProto || (!m_bPaused && !m_bFirstResume))
- {
- return HXR_OK;
- }
- if(m_bPlayFromRecordControl && !m_bDelayed && !m_bFirstResume && !m_bResumePending)
- {
- m_bPaused = FALSE;
- return HXR_OK;
- }
- if (m_bSourceEnd || CanBeResumed())
- {
- m_bResumePending = FALSE;
- HX_ASSERT(m_pSourceInfo);
- if (!m_bSourceEnd)
- {
- /* This is temporary. This assert is currently tripping...
- * Ideally, it should not. Fix it after B1.
- * For now, added a work around
- * - Rahul
- */
- // HX_ASSERT(!m_pSourceInfo || m_pSourceInfo->IsRegistered() || !m_pSourceInfo->IsActive());
- if (m_pSourceInfo && !m_pSourceInfo->IsRegistered() && m_pSourceInfo->IsActive())
- {
- m_pSourceInfo->Register();
- if (m_pPlayer)
- {
- m_pPlayer->RegisterSourcesDone();
- }
- }
- SetNoLatency();
- if (m_bBruteForceReconnected && m_bSeekPending)
- {
- theErr = m_pProto->seek(m_ulSeekPendingTime);
- }
- HX_ASSERT(INT64_TO_ULONG32(m_llLastExpectedPacketTime) <= MAX_UINT32);
- theErr = m_pProto->resume(INT64_TO_UINT32(m_llLastExpectedPacketTime));
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- if (m_bSendStatistics && m_ulStatsInterval > 0)
- {
- if (!m_pStatsCallback)
- {
- m_pStatsCallback = new ReconnectCallback(this, TRUE);
- m_pStatsCallback->AddRef();
- }
- if (m_pStatsCallback->IsPaused())
- {
- m_pStatsCallback->ResumeCallback();
- }
- else
- {
- m_pStatsCallback->ScheduleCallback(m_ulStatsInterval);
- }
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- }
- // resume the audio streams if the source is added
- // while the player is in play
- // CAUTION: this will cause rewind in audio service
- if (m_bFirstResume &&
- IsPlaying() &&
- (m_state == NETSRC_READY) &&
- m_pPlayer && m_ulDelay <= m_pPlayer->GetInternalCurrentPlayTime())
- {
- ResumeAudioStreams();
- }
- m_bFirstResume = FALSE;
- m_bPaused = FALSE;
- if (m_pSourceInfo)
- {
- m_pSourceInfo->Resumed();
- }
-
- if (m_pBufferCtl)
- {
- m_pBufferCtl->OnResume();
- }
- }
- if (!m_bIsActive && !m_bDelayed && m_pPlayer &&
- m_pPlayer->GetInternalCurrentPlayTime() >= m_ulDelay)
- {
- AdjustClipBandwidthStats(TRUE);
- }
- return theErr;
- }
- /************************************************************************
- * Method:
- * IHXPendingStatus::GetStatus
- * Purpose:
- * Called by the user to get the current pending status from an object
- */
- STDMETHODIMP
- HXNetSource::GetStatus
- (
- REF(UINT16) uStatusCode,
- REF(IHXBuffer*) pStatusDesc,
- REF(UINT16) ulPercentDone
- )
- {
- HX_RESULT rc = HXR_OK;
- UINT16 buffer = 100;
- UINT16 statusCode = HX_STATUS_READY;
- UINT16 percentDone = 0;
- /* Default values*/
- uStatusCode = statusCode;
- pStatusDesc = NULL;
- ulPercentDone = buffer;
- UINT16 uSrcPercentDone = 100;
- UINT16 uSrcStatusCode = HX_STATUS_READY;
- if (m_bDelayed)
- {
- goto cleanup;
- }
- #if defined(HELIX_FEATURE_TURBOPLAY)
- if (m_bFastStart &&
- m_bRARVSource &&
- (!m_pSourceInfo || !m_pSourceInfo->m_bIsPersistentSource))
- {
- if (HXR_OK == IsFaststartPushdownFullfilled(uStatusCode, ulPercentDone))
- {
- goto cleanup;
- }
- }
- #endif /* HELIX_FEATURE_TURBOPLAY */
- if (m_bSourceEnd)
- {
- if (!IsRebufferDone())
- {
- uStatusCode = HX_STATUS_BUFFERING;
- ulPercentDone = 99;
- }
- else
- {
- if (m_bInitialBuffering)
- {
- InitialBufferingDone();
- }
- m_uLastBuffering = 100;
- uStatusCode = HX_STATUS_READY;
- }
- goto cleanup;
- }
- if (m_bInitialized)
- {
- m_pBufferManager->GetStatus(uSrcStatusCode, pStatusDesc, uSrcPercentDone);
- statusCode = uSrcStatusCode;
- buffer = uSrcPercentDone;
- }
- else
- {
- buffer = 0;
- statusCode = HX_STATUS_INITIALIZING;
- percentDone = 0;
- uStatusCode = statusCode;
- pStatusDesc = NULL;
- ulPercentDone = buffer;
- }
- #ifdef _RAHULDEBUG
- {
- char str[255]; /* Flawfinder: ignore */
- ::sprintf(str, "GetStatus: BufMgr %u ", buffer); /* Flawfinder: ignore */
- OutputDebugString(str);
- }
- #endif
- if (buffer > 100)
- buffer = 0;
- /* If we have not yet received a single packet, do not claim to
- * be done with buffering. This is needed to correctyl playback sparse
- * datatypes with no preroll.
- */
- if (!m_bReceivedData && buffer == 100)
- {
- buffer = 99;
- }
- /* We only aggregate buffering from a lower level if we are in a buffering mode.
- * Reason: Once the initial bufering is done, we go in buffering more ONLY IF the
- * renderer tells us that it is in a panic state and we run out of packets.
- */
- if (buffer == 100 && !m_bInitialBuffering)
- {
- // Rebuffer requested by the Renderer might not be
- // done yet
- if (!IsRebufferDone())
- {
- uStatusCode = HX_STATUS_BUFFERING;
- ulPercentDone = 99;
- }
- else
- {
- uStatusCode = HX_STATUS_READY;
- }
- goto cleanup;
- }
- if (HX_STATUS_CONTACTING == statusCode)
- {
- uStatusCode = HX_STATUS_CONTACTING;
- ulPercentDone = 0;
- }
- else if (HX_STATUS_READY == statusCode && 100 == buffer)
- {
- uStatusCode = HX_STATUS_READY;
- ulPercentDone = 0;
- }
- else if (HX_STATUS_INITIALIZING == statusCode || HX_STATUS_INITIALIZING == uStatusCode)
- {
- uStatusCode = HX_STATUS_BUFFERING;
- ulPercentDone = 0;
- }
- else
- {
- uStatusCode = HX_STATUS_BUFFERING;
- ulPercentDone = buffer;
- }
- if (uStatusCode == HX_STATUS_BUFFERING && m_uLastBuffering < 100)
- {
- if (ulPercentDone < m_uLastBuffering)
- {
- ulPercentDone = m_uLastBuffering;
- }
- else
- {
- m_uLastBuffering = ulPercentDone;
- }
- }
- if (m_bInitialBuffering && HX_STATUS_READY == uStatusCode)
- {
- InitialBufferingDone();
- m_uLastBuffering = 100;
- }
- /* If we had a delayed start, we do not want to show that we are
- * in buffering state UNLESS it is really time to give out packets
- * and we do not have any.
- */
- if (m_bInitialized && m_ulDelay > 0 && m_pPlayer &&
- uStatusCode == HX_STATUS_BUFFERING &&
- ulPercentDone < 100)
- {
- UINT32 ulCurrentTime = m_pPlayer->GetInternalCurrentPlayTime();
- if ((ulCurrentTime+MIN_BUFFERTIME_BEFORE_DELAY) < m_ulDelay)
- {
- ulPercentDone = 100;
- }
- }
- cleanup:
- if (m_pBufferCtl)
- {
- if ((HX_STATUS_READY == m_uLastStatusCode) &&
- (HX_STATUS_BUFFERING == uStatusCode))
- {
- UINT32 ulRemainToBufferInMs = 0;
- UINT32 ulRemainToBuffer = 0;
- if (m_pBufferManager)
- {
- m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs,
- ulRemainToBuffer);
- }
-
- m_pBufferCtl->OnBuffering(ulRemainToBufferInMs, ulRemainToBuffer);
- }
- else if ((HX_STATUS_BUFFERING == m_uLastStatusCode) &&
- (HX_STATUS_READY == uStatusCode))
- {
- m_pBufferCtl->OnBufferingDone();
- }
- }
- m_uLastStatusCode = uStatusCode;
- if (m_bFastStart && !m_turboPlayStats.bBufferDone && HX_STATUS_READY == uStatusCode)
- {
- m_turboPlayStats.bBufferDone = TRUE;
- m_turboPlayStats.ulBufferedTime = CALCULATE_ELAPSED_TICKS(m_ulStartDataWait, HX_GET_TICKCOUNT());
- }
- return rc;
- }
- BOOL
- HXNetSource::CanBeFastStarted(void)
- {
- // In low heap mode we always want TurboPlay off.
- #if defined(HELIX_FEATURE_TURBOPLAY)
- HXStream* pStream = NULL;
- CHXSimpleList::Iterator i;
- m_bFastStart = TRUE;
- if (FALSE == m_pPlayer->CanBeFastStarted(m_pSourceInfo))
- {
- m_turboPlayStats.tpOffReason = m_pPlayer->m_turboPlayOffReason;
- m_bFastStart = FALSE;
- goto cleanup;
- }
- // no faststart on non-RTSP protocol
- if (!m_bRTSPProtocol)
- {
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s,"(%p)Not RTSP - TurboPlay Off", this));
- m_turboPlayStats.tpOffReason = TP_OFF_BY_NONRTSP;
- m_bFastStart = FALSE;
- goto cleanup;
- }
- // faststart can be disabled by the server
- if (TURBO_PLAY_OFF == m_serverTurboPlay)
- {
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s,"(%p)Disabled By Server - TurboPlay Off", this));
- m_turboPlayStats.tpOffReason = TP_OFF_BY_SERVER;
- m_bFastStart = FALSE;
- goto cleanup;
- }
- // no faststart on live source served from >= 9.0 server which get
- // rid of the ring buffer by default
- if (mLiveStream && HX_GET_MAJOR_VERSION(m_ulServerVersion) >= 9 &&
- (TURBO_PLAY_ON != m_serverTurboPlay))
- {
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s,"(%p)Live From Server(>=9) - TurboPlay Off", this));
- m_turboPlayStats.tpOffReason = TP_OFF_BY_LIVE;
- m_bFastStart = FALSE;
- goto cleanup;
- }
- // no faststart on ROB presentation
- if (m_pPlayer->m_pEngine->m_lROBActive > 0)
- {
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s,"(%p)ROB Presentation - TurboPlay Off", this));
- m_turboPlayStats.tpOffReason = TP_OFF_BY_ROB;
- m_bFastStart = FALSE;
- goto cleanup;
- }
- if (m_bFastStart)
- {
- if (!m_bRARVSourceVerified)
- {
- m_bRARVSourceVerified = TRUE;
- m_bRARVSource = IsRARVSource();
- }
- EnterFastStart();
- }
- cleanup:
- return m_bFastStart;
- #else
- return FALSE;
- #endif /* HELIX_FEATURE_TURBOPLAY */
- }
- HX_RESULT
- HXNetSource::IsFaststartPushdownFullfilled(REF(UINT16) uStatusCode,
- REF(UINT16) ulPercentDone)
- {
- #if defined(HELIX_FEATURE_TURBOPLAY)
- HX_RESULT rc = HXR_OK;
- UINT32 ulWaitTime = 0;
- UINT32 ulPlayerTime = 0;
- UINT32 ulDiff = 0;
- UINT32 ulPushdownMS = 0;
- UINT32 ulNumFrames =0;
- CHXAudioStream* pCHXAudioStream = NULL;
- CHXAudioSession* pAudioSession = NULL;
- HXStream* pStream = NULL;
- HXAudioData audioData;
- IUnknown* pUnknown = NULL;
- IHXMediaPushdown* pMediaPushdown = NULL;
- UINT32 ulAudioPushDownThreshold;
- UINT32 ulVideoPushDownThreshold;
- CHXSimpleList::Iterator i;
- uStatusCode = HX_STATUS_READY;
- ulPercentDone = 100;
- if (PUSHDOWN_ALL_DONE == m_pushDownStatus)
- {
- return rc;
- }
- if (!m_pPlayer)
- {
- return HXR_FAILED;
- }
- // compute our thresholds
- // I know peice wise defined functions are LAME!!
- // hello patel, this type of code is for you!
- if (m_maxPossibleAccelRatio > 3.9)
- {
- ulAudioPushDownThreshold = m_ulTurboPushDown / 2;
- ulVideoPushDownThreshold = 4;
- }
- else if (m_maxPossibleAccelRatio > 2.5)
- {
- ulAudioPushDownThreshold = (ULONG32) (m_ulTurboPushDown / 1.7);
- ulVideoPushDownThreshold = 8;
- }
- else
- {
- ulAudioPushDownThreshold = (ULONG32) (m_ulTurboPushDown / 1.6);
- ulVideoPushDownThreshold = 12;
- }
- if (!(PUSHDOWN_AUDIO_DONE & m_pushDownStatus))
- {
- #if defined(HELIX_FEATURE_AUDIO)
- if (!m_pAudioStreamList)
- {
- CollectAudioStreams(m_pAudioStreamList);
- }
- if (m_pAudioStreamList && m_pAudioStreamList->GetCount())
- {
- memset(&audioData, 0, sizeof(HXAudioData));
- ulPlayerTime = m_pPlayer->GetCurrentPlayTime();
- if (mLiveStream)
- {
- ulPlayerTime += m_ulFirstPacketTime;
- }
- for(i = m_pAudioStreamList->Begin(); i != m_pAudioStreamList->End(); ++i)
- {
- pCHXAudioStream = (CHXAudioStream*)*i;
- pCHXAudioStream->Write(&audioData);
- // check audio push down
- if (!m_bPushDownSet)
- {
- m_bPushDownSet = TRUE;
- if (pCHXAudioStream && pCHXAudioStream->m_Owner)
- {
- pAudioSession = pCHXAudioStream->m_Owner->GetOwner();
- }
- if (pAudioSession && m_ulTurboPushDown < 2000)
- {
- pAudioSession->SetAudioPushdown(m_ulTurboPushDown);
- }
- }
- // For live, ulPlayerTime could be > audioData.ulAudioTime if
- // the renderer hasn't send 1st audio packet to the audio stream
- if (audioData.ulAudioTime >= ulPlayerTime)
- {
- ulDiff = audioData.ulAudioTime - ulPlayerTime;
- }
- if (ulDiff >= ulAudioPushDownThreshold)
- {
- m_pushDownStatus = (PushDownStatus)(m_pushDownStatus | PUSHDOWN_AUDIO_DONE);
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)AudioPushDown Satisfied %lu %lu", this, ulDiff, ulAudioPushDownThreshold));
- break;
- }
- }
- }
- // no audio stream
- else
- #endif /* HELIX_FEATURE_AUDIO */
- {
- m_pushDownStatus = (PushDownStatus)(m_pushDownStatus | PUSHDOWN_AUDIO_DONE);
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)AudioPushDown Satisfied(no audio)", this));
- }
- }
- if (!(PUSHDOWN_VIDEO_DONE & m_pushDownStatus))
- {
- // check video push down
- for (i = m_HXStreamList.Begin(); i != m_HXStreamList.End(); ++i)
- {
- pStream = (HXStream*) (*i);
- // there should be 1 renderer per stream
- if (HXR_OK == pStream->GetRenderer(0, pUnknown))
- {
- if (HXR_OK == pUnknown->QueryInterface(IID_IHXMediaPushdown, (void**)&pMediaPushdown))
- {
- if (pStream->m_bPostSeekToBeSent)
- {
- goto cleanup;
- }
- pMediaPushdown->GetCurrentPushdown(ulPushdownMS, ulNumFrames);
- // check to see if we are using G2 video
- if (pMediaPushdown->IsG2Video())
- {
- if (ulNumFrames < 9 && ulNumFrames < ulVideoPushDownThreshold)
- {
- goto cleanup;
- }
- }
- else
- {
- if (ulNumFrames < ulVideoPushDownThreshold)
- {
- goto cleanup;
- }
- }
- }
- HX_RELEASE(pMediaPushdown);
- }
- HX_RELEASE(pUnknown);
- }
- m_pushDownStatus = (PushDownStatus)(m_pushDownStatus | PUSHDOWN_VIDEO_DONE);
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)VideoPushDown Satisfied %lu %lu", this, ulNumFrames, ulVideoPushDownThreshold));
- }
- // Milko wants to make it such that TimeStampDelivered
- // IsTimeStampDelivery
- cleanup:
- HX_RELEASE(pMediaPushdown);
- HX_RELEASE(pUnknown);
- if (PUSHDOWN_ALL_DONE == m_pushDownStatus)
- {
- if (m_bInitialBuffering)
- {
- InitialBufferingDone();
- }
- m_uLastBuffering = 100;
- m_ulTurboStartActiveTime = HX_GET_TICKCOUNT();
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)TURBO Started", this));
- }
- else
- {
- uStatusCode = HX_STATUS_BUFFERING;
- ulPercentDone = 0;
- // we switch to the normal status calculation if
- // we detect the TurboPlay takes unreasonable amount of time to start(>8s)
- ulWaitTime = CALCULATE_ELAPSED_TICKS(m_ulStartDataWait, HX_GET_TICKCOUNT());
- if (ulWaitTime >= 8000)
- {
- rc = HXR_FAILED;
- }
- }
- return rc;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_TURBOPLAY */
- }
- BOOL
- HXNetSource::IsRARVSource(void)
- {
- #if defined(HELIX_FEATURE_TURBOPLAY)
- BOOL bResult = TRUE;
- IHXBuffer* pMimeType = NULL;
- STREAM_INFO* pStreamInfo = NULL;
- CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
- for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
- {
- pStreamInfo = (STREAM_INFO*) (*lStreamIterator);
- if (pStreamInfo->m_pHeader &&
- HXR_OK == pStreamInfo->m_pHeader->GetPropertyCString("MimeType", pMimeType))
- {
- const char* pszMimeType = (const char*)pMimeType->GetBuffer();
- // all "-encrypted" mimetypes should have been stripped in FixUpMime()
- if (strcmp(pszMimeType, REALMEDIA_MIME_TYPE) != 0 &&
- strcmp(pszMimeType, REALAUDIO_MIME_TYPE) != 0 &&
- strcmp(pszMimeType, REALVIDEO_MIME_TYPE) != 0 &&
- strcmp(pszMimeType, REALAUDIO_MULTIRATE_MIME_TYPE) != 0 &&
- strcmp(pszMimeType, REALAUDIO_MULTIRATE_LIVE_MIME_TYPE) != 0 &&
- strcmp(pszMimeType, REALVIDEO_MULTIRATE_MIME_TYPE) != 0)
- {
- bResult = FALSE;
- break;
- }
- }
- HX_RELEASE(pMimeType);
- }
- HX_RELEASE(pMimeType);
- return bResult;
- #else
- return FALSE;
- #endif /* HELIX_FEATURE_TURBOPLAY */
- }
- UINT16
- HXNetSource::GetNumStreams(void)
- {
- HX_ASSERT(m_bInitialized);
- return m_uNumStreams;
- }
- HX_RESULT
- HXNetSource::GetStreamInfo(ULONG32 ulStreamNumber,
- STREAM_INFO*& theStreamInfo)
- {
- HX_RESULT theErr = HXR_OK;
- STREAM_INFO* pStreamInfo = NULL;
- STREAM_STATS* pStreamStats = NULL;
- if (!mStreamInfoTable->Lookup((LONG32)ulStreamNumber, (void *&)pStreamInfo))
- {
- theErr = HXR_INVALID_PARAMETER;
- }
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- if (m_pProto && HXR_OK == m_pProto->GetStreamStatistics(ulStreamNumber, &pStreamStats))
- {
- pStreamInfo->m_pStats = pStreamStats;
- if (!pStreamInfo->m_pStats)
- {
- return HXR_UNEXPECTED;
- }
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- theStreamInfo = pStreamInfo;
- return theErr;
- }
- HX_RESULT
- HXNetSource::GetEvent(UINT16 usStreamNumber, CHXEvent*& pEvent)
- {
- HX_TRACE("HXNetSource::GetEvent");
- if (!m_bPlayFromRecordControl)
- {
- HX_RESULT nResult = GetEventFromProtocol(usStreamNumber, pEvent);
- #if defined(HELIX_FEATURE_RECORDCONTROL)
- // Case of record-only RecordControl (no playback support).
- if (pEvent && m_pRecordControl)
- {
- m_pRecordControl->OnPacket(pEvent->GetPacket(), pEvent->GetTimeOffset());
- }
- #endif /* HELIX_FEATURE_RECORDCONTROL */
- return nResult;
- }
- pEvent = NULL;
- HX_RESULT nResult = HXR_OK;
- STREAM_INFO* pStreamInfo = NULL;
- if (!mStreamInfoTable->Lookup((LONG32) usStreamNumber, (void *&) pStreamInfo))
- {
- HX_ASSERT(FALSE);
- return HXR_INVALID_PARAMETER;
- }
- if (pStreamInfo->m_bReconnectToBeDone)
- {
- CHXEventList* pEventList = &pStreamInfo->m_EventList;
- if (pEventList->GetNumEvents())
- pEvent = pEventList->RemoveHead();
- return pEvent ? HXR_OK : HXR_NO_DATA;
- }
- return GetEventFromRecordControl(usStreamNumber, pEvent);
- }
- HX_RESULT
- HXNetSource::GetEventFromRecordControl(UINT16 usStreamNumber, CHXEvent*& pEvent)
- {
- #if defined(HELIX_FEATURE_RECORDCONTROL)
- if(!m_bPlayFromRecordControl)
- return HXR_UNEXPECTED;
- HX_ASSERT(m_pRecordControl);
- pEvent = NULL;
- IHXPacket* pPacket = NULL;
- HX_RESULT nResult = m_pRecordControl->GetPacket(usStreamNumber, pPacket);
- STREAM_INFO* pStreamInfo = NULL;
- mStreamInfoTable->Lookup((LONG32) usStreamNumber, (void *&) pStreamInfo);
- if(nResult == HXR_OK)
- {
- UINT32 ulEventTime = 0;
- if (pStreamInfo)
- {
- if (!CanSendToDataCallback(pPacket))
- {
- UINT32 ulLastPkt =
- pStreamInfo->BufferingState().LastPacketTimestamp();
- // Use timestamp from the last packet
- ulEventTime = AdjustEventTime(pStreamInfo, ulLastPkt);
- }
- else
- {
- ulEventTime = AdjustEventTime(pStreamInfo, pPacket->GetTime());
- /* Update buffering info and stats */
- DataCallback(pPacket);
- }
- }
- pEvent = new CHXEvent(pPacket, 0);
- HX_RELEASE(pPacket);
- if(!pEvent)
- return HXR_FAILED;
- pEvent->SetTimeStartPos(ulEventTime);
- pEvent->SetTimeOffset(m_ulStartTime - m_ulDelay);
- }
- else
- {
- if(nResult == HXR_NO_DATA && (m_bSourceEnd || pStreamInfo->m_bSrcStreamDone))
- nResult = HXR_AT_END;
- if(nResult == HXR_NO_DATA && m_pBufferManager)
- {
- UINT32 ulRemainToBufferInMs = 0;
- UINT32 ulRemainToBuffer = 0;
- m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs, ulRemainToBuffer);
- if (ulRemainToBufferInMs || ulRemainToBuffer)
- {
- nResult = HXR_BUFFERING;
- }
- else if (pStreamInfo->m_unNeeded > 0 &&
- pStreamInfo->m_unNeeded != pStreamInfo->m_unAvailable)
- {
- nResult = HXR_BUFFERING;
- m_uLastBuffering = 0;
- m_pBufferManager->ReBuffer();
- }
- }
- }
- return nResult;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_RECORDCONTROL */
- }
- HX_RESULT
- HXNetSource::GetEventFromProtocol(UINT16 usStreamNumber, CHXEvent*& pEvent)
- {
- HX_RESULT theErr = HXR_OK;
- UINT32 ulEventTime = 0;
- UINT32 ulRemainToBufferInMs = 0;
- UINT32 ulRemainToBuffer = 0;
- IHXPacket* pPacket = NULL;
- STREAM_INFO* pStreamInfo = NULL;
- CHXEvent* pTempEvent = NULL;
- CHXEventList* pEventList = NULL;
- CHXSimpleList::Iterator lIter;
- pEvent = NULL;
- if (!m_bInitialized && m_state == NETSRC_READY)
- {
- return HXR_NO_DATA;
- }
- if (m_bPaused && m_bDelayed)
- {
- if (TryResume() && m_pPlayer)
- {
- m_pPlayer->RegisterSourcesDone();
- DoResume();
- }
- else
- {
- return HXR_NO_DATA;
- }
- }
- /* give some time to the net object...*/
- theErr = _ProcessIdle();
- if (theErr)
- {
- return theErr;
- }
- if (!mStreamInfoTable->Lookup((LONG32) usStreamNumber, (void *&) pStreamInfo))
- {
- HX_ASSERT(FALSE);
- return HXR_INVALID_PARAMETER;
- }
- if (pStreamInfo->m_bReconnectToBeDone)
- {
- pEventList = &pStreamInfo->m_EventList;
- if (pEventList->GetNumEvents() && !m_bPlayFromRecordControl)
- {
- pEvent = pEventList->RemoveHead();
- //{FILE* f1 = ::fopen("c:\temp\reconnect.txt", "a+"); ::fprintf(f1, "GetEventFromPreReconnectt%lut%lun", usStreamNumber, pEvent->GetPacket()->GetTime());::fclose(f1);}
- }
- if (m_pProto)
- {
- while (TRUE)
- {
- theErr = m_pProto->GetEvent(usStreamNumber, pTempEvent);
- if (theErr)
- {
- // Mask off any non-crucial errors
- switch (theErr)
- {
- case HXR_AT_END:
- case HXR_NO_DATA:
- case HXR_BUFFERING:
- theErr = HXR_OK;
- break;
- default:
- break;
- }
- // if there is still an error, it needs to be reported
- if (theErr)
- {
- return theErr;
- }
- break;
- }
- HX_ASSERT(pTempEvent);
- if (!pStreamInfo->m_pPosReconnectEventList)
- {
- pStreamInfo->m_pPosReconnectEventList = new CHXEventList;
- }
- //{FILE* f1 = ::fopen("c:\temp\reconnect.txt", "a+"); ::fprintf(f1, "AddEventToPosReconnectt%lut%lun", usStreamNumber, pTempEvent->GetPacket()->GetTime());::fclose(f1);}
- pStreamInfo->m_pPosReconnectEventList->InsertEvent(pTempEvent);
- }
- ProcessReconnect(pStreamInfo);
- }
- }
- else
- {
- pEventList = pStreamInfo->m_pPosReconnectEventList;
- if (pEventList && pEventList->GetNumEvents())
- {
- pEvent = pEventList->RemoveHead();
- //{FILE* f1 = ::fopen("c:\temp\reconnect.txt", "a+"); ::fprintf(f1, "GetEventFromPosReconnectt%lut%lun", usStreamNumber, pEvent->GetPacket()->GetTime());::fclose(f1);}
- }
- if (!pEvent && m_pProto)
- {
- while (TRUE)
- {
- theErr = m_pProto->GetEvent(usStreamNumber, pEvent);
- if (theErr)
- {
- // Mask off any non-crucial errors
- switch (theErr)
- {
- case HXR_AT_END:
- case HXR_NO_DATA:
- case HXR_BUFFERING:
- theErr = HXR_OK;
- break;
- default:
- break;
- }
- // if there is still an error, it needs to be reported
- if (theErr)
- {
- return theErr;
- }
- break;
- }
- HX_ASSERT(pEvent);
- if (!pStreamInfo->m_ulReconnectOverlappedPackets)
- {
- break;
- }
- //{FILE* f1 = ::fopen("c:\temp\reconnect.txt", "a+"); ::fprintf(f1, "DeleteEvent(overlapped)t%lut%lun", usStreamNumber, pEvent->GetPacket()->GetTime());::fclose(f1);}
- HX_DELETE(pEvent);
- pStreamInfo->m_ulReconnectOverlappedPackets--;
- }
- if (pEvent)
- {
- //{FILE* f1 = ::fopen("c:\temp\reconnect.txt", "a+"); ::fprintf(f1, "GetEventFromTransportt%lut%lun", usStreamNumber, pEvent->GetPacket()->GetTime());::fclose(f1);}
- }
- }
- if (pEvent)
- {
- AddToPreReconnectEventList(pStreamInfo, pEvent);
- }
- }
- if (pEvent)
- {
- pPacket = pEvent->GetPacket();
- if (pPacket)
- {
- if (!m_bPlayFromRecordControl &&
- CanSendToDataCallback(pPacket)&& !pEvent->IsPreSeekEvent())
- {
- /* Update buffering info and stats */
- DataCallback(pPacket);
- }
- if (pPacket->IsLost())
- {
- UINT32 ulLastPkt =
- pStreamInfo->BufferingState().LastPacketTimestamp();
- // Use timestamp from the last packet
- ulEventTime = AdjustEventTime(pStreamInfo, ulLastPkt);
- }
- else
- {
- ulEventTime = AdjustEventTime(pStreamInfo, pPacket->GetTime());
- }
- pEvent->SetTimeStartPos(ulEventTime);
- }
- pEvent->SetTimeOffset(m_ulStartTime - m_ulDelay);
- }
- else if (m_bSourceEnd || pStreamInfo->m_bSrcStreamDone)
- {
- theErr = HXR_AT_END;
- }
- else
- {
- if(m_bPlayFromRecordControl)
- {
- theErr = HXR_NO_DATA;
- }
- else
- {
- m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs, ulRemainToBuffer);
- if (ulRemainToBufferInMs || ulRemainToBuffer)
- {
- theErr = HXR_BUFFERING;
- }
- else if (pStreamInfo->m_unNeeded > 0 &&
- pStreamInfo->m_unNeeded != pStreamInfo->m_unAvailable)
- {
- theErr = HXR_BUFFERING;
- m_uLastBuffering = 0;
- m_pBufferManager->ReBuffer();
- }
- else
- {
- theErr = HXR_NO_DATA;
- }
- }
- }
- if (m_pBufferCtl)
- {
- if (theErr == HXR_BUFFERING)
- {
- /* Make sure we have not paused the server when we are in a
- * buffering state
- */
- m_pBufferCtl->OnBuffering(ulRemainToBufferInMs, ulRemainToBuffer);
- }
- else if (theErr == HXR_AT_END)
- {
- m_pBufferCtl->OnClipEnd();
- }
- }
- #ifdef LOSS_HACK
- if (m_ulLossHack > 0 && ((UINT32) (rand() % 100) < m_ulLossHack) &&
- !theErr && pEvent && !(pEvent->GetPacket())->IsLost())
- {
- GenerateFakeLostPacket(pEvent);
- /* Update the stats */
- pStreamInfo->m_ulLost++;
- }
- #endif /* LOSS_HACK */
- return theErr;
- }
- void
- HXNetSource::ReBuffer()
- {
- UINT32 ulRemainToBufferInMs = 0;
- UINT32 ulRemainToBuffer = 0;
- m_pBufferManager->GetRemainToBuffer(ulRemainToBufferInMs,
- ulRemainToBuffer);
- // DEBUG_OUT(m_pPlayer, DOL_GENERIC, (s,
- // "Rebuffer %p CurrentTime: %lu RemainMs: %lu RemainBytes: %lu", this,
- // HX_GET_TICKCOUNT(), ulRemainToBufferInMs, ulRemainToBuffer));
- if (ulRemainToBufferInMs == 0 &&
- ulRemainToBuffer == 0)
- {
- m_uLastBuffering = 0;
- m_pBufferManager->ReBuffer();
- }
- }
- HX_RESULT
- HXNetSource::UpdateRegistry(UINT32 ulRegistryID)
- {
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- HX_RESULT theErr = HXR_OK;
- UINT32 ulRepeatedRegistryID = 0;
- UINT32 ulRegId = 0;
- char szRegName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
- IHXBuffer* pParentName = NULL;
- IHXBuffer* pRepeatRegName = NULL;
- STREAM_INFO* pStreamInfo = NULL;
- SOURCE_STATS* pNewStats = NULL;
- CHXMapLongToObj::Iterator ndxStream;
- m_ulRegistryID = ulRegistryID;
- if (!m_pStats)
- {
- // XXX HP, Hummmmmmmm ....
- HX_ASSERT(FALSE);
- SetupRegistry();
- }
- else if (m_ulRegistryID != m_pStats->m_ulRegistryID)
- {
- #if defined(HELIX_FEATURE_SMIL_REPEAT)
- // repeated source
- if (!m_pSourceInfo->m_bLeadingSource ||
- m_pSourceInfo->m_pRepeatList)
- {
- if (m_pStatsManager)
- {
- m_pStatsManager->UpdateRegistry(m_ulRegistryID);
- }
- else if (m_pRegistry &&
- HXR_OK == m_pRegistry->GetPropName(m_pPlayer->m_ulRepeatedRegistryID, pRepeatRegName))
- {
- SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.%ld%ld%ld",
- pRepeatRegName->GetBuffer(),
- m_pSourceInfo->m_uGroupID,
- m_pSourceInfo->m_uTrackID,
- (int)m_pSourceInfo->m_bLeadingSource);
- ulRepeatedRegistryID = m_pRegistry->GetId(szRegName);
- if (!ulRepeatedRegistryID)
- {
- ulRepeatedRegistryID = m_pRegistry->AddComp(szRegName);
- }
- m_pStatsManager = new StatsManager(m_pRegistry, m_ulRegistryID, ulRepeatedRegistryID);
- m_pStatsManager->AddRef();
- pNewStats = new SOURCE_STATS(m_pRegistry, ulRepeatedRegistryID);
- }
- else
- {
- // why stats' creation failed??
- HX_ASSERT(FALSE);
- }
- HX_RELEASE(pRepeatRegName);
- }
- // normal source
- else
- #endif /* HELIX_FEATURE_SMIL_REPEAT */
- {
- pNewStats = new SOURCE_STATS(m_pRegistry, m_ulRegistryID);
- }
- if (pNewStats && m_pPlayer)
- {
- *pNewStats = *m_pStats;
- ndxStream = mStreamInfoTable->Begin();
- for(; ndxStream != mStreamInfoTable->End(); ++ndxStream)
- {
- pStreamInfo = (STREAM_INFO*) (*ndxStream);
- if (m_pRegistry &&
- pNewStats &&
- HXR_OK == m_pRegistry->GetPropName(pNewStats->m_ulRegistryID, pParentName))
- {
- SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.Stream%ld", pParentName->GetBuffer(),
- pStreamInfo->m_uStreamNumber);
- ulRegId = m_pRegistry->GetId(szRegName);
- if (!ulRegId)
- {
- ulRegId = m_pRegistry->AddComp(szRegName);
- }
- if(m_pProto)
- m_pProto->UpdateRegistry(pStreamInfo->m_uStreamNumber, ulRegId);
- }
- HX_RELEASE(pParentName);
- }
- HX_DELETE(m_pStats);
- m_pStats = pNewStats;
- }
- }
- return theErr;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- }
- void
- HXNetSource::LeavePrefetch(void)
- {
- #if defined(HELIX_FEATURE_PREFETCH)
- m_bPrefetch = FALSE;
- if (m_pProto)
- {
- m_pProto->LeavePrefetch();
- }
- // send prefetch notification so that SMIL
- // renderer can resolve the duration on this prefetch track
- if (m_pSourceInfo)
- {
- m_pPlayer->PrefetchTrackDone(m_pSourceInfo->m_uGroupID,
- m_pSourceInfo->m_uTrackID,
- HXR_OK);
- }
- #endif /* HELIX_FEATURE_PREFETCH */
- return;
- }
- void
- HXNetSource::EnterFastStart(void)
- {
- #if defined(HELIX_FEATURE_TURBOPLAY)
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Enter TurboPlay", this));
- m_bFastStart = TRUE;
- if (m_pProto)
- {
- m_pProto->EnterFastStart();
- }
- #endif /* HELIX_FEATURE_TURBOPLAY */
- return;
- }
- void
- HXNetSource::LeaveFastStart(TurboPlayOffReason leftReason)
- {
- #if defined(HELIX_FEATURE_TURBOPLAY)
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Leave TurboPlay", this));
- m_turboPlayStats.tpOffReason = leftReason;
- m_bFastStart = FALSE;
- if (m_pProto)
- {
- m_pProto->LeaveFastStart();
- }
- #endif /* HELIX_FEATURE_TURBOPLAY */
- return;
- }
- BOOL
- HXNetSource::IsPrefetchEnded(void)
- {
- #if defined(HELIX_FEATURE_PREFETCH)
- BOOL bResult = FALSE;
- UINT16 uStreamDone = 0;
- UINT32 ulNumBytes = 0;
- INT64 llLowestTimestamp = MAX_UINT32;
- INT64 llHighestTimestamp = 0;
- CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
- for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
- {
- STREAM_INFO* pStreamInfo = (STREAM_INFO*) (*lStreamIterator);
- UINT16 uStreamNumber = pStreamInfo->m_uStreamNumber;
- INT64 llStreamLowestTimestamp = 0;
- INT64 llStreamHighestTimestamp = 0;
- UINT32 ulStreamNumBytes = 0;
- BOOL bStreamDone = FALSE;
- GetCurrentBuffering(uStreamNumber,
- llStreamLowestTimestamp,
- llStreamHighestTimestamp,
- ulStreamNumBytes,
- bStreamDone);
- if (llLowestTimestamp > llStreamLowestTimestamp)
- {
- llLowestTimestamp = llStreamLowestTimestamp;
- }
- if (llHighestTimestamp < llStreamHighestTimestamp)
- {
- llHighestTimestamp = llStreamHighestTimestamp;
- }
- ulNumBytes += ulStreamNumBytes;
- if (bStreamDone)
- {
- uStreamDone++;
- }
- }
- // prefetch done once we have cached all the data
- if (uStreamDone == mStreamInfoTable->GetCount())
- {
- bResult = TRUE;
- }
- // verify the status of prefetch based on prefetch type/value
- else
- {
- switch (m_prefetchType)
- {
- case PrefetchTime:
- if (llHighestTimestamp - llLowestTimestamp >= m_ulPrefetchValue)
- {
- bResult = TRUE;
- }
- break;
- case PrefetchTimePercent:
- // convert to PrefetchTime
- m_prefetchType = PrefetchTime;
- m_ulPrefetchValue = (UINT32)(m_ulOriginalDuration * m_ulPrefetchValue / 100.0);
- break;
- case PrefetchBytes:
- if (ulNumBytes >= m_ulPrefetchValue)
- {
- bResult = TRUE;
- }
- break;
- case PrefetchBytesPercent:
- // convert to PrefetchBytes
- m_prefetchType = PrefetchBytes;
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- m_ulPrefetchValue = (UINT32)(m_pStats->m_pClipBandwidth->GetInt() * m_ulOriginalDuration * m_ulPrefetchValue / 800.0);
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- break;
- case PrefetchBandwidth:
- // no bandwidth control for PNA
- if (!m_bRTSPProtocol)
- {
- bResult = TRUE;
- }
- else
- {
- IHXThinnableSource* pThin = NULL;
- if (m_pProto &&
- HXR_OK == m_pProto->QueryInterface(IID_IHXThinnableSource, (void **)&pThin))
- {
- pThin->SetDeliveryBandwidth(m_ulPrefetchValue, 0);
- }
- HX_RELEASE(pThin);
- // change the prefetch type so we only SetDeliveryBandwidth once
- m_prefetchType = PrefetchUnknown;
- m_ulPrefetchValue = 0;
- }
- break;
- case PrefetchBandwidthPercent:
- {
- // convert to PrefetchBandwidth
- m_prefetchType = PrefetchBandwidth;
- // get total bandwidth from the preferences
- UINT32 ulBandwidth = 0;
- if (HXR_OK == ReadPrefINT32(m_pPreferences, "Bandwidth", ulBandwidth))
- {
- m_ulPrefetchValue = (UINT32)(ulBandwidth * m_ulPrefetchValue / 100.0);
- }
- }
- break;
- case PrefetchMaxAllowedPlus1:
- // what's this???
- break;
- default:
- break;
- }
- }
- return bResult;
- #else
- return TRUE;
- #endif /* HELIX_FEATURE_PREFETCH */
- }
- HX_RESULT
- HXNetSource::UpdateStatistics(void)
- {
- #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
- ULONG32 ulSourceTotal = 0;
- ULONG32 ulSourceReceived = 0;
- ULONG32 ulSourceNormal = 0;
- UINT32 ulSourceTotal30 = 0;
- UINT32 ulSourceLost30 = 0;
- ULONG32 ulSourceRecovered = 0;
- ULONG32 ulSourceDuplicate = 0;
- ULONG32 ulSourceOutOfOrder = 0;
- ULONG32 ulSourceLost = 0;
- ULONG32 ulSourceLate = 0;
- ULONG32 ulSourceResendRequested = 0;
- ULONG32 ulSourceResendReceived = 0;
- ULONG32 ulSourceBandwidth = 0;
- ULONG32 ulSourceCurBandwidth = 0;
- ULONG32 ulSourceAvgBandwidth = 0;
- INT32 lAvgLatency = 0;
- INT32 lHighLatency = 0;
- INT32 lLowLatency = 0xFFFF;
- IHXStatistics* pStatistics = NULL;
- if (!m_bInitialized)
- {
- return HXR_OK;
- }
- if (m_pProto && HXR_OK == m_pProto->QueryInterface(IID_IHXStatistics, (void**) &pStatistics))
- {
- pStatistics->UpdateStatistics();
- pStatistics->Release();
- pStatistics = NULL;
- }
- CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
- for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
- {
- ULONG32 ulStreamNumber = 0;
- STREAM_INFO* pStreamInfo = (STREAM_INFO*) (*lStreamIterator);
- STREAM_STATS* pStreamStats = NULL;
- if (m_pProto && HXR_OK == m_pProto->GetStreamStatistics((ULONG32) pStreamInfo->m_uStreamNumber, &pStreamStats))
- {
- if (!pStreamStats || !pStreamStats->m_bInitialized)
- {
- continue;
- }
- ulSourceTotal += pStreamStats->m_pTotal->GetInt();
- ulSourceReceived += pStreamStats->m_pReceived->GetInt();
- ulSourceNormal += pStreamStats->m_pNormal->GetInt();
- ulSourceRecovered += pStreamStats->m_pRecovered->GetInt();
- ulSourceDuplicate += pStreamStats->m_pDuplicate->GetInt();
- ulSourceOutOfOrder += pStreamStats->m_pOutOfOrder->GetInt();
- ulSourceLost += pStreamStats->m_pLost->GetInt();
- ulSourceLate += pStreamStats->m_pLate->GetInt();
- ulSourceResendRequested += pStreamStats->m_pResendRequested->GetInt();
- ulSourceResendReceived += pStreamStats->m_pResendReceived->GetInt();
- if (m_ulLossHack > 0 && pStreamInfo->m_ulLost > 0)
- {
- ulSourceReceived -= pStreamInfo->m_ulLost;
- ulSourceNormal -= pStreamInfo->m_ulLost;
- ulSourceLost += pStreamInfo->m_ulLost;
- pStreamStats->m_pReceived->SetInt((INT32) ulSourceReceived);
- pStreamStats->m_pNormal->SetInt((INT32) ulSourceNormal);
- pStreamStats->m_pLost->SetInt((INT32) ulSourceLost);
- }
- ulSourceTotal30 += pStreamStats->m_pTotal30->GetInt();
- ulSourceLost30 += pStreamStats->m_pLost30->GetInt();
- ulSourceAvgBandwidth += pStreamStats->m_pAvgBandwidth->GetInt();
- ulSourceCurBandwidth += pStreamStats->m_pCurBandwidth->GetInt();
- ulSourceBandwidth += pStreamStats->m_pClipBandwidth->GetInt();
- lAvgLatency += pStreamStats->m_pAvgLatency->GetInt();
- if (lHighLatency < pStreamStats->m_pHighLatency->GetInt())
- {
- lHighLatency = pStreamStats->m_pHighLatency->GetInt();
- }
- if (lLowLatency > pStreamStats->m_pLowLatency->GetInt())
- {
- lLowLatency = pStreamStats->m_pLowLatency->GetInt();
- }
- }
- }
- if (m_bSourceEnd)
- {
- ulSourceCurBandwidth = 0;
- ulSourceAvgBandwidth = 0;
- }
- if (m_pStats->m_pNormal) m_pStats->m_pNormal->SetInt((INT32)ulSourceNormal);
- if (m_pStats->m_pRecovered) m_pStats->m_pRecovered->SetInt((INT32)ulSourceRecovered);
- if (m_pStats->m_pDuplicate) m_pStats->m_pDuplicate->SetInt((INT32)ulSourceDuplicate);
- if (m_pStats->m_pOutOfOrder) m_pStats->m_pOutOfOrder->SetInt((INT32)ulSourceOutOfOrder);
- if (m_pStats->m_pReceived) m_pStats->m_pReceived->SetInt((INT32)ulSourceReceived);
- if (m_pStats->m_pLost) m_pStats->m_pLost->SetInt((INT32)ulSourceLost);
- if (m_pStats->m_pLate) m_pStats->m_pLate->SetInt((INT32)ulSourceLate);
- if (m_pStats->m_pTotal) m_pStats->m_pTotal->SetInt((INT32)ulSourceTotal);
- if (m_pStats->m_pTotal30) m_pStats->m_pTotal30->SetInt((INT32)ulSourceTotal30);
- if (m_pStats->m_pLost30) m_pStats->m_pLost30->SetInt((INT32)ulSourceLost30);
- if (m_pStats->m_pResendRequested) m_pStats->m_pResendRequested->SetInt((INT32)ulSourceResendRequested);
- if (m_pStats->m_pResendReceived) m_pStats->m_pResendReceived->SetInt((INT32)ulSourceResendReceived);
- if (m_pStats->m_pClipBandwidth) m_pStats->m_pClipBandwidth->SetInt((INT32)ulSourceBandwidth);
- if (m_pStats->m_pCurBandwidth) m_pStats->m_pCurBandwidth->SetInt((INT32)ulSourceCurBandwidth);
- if (m_pStats->m_pAvgBandwidth) m_pStats->m_pAvgBandwidth->SetInt((INT32)ulSourceAvgBandwidth);
- if (m_pStats->m_pAvgLatency) m_pStats->m_pAvgLatency->SetInt((INT32)lAvgLatency);
- if (m_pStats->m_pHighLatency) m_pStats->m_pHighLatency->SetInt((INT32)lHighLatency);
- if (m_pStats->m_pLowLatency) m_pStats->m_pLowLatency->SetInt((INT32)lLowLatency);
- // XXXHP: we should only update these info. once
- // update transport mode
- switch (m_CurrentTransport)
- {
- case UnknownMode:
- m_pStats->m_pTransportMode->SetStr("Unknown");
- break;
- case MulticastMode:
- if (helixSDPProtocol == m_uProtocolType)
- {
- m_pStats->m_pTransportMode->SetStr("Scalable Multicast");
- }
- else
- {
- m_pStats->m_pTransportMode->SetStr("Multicast");
- }
- break;
- case UDPMode:
- m_pStats->m_pTransportMode->SetStr("UDP");
- break;
- case TCPMode:
- m_pStats->m_pTransportMode->SetStr("TCP");
- break;
- case HTTPCloakMode:
- if (m_bRTSPProtocol)
- {
- m_pStats->m_pTransportMode->SetStr("RTSPvHTTP");
- }
- else
- {
- m_pStats->m_pTransportMode->SetStr("PNAvHTTP");
- }
- break;
- default:
- break;
- }
- // update buffering mode(local machine)
- if (m_pStats->m_pBufferingMode)
- {
- if (m_bForcePerfectPlay && m_bPerfectPlay)
- {
- if (m_bCannotBufferEntireClip)
- {
- m_pStats->m_pBufferingMode->SetInt(BUFFERED_PLAY_NOT_ENTIRE_CLIP);
- }
- else
- {
- m_pStats->m_pBufferingMode->SetInt(BUFFERED_PLAY);
- }
- }
- else if (m_bPerfectPlay)
- {
- if (m_bCannotBufferEntireClip)
- {
- m_pStats->m_pBufferingMode->SetInt(PERFECT_PLAY_NOT_ENTIRE_CLIP);
- }
- else
- {
- m_pStats->m_pBufferingMode->SetInt(PERFECT_PLAY);
- }
- }
- else if (m_bBufferedPlay)
- {
- m_pStats->m_pBufferingMode->SetInt(BUFFERED_PLAY);
- }
- else
- {
- m_pStats->m_pBufferingMode->SetInt(NORMAL_PLAY);
- }
- }
- #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
- return HXR_OK;
- }
- HX_RESULT
- HXNetSource::_ProcessIdle(BOOL atInterrupt)
- {
- HX_RESULT theErr = HXR_OK;
- UINT32 ulAlert = 0;
- const char* pszAlert = NULL;
- if (m_bLocked)
- {
- return HXR_OK;
- }
- theErr = _ProcessIdleExt(atInterrupt);
- if (HXR_ABORT == theErr)
- {
- return HXR_OK;
- }
- m_bLocked = TRUE;
- if (m_bRedirectPending && !m_bPartOfNextGroup)
- {
- m_bRedirectPending = FALSE;
- HX_ASSERT(m_pszRedirectURL);
- theErr = m_pSourceInfo->HandleRedirectRequest(m_pszRedirectURL);
- HX_VECTOR_DELETE(m_pszRedirectURL);
-
- goto exit;
- }
- switch (m_state)
- {
- case NETSRC_PACREADY:
- case NETSRC_TRANSPORTREADY:
- m_state = NETSRC_READY;
- theErr = FinishSetup();
- goto exit;
- break;
- case NETSRC_PACPENDING:
- case NETSRC_TRANSPORTPENDING:
- goto exit;
- break;
- default:
- break;
- }
- if (!m_pProto)
- {
- goto exit;
- }
- #ifdef _MACINTOSH
- if (m_bBruteForceConnectToBeDone)
- {
- BOOL bAtInterrupt = FALSE;
- IHXInterruptState* pInterruptState = NULL;
- if (m_pEngine &&
- m_pEngine->QueryInterface(IID_IHXInterruptState, (void**) &pInterruptState) == HXR_OK)
- {
- bAtInterrupt = pInterruptState->AtInterruptTime();
- HX_RELEASE(pInterruptState);
- }
- if (!bAtInterrupt)
- {
- m_bBruteForceConnectToBeDone = FALSE;
- theErr = handleTransportSwitch();
- }
- goto exit;
- }
- #endif
- if (m_bBruteForceReconnected && m_bInitialized)
- {
- /* If user has not called DoResume yet, do not call it here */
- if (m_bUserHasCalledResume)
- {
- if (CanBeResumed())
- {
- if (m_pSourceInfo)
- {
- m_pSourceInfo->Register();
- }
- if (m_pPlayer)
- {
- m_pPlayer->RegisterSourcesDone();
- }
- DoResume();
- }
- }
- else if (m_bUserHasCalledStartInit)
- {
- StartInitialization();
- }
- m_bBruteForceReconnected = FALSE;
- }
- if (atInterrupt)
- {
- m_bAtInterrupt = TRUE;
- theErr = m_pProto->process_idle(TRUE);
- m_bAtInterrupt = FALSE;
- }
- else
- {
- BOOL bAlreadySwitchedPorts = FALSE;
- theErr = m_pProto->process_idle(FALSE);
- if (!theErr && mLastError)
- {
- theErr = mLastError;
- }
- if (m_bInitialized &&
- m_bPerfectPlay &&
- !m_bPerfectPlayErrorChecked)
- {
- m_bPerfectPlayErrorChecked = TRUE;
- if(!m_bServerHasPerfectPlay)
- {
- theErr = HXR_PERFECTPLAY_NOT_SUPPORTED;
- }
- else
- {
- // Check for attempt to use perfect play on live stream...
- if (mLiveStream)
- {
- theErr = HXR_NO_LIVE_PERFECTPLAY;
- }
- // we will not allow perfect play if perfect play bit is NOT set.
- if(!m_bPerfectPlayAllowed)
- {
- theErr = HXR_PERFECTPLAY_NOT_ALLOWED;
- }
- }
- }
- if (theErr == HXR_UNEXPECTED_STREAM_END)
- {
- theErr = AttemptReconnect();
- mLastError = theErr;
- }
- // handle HXR_REDIRECTION explicitly
- if (theErr == HXR_REDIRECTION)
- {
- // determine whether it's too late to do redirect within the same
- // source - any redirect received before SetupResponse received is OK
- // since we haven't initialized all the renderers yet
- //
- // we used to decide upon m_bReceivedHeader which is set within
- // HandleDescribeResponse, we now enlarge the window a bit by
- // deciding upon m_bInitialized which is set within HandleSetupResponse
- if (!m_bInitialized)
- {
- // redirect at source level
- // we don't need to tear down the source since we
- // haven't receive any headers yet
- m_CurrentTransport = UnknownMode;
- mLastError = HXR_OK;
- DeleteStreamTable();
- theErr = handleRedirect();
- }
- else if (m_pSourceInfo && m_pszRedirectURL)
- {
- if (m_bPartOfNextGroup)
- {
- m_bRedirectPending = TRUE;
- }
- else
- {
- // too late to do the Redirect at source level
- // let the player to handle it
- theErr = m_pSourceInfo->HandleRedirectRequest(m_pszRedirectURL);
- }
- }
- }
- else if (!m_bReceivedData && theErr)
- {
- // NOTE: Handle automatic transport switching here...
- switch(theErr)
- {
- case HXR_NET_CONNECT:
- case HXR_SERVER_DISCONNECTED:
- if (HTTPCloakMode == m_CurrentTransport)
- {
- theErr = handleProxySwitch(theErr);
- }
- if (HXR_OK != theErr)
- {
- theErr = switch_to_next_transport(theErr);
- }
- break;
- case HXR_MULTICAST_UDP:
- case HXR_NET_UDP:
- case HXR_NET_TCP:
- case HXR_BAD_TRANSPORT:
- theErr = switch_to_next_transport(theErr);
- break;
- case HXR_PERFECTPLAY_NOT_SUPPORTED:
- case HXR_NO_LIVE_PERFECTPLAY:
- case HXR_PERFECTPLAY_NOT_ALLOWED:
- theErr = switch_out_of_perfectplay();
- break;
- case HXR_FORCE_PERFECTPLAY:
- // if we have connected to an old server and we wanted PerfectPlay, we
- // we need to reconnect to the server using the Protocol 8 PerfectPlay
- // mechanism to ensure that we get the data via UDP
- m_bPerfectPlay = TRUE;
- /* If the server is forcing us into PerfectPlay, it means
- * it does allow it AND the clip is perfectPlay-able.
- */
- m_bPerfectPlayAllowed = TRUE;
- m_bServerHasPerfectPlay = TRUE;
- WritePerfectPlayToRegistry();
- theErr = switch_to_next_transport(HXR_OK);
- break;
- default:
- break;
- };
- if (!m_bRTSPProtocol &&
- HTTPCloakMode == m_CurrentTransport &&
- m_pCloakPortList &&
- m_nCurrPortIdx < m_nNumberOfCloakPorts-1 &&
- (HXR_NET_CONNECT == theErr ||
- HXR_DNR == theErr ||
- HXR_SERVER_DISCONNECTED == theErr ||
- HXR_DOC_MISSING == theErr ||
- HXR_BAD_SERVER == theErr ||
- HXR_PROXY_NET_CONNECT == theErr))
- {
- m_PreferredTransport = HTTPCloakMode;
- m_uCurrCloakedPort = m_pCloakPortList[++m_nCurrPortIdx];
- theErr = handleTransportSwitch();
- mLastError = theErr;
- }
- }
- }
- if (theErr)
- {
- if (theErr == HXR_NET_CONNECT && m_bUseProxy)
- {
- mLastError = HXR_PROXY_NET_CONNECT;
- }
- else if (theErr == HXR_NET_CONNECT && HTTPCloakMode == m_CurrentTransport)
- {
- // we mask to HTTP connection error only if we are in HTTP only mode
- if (m_ulTransportPrefMask == ATTEMPT_HTTPCLOAK)
- {
- mLastError = HXR_HTTP_CONNECT;
- }
- else
- {
- mLastError = theErr;
- }
- }
- else if (theErr == HXR_DNR && m_bUseProxy)
- {
- mLastError = HXR_PROXY_DNR;
- }
- else
- {
- mLastError = theErr;
- }
- }
- if (m_bReceivedData && HXR_OK != mLastError)
- {
- if (m_state == NETSRC_RECONNECTSTARTED)
- {
- DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Reconnect Failed", this));
- }
- // we are reconnecting now
- else if (m_state == NETSRC_RECONNECTPENDING)
- {
- mLastError = theErr = HXR_OK;
- }
- // issue reconnect on the following network errors
- else
- {
- if (HXR_SERVER_DISCONNECTED == mLastError ||
- HXR_SERVER_TIMEOUT == mLastError ||
- HXR_NET_SOCKET_INVALID == mLastError ||
- HXR_GENERAL_NONET == mLastError ||
- IS_SERVER_ALERT(mLastError))
- {
- HX_ASSERT(m_state == NETSRC_READY);
- if (m_bSourceEnd)
- {
- mLastError = theErr = HXR_OK;
- }
- else if (IsNetworkAvailable() && m_bAttemptReconnect)
- {
- if (IS_SERVER_ALERT(mLastError))
- {
- pszAlert = m_pProto->GetLastAlertInfo(ulAlert);
- if (PE_PROXY_ORIGIN_DISCONNECTED == ulAlert)
- {
- theErr = AttemptReconnect();
- mLastError = theErr;
- }
- }
- else
- {
- theErr = AttemptReconnect();
- mLastError = theErr;
- }
- }
- }
- else
- {
- // hummm, what error is this??
- HX_ASSERT(FALSE);
- }
- }
- }
- /* tell the player about the error...
- * This is crucial...
- */
- if (m_pPlayer && mLastError)
- {
- #if defined(HELIX_FEATURE_SMARTERNETWORK)
- if (m_pPreferredTransport)
- {
- m_pPreferredTransport->RemoveTransport();
- m_pPreferredTransport->RemoveTransportSink(this);
- HX_RELEASE(m_pPreferredTransport);
- }
- #endif /* HELIX_FEATURE_SMARTERNETWORK */
- char* pErrorBuf = NULL;
- if (IS_SERVER_ALERT(mLastError))
- {
- pszAlert = m_pProto->GetLastAlertInfo(ulAlert);
- if(pszAlert)
- {
- int lenBuf = strlen(pszAlert) + strlen(m_pszURL) + 5;
- pErrorBuf = new char[lenBuf];
- SafeSprintf(pErrorBuf, lenBuf, "%srn%s", pszAlert, m_pszURL); /* Flawfinder: ignore */
- }
- }
- if (!pErrorBuf && helixSDPProtocol != m_uProtocolType)
- {
- pErrorBuf = new char[strlen(m_pszURL) + 1];
- strcpy(pErrorBuf, m_pszURL); /* Flawfinder: ignore */
- }
- m_pPlayer->ReportError(this, mLastError, pErrorBuf);
- delete[] pErrorBuf;
- }
- if (!theErr && m_bInitialized)
- {
- UINT32 ulCurrentTime = m_pPlayer->GetInternalCurrentPlayTime();
- // set m_bDelayed to FALSE as soon as it's due to begin playback
- // even it's still in pre-fetch mode
- if (!m_bPaused && m_bDelayed)
- {
- UINT32 ulStartTime = 0;
- if (m_ulDelay > m_ulPreRollInMs + NETWORK_FUDGE_FACTOR)
- {
- ulStartTime = m_ulDelay - (m_ulPreRollInMs + NETWORK_FUDGE_FACTOR);
- }
- if (ulCurrentTime >= ulStartTime)
- {
- m_bDelayed = FALSE;
- }
- }
- #if defined(HELIX_FEATURE_PREFETCH)
- // verify the status of prefetch
- if (m_bPrefetch)
- {
- BOOL bPrefetchDone = IsPrefetchEnded();
- // stop prefetch when either the prefetch has been done or
- // the active source itself started playback
- if (bPrefetchDone ||
- (!m_bDelayed && !m_bPartOfPrefetchGroup))
- {
- LeavePrefetch();
- // pause delayed source
- if (bPrefetchDone && m_bDelayed)
- {
- DoPause();
- }
- }
- }
- #endif /* HELIX_FEATURE_PREFETCH */
- if (!m_bSourceEnd)
- {
- /* Get Current buffering status every 1 sec. */
- UINT32 ulCurrentSystemTime = HX_GET_TICKCOUNT();
- if (CALCULATE_ELAPSED_TICKS(m_ulLastBufferingCalcTime,
- ulCurrentSystemTime) > 1000)
- {
- m_ulLastBufferingCalcTime = ulCurrentSystemTime;
- CalculateCurrentBuffering();
- }
- }
- // rebuffer if the source hasn't satisfy its initial preroll when it's
- // time to start
- // resume in InitialBufferingDone()
- if (IsPlaying() &&
- !m_bPartOfPrefetchGroup &&
- m_bInitialBuffering &&
- !m_bRebufferingRequired &&
- (ulCurrentTime + MIN_BUFFERTIME_BEFORE_DELAY) >= m_ulDelay)
- {
- DoRebuffer();
- }
- }
- exit:
- if (!theErr && !m_bIsActive && !m_bDelayed && m_pPlayer &&
- m_bInitialized && m_pPlayer->GetInternalCurrentPlayTime() >= m_ulDelay)
- {
- AdjustClipBandwidthStats(TRUE);
- }
- m_bLocked = FALSE;
- return(theErr);
- }
- HX_RESULT
- HXNetSource::_ProcessIdleExt(BOOL atInterrupt)
- {
- return HXR_OK;
- }
- // set the various parameters that are used by all the protocols
- HX_RESULT
- HXNetSource::InitializeProtocol()
- {
- HX_TRACE("HXNetSource::InitializeProtocol");
- HX_RESULT theErr = HXR_OK;
- // set the client ID
- theErr = m_pProto->set_client_id( mClientID );
- if (HXR_OK != theErr)
- {
- goto cleanup;
- }