hxntsrc.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:180k
源码类别:

Symbian

开发平台:

Visual C++

  1.     // set the client ID
  2.     theErr = m_pProto->set_client_id( mClientID );
  3.     if (HXR_OK != theErr)
  4.     {
  5.         goto cleanup;
  6.     }
  7.     // If we reach to an unknown mode during transport switching, then
  8.     // we are all out of possibilities, and we can consider the server
  9.     // connection timed out...
  10.     if (m_PreferredTransport == UnknownMode)
  11.     {
  12.         theErr = HXR_SERVER_TIMEOUT;
  13.         goto cleanup;
  14.     }
  15.     else
  16.     {
  17.         set_transport(m_PreferredTransport);
  18.     }
  19.     // If we were asked to use a specific UDP Port. Then
  20.     // tell the protocol object about the request...
  21.     if (m_bUseUDPPort)
  22.     {
  23.         m_pProto->set_UDP_port();
  24.     }
  25.     if (m_bUseProxy)
  26.     {
  27.         theErr = m_pProto->set_proxy(m_pProxy,m_uProxyPort);
  28.         if (HXR_OK != theErr)
  29.         {
  30.             goto cleanup;
  31.         }
  32.     }
  33.     if (HTTPCloakMode == m_CurrentTransport &&
  34.         PTS_READY != m_prefTransportState)
  35.     {
  36.         CreateCloakedPortList();
  37.         m_pProto->SetCloakPortAttempted(m_pCloakPortList, m_nNumberOfCloakPorts);
  38.     }
  39. #if defined(HELIX_FEATURE_PREFETCH)
  40.     if (m_bPrefetch)
  41.     {
  42.         m_pProto->EnterPrefetch();
  43.     }
  44. #endif /* HELIX_FEATURE_PREFETCH */
  45.     m_pProto->set_server_timeout(m_ulServerTimeOut);
  46.     m_pProto->set_perfect_play(m_bPerfectPlay);
  47. cleanup:
  48.     return theErr;
  49. }
  50. void
  51. HXNetSource::set_transport(TransportMode mode)
  52. {
  53.     DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)set_transport %lu", this, mode));
  54.     m_CurrentTransport = mode;
  55.     // Tell the protocol object, (in case it doesn't remember <g>).
  56.     if(m_pProto)
  57.         m_pProto->set_transport(m_CurrentTransport, m_ulTransportPrefMask);
  58. }
  59. // sets up HXSource to use a RealMedia splitter
  60. HX_RESULT
  61. HXNetSource::set_proxy(const char* proxy, UINT16 port)
  62. {
  63.     HX_TRACE("HXNetSource::set_proxy");
  64.     HX_RESULT           theErr = HXR_OK;
  65.     IHXProxyManager*    pProxyManager = NULL;
  66.     if(proxy == 0 || *proxy == 0)
  67.     {
  68.         theErr = HXR_OK;
  69.         goto cleanup;
  70.     }
  71.     if(m_pProxy)
  72.     {
  73.         delete [] m_pProxy;
  74.         m_pProxy = NULL;
  75.     }
  76.     m_pProxy = new char[::strlen(proxy) + 1];
  77.     if(m_pProxy == NULL)
  78.     {
  79.         theErr = HXR_OUTOFMEMORY;
  80.         goto cleanup;
  81.     }
  82.     ::strcpy(m_pProxy, proxy); /* Flawfinder: ignore */
  83.     m_uProxyPort = port;
  84.     m_bUseProxy = TRUE;
  85.     if (m_pPlayer &&
  86.         HXR_OK == m_pPlayer->QueryInterface(IID_IHXProxyManager, (void**)&pProxyManager) &&
  87.         pProxyManager)
  88.     {
  89.         m_bUseProxy = !(pProxyManager->IsExemptionHost(m_pHost));
  90.     }
  91.     HX_RELEASE(pProxyManager);
  92. cleanup:
  93.     return(theErr);
  94. }
  95. HX_RESULT
  96. HXNetSource::cleanup_proxy(void)
  97. {
  98.     HX_TRACE("HXNetSource::cleanup_proxy");
  99.     HX_RESULT       theErr = HXR_OK;
  100.     m_uProxyPort = 0;
  101.     HX_VECTOR_DELETE(m_pProxy);
  102.     m_bUseProxy = FALSE;
  103.     return(theErr);
  104. }
  105. HX_RESULT
  106. HXNetSource::ReadPreferences()
  107. {
  108.     HX_TRACE("HXNetSource::ReadPreferences");
  109.     HX_RESULT       theErr = HXR_OK;
  110.     UINT32          un16Temp = 0;
  111.     TransportMode   preferredTransMode = UnknownMode;
  112.     TransportMode   desiredTransMode = UnknownMode;
  113.     IHXBuffer*      pValue = NULL;
  114.     theErr = HXSource::ReadPreferences();
  115.     if (theErr)
  116.     {
  117.             return theErr;
  118.     }
  119.     // Read Client ID
  120.     IHXBuffer* pBuffer = NULL;
  121.     IHXBuffer* pProxyHost = NULL;
  122.     IHXBuffer* pProxyPort = NULL;
  123.     /* We only want to read PerfectPlay preference once.
  124.      * This is because we may disable PerfectPlay if the server
  125.      * does not allow it OR if the content is not "PerfectPlay"able.
  126.      * In each of these cases, we call brute_force_reconnect()
  127.      * and we do not want to over-write m_bPerfectPlay
  128.      */
  129.     if (!m_bPerfectPlayPreferenceRead)
  130.     {
  131.         m_bPerfectPlayPreferenceRead = TRUE;
  132.         ReadPrefBOOL(m_pPreferences, "PerfectPlay", m_bPerfectPlay);         
  133.     }
  134.     const char* pcszClientID = NULL;
  135.     IHXRegistry* pRegistry = NULL;
  136.     if (m_pEngine->QueryInterface(IID_IHXRegistry, (void**)&pRegistry) == HXR_OK)
  137.     {
  138.         // Form clientID registry string
  139.         CHXString strTemp;
  140.         strTemp = HXREGISTRY_PREFPROPNAME;
  141.         strTemp += '.';
  142.         strTemp += CLIENT_ID_REGNAME;
  143.         if (pRegistry->GetStrByName(strTemp, pBuffer) == HXR_OK)
  144.         {
  145.             pcszClientID = (const char*)pBuffer->GetBuffer();
  146.         }
  147.         pRegistry->Release();
  148.     }
  149.     else
  150.     {
  151.         // Encode the client ID with the pieces of interest.
  152.         HXVERSIONINFO verInfo;
  153.         HXGetWinVer(&verInfo);
  154.         pcszClientID = HXGetVerEncodedName(&verInfo,
  155.                                            PRODUCT_ID,
  156.                                            TARVER_STRING_VERSION,
  157.                                            LANGUAGE_CODE,
  158.                                            "RN01");
  159.     }
  160.     if (pcszClientID)
  161.     {
  162.         UINT32 ulSizeof_mClientID = sizeof(mClientID);
  163.         UINT32 ulSafeStrlenClientId = HX_SAFESIZE_T(strlen(pcszClientID));
  164.         HX_ASSERT(ulSafeStrlenClientId < ulSizeof_mClientID);
  165.         if (ulSafeStrlenClientId >= ulSizeof_mClientID)
  166.         {
  167.             // /Limiting too-large string fixes PR 86928 (but whatever
  168.             // writes to props|prefs needs to be sure not to overflow
  169.             // the max size):
  170.             ulSafeStrlenClientId = ulSizeof_mClientID - 1;
  171.         }
  172.         
  173.         memcpy(mClientID, pcszClientID, ulSafeStrlenClientId); /* Flawfinder: ignore */
  174.         mClientID[ulSafeStrlenClientId] = '';
  175.     }
  176.     HX_RELEASE(pBuffer);
  177.     ReadPrefINT32(m_pPreferences, "ServerTimeOut", m_ulServerTimeOut);
  178.     if (m_ulServerTimeOut < MINIMUM_TIMEOUT)
  179.     {
  180.         m_ulServerTimeOut = MINIMUM_TIMEOUT;
  181.     }
  182.     ReadPrefINT32(m_pPreferences, "ConnectionTimeOut", m_ulConnectionTimeout);
  183.     if (m_ulConnectionTimeout < MINIMUM_TIMEOUT)
  184.     {
  185.         m_ulConnectionTimeout = MINIMUM_TIMEOUT;
  186.     }
  187.     ReadPrefINT32(m_pPreferences, "MulticastTimeout", m_ulMulticastTimeout);
  188.     ReadPrefINT32(m_pPreferences, "UDPTimeout", m_ulUDPTimeout);
  189.     ReadPrefINT32(m_pPreferences, "TCPTimeout", m_ulTCPTimeout);
  190.     
  191.     ReadPrefBOOL(m_pPreferences, "SendStatistics", m_bSendStatistics);
  192.     /////////////////////////////////////////////////////////////
  193.     //
  194.     // Handle Specific UDP Port Preferences here....
  195.     //
  196.     ReadPrefBOOL(m_pPreferences, "UseUDPPort", m_bUseUDPPort);
  197. #if defined(HELIX_FEATURE_SMARTERNETWORK)
  198.     if (!m_pPreferredTransport)
  199.     {
  200.         m_pPreferredTransportManager->GetTransportPreference(m_bRTSPProtocol?PTP_RTSP:PTP_PNM, m_ulTransportPrefMask);
  201.         HX_ASSERT(m_ulTransportPrefMask);
  202.         m_pPreferredTransportManager->GetPrefTransport(m_pHost,
  203.                                                        m_bRTSPProtocol?PTP_RTSP:PTP_PNM,
  204.                                                        m_pPreferredTransport);
  205.         HX_ASSERT(m_pPreferredTransport);
  206.         m_prefTransportState = m_pPreferredTransport->GetState();
  207.         if (m_prefTransportState == PTS_READY ||
  208.             m_prefTransportState == PTS_CREATE)
  209.         {
  210.             m_pPreferredTransport->GetTransport(m_PreferredTransport,
  211.                                                 m_uCurrCloakedPort);
  212. #if !defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
  213.             if (MulticastMode == m_PreferredTransport)
  214.             {
  215.                 m_PreferredTransport = UDPMode;
  216.             }
  217. #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
  218.         }
  219.         else if (m_prefTransportState == PTS_PENDING)
  220.         {
  221.             m_state = NETSRC_TRANSPORTPENDING;
  222.             m_pPreferredTransport->AddTransportSink(this);
  223.             theErr = HXR_WOULD_BLOCK;
  224.         }
  225.     }
  226. #else
  227.     if (UnknownMode == m_PreferredTransport)
  228.     {
  229.         m_PreferredTransport = UDPMode;
  230.     }
  231. #endif /* HELIX_FEATURE_SMARTERNETWORK */
  232.     // if the "Use Proxy" is explicitly set, we will use proxy settings accordingly
  233.     // regardless what server type(internal vs external) it is.
  234.     //if (m_pPreferredTransport->GetClass() == PTC_EXTERNAL)
  235.     {
  236.         // handle proxies
  237.         if (HTTPCloakMode == m_PreferredTransport)
  238.         {
  239.             un16Temp = 0;
  240. #if defined(HELIX_FEATURE_PAC)
  241.             if (HXR_OK != ReadPrefINT32(m_pPreferences, "HTTPProxyAutoConfig", un16Temp))
  242.             {
  243.                 // previously released Enterprise player may use "ProxyAutoConfig" for
  244.                 // HTTP proxy auto config
  245.                 ReadPrefINT32(m_pPreferences, "ProxyAutoConfig", un16Temp);
  246.             }
  247.             // HTTP Proxy Auto Config
  248.             if (un16Temp)
  249.             {
  250.                 if (!m_pPAC)
  251.                 {
  252.                     m_pEngine->QueryInterface(IID_IHXProxyAutoConfig, (void**)&m_pPAC);
  253.                 }
  254.                 if (m_pPAC &&
  255.                     (!m_pPACInfoList || 0 == m_pPACInfoList->GetCount()))
  256.                 {
  257.                     theErr = m_pPAC->GetHTTPProxyInfo((IHXProxyAutoConfigCallback*)this,
  258.                                                       m_pszURL,
  259.                                                       m_pHost);
  260.                 }
  261.                 // attempt the next proxy info from m_pPACInfoList
  262.                 else if (m_pPACInfoList && m_PACInfoPosition)
  263.                 {
  264.                     PACInfo* pPACInfo = (PACInfo*)m_pPACInfoList->GetNext(m_PACInfoPosition);
  265.                     if (pPACInfo && pPACInfo->type != PAC_DIRECT)
  266.                     {
  267.                         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)PAC: %s %lu", this, pPACInfo->pszHost, pPACInfo->ulPort));
  268.                         set_proxy(pPACInfo->pszHost, (UINT16)pPACInfo->ulPort);
  269.                     }
  270.                     else if (pPACInfo)
  271.                     {
  272.                         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)PAC: DIRECT", this));
  273.                     }
  274.                 }
  275.                 if (HXR_WOULD_BLOCK == theErr)
  276.                 {
  277.                     m_state = NETSRC_PACPENDING;
  278.                 }
  279.             }
  280.             else
  281. #endif /* HELIX_FEATURE_PAC */
  282.             {
  283.                 if (HXR_OK == ReadPrefINT32(m_pPreferences, "HTTPProxySupport", un16Temp))
  284.                 {
  285.                     if (un16Temp)
  286.                     {
  287.                         if (m_pszReconnectProxy)
  288.                         {
  289.                             set_proxy(m_pszReconnectProxy, (UINT16)m_ulReconnectProxyPort);
  290.                         }
  291.                         else if (m_pPreferences && m_pPreferences->ReadPref("HTTPProxyHost", pProxyHost) == HXR_OK &&
  292.                                  m_pPreferences->ReadPref("HTTPProxyPort", pProxyPort) == HXR_OK)
  293.                         {
  294.                             set_proxy((const char*)pProxyHost->GetBuffer(), atoi((const char*)pProxyPort->GetBuffer()));
  295.                         }
  296.                         HX_RELEASE(pProxyHost);
  297.                         HX_RELEASE(pProxyPort);
  298.                     }
  299.                 }
  300.             }
  301.         }
  302.         else
  303.         {
  304. #if defined(HELIX_FEATURE_PAC)
  305.             // RTSP/PNM Proxy Auto Config
  306.             if (HXR_OK == ReadPrefINT32(m_pPreferences, "RTSPPNMProxyAutoConfig", un16Temp) && un16Temp)
  307.             {
  308.                 if (!m_pPAC)
  309.                 {
  310.                     m_pEngine->QueryInterface(IID_IHXProxyAutoConfig, (void**)&m_pPAC);
  311.                 }
  312.                 if (m_pPAC &&
  313.                     (!m_pPACInfoList || 0 == m_pPACInfoList->GetCount()))
  314.                 {
  315.                     theErr = m_pPAC->GetRTSPPNMProxyInfo((IHXProxyAutoConfigCallback*)this,
  316.                                                          m_pszURL,
  317.                                                          m_pHost);
  318.                 }
  319.                 // attempt the next proxy info from m_pPACInfoList
  320.                 else if (m_pPACInfoList && m_PACInfoPosition)
  321.                 {
  322.                     PACInfo* pPACInfo = (PACInfo*)m_pPACInfoList->GetNext(m_PACInfoPosition);
  323.                     if (pPACInfo && pPACInfo->type != PAC_DIRECT)
  324.                     {
  325.                         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)PAC: %s %lu", this, pPACInfo->pszHost, pPACInfo->ulPort));
  326.                         set_proxy(pPACInfo->pszHost, (UINT16)pPACInfo->ulPort);
  327.                     }
  328.                     else if (pPACInfo)
  329.                     {
  330.                         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)PAC: DIRECT", this));
  331.                     }
  332.                 }
  333.                 if (HXR_WOULD_BLOCK == theErr)
  334.                 {
  335.                     m_state = NETSRC_PACPENDING;
  336.                 }
  337.             }
  338.             else
  339. #endif /* HELIX_FEATURE_PAC */
  340.             {
  341.                 // RTSP proxy
  342.                 if (m_bRTSPProtocol)
  343.                 {
  344.                     if (HXR_OK == ReadPrefINT32(m_pPreferences, "RTSPProxySupport", un16Temp) && un16Temp)
  345.                     {
  346.                         if (m_pszReconnectProxy)
  347.                         {
  348.                             set_proxy(m_pszReconnectProxy, (UINT16)m_ulReconnectProxyPort);
  349.                         }
  350.                         else if (m_pPreferences && m_pPreferences->ReadPref("RTSPProxyHost", pProxyHost) == HXR_OK &&
  351.                                  m_pPreferences->ReadPref("RTSPProxyPort", pProxyPort) == HXR_OK)
  352.                         {
  353.                             set_proxy((const char*)pProxyHost->GetBuffer(), atoi((const char*)pProxyPort->GetBuffer()));
  354.                         }
  355.                         HX_RELEASE(pProxyHost);
  356.                         HX_RELEASE(pProxyPort);
  357.                     }
  358.                 }
  359. #if defined(HELIX_FEATURE_PNA)
  360.                 // PNA proxy
  361.                 else
  362.                 {
  363.                     if (HXR_OK == ReadPrefINT32(m_pPreferences, "PNAProxySupport", un16Temp) && un16Temp)
  364.                     {
  365.                         if (m_pszReconnectProxy)
  366.                         {
  367.                             set_proxy(m_pszReconnectProxy, m_ulReconnectProxyPort);
  368.                         }
  369.                         else if (m_pPreferences && m_pPreferences->ReadPref("PNAProxyHost", pProxyHost) == HXR_OK &&
  370.                                  m_pPreferences->ReadPref("PNAProxyPort", pProxyPort) == HXR_OK)
  371.                         {
  372.                             set_proxy((const char*)pProxyHost->GetBuffer(), atoi((const char*)pProxyPort->GetBuffer()));
  373.                         }
  374.                         HX_RELEASE(pProxyHost);
  375.                         HX_RELEASE(pProxyPort);
  376.                     }
  377.                 }
  378. #endif /* defined(HELIX_FEATURE_PNA)*/
  379.             }
  380.         }
  381.     }
  382.     return theErr;
  383. }
  384. HX_RESULT
  385. HXNetSource::CreateProtocol()
  386. {
  387.     IHXStatistics*      pStatistics = NULL;
  388.     HX_TRACE("HXNetSource::CreateProtocol");
  389.     HX_RESULT theErr = HXR_OK;
  390.     // delete the earlier protocol if one exists
  391.     HX_RELEASE(m_pProto);
  392.     if (m_bRTSPProtocol)
  393.     {
  394.         m_pProto = new RTSPProtocol(this, 0);
  395.     }
  396.     else
  397.     {
  398. #if defined(HELIX_FEATURE_PNA)
  399.         m_pProto = new PNAProtocol(this, 0);
  400. #else
  401.         theErr = HXR_INVALID_PROTOCOL;
  402. #endif /* HELIX_FEATIRE_PNA */
  403.     }
  404.     if (HXR_OK == theErr)
  405.     {
  406.         if (m_pProto == NULL)
  407.         {
  408.             theErr = HXR_OUTOFMEMORY;
  409.         }
  410.         else
  411.         {
  412.             HX_ADDREF(m_pProto);
  413.         }
  414.     }
  415.     // set the proxy
  416.     if (!theErr && m_bUseProxy)
  417.     {
  418.         theErr = m_pProto->set_proxy(m_pProxy, m_uProxyPort);
  419.     }
  420. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  421.     if (!theErr && HXR_OK == m_pProto->QueryInterface(IID_IHXStatistics, (void**) &pStatistics))
  422.     {
  423.         if (m_pStats)
  424.         {
  425.             pStatistics->InitializeStatistics(m_pStats->m_ulRegistryID);
  426.         }
  427.         HX_RELEASE(pStatistics);
  428.     }
  429. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  430.     return theErr;
  431. }
  432. BOOL
  433. HXNetSource::CheckTransportTimeout(ULONG32 ulTime)
  434. {
  435.     BOOL    bTimedOut = FALSE;
  436.     ULONG32 ulTimeOut = 0;
  437.     if (!m_bDataWaitStarted)
  438.     {
  439.         return FALSE;
  440.     }
  441.     ULONG32 elapsed = CALCULATE_ELAPSED_TICKS(m_ulStartDataWait,ulTime);
  442.     if (m_bConnectionWait)
  443.     {
  444.         ulTimeOut = m_ulConnectionTimeout * MILLISECS_PER_SECOND;
  445.     }
  446.     else
  447.     {
  448.         switch (m_CurrentTransport)
  449.         {
  450.         case MulticastMode:
  451.             ulTimeOut = m_ulMulticastTimeout;
  452.             break;
  453.         case UDPMode:
  454.             ulTimeOut = m_ulUDPTimeout;
  455.             break;
  456.         case TCPMode:
  457.             ulTimeOut = m_ulTCPTimeout;
  458.             break;
  459.         default:
  460.             ulTimeOut = m_ulServerTimeOut * MILLISECS_PER_SECOND;
  461.             break;
  462.         }
  463.     }
  464.     if (elapsed > ulTimeOut)
  465.     {
  466.         bTimedOut = TRUE;
  467.     }
  468.     return bTimedOut;
  469. }
  470. HX_RESULT
  471. HXNetSource::HandleRetry(char* pszHost, UINT16 ulPort)
  472. {
  473.     HX_RESULT theErr = HXR_OK;
  474.     if (!pszHost)
  475.     {
  476.         theErr = HXR_FAILED;
  477.         goto cleanup;
  478.     }
  479.     HX_VECTOR_DELETE(m_pHost);
  480.     m_pHost = new char[strlen(pszHost) + 1];
  481.     strcpy(m_pHost, pszHost); /* Flawfinder: ignore */
  482.     m_uPort = ulPort;
  483. cleanup:
  484.     return theErr;
  485. }
  486. HX_RESULT
  487. HXNetSource::SetRedirectURL(char* pHost, UINT16 nPort, char* pPath, CHXURL* pURL)
  488. {
  489.     HX_RESULT   theErr = HXR_OK;
  490.     if (!pHost || !pPath || !pURL)
  491.     {
  492.         theErr = HXR_FAILED;
  493.         goto cleanup;
  494.     }
  495. #if defined(HELIX_FEATURE_SMARTERNETWORK)
  496.     // since we received the redirect request from server,
  497.     // report the success of transport
  498.     if (m_pPlayer && m_prefTransportState != PTS_READY)
  499.     {
  500.         HX_ASSERT(m_prefTransportState == PTS_CREATE);
  501.         m_prefTransportState = PTS_READY;
  502.         m_pPreferredTransport->SetTransport(m_CurrentTransport, m_uCurrCloakedPort);
  503.     }
  504.     m_pPreferredTransport->RemoveTransportSink(this);
  505.     HX_RELEASE(m_pPreferredTransport);
  506. #endif /* HELIX_FEATURE_SMARTERNETWORK */
  507.     HX_VECTOR_DELETE(m_pszRedirectServer);
  508.     HX_VECTOR_DELETE(m_pszRedirectResource);
  509.     HX_VECTOR_DELETE(m_pszRedirectURL);
  510.     HX_DELETE(m_pRedirectURL);
  511.     m_pszRedirectServer = new char[strlen(pHost) + 1];
  512.     strcpy(m_pszRedirectServer, pHost); /* Flawfinder: ignore */
  513.     m_pszRedirectResource = new char[strlen(pPath) + 1];
  514.     strcpy(m_pszRedirectResource, pPath); /* Flawfinder: ignore */
  515.     m_ulRedirectServerPort = nPort;
  516.     m_pszRedirectURL = new char[strlen(pHost) + strlen(pPath) + 32];
  517.     if (m_bRTSPProtocol)
  518.     {
  519.         SafeSprintf(m_pszRedirectURL, strlen(pHost) + strlen(pPath) + 32, "rtsp://%s:%u/%s", pHost, nPort, pPath); /* Flawfinder: ignore */
  520.     }
  521.     else
  522.     {
  523.         SafeSprintf(m_pszRedirectURL, strlen(pHost) + strlen(pPath) + 32, "pnm://%s:%u/%s", pHost, nPort, pPath); /* Flawfinder: ignore */
  524.     }
  525.     // we may use pURL to support different protocol in RTSP redirect
  526.     // instead of contruct m_pszRedirectURL and always assume it's RTSP
  527.     m_pRedirectURL = new CHXURL(m_pszRedirectURL);
  528. cleanup:
  529.     return theErr;
  530. }
  531. HX_RESULT
  532. HXNetSource::SetReconnectInfo(IHXValues* pValues)
  533. {
  534.     HX_RESULT   rc = HXR_OK;
  535.     UINT32      ulValue = 0;
  536.     IHXBuffer*  pServer = NULL;
  537.     if (HXR_OK == pValues->GetPropertyULONG32("Reconnect", ulValue) &&
  538.         0 == ulValue)
  539.     {
  540.         HX_VECTOR_DELETE(m_pszReconnectServer);
  541.         HX_VECTOR_DELETE(m_pszReconnectProxy);
  542.         HX_VECTOR_DELETE(m_pszReconnectURL);
  543.         m_bAttemptReconnect = FALSE;
  544.         goto cleanup;
  545.     }
  546.     m_bAttemptReconnect = TRUE;
  547.     if (HXR_OK == pValues->GetPropertyCString("Alternate-Server", pServer))
  548.     {
  549.         HX_VECTOR_DELETE(m_pszReconnectServer);
  550.         HX_VECTOR_DELETE(m_pszReconnectURL);
  551.         m_pszReconnectServer = new char[pServer->GetSize() + 1];
  552.         ::strcpy(m_pszReconnectServer, (const char*)pServer->GetBuffer()); /* Flawfinder: ignore */
  553.         pValues->GetPropertyULONG32("Alternate-ServerPort", m_ulReconnectServerPort);
  554.         m_pszReconnectURL = new char[pServer->GetSize() + strlen(m_pResource) + 32];
  555.         if (m_bRTSPProtocol)
  556.         {
  557.             SafeSprintf(m_pszReconnectURL,pServer->GetSize() + strlen(m_pResource) + 32, "rtsp://%s:%u/%s", pServer->GetBuffer(), m_ulReconnectServerPort, m_pResource); /* Flawfinder: ignore */
  558.         }
  559.         else
  560.         {
  561.             SafeSprintf(m_pszReconnectURL, pServer->GetSize() + strlen(m_pResource) + 32, "pnm://%s:%u/%s", pServer->GetBuffer(), m_ulReconnectServerPort, m_pResource); /* Flawfinder: ignore */
  562.         }
  563.     }
  564.     HX_RELEASE(pServer);
  565.     if (HXR_OK == pValues->GetPropertyCString("Alternate-Proxy", pServer))
  566.     {
  567.         HX_VECTOR_DELETE(m_pszReconnectProxy);
  568.         m_pszReconnectProxy = new char[pServer->GetSize() + 1];
  569.         ::strcpy(m_pszReconnectProxy, (const char*)pServer->GetBuffer()); /* Flawfinder: ignore */
  570.         pValues->GetPropertyULONG32("Alternate-ProxyPort", m_ulReconnectProxyPort);
  571.     }
  572.     HX_RELEASE(pServer);
  573. cleanup:
  574.     return rc;
  575. }
  576. void
  577. HXNetSource::StartDataWait(BOOL bConnectionWait)
  578. {
  579.     m_ulStartDataWait   = HX_GET_TICKCOUNT();
  580.     m_bDataWaitStarted  = TRUE;
  581.     m_bConnectionWait   = bConnectionWait;
  582.     m_turboPlayStats.bBufferDone = FALSE;
  583. }
  584. void
  585. HXNetSource::StopDataWait()
  586. {
  587.     m_ulStartDataWait   = 0;
  588.     m_bDataWaitStarted  = FALSE;
  589. }
  590. HX_RESULT
  591. HXNetSource::FileHeaderReady(IHXValues* pHeader)
  592. {
  593.     HX_RELEASE(m_pFileHeader);
  594.     m_pFileHeader = pHeader;
  595.     m_pFileHeader->AddRef();
  596. #if defined(HELIX_FEATURE_RECORDCONTROL)
  597.     SendHeaderToRecordControl(TRUE, pHeader);
  598. #endif /* HELIX_FEATURE_RECORDCONTROL */
  599. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  600.     if (!pHeader || !m_pStats || m_bInRetryMode)
  601. #else
  602.     if (!pHeader || m_bInRetryMode)
  603. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  604.     {
  605.         return HXR_OK;
  606.     }
  607.     HX_RESULT retVal = PreFileHeaderReadyExt(pHeader);
  608.     if (retVal == HXR_REQUEST_UPGRADE)
  609.     {
  610.         mLastError = retVal;
  611.         return HXR_OK;
  612.     }
  613.     else if (retVal == HXR_WOULD_BLOCK)
  614.     {
  615.         return HXR_OK;
  616.     }
  617.     m_bContinueWithHeaders = FALSE;
  618.     ProcessFileHeader();
  619.     UINT32 ulNoLatency = 0;
  620.     if (pHeader->GetPropertyULONG32("MinimizeLatency", ulNoLatency) == HXR_OK)
  621.     {
  622.         m_bNoLatency = (ulNoLatency == 1);
  623.     }
  624.     // "MinimizeLatency" in player's preference
  625.     // can overwrite the one in file header
  626.     ReadPrefBOOL(m_pPreferences, "MinimizeLatency", m_bNoLatency);
  627.     PostFileHeaderReadyExt();
  628.     return HXR_OK;
  629. }
  630. HX_RESULT
  631. HXNetSource::PreFileHeaderReadyExt(IHXValues* pHeader)
  632. {
  633.     return HXR_OK;
  634. }
  635. HX_RESULT
  636. HXNetSource::PostFileHeaderReadyExt(void)
  637. {
  638.     return HXR_OK;
  639. }
  640. HX_RESULT
  641. HXNetSource::TACInfoFromHeader(IHXValues* pValues)
  642. {
  643.     // remove this method
  644.     return HXR_OK;
  645. }
  646. HX_RESULT
  647. HXNetSource::HeaderCallback(IHXValues* theHeader)
  648. {
  649.     HX_RESULT           theErr = HXR_OK;
  650.     STREAM_INFO*        pStreamInfo = NULL;
  651. #if defined(HELIX_FEATURE_RECORDCONTROL)
  652.     SendHeaderToRecordControl(FALSE, theHeader);
  653. #endif /* HELIX_FEATURE_RECORDCONTROL */
  654.     if (m_bInRetryMode)
  655.     {
  656.         return HXR_OK;
  657.     }
  658.     theErr = PreHeaderCallbackExt(theHeader);
  659.     if (HXR_ABORT == theErr)
  660.     {
  661.         return HXR_OK;
  662.     }
  663.     // we do not support receving headers once we have started getting data.
  664.     if (m_bReceivedData)
  665.     {
  666.         return HXR_FAILED; // define some more appropriate error code.
  667.     }
  668.     if (!theHeader)
  669.     {
  670.         return HX_INVALID_HEADER;
  671.     }
  672.     PostHeaderCallbackExt(theHeader);
  673.     theErr = ProcessStreamHeaders(theHeader, pStreamInfo);
  674.     if (HXR_OK == theErr)
  675.     {
  676.         HX_ASSERT(pStreamInfo);
  677.         IHXBuffer* pMimeType = NULL;
  678.         if (HXR_OK == pStreamInfo->m_pHeader->GetPropertyCString("MimeType", pMimeType))
  679.         {
  680.             if (strcmp((char*)pMimeType->GetBuffer(), REALAUDIO_MIME_TYPE) == 0             ||
  681.                 strcmp((char*)pMimeType->GetBuffer(), REALAUDIO_MULTIRATE_MIME_TYPE) == 0   ||
  682.                 strcmp((char*)pMimeType->GetBuffer(), REALAUDIO_MULTIRATE_LIVE_MIME_TYPE) == 0)
  683.             {
  684.                 m_lRAStreamNumber = pStreamInfo->m_uStreamNumber;
  685.             }
  686.             HX_RELEASE(pMimeType);
  687.         }
  688.         m_ulStreamIndex++;
  689.         m_uNumStreams++;
  690.     }
  691.     return theErr;
  692. }
  693. HX_RESULT
  694. HXNetSource::PreHeaderCallbackExt(IHXValues* theHeader)
  695. {
  696.     return HXR_OK;
  697. }
  698. HX_RESULT
  699. HXNetSource::PostHeaderCallbackExt(IHXValues* theHeader)
  700. {
  701.     return HXR_OK;
  702. }
  703. BOOL HXNetSource::CanSendToDataCallback(IHXPacket* packet) const
  704. {
  705.     BOOL bRet = FALSE;
  706.     
  707.     // We send normal data packets and dropped packets to
  708.     // DataCallback()
  709.     if (packet && 
  710. (!packet->IsLost() || (packet->GetASMFlags() & HX_ASM_DROPPED_PKT)))
  711.     {
  712. bRet = TRUE;
  713.     }
  714.     return bRet;
  715. }
  716. HX_RESULT
  717. HXNetSource::DataCallback(IHXPacket* pPacket)
  718. {
  719.     HX_TRACE("HXNetSource::DataCallback");
  720.     HX_RESULT       theErr      = HXR_OK;
  721.     STREAM_INFO*    pStreamInfo = NULL;
  722.     IHXBuffer*      pValue      = NULL;
  723.     if (!m_bInitialized)
  724.     {
  725.         return HXR_NOT_INITIALIZED;
  726.     }
  727.     // make sure data is valid...
  728.     if (!pPacket)
  729.     {
  730.         return HXR_INVALID_PARAMETER;   // HX_INVALID_DATA;
  731.     }
  732.     if (!mStreamInfoTable->Lookup(pPacket->GetStreamNumber(), (void*&)pStreamInfo))
  733.     {
  734.         return HXR_INVALID_PARAMETER;
  735.     }
  736.     if (!CanSendToDataCallback(pPacket))
  737.     {
  738.         return HXR_OK;
  739.     }
  740.     // If this is the first time we received data,
  741.     // then remember the time so we can report it...
  742.     if (!m_bReceivedData)
  743.     {
  744.         m_bReceivedData = TRUE;
  745.         m_bSeekPending = FALSE;
  746.         FirstDataArrives();
  747.         if (mLiveStream || m_bRestrictedLiveStream)
  748.         {
  749.             m_ulFirstPacketTime = pPacket->GetTime();
  750.             if (m_bRestrictedLiveStream)
  751.             {
  752.                 m_llLastExpectedPacketTime = CAST_TO_INT64 pPacket->GetTime() + CAST_TO_INT64 m_ulEndTime;
  753.             }
  754.         }
  755.     }
  756.     m_pBufferManager->UpdateCounters(pPacket);
  757.     return theErr;
  758. }
  759. void
  760. HXNetSource::Initialize()
  761. {
  762.     if (!m_bInitialized)
  763.     {
  764.         _Initialize();
  765.     }
  766. }
  767. ULONG32
  768. HXNetSource::GetCurrentPlayTime(void)
  769. {
  770.     if (m_pPlayer)
  771.     {
  772.         return m_pPlayer->GetInternalCurrentPlayTime();
  773.     }
  774.     else
  775.     {
  776.         return 0;
  777.     }
  778. }
  779. void
  780. HXNetSource::FirstDataArrives()
  781. {
  782.     IHXBuffer* pValue = NULL;
  783.     m_bAltURL = FALSE;
  784.     /* calculate elapsed time taking into consideration overflow...*/
  785.     m_ulFirstDataArrives = CALCULATE_ELAPSED_TICKS(m_ulStartDataWait,
  786.                                                   HX_GET_TICKCOUNT());
  787. }
  788. HX_RESULT
  789. HXNetSource::SetCookie(IHXBuffer* pCookie)
  790. {
  791.     HX_RESULT hr = HXR_OK;
  792.     if (!m_pCookies)
  793.     {
  794.         hr = HXR_FAILED;
  795.         goto cleanup;
  796.     }
  797.     hr = m_pCookies->SetCookies(m_pHost, m_pPath, pCookie);
  798. cleanup:
  799.     return hr;
  800. }
  801. HX_RESULT
  802. HXNetSource::SetOption(UINT16 option, void* data)
  803. {
  804.     HX_TRACE("HXNetSource::SetOption");
  805.     HX_RESULT   theErr = HXR_OK;
  806.     UINT32      ulMaxBandwidth = 0;
  807.     BOOL        bTurboPlay = FALSE;
  808.     switch (option)
  809.     {
  810.         case HX_PERFECTPLAY_SUPPORTED:
  811.             {
  812.                 BOOL bServerHasPerfectPlay = TRUE;
  813.                 ::memcpy(&bServerHasPerfectPlay,data,sizeof(BOOL)); /* Flawfinder: ignore */
  814.                 m_bServerHasPerfectPlay |= bServerHasPerfectPlay;
  815.             }
  816.             break;
  817.         case HX_RESEND_SUPPORTED:
  818. //          ::memcpy(&m_bServerHasResend,data,sizeof(BOOL));
  819.             break;
  820. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  821.         case HX_STATS_MASK:
  822.             ::memcpy(&m_ulSendStatsMask,data,sizeof(ULONG32)); /* Flawfinder: ignore */
  823.             if (m_ulSendStatsMask > MAX_STATS_MASK)
  824.                 m_ulSendStatsMask = MAX_STATS_MASK;
  825.             break;
  826.         case HX_STATS_INTERVAL:
  827.             {
  828.                 UINT32 ulStatsInterval = 0;
  829.                 ::memcpy(&ulStatsInterval,data,sizeof(ULONG32)); /* Flawfinder: ignore */
  830.                 // did it change. if so, re-schedule
  831.                 if (ulStatsInterval != m_ulStatsInterval)
  832.                 {
  833.                     m_ulStatsInterval = ulStatsInterval;
  834.                     if (m_pStatsCallback)
  835.                     {
  836.                         // disable Stats report if m_ulStatsInterval is set to 0
  837.                         if (m_ulStatsInterval == 0)
  838.                         {
  839.                             m_pStatsCallback->CancelCallback();
  840.                         }
  841.                         else if (!m_pStatsCallback->IsPaused())
  842.                         {
  843.                             m_pStatsCallback->ScheduleCallback(m_ulStatsInterval);
  844.                         }
  845.                     }
  846.                 }
  847.             }
  848.             break;
  849. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  850.         case HX_TRANSPORTSWITCHING_SUPPORTED:
  851.             ::memcpy(&m_bServerHasTransportSwitching,data,sizeof(BOOL)); /* Flawfinder: ignore */
  852.             break;
  853.         case HX_FORCE_PERFECT_PLAY:
  854.             // the server is forcing us into perfect play mode
  855.             ::memcpy(&m_bForcePerfectPlay,data,sizeof(BOOL)); /* Flawfinder: ignore */
  856.             if(m_bForcePerfectPlay)
  857.             {
  858.                 m_bPerfectPlay = TRUE;
  859.                 /* If the server is forcing us into PerfectPlay, it means
  860.                  * it does allow it AND the clip is perfectPlay-able.
  861.                  */
  862.                 m_bPerfectPlayAllowed   = TRUE;
  863.                 m_bServerHasPerfectPlay = TRUE;
  864.                 WritePerfectPlayToRegistry();
  865.                 if(m_pProto)
  866.                 {
  867.                     m_pProto->set_transport(TCPMode, m_ulTransportPrefMask);
  868.                     m_pProto->set_perfect_play(m_bPerfectPlay);
  869.                 }
  870.             }
  871.             break;
  872.         case HX_SELECTIVE_RECORD_SUPPORTED:
  873.             ::memcpy(&mServerSelRecordSupport,data,sizeof(BOOL)); /* Flawfinder: ignore */
  874.             break;
  875.         case HX_GENERIC_MESSAGE_SUPPORT:
  876.             /* RV client/server does not use it curently */
  877.             break;
  878.         case HX_INTERFRAME_CONTROL_SUPPORT:
  879.             ::memcpy(&mInterframeControlSupport,data,sizeof(BOOL)); /* Flawfinder: ignore */
  880.             break;
  881.         case HX_BANDWIDTH_REPORT_SUPPORT:
  882.             ::memcpy(&mServerHasBandwidthReport,data,sizeof(BOOL)); /* Flawfinder: ignore */
  883.             break;
  884.         case HX_FRAME_CONTROL_SUPPORT:
  885.             ::memcpy(&mServerHasFrameControl,data,sizeof(BOOL)); /* Flawfinder: ignore */
  886.             break;
  887.         case HX_MAX_BANDWIDTH:
  888.             ::memcpy(&ulMaxBandwidth,data,sizeof(UINT32)); /* Flawfinder: ignore */
  889.             if (ulMaxBandwidth == 0)
  890.             {
  891.                 m_serverTurboPlay = TURBO_PLAY_OFF;
  892.             }
  893.             else
  894.             {
  895.                 m_ulMaxBandwidth = ulMaxBandwidth;
  896.             }
  897.             break;
  898.         case HX_TURBO_PLAY:
  899.             ::memcpy(&bTurboPlay,data,sizeof(BOOL)); /* Flawfinder: ignore */
  900.             if (bTurboPlay)
  901.             {
  902.                 m_serverTurboPlay = TURBO_PLAY_ON;
  903.             }
  904.             else
  905.             {
  906.                 m_serverTurboPlay = TURBO_PLAY_OFF;
  907.             }
  908.             break;
  909.         default:
  910.             theErr = HXR_INVALID_PARAMETER;             //HX_INVALID_OPTION;
  911.             break;
  912.     }
  913.     return theErr;
  914. }
  915. HX_RESULT
  916. HXNetSource::TransportStarted(TransportMode mode)
  917. {
  918.     HX_RESULT rc = HXR_OK;
  919. #if defined(HELIX_FEATURE_SMARTERNETWORK)
  920.     if (m_pPreferredTransport && m_pPreferredTransport->ValidateTransport(mode))
  921.     {
  922.         set_transport(mode);
  923.     }
  924.     else
  925.     {
  926.         rc = HXR_BAD_TRANSPORT;
  927.         ReportError(rc);
  928.     }
  929. #endif /* HELIX_FEATURE_SMARTERNETWORK */
  930.     return rc;
  931. }
  932. HX_RESULT
  933. HXNetSource::switch_out_of_perfectplay()
  934. {
  935.     // Turn off perfect play mode.
  936.     m_bPerfectPlay = FALSE;
  937.     // Reset "transport" selection...
  938.     m_CurrentTransport = UnknownMode;
  939.     // Reconnect...
  940.     return handleTransportSwitch();
  941. }
  942. HX_RESULT
  943. HXNetSource::handleTransportSwitch()
  944. {
  945.     HX_RESULT rc = HXR_OK;
  946. #ifdef _MACINTOSH
  947.     BOOL bAtInterrupt = FALSE;
  948.     IHXInterruptState* pInterruptState = NULL;
  949.     if (m_pEngine &&
  950.         m_pEngine->QueryInterface(IID_IHXInterruptState, (void**) &pInterruptState) == HXR_OK)
  951.     {
  952.         bAtInterrupt = pInterruptState->AtInterruptTime();
  953.         HX_RELEASE(pInterruptState);
  954.     }
  955.     if (bAtInterrupt)
  956.     {
  957.         m_bBruteForceConnectToBeDone = TRUE;
  958.         HX_ASSERT(m_pSourceInfo);
  959.         if (m_pSourceInfo)
  960.         {
  961.             m_pSourceInfo->ScheduleProcessCallback();
  962.         }
  963.         return HXR_OK;
  964.     }
  965. #endif
  966.     Reset();
  967.     HX_VECTOR_DELETE(m_pszRedirectServer);
  968.     HX_VECTOR_DELETE(m_pszRedirectResource);
  969.     HX_VECTOR_DELETE(m_pszRedirectURL);
  970.     HX_VECTOR_DELETE(m_pszReconnectServer);
  971.     HX_VECTOR_DELETE(m_pszReconnectURL);
  972.     // have we already received the headers
  973.     if (mStreamInfoTable->GetCount() > 0)
  974.     {
  975.         m_bInRetryMode = TRUE;
  976.     }
  977.     m_bBruteForceReconnected = TRUE;
  978.     DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)TransportSwitch %s", this, m_pszURL));
  979.     rc = Setup(m_pHost, m_pResource, m_uPort,
  980.                m_bLossCorrection, m_pURL, m_bAltURL);
  981.     return rc;
  982. }
  983. HX_RESULT
  984. HXNetSource::handleProxySwitch(HX_RESULT inError)
  985. {
  986. #if defined(HELIX_FEATURE_PAC)
  987.     HX_RESULT   rc = HXR_FAILED;
  988.     if (m_pPACInfoList && m_pPACInfoList->GetCount() && m_PACInfoPosition)
  989.     {
  990.         Reset();
  991.         m_bUseProxy = FALSE;
  992.         HX_VECTOR_DELETE(m_pProxy);
  993.         m_bBruteForceReconnected = TRUE;
  994.         rc = Setup(m_pHost, m_pResource, m_uPort, m_bLossCorrection, m_pURL, m_bAltURL);
  995.     }
  996.     if (HXR_OK != rc)
  997.     {
  998.         rc = inError;
  999.     }
  1000.     return rc;
  1001. #else
  1002.     return HXR_NOTIMPL;
  1003. #endif /* HELIX_FEATURE_PAC */
  1004. }
  1005. HX_RESULT
  1006. HXNetSource::handleRedirect()
  1007. {
  1008.     HX_RESULT   rc = HXR_OK;
  1009.     if (!m_pszRedirectURL)
  1010.     {
  1011.         rc = HXR_FAILED;
  1012.         goto cleanup;
  1013.     }
  1014.     Reset();
  1015.     m_ulDuration = 0;
  1016.     m_ulPreRollInMs = 0;
  1017.     m_ulPreRoll = 0;
  1018.     m_ulAvgBandwidth = 0;
  1019.     m_ulLastBufferingCalcTime = 0;
  1020.     m_bRARVSource = FALSE;
  1021.     m_bRARVSourceVerified = FALSE;
  1022.     // remove obsolete reconnect information
  1023.     HX_VECTOR_DELETE(m_pszReconnectServer);
  1024.     HX_VECTOR_DELETE(m_pszReconnectProxy);
  1025.     HX_VECTOR_DELETE(m_pszReconnectURL);
  1026.     // have we already received the headers
  1027.     if (mStreamInfoTable->GetCount() > 0)
  1028.     {
  1029.         m_bInRetryMode = TRUE;
  1030.     }
  1031.     m_bBruteForceReconnected = TRUE;
  1032.     if (strcasecmp(m_pszRedirectServer, m_pHost) != 0)
  1033.     {
  1034.         while (m_pPACInfoList && m_pPACInfoList->GetCount())
  1035.         {
  1036.             PACInfo* pPACInfo = (PACInfo*)m_pPACInfoList->RemoveHead();
  1037.             HX_DELETE(pPACInfo);
  1038.         }
  1039. #if defined(HELIX_FEATURE_SMARTERNETWORK)
  1040.         if (m_pPreferredTransport)
  1041.         {
  1042.             m_pPreferredTransport->RemoveTransportSink(this);
  1043.             HX_RELEASE(m_pPreferredTransport);
  1044.         }
  1045. #endif /* HELIX_FEATURE_SMARTERNETWORK */
  1046.     }
  1047.     DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Redirect %s", this, m_pszRedirectURL));
  1048.     rc = Setup(m_pszRedirectServer, m_pszRedirectResource, (UINT16)m_ulRedirectServerPort,
  1049.                m_bLossCorrection, m_pRedirectURL, m_bAltURL);
  1050. cleanup:
  1051.     HX_VECTOR_DELETE(m_pszRedirectServer);
  1052.     HX_VECTOR_DELETE(m_pszRedirectResource);
  1053.     HX_VECTOR_DELETE(m_pszRedirectURL);
  1054.     return rc;
  1055. }
  1056. HX_RESULT
  1057. HXNetSource::handleReconnect()
  1058. {
  1059.     HX_RESULT   rc = HXR_OK;
  1060.     Reset();
  1061.     HX_VECTOR_DELETE(m_pszRedirectServer);
  1062.     HX_VECTOR_DELETE(m_pszRedirectResource);
  1063.     HX_VECTOR_DELETE(m_pszRedirectURL);
  1064.     // have we already received the headers
  1065.     if (mStreamInfoTable->GetCount() > 0)
  1066.     {
  1067.         m_bInRetryMode = TRUE;
  1068.     }
  1069.     m_bBruteForceReconnected = TRUE;
  1070.     if (m_pszReconnectURL)
  1071.     {
  1072.         while (m_pPACInfoList && m_pPACInfoList->GetCount())
  1073.         {
  1074.             PACInfo* pPACInfo = (PACInfo*)m_pPACInfoList->RemoveHead();
  1075.             HX_DELETE(pPACInfo);
  1076.         }
  1077. #if defined(HELIX_FEATURE_SMARTERNETWORK)
  1078.         if (m_pPreferredTransport && strcasecmp(m_pszReconnectServer, m_pHost) != 0)
  1079.         {
  1080.             m_pPreferredTransport->RemoveTransportSink(this);
  1081.             HX_RELEASE(m_pPreferredTransport);
  1082.         }
  1083. #endif /* HELIX_FEATURE_SMARTERNETWORK */
  1084.         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Reconnect %s", this, m_pszReconnectURL));
  1085.         CHXURL obj(m_pszReconnectURL);
  1086.         rc = Setup(m_pszReconnectServer, m_pResource, (UINT16)m_ulReconnectServerPort,
  1087.                    m_bLossCorrection, &obj, m_bAltURL);
  1088.     }
  1089.     else
  1090.     {
  1091.         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Reconnect %s", this, m_pszURL));
  1092.         rc = Setup(m_pHost, m_pResource, m_uPort,
  1093.                    m_bLossCorrection, m_pURL, m_bAltURL);
  1094.     }
  1095.     HX_VECTOR_DELETE(m_pszReconnectServer);
  1096.     HX_VECTOR_DELETE(m_pszReconnectProxy);
  1097.     HX_VECTOR_DELETE(m_pszReconnectURL);
  1098.     return rc;
  1099. }
  1100. BOOL
  1101. HXNetSource::IsNetworkAvailable()
  1102. {
  1103. #if defined(HELIX_FEATURE_NETCHECK)
  1104.     CHXNetCheck* pNetCheck = new CHXNetCheck(4000);
  1105.     BOOL bIsNetAvailable = FALSE;
  1106.     if(pNetCheck)
  1107.     {
  1108.         pNetCheck->AddRef();
  1109.         if (HXR_OK == pNetCheck->Init((IUnknown*)(IHXPlayer*)m_pPlayer))
  1110.         {
  1111.             bIsNetAvailable = pNetCheck->FInternetAvailable(FALSE, m_bUseProxy);
  1112.         }
  1113.     }
  1114.     HX_RELEASE(pNetCheck);
  1115.     DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)IsNetworkAvailable %lu", this, bIsNetAvailable));
  1116.     return bIsNetAvailable;
  1117. #else
  1118.     return FALSE;
  1119. #endif /* HELIX_FEATURE_NETCHECK */
  1120. }
  1121. HX_RESULT
  1122. HXNetSource::AttemptReconnect()
  1123. {
  1124.     HX_RESULT       rc = HXR_OK;
  1125.     BOOL            bDoneAtTransport = FALSE;
  1126.     UINT32          ulCurrentPlayPos = 0;
  1127.     UINT32          ulPacketsAheadInTime = 0;
  1128.     UINT32          ulReconnectStartTime = 0;
  1129.     UINT32          ulLastPacketTime = 0;
  1130.     UINT32          ulLastEventTime = 0;
  1131.     UINT32          ulLowestLastEventTime = MAX_UINT32;
  1132.     INT64           llLowestTimestampAtTransport = 0;
  1133.     INT64           llHighestTimestampAtTransport = 0;
  1134.     UINT32          ulNumBytesAtTransport = 0;
  1135.     STREAM_INFO*    pStreamInfo = NULL;
  1136.     m_state = NETSRC_RECONNECTPENDING;
  1137.     // caculate how far ahead the packets received at transport
  1138.     CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
  1139.     for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
  1140.     {
  1141.         pStreamInfo = (STREAM_INFO*) (*lStreamIterator);
  1142.         GetCurrentBuffering(pStreamInfo->m_uStreamNumber,
  1143.                             llLowestTimestampAtTransport,
  1144.                             llHighestTimestampAtTransport,
  1145.                             ulNumBytesAtTransport,
  1146.                             bDoneAtTransport);
  1147.         // in case we have no more packets at transport
  1148.         // get the last packet time from the saved queue
  1149.         if (ulNumBytesAtTransport == 0 &&
  1150.             pStreamInfo->m_pPreReconnectEventList)
  1151.         {
  1152.             ulLastPacketTime = *(UINT32*)pStreamInfo->m_pPreReconnectEventList->GetTail();
  1153.         }
  1154.         else
  1155.         {
  1156.             // XXX HP need to handle timestamp rollover
  1157.             ulLastPacketTime = INT64_TO_ULONG32(llHighestTimestampAtTransport);
  1158.         }
  1159.         ulLastEventTime = AdjustEventTime(pStreamInfo, ulLastPacketTime);
  1160.         if (ulLastEventTime < ulLowestLastEventTime)
  1161.         {
  1162.             ulLowestLastEventTime = ulLastEventTime;
  1163.         }
  1164.     }
  1165.     // if we have received all the packets, we simply set the reconnect pending state without
  1166.     // schedule/start reconnect since it's not needed if the user let the playback continues
  1167.     // to the end.
  1168.     // reconnect will occur if the seek happens afterwards.
  1169.     if (bDoneAtTransport)
  1170.     {
  1171.         return HXR_OK;
  1172.     }
  1173.     if(!mLiveStream)
  1174.     {
  1175.         // retrieve all the packets at transport layer to the source layer
  1176. #if defined(HELIX_FEATURE_RECORDCONTROL)
  1177.         if(m_bPlayFromRecordControl)
  1178.         {
  1179.             m_state = NETSRC_READY;
  1180.             FillRecordControl();
  1181.             m_state = NETSRC_RECONNECTPENDING;
  1182.         }
  1183.         else
  1184. #endif /* HELIX_FEATURE_RECORDCONTROL */
  1185.         {
  1186.             CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
  1187.             for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
  1188.             {
  1189.                 CHXEvent* pEvent = NULL;
  1190.                 pStreamInfo = (STREAM_INFO*) (*lStreamIterator);
  1191.                 UINT16 uStreamNumber = pStreamInfo->m_uStreamNumber;
  1192.                 CHXEventList* pEventList = &pStreamInfo->m_EventList;
  1193.                 // in case we reconnect again right after reconnect
  1194.                 // get all the packets from PosReconnectEventList first since they are ahead of
  1195.                 // the packets from protocol
  1196.                 while (pStreamInfo->m_pPosReconnectEventList &&
  1197.                        pStreamInfo->m_pPosReconnectEventList->GetNumEvents())
  1198.                 {
  1199.                     pEvent = (CHXEvent*)pStreamInfo->m_pPosReconnectEventList->RemoveHead();
  1200.                     pEventList->InsertEvent(pEvent);
  1201.                 }
  1202.                 // get all the packets from the protocol
  1203.                 if(m_pProto)
  1204.                 {
  1205.                     while (HXR_OK == m_pProto->GetEvent(uStreamNumber, pEvent))
  1206.                     {
  1207.                         pEventList->InsertEvent(pEvent);
  1208.                     }
  1209.                 }
  1210.             }
  1211.         }
  1212.         Reset();
  1213.     }
  1214.     ulCurrentPlayPos = m_pPlayer->GetInternalCurrentPlayTime();
  1215.     if (ulCurrentPlayPos <= ulLowestLastEventTime)
  1216.     {
  1217.         ulPacketsAheadInTime = ulLowestLastEventTime - ulCurrentPlayPos;
  1218.         if (ulPacketsAheadInTime >= NEW_DEF_SETTINGS_TIMEOUT)
  1219.         {
  1220.             ulReconnectStartTime = ulPacketsAheadInTime - NEW_DEF_SETTINGS_TIMEOUT;
  1221.             if (!m_pReconnectCallback)
  1222.             {
  1223.                 m_pReconnectCallback = new ReconnectCallback(this);
  1224.                 m_pReconnectCallback->AddRef();
  1225.             }
  1226.             DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)AttemptReconnect in %lu ms", this, ulReconnectStartTime));
  1227.             m_pReconnectCallback->ScheduleCallback(ulReconnectStartTime);
  1228.             return HXR_OK;
  1229.         }
  1230.     }
  1231.     DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)AttemptReconnect now", this));
  1232.     return StartReconnect();
  1233. }
  1234. HX_RESULT
  1235. HXNetSource::StartReconnect()
  1236. {
  1237.     HX_RESULT       rc = HXR_OK;
  1238.     BOOL            bFirstEvent = TRUE;
  1239.     UINT16          uStreamNumber = 0;
  1240.     UINT32          ulPrevPacketTime = 0;
  1241.     UINT32          ulLargestGapInPacketTime = 0;
  1242.     UINT32          ulLastPacketTime = 0;
  1243.     UINT32          ulLowestLastPacketTime = MAX_UINT32;
  1244.     UINT32*         pPacketTime = NULL;
  1245.     STREAM_INFO*    pStreamInfo = NULL;
  1246.     CHXEvent*       pEvent = NULL;
  1247.     CHXEventList*  pEventList = NULL;
  1248.     IHXPacket*      pPacket = NULL;
  1249.     CHXSimpleList::Iterator lIter;
  1250.     DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)StartReconnect", this));
  1251.     // for live source, nothing we can do to archieve seamless user experience like
  1252.     // the static content does except tearn down the source and start all over with
  1253.     // new source as if it were a redirect
  1254.     if (mLiveStream)
  1255.     {
  1256.         if (m_pszReconnectURL)
  1257.         {
  1258.             rc = m_pSourceInfo->HandleRedirectRequest(m_pszReconnectURL);
  1259.         }
  1260.         else
  1261.         {
  1262.             rc = m_pSourceInfo->HandleRedirectRequest(m_pszURL);
  1263.         }
  1264.     }
  1265.     else if (NETSRC_RECONNECTPENDING == m_state)
  1266.     {
  1267.         // retrieve all the packets at transport layer to the source layer
  1268.         CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
  1269.         for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
  1270.         {
  1271.             pStreamInfo = (STREAM_INFO*) (*lStreamIterator);
  1272.             uStreamNumber = pStreamInfo->m_uStreamNumber;
  1273.             pEventList = &pStreamInfo->m_EventList;
  1274.             pStreamInfo->m_bReconnectToBeDone = TRUE;
  1275.             pStreamInfo->m_ulReconnectOverlappedPackets = 0;
  1276.             bFirstEvent = TRUE;
  1277.             if(m_bPlayFromRecordControl)
  1278.             {
  1279.                 // Now we can get all available events out of RecordControl
  1280.                 // in order to use them for reconnection.
  1281.                 while (TRUE)
  1282.                 {
  1283.                     HX_RESULT nRes = GetEventFromRecordControl(uStreamNumber, pEvent);
  1284.                     if(nRes == HXR_OK)
  1285.                     {
  1286.                         pEventList->InsertEvent(pEvent);
  1287.                     }
  1288.                     if(nRes != HXR_OK && nRes != HXR_WOULD_BLOCK)
  1289.                         break;
  1290.                 }
  1291.             HX_ASSERT(pEventList->GetCount());
  1292.             }
  1293.             // save the prereconnect packet time so that we can
  1294.             // find the adjointing point after reconnect
  1295.             lIter = pEventList->Begin();
  1296.             for (; lIter != pEventList->End(); ++lIter)
  1297.             {
  1298.                 pEvent = (CHXEvent*) (*lIter);
  1299.                 AddToPreReconnectEventList(pStreamInfo, pEvent);
  1300.             }
  1301.             CHXSimpleList* pPreReconnectEventList = pStreamInfo->m_pPreReconnectEventList;
  1302.             HX_ASSERT(pPreReconnectEventList);
  1303.             // determine the seek position after reconnect
  1304.             // enough overlapped packets to ensure searching of adjointing point
  1305.             // successfully after the reconnect
  1306.             if (pPreReconnectEventList)
  1307.             {
  1308.                 CHXSimpleList::Iterator lIterator = pPreReconnectEventList->Begin();
  1309.                 for (; lIterator != pPreReconnectEventList->End(); ++lIterator)
  1310.                 {
  1311.                     UINT32* pPreReconnectEventTime = (UINT32*)(*lIterator);
  1312.                     UpdateReconnectInfo(*pPreReconnectEventTime,
  1313.                                         bFirstEvent,
  1314.                                         ulPrevPacketTime,
  1315.                                         ulLargestGapInPacketTime,
  1316.                                         ulLastPacketTime);
  1317.                 }
  1318.             }
  1319.             if (ulLastPacketTime < ulLowestLastPacketTime)
  1320.             {
  1321.                 ulLowestLastPacketTime = ulLastPacketTime;
  1322.             }
  1323.         }
  1324.         if (ulLowestLastPacketTime > ulLargestGapInPacketTime)
  1325.         {
  1326.             m_ulSeekPendingTime = ulLowestLastPacketTime - ulLargestGapInPacketTime;
  1327.         }
  1328.         else
  1329.         {
  1330.             m_ulSeekPendingTime = 0;
  1331.         }
  1332.         m_bSeekPending = TRUE;
  1333.         m_state = NETSRC_RECONNECTSTARTED;
  1334.         rc = handleReconnect();
  1335.     }
  1336.     else if (NETSRC_RECONNECTFORCED == m_state)
  1337.     {
  1338.         // we don't need to retrieve the left-over packets if the reconnect
  1339.         // is forced(i.e. seek)
  1340.         m_state = NETSRC_RECONNECTSTARTED;
  1341.         rc = handleReconnect();
  1342.     }
  1343.     return rc;
  1344. }
  1345. HX_RESULT
  1346. HXNetSource::ProcessReconnect(STREAM_INFO* pStreamInfo)
  1347. {
  1348.     HX_RESULT       rc = HXR_OK;
  1349.     BOOL            bAdjointFound = FALSE;
  1350.     BOOL            bOverlapped = FALSE;
  1351.     UINT32          ulAdjointTimeFrom = 0;
  1352.     UINT32          ulAdjointTimeTo = 0;
  1353.     IHXPacket*      pPacket = NULL;
  1354.     IHXPacket*      pNextPacket = NULL;
  1355.     UINT32*         pPreReconnectEventTime = NULL;
  1356.     UINT32*         pPreReconnectNextEventTime = NULL;
  1357.     CHXEvent*       pPosReconnectEvent = NULL;
  1358.     CHXEvent*       pPosReconnectNextEvent = NULL;
  1359.     CHXSimpleList*  pPreReconnectEventList = NULL;
  1360.     CHXEventList*  pPosReconnectEventList = NULL;
  1361.     LISTPOSITION    preReconnectPos = 0;
  1362.     LISTPOSITION    posReconnectPos = 0;
  1363.     //DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "EnterProcessReconnect %p %lu", this, pStreamInfo->m_uStreamNumber));
  1364.     if (!pStreamInfo || !pStreamInfo->m_pPosReconnectEventList)
  1365.     {
  1366.         rc = HXR_FAILED;
  1367.         goto cleanup;
  1368.     }
  1369.     if(!pStreamInfo->m_pPreReconnectEventList || !pStreamInfo->m_pPreReconnectEventList->GetCount())
  1370.     {
  1371.         // We need to use all the packets in pStreamInfo->m_pPosReconnectEventList.
  1372.         pStreamInfo->m_bReconnectToBeDone = FALSE;
  1373.     }
  1374.     pPosReconnectEventList = pStreamInfo->m_pPosReconnectEventList;
  1375.     posReconnectPos = pPosReconnectEventList->GetHeadPosition();
  1376.     if (posReconnectPos)
  1377.     {
  1378.         pPosReconnectEvent = (CHXEvent*) pPosReconnectEventList->GetAt(posReconnectPos);
  1379.         while (pPosReconnectEvent && pStreamInfo->m_bReconnectToBeDone)
  1380.         {
  1381.             pPosReconnectEventList->GetNext(posReconnectPos);
  1382.             if (!posReconnectPos)
  1383.             {
  1384.                 break;
  1385.             }
  1386.             pPacket = pPosReconnectEvent->GetPacket();
  1387.             pPosReconnectNextEvent = (CHXEvent*) pPosReconnectEventList->GetAt(posReconnectPos);
  1388.             pNextPacket = pPosReconnectNextEvent->GetPacket();
  1389.             if (pPacket->GetTime() != pNextPacket->GetTime())
  1390.             {
  1391.                 bAdjointFound = TRUE;
  1392.                 ulAdjointTimeFrom = pPacket->GetTime();
  1393.                 ulAdjointTimeTo = pNextPacket->GetTime();
  1394.             }
  1395.             if (bAdjointFound && pStreamInfo->m_pPreReconnectEventList)
  1396.             {
  1397.                 pPreReconnectEventList = pStreamInfo->m_pPreReconnectEventList;
  1398.                 preReconnectPos = pPreReconnectEventList->GetHeadPosition();
  1399.                 pPreReconnectEventTime = (UINT32*) pPreReconnectEventList->GetAt(preReconnectPos);
  1400.                 while (pPreReconnectEventTime)
  1401.                 {
  1402.                     pPreReconnectEventList->GetNext(preReconnectPos);
  1403.                     if (!preReconnectPos)
  1404.                     {
  1405.                         break;
  1406.                     }
  1407.                     pPreReconnectNextEventTime = (UINT32*) pPreReconnectEventList->GetAt(preReconnectPos);
  1408.                     if (*pPreReconnectEventTime == ulAdjointTimeFrom &&
  1409.                         *pPreReconnectNextEventTime == ulAdjointTimeTo)
  1410.                     {
  1411.     //{FILE* f1 = ::fopen("c:\temp\reconnect.txt", "a+"); ::fprintf(f1, "ProcessReconnect(succeeded)t%lut%lut%lun", pStreamInfo->m_uStreamNumber, ulAdjointTimeFrom, ulAdjointTimeTo);::fclose(f1);}
  1412.                         pStreamInfo->m_bReconnectToBeDone = FALSE;
  1413.                         break;
  1414.                     }
  1415.                     pPreReconnectEventTime = pPreReconnectNextEventTime;
  1416.                 }
  1417.             }
  1418.             pPosReconnectEvent = pPosReconnectNextEvent;
  1419.         }
  1420.     }
  1421.     if (!pStreamInfo->m_bReconnectToBeDone)
  1422.     {
  1423.         if (pPreReconnectEventList)
  1424.         {
  1425.             pPreReconnectEventList->GetNext(preReconnectPos);
  1426.             while (preReconnectPos)
  1427.             {
  1428.                 pStreamInfo->m_ulReconnectOverlappedPackets++;
  1429.                 pPreReconnectEventList->GetNext(preReconnectPos);
  1430.             }
  1431.         }
  1432. //{FILE* f1 = ::fopen("c:\temp\reconnect.txt", "a+"); ::fprintf(f1, "EventsOverlappedt%lut%lun", pStreamInfo->m_uStreamNumber, pStreamInfo->m_ulReconnectOverlappedPackets);::fclose(f1);}
  1433.         while (pPosReconnectEventList->GetNumEvents() &&
  1434.                pStreamInfo->m_ulReconnectOverlappedPackets)
  1435.         {
  1436.             pPosReconnectEvent = pPosReconnectEventList->RemoveHead();
  1437.             if (bOverlapped)
  1438.             {
  1439.                 pStreamInfo->m_ulReconnectOverlappedPackets--;
  1440.             }
  1441.             if (pPosReconnectEvent == pPosReconnectNextEvent)
  1442.             {
  1443.                 bOverlapped = TRUE;
  1444.             }
  1445. //{FILE* f1 = ::fopen("c:\temp\reconnect.txt", "a+"); ::fprintf(f1, "DeleteEvent(overlapped)t%lut%lun", pStreamInfo->m_uStreamNumber, pPosReconnectEvent->GetPacket()->GetTime());::fclose(f1);}
  1446.             HX_DELETE(pPosReconnectEvent);
  1447.         }
  1448.         EndReconnect();
  1449.     }
  1450. cleanup:
  1451.     //DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "LeaveProcessReconnect %p %lu %lu", this, pStreamInfo->m_uStreamNumber, pStreamInfo->m_bReconnectToBeDone));
  1452.     return rc;
  1453. }
  1454. HX_RESULT
  1455. HXNetSource::EndReconnect()
  1456. {
  1457.     HX_RESULT       rc = HXR_OK;
  1458.     BOOL            bReconnectToBeDone = FALSE;
  1459.     STREAM_INFO*    pStreamInfo = NULL;
  1460.     CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
  1461.     for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
  1462.     {
  1463.         pStreamInfo = (STREAM_INFO*) (*lStreamIterator);
  1464.         if (pStreamInfo->m_bReconnectToBeDone)
  1465.         {
  1466.             bReconnectToBeDone = TRUE;
  1467.             break;
  1468.         }
  1469.     }
  1470.     if (!bReconnectToBeDone)
  1471.     {
  1472.         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)EndReconnect", this));
  1473.         m_state = NETSRC_READY;
  1474.     }
  1475.     return rc;
  1476. }
  1477. HX_RESULT
  1478. HXNetSource::AddToPreReconnectEventList(STREAM_INFO* pStreamInfo, CHXEvent* pEvent)
  1479. {
  1480.     HX_RESULT       rc = HXR_OK;
  1481.     UINT32*         pPacketTime = NULL;
  1482.     CHXSimpleList*  pPreReconnectEventList = NULL;
  1483.     if (!pStreamInfo->m_pPreReconnectEventList)
  1484.     {
  1485.         pStreamInfo->m_pPreReconnectEventList = new CHXSimpleList;
  1486.     }
  1487.     pPreReconnectEventList = pStreamInfo->m_pPreReconnectEventList;
  1488.     if (pPreReconnectEventList->GetCount() == 30)
  1489.     {
  1490.         pPacketTime = (UINT32*)pPreReconnectEventList->RemoveHead();
  1491.         HX_DELETE(pPacketTime);
  1492.     }
  1493.     if (!pPacketTime)
  1494.     {
  1495.         pPacketTime = new UINT32;
  1496.     }
  1497.     *pPacketTime = pEvent->GetPacket()->GetTime();
  1498.     pPreReconnectEventList->AddTail(pPacketTime);
  1499.     HX_ASSERT(pPreReconnectEventList->GetCount() <= 30);
  1500.     return rc;
  1501. }
  1502. void
  1503. HXNetSource::UpdateReconnectInfo(UINT32         ulPacketTime,
  1504.                                   BOOL&         bFirstEvent,
  1505.                                   UINT32&       ulPrevPacketTime,
  1506.                                   UINT32&       ulLargestGapInPacketTime,
  1507.                                   UINT32&       ulLastPacketTime)
  1508. {
  1509.     UINT32          ulGapInPacketTime = 0;
  1510.     if (bFirstEvent)
  1511.     {
  1512.         bFirstEvent = FALSE;
  1513.         ulPrevPacketTime = 0;
  1514.         ulLargestGapInPacketTime = 0;
  1515.         ulLastPacketTime = 0;
  1516.     }
  1517.     else
  1518.     {
  1519.         HX_ASSERT(ulPacketTime >= ulPrevPacketTime);
  1520.         ulGapInPacketTime = ulPacketTime - ulPrevPacketTime;
  1521.         if (ulLargestGapInPacketTime < ulGapInPacketTime)
  1522.         {
  1523.             ulLargestGapInPacketTime = ulGapInPacketTime;
  1524.         }
  1525.     }
  1526.     ulPrevPacketTime = ulPacketTime;
  1527.     if (ulLastPacketTime < ulPacketTime)
  1528.     {
  1529.         ulLastPacketTime = ulPacketTime;
  1530.     }
  1531.     return;
  1532. }
  1533. void
  1534. HXNetSource::Reset()
  1535. {
  1536.     // Consider the net play object uninitialized.
  1537.     m_bInitialized              = FALSE;
  1538.     m_bPerfectPlayErrorChecked  = FALSE;
  1539. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1540.     if (m_pStatsCallback)
  1541.     {
  1542.         m_pStatsCallback->CancelCallback();
  1543.     }
  1544. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1545.     // Stop current connection. This will totally disconnect
  1546.     // from the server, and shut down the communication ports.
  1547.     // DoCleanup();
  1548.     //  Close down the net connection
  1549.     HX_RELEASE(m_pProtocolStatus);
  1550.     /* UnRegister any previously registered source */
  1551.     if (m_pSourceInfo)
  1552.         m_pSourceInfo->UnRegister();
  1553.     if (m_pProto)
  1554.     {
  1555.         m_pProto->stop();
  1556.         HX_RELEASE (m_pProto);
  1557.     }
  1558.     // cleanup the log list
  1559.     if (m_pLogInfoList)
  1560.     {
  1561.         while (m_pLogInfoList->GetCount() > 0)
  1562.         {
  1563.             char* pszInfo = (char*) m_pLogInfoList->RemoveHead();
  1564.             delete [] pszInfo;
  1565.         }
  1566.         HX_DELETE(m_pLogInfoList);
  1567.     }
  1568.     m_ulMaxBandwidth = 4000;
  1569.     m_bPushDownSet = FALSE;
  1570.     m_pushDownStatus = PUSHDOWN_NONE;
  1571.     m_bReceivedData = FALSE;
  1572.     m_bDataWaitStarted  = FALSE;
  1573.     m_bFirstResume = TRUE;
  1574.     m_bResendAuthenticationInfo = TRUE;
  1575.     m_bRTSPRuleFlagWorkAround = FALSE;
  1576.     m_bNoLatencySet = FALSE;
  1577.     m_bIsActive = FALSE;
  1578.     return;
  1579. }
  1580. void
  1581. HXNetSource::ReSetup()
  1582. {
  1583.     HX_RESULT theErr = HXR_OK;
  1584.     Reset();
  1585.     mServerSelRecordSupport = FALSE;
  1586.     mInterframeControlSupport = FALSE;
  1587.     mServerHasBandwidthReport = FALSE;
  1588.     mServerHasFrameControl = FALSE;
  1589.     m_bConnectionWait = FALSE;
  1590.     m_bUseUDPPort = FALSE;
  1591.     m_bTimeBased = FALSE;
  1592.     m_bAtInterrupt = FALSE;
  1593.     m_bInRetryMode = FALSE;
  1594.     m_bBruteForceReconnected = FALSE;
  1595.     m_bBruteForceConnectToBeDone = FALSE;
  1596.     m_bUserHasCalledResume = FALSE;
  1597.     m_bUserHasCalledStartInit = FALSE;
  1598.     m_CurrentTransport = UnknownMode;
  1599.     m_ulSeekPendingTime = 0;
  1600.     m_bSeekPending = FALSE;
  1601.     m_ulStatsInterval = 0;
  1602.     m_ulSendStatsMask = 0;
  1603. #if defined(HELIX_FEATURE_SMIL_REPEAT)
  1604.     if (m_pSourceInfo)
  1605.     {
  1606.         CHXSimpleList* pRepeatList = m_pSourceInfo->m_bLeadingSource?m_pSourceInfo->m_pRepeatList:
  1607.                                                                      m_pSourceInfo->m_pPeerSourceInfo->m_pRepeatList;
  1608.         if (pRepeatList)
  1609.         {
  1610.             RepeatInfo* pRepeatInfo = (RepeatInfo*)pRepeatList->GetAt(m_pSourceInfo->m_curPosition);
  1611.             m_ulDelay = m_pSourceInfo->m_ulRepeatDelayTimeOffset + pRepeatInfo->ulDelay;
  1612.             if (m_pSourceInfo->m_bRepeatIndefinite      &&
  1613.                 m_pSourceInfo->m_ulMaxDuration  &&
  1614.                 m_ulDelay + pRepeatInfo->ulDuration > m_ulOriginalDelay + m_pSourceInfo->m_ulMaxDuration)
  1615.             {
  1616.                 m_ulRestrictedDuration = m_ulOriginalDelay + m_pSourceInfo->m_ulMaxDuration - m_ulDelay;
  1617.             }
  1618.             else
  1619.             {
  1620.                 m_ulRestrictedDuration = pRepeatInfo->ulDuration;
  1621.             }
  1622.         }
  1623.     }
  1624. #endif /* HELIX_FEATURE_SMIL_REPEAT */
  1625. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1626.     m_pStats->Reset();
  1627. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1628.     m_bReSetup = TRUE;
  1629.     theErr = Setup(m_pHost, m_pResource, m_uPort, m_bLossCorrection,
  1630.                    m_pURL, m_bAltURL);
  1631.     return;
  1632. }
  1633. char*
  1634. HXNetSource::GetAltURL(BOOL& bDefault)
  1635. {
  1636. #if defined(HELIX_FEATURE_ALT_URL)
  1637.     char*   pszAltURL = NULL;
  1638.     CHXURL* pAltURL = NULL;
  1639.     UINT16  uHTTPPort = DEF_HTTP_PORT;
  1640.     UINT32  ulValue = 0;
  1641.     IHXValues* pProperties = NULL;
  1642.     if (!m_pURL || m_bInitialized)
  1643.     {
  1644.         goto cleanup;
  1645.     }
  1646.     pszAltURL = m_pURL->GetAltURL(bDefault);
  1647. /*  XXX HP we can't simply exempt AltURL if the same port has
  1648.            been attempted during HTTPCloaking since the same port
  1649.            failed in HTTPCloaking may works for HTTP streaming
  1650.            we really need to determine the actual error code of
  1651.            HTTPCloaking's failure of the port(such as Connection
  1652.            failure vs bad server which doesn't support HTTPCloaking)
  1653.     // no attempt on AltURL if HTTPCloaking has failed on
  1654.     // the same port
  1655.     if (HTTPCloakMode == m_CurrentTransport)
  1656.     {
  1657.         if (!bDefault)
  1658.         {
  1659.             pAltURL = new CHXURL(pszAltURL);
  1660.             pProperties = pAltURL->GetProperties();
  1661.             if (pProperties &&
  1662.                 HXR_OK == pProperties->GetPropertyULONG32(PROPERTY_PORT, ulValue))
  1663.             {
  1664.                 uHTTPPort = (UINT16)ulValue;
  1665.             }
  1666.             HX_RELEASE(pProperties);
  1667.             HX_DELETE(pAltURL);
  1668.         }
  1669.         if (uHTTPPort == m_uCurrCloakedPort ||
  1670.             IsInCloakPortList(uHTTPPort))
  1671.         {
  1672.             HX_VECTOR_DELETE(pszAltURL);
  1673.         }
  1674.     }
  1675. */
  1676. cleanup:
  1677.     return pszAltURL;
  1678. #else
  1679.     return NULL;
  1680. #endif /* HELIX_FEATURE_ALT_URL */
  1681. }
  1682. HX_RESULT
  1683. HXNetSource::switch_to_next_transport(HX_RESULT incomingError)
  1684. {
  1685.     HX_RESULT theErr = HXR_OK;
  1686.     /* Use TCP for PercectPlay for PNA protocol.
  1687.      * for RTSP, we always use UDP..
  1688.      * m_bTimeBased is set to TRUE for RTSP protocol
  1689.      */
  1690.     if ((m_bPerfectPlay && !m_bTimeBased) || !m_pPreferredTransport)
  1691.     {
  1692.         if (UDPMode == m_CurrentTransport)
  1693.         {
  1694.             m_PreferredTransport = TCPMode;
  1695.         }
  1696.         else
  1697.         {
  1698.             m_PreferredTransport = UnknownMode;
  1699.         }
  1700.     }
  1701. #if defined(HELIX_FEATURE_SMARTERNETWORK)
  1702.     else
  1703.     {
  1704.         theErr = m_pPreferredTransport->SwitchTransport(incomingError, m_PreferredTransport);
  1705.     }
  1706. #endif /* HELIX_FEATURE_SMARTERNETWORK */
  1707.     // If there is no new transport, then we are done!
  1708.     if (HXR_OK != theErr || UnknownMode == m_PreferredTransport)
  1709.     {
  1710.         theErr = incomingError;
  1711.         goto exit;
  1712.     }
  1713.     // reset transport state to PTS_CREATE so the PreferredTransport object
  1714.     // will be notified on the success/failure of this transport switch
  1715.     m_prefTransportState = PTS_CREATE;
  1716.     // Actually switch here!
  1717.     if (m_pProto && m_pProto->can_switch_transport())
  1718.     {
  1719.         theErr = m_pProto->switch_transport(m_PreferredTransport);
  1720.     }
  1721.     else
  1722.     {
  1723.         // Switch transport via brute force, non-optimal manner.
  1724.         theErr = handleTransportSwitch();
  1725.         mLastError = theErr;
  1726.     }
  1727. exit:
  1728.     return theErr;
  1729. }
  1730. HX_RESULT
  1731. HXNetSource::_Initialize(void)
  1732. {
  1733.     HX_RESULT theErr = HXR_OK;
  1734.     ResetASMSource();
  1735.     if (m_bInRetryMode)
  1736.     {
  1737.         if (m_bBruteForceReconnected)
  1738.         {
  1739.             // reset ASMSource
  1740.             CHXSimpleList::Iterator lIter = m_HXStreamList.Begin();
  1741.             for (; lIter != m_HXStreamList.End(); ++lIter)
  1742.             {
  1743.                 HXStream* pStream = (HXStream*) (*lIter);
  1744.                 pStream->ResetASMSource((IHXASMSource*)m_pProto);
  1745.             }
  1746.             if (m_pSourceInfo)
  1747.             {
  1748.                 m_pSourceInfo->ReInitializeStats();
  1749.             }
  1750.             if (m_bFastStart)
  1751.             {
  1752.                 EnterFastStart();
  1753.             }
  1754.         }
  1755.         if (m_bClipTimeAdjusted)
  1756.         {
  1757.             m_bInitialized = TRUE;
  1758.             /* Initial seek if a start time is specified */
  1759.             if (m_ulStartTime > 0)
  1760.             {
  1761.                 DoSeek(0);
  1762.             }
  1763.         }
  1764.     }
  1765.     /* get all the flags */
  1766.     if (!theErr && m_pProto)
  1767.     {
  1768.         m_bPerfectPlayAllowed |= m_pProto->IsPerfectPlayAllowed();
  1769.         mSaveAsAllowed        |= m_pProto->IsSaveAllowed();
  1770.         WritePerfectPlayToRegistry();
  1771.         mLiveStream = m_pProto->IsLive();
  1772.         if (mLiveStream && m_bCustomEndTime)
  1773.         {
  1774.             m_bRestrictedLiveStream = TRUE;
  1775.         }
  1776.     }
  1777.     if (m_bInitialized)
  1778.     {
  1779.         return HXR_OK;
  1780.     }
  1781.     /* calculated weigthed preroll for the source */
  1782.     if (!m_bTimeBased && m_ulAvgBandwidth > 0)
  1783.     {
  1784.         m_ulPreRollInMs  = m_ulPreRollInMs / m_ulAvgBandwidth;
  1785.     }
  1786.     if (!theErr)
  1787.     {
  1788.         m_bInitialized = TRUE;
  1789.         m_ulOriginalDuration = m_ulDuration;
  1790.         theErr = AdjustClipTime();
  1791.     }
  1792.     m_pBufferManager->Init();
  1793. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1794.     /*
  1795.      * put the protocol and protocol version into the stats so rarenderer
  1796.      * and any other part of the system that needs to work with old servers
  1797.      * can know what the version and protocol is.
  1798.      */
  1799.     if (m_pStats != NULL && m_pProto != NULL)
  1800.     {
  1801.         m_pStats->m_pProtocolVersion->SetInt(m_pProto->get_protocol_version());
  1802.         m_pStats->m_pProtocol->SetStr((char*)m_pProto->get_protocol_name());
  1803.     }
  1804.     IHXBuffer* pBuffer = NULL;
  1805.     IHXValues* pResponseHeaders = NULL;
  1806.     if (HXR_OK == m_pRequest->GetResponseHeaders(pResponseHeaders) &&
  1807.         pResponseHeaders)
  1808.     {
  1809.         if (HXR_OK == pResponseHeaders->GetPropertyCString("Server", pBuffer))
  1810.         {
  1811.             if (m_pStats->m_pServerInfo)
  1812.             {
  1813.                 m_pStats->m_pServerInfo->SetStr((char*)pBuffer->GetBuffer());
  1814.             }
  1815.             ::GetVersionFromString((char*)pBuffer->GetBuffer(), m_ulServerVersion);
  1816.         }
  1817.         HX_RELEASE(pBuffer);
  1818.     }
  1819.     HX_RELEASE(pResponseHeaders);
  1820. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1821.     return theErr;
  1822. }
  1823. /*
  1824.  *      IHXRegistryID methods
  1825.  */
  1826. /************************************************************************
  1827.  *      Method:
  1828.  *          IHXRegistryID::GetID
  1829.  *      Purpose:
  1830.  *          Get registry ID(hash_key) of the objects(player, source and stream)
  1831.  *
  1832.  */
  1833. STDMETHODIMP
  1834. HXNetSource::GetID(REF(UINT32) /*OUT*/ ulRegistryID)
  1835. {
  1836. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1837.     (m_pStats)?(ulRegistryID = m_pStats->m_ulRegistryID):(ulRegistryID = 0);
  1838.     return HXR_OK;
  1839. #else
  1840.     return HXR_NOTIMPL;
  1841. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1842. }
  1843. /************************************************************************
  1844.  *      Method:
  1845.  *          IHXInfoLogger::LogInformation
  1846.  *      Purpose:
  1847.  *          Logs any user defined information in form of action and
  1848.  *          associated data.
  1849.  */
  1850. STDMETHODIMP
  1851. HXNetSource::LogInformation(const char* /*IN*/ pAction,
  1852.                              const char* /*IN*/ pData)
  1853. {
  1854.     HX_RESULT   hr = HXR_OK;
  1855.     UINT32      ulTimeSinceStart = 0;
  1856.     UINT32      ulCurrentPlayPos = 0;
  1857.     UINT32      ulInfoLen = 0;
  1858.     // action Name is a must
  1859.     if (!pAction)
  1860.     {
  1861.         return HXR_FAILED;
  1862.     }
  1863.     if (!m_pLogInfoList)
  1864.     {
  1865.         return HXR_UNEXPECTED;
  1866.     }
  1867.     // If we've already reached our limit, don't add any more info.
  1868.     if (m_ulLogInfoLength > MAX_LOGINFO_LENGTH)
  1869.     {
  1870.         return HXR_OK;
  1871.     }
  1872.     ulTimeSinceStart = CALCULATE_ELAPSED_TICKS(m_ulSourceStartTime, HX_GET_TICKCOUNT());
  1873.     // XXXCP: during auto-config there is no m_pPlayer
  1874.     if (m_pPlayer)
  1875.         ulCurrentPlayPos = m_pPlayer->GetInternalCurrentPlayTime();
  1876.     // 10 chars for max UINT32, 1 for |, 1 for last 
  1877.     // additional 1 for 
  1878.     ulInfoLen = 10*2 + 1*3 + 1;
  1879.     ulInfoLen += strlen(pAction);
  1880.     ulInfoLen += pData ? (strlen(pData) + 2) : 0; // +2 for ()
  1881.     char*   pszInfo = new char[ulInfoLen];
  1882.     memset(pszInfo, 0, ulInfoLen);
  1883.     SafeSprintf(pszInfo, ulInfoLen, "%lu|%lu|%s|", ulTimeSinceStart, ulCurrentPlayPos, pAction); /* Flawfinder: ignore */
  1884.     if (pData)
  1885.     {
  1886.         SafeStrCat(pszInfo, "(", ulInfoLen);
  1887.         SafeStrCat(pszInfo, pData, ulInfoLen);
  1888.         SafeStrCat(pszInfo, ")", ulInfoLen);
  1889.     }
  1890.     SafeStrCat(pszInfo, ";", ulInfoLen);
  1891.     m_ulLogInfoLength += strlen(pszInfo);
  1892.     // append to the list
  1893.     m_pLogInfoList->AddTail((void*) pszInfo);
  1894.     // If we just reached our size limit, add "..." to the end
  1895.     if (m_ulLogInfoLength > MAX_LOGINFO_LENGTH)
  1896.     {
  1897.         pszInfo = new char[4];
  1898.         strcpy(pszInfo, "..."); /* Flawfinder: ignore */
  1899.         m_pLogInfoList->AddTail((void*) pszInfo);
  1900.         m_ulLogInfoLength += 4;
  1901.     }
  1902.     return hr;
  1903. }
  1904. /*
  1905.  * IHXPreferredTransportSink methods
  1906.  */
  1907. STDMETHODIMP
  1908. HXNetSource::TransportSucceeded(TransportMode   /* IN */   prefTransportType,
  1909.                                  UINT16         /* IN */   uCloakPort)
  1910. {
  1911. #if defined(HELIX_FEATURE_SMARTERNETWORK)
  1912.     HX_ASSERT(m_pPreferredTransport);
  1913.     if (m_prefTransportState == PTS_CREATE)
  1914.     {
  1915.         m_prefTransportState = PTS_READY;
  1916.         m_pPreferredTransport->SetTransport(prefTransportType, uCloakPort);
  1917.     }
  1918.     else if (m_prefTransportState == PTS_PENDING)
  1919.     {
  1920.         m_prefTransportState = PTS_READY;
  1921.         HX_ASSERT(m_prefTransportState == m_pPreferredTransport->GetState());
  1922.         m_pPreferredTransport->GetTransport(m_PreferredTransport,
  1923.                                             m_uCurrCloakedPort);
  1924.         m_state = NETSRC_TRANSPORTREADY;
  1925.     }
  1926.     HX_ASSERT(m_prefTransportState == PTS_READY);
  1927. #endif /* HELIX_FEATURE_SMARTERNETWORK */
  1928.     return HXR_OK;
  1929. }
  1930. STDMETHODIMP
  1931. HXNetSource::TransportFailed()
  1932. {
  1933.     return HXR_OK;
  1934. }
  1935. void
  1936. HXNetSource::ReportError(HX_RESULT theErr)
  1937. {
  1938.     if (!mLastError && theErr)
  1939.         mLastError = theErr;
  1940. }
  1941. void
  1942. HXNetSource::CalculateCurrentBuffering(void)
  1943. {
  1944.     UINT32      ulRemainToBufferInMs    = 0;
  1945.     UINT32      ulRemainToBuffer        = 0;
  1946.     UINT32      ulExcessBufferInMs      = 0;
  1947.     UINT32      ulExcessBuffer          = 0;
  1948.     BOOL        bValidInfo              = FALSE;
  1949.     UINT32      ulActualExcessBufferInMs= 0;
  1950.     UINT32      ulActualExcessBuffer    = 0;
  1951.     m_pBufferManager->GetExcessBufferInfo(ulRemainToBufferInMs,
  1952.                                           ulRemainToBuffer,
  1953.                                           ulExcessBufferInMs,
  1954.                                           ulExcessBuffer,
  1955.                                           bValidInfo,
  1956.                                           ulActualExcessBufferInMs,
  1957.                                           ulActualExcessBuffer);
  1958.     if (bValidInfo)
  1959.     {
  1960.         /* Be conservative in marking pre-buffering done */
  1961.         if (!m_bIsPreBufferingDone &&
  1962.             ulRemainToBufferInMs == 0 && ulRemainToBuffer == 0 &&
  1963.             (ulExcessBuffer > m_ulAvgBandwidth/8 ||
  1964.              ulExcessBufferInMs > m_ulPreRollInMs))
  1965.         {
  1966.             if (m_bDelayed && m_pPlayer)
  1967.             {
  1968.                 // pause the src if it's not time to play but it's done
  1969.                 // with the pre-fetch
  1970.                 if (m_pSourceInfo)
  1971.                 {
  1972.                     m_pSourceInfo->UnRegister();
  1973.                 }
  1974.                 DoPause();
  1975.             }
  1976.             m_bIsPreBufferingDone = TRUE;
  1977.         }
  1978. if (m_pWMBufferCtl)
  1979. {
  1980.     m_pWMBufferCtl->OnBufferReport(ulActualExcessBufferInMs,
  1981.    ulActualExcessBuffer);
  1982. }
  1983.     }
  1984. }
  1985. UINT32
  1986. HXNetSource::AdjustEventTime(STREAM_INFO* pStreamInfo, UINT32 ulTime)
  1987. {
  1988.     UINT32      ulEventTime = 0;
  1989.     UINT32      stream_ulPreRoll = 0;
  1990.     UINT32      ulMinimumTotalPreroll = 0;
  1991.     INT64       llActualEventTime = 0;
  1992.     llActualEventTime = 
  1993. pStreamInfo->BufferingState().CreateINT64Timestamp(ulTime);
  1994.     llActualEventTime += m_ulDelay;
  1995.     /* subtract start time from packet time */
  1996.     if (m_ulStartTime < llActualEventTime)
  1997.     {
  1998.         llActualEventTime -= CAST_TO_INT64 m_ulStartTime;
  1999.     }
  2000.     else
  2001.     {
  2002.         llActualEventTime = 0;
  2003.     }
  2004.     if (mLiveStream || m_bRestrictedLiveStream)
  2005.     {
  2006.         // validate the timestamp of 1st live packet: the lowest
  2007.         // in case of out-of-order packets
  2008.         if (CAST_TO_INT64 m_ulFirstPacketTime > llActualEventTime)
  2009.         {
  2010.             m_ulFirstPacketTime = INT64_TO_UINT32(llActualEventTime);
  2011.         }
  2012.         ulEventTime = INT64_TO_UINT32(llActualEventTime - m_ulFirstPacketTime);
  2013.     }
  2014.     else
  2015.     {
  2016.         HX_ASSERT(llActualEventTime < MAX_UINT32);
  2017.         ulEventTime = INT64_TO_UINT32(llActualEventTime);
  2018.     }
  2019.     stream_ulPreRoll = max(pStreamInfo->BufferingState().GetMinPrerollInMs(),1000);
  2020.     /* This is the time according to the stream...*/
  2021.     ulEventTime = (ulEventTime > stream_ulPreRoll) ? (ulEventTime - stream_ulPreRoll) : 0;
  2022.     return ulEventTime;
  2023. }
  2024. void
  2025. HXNetSource::SetEndOfClip(BOOL bForcedEndofClip)
  2026. {
  2027.     m_bForcedSourceEnd = bForcedEndofClip;
  2028.     if (!m_bSourceEnd)
  2029.     {
  2030.         /* Pause the source, if it is not done yet to free up the bandwidth.
  2031.          * This will happen when there is end /dur times on the url.
  2032.          */
  2033.         if (m_bForcedSourceEnd && !m_bPaused)
  2034.         {
  2035.             if(m_pProto)
  2036.                 m_pProto->pause();
  2037. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2038.             if (m_pStatsCallback)
  2039.             {
  2040.                 m_pStatsCallback->PauseCallback();
  2041.             }
  2042. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2043.         }
  2044.         m_bSourceEnd = TRUE;
  2045.         m_pBufferManager->Stop();
  2046. if (m_pWMBufferCtl)
  2047. {
  2048.     m_pWMBufferCtl->ClearChillState();
  2049. }
  2050.         /* UnRegister any previously registered source */
  2051.         if (m_pSourceInfo)
  2052.             m_pSourceInfo->UnRegister();
  2053.         if (m_pPlayer)
  2054.         {
  2055.             m_pPlayer->EndOfSource(this);
  2056.         }
  2057. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2058.         if (m_pStatsCallback)
  2059.         {
  2060.             m_pStatsCallback->CancelCallback();
  2061.         }
  2062. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2063. #if defined(HELIX_FEATURE_RECORDCONTROL)
  2064.         if (m_pRecordControl)
  2065.         {
  2066.             m_pRecordControl->OnEndOfPackets();
  2067.         }
  2068. #endif /* HELIX_FEATURE_RECORDCONTROL*/
  2069.     }
  2070. }
  2071. BOOL
  2072. HXNetSource::IsSourceDone(void)
  2073. {
  2074.     return m_bSourceEnd;
  2075. }
  2076. void
  2077. HXNetSource::EnterBufferedPlay(void)
  2078. {
  2079. #if !defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
  2080.     if (!m_bBufferedPlay)
  2081.     {
  2082.         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s,
  2083.             "(%p)Enter BufferedPlay", this));
  2084.         m_bBufferedPlay = TRUE;
  2085.         if (m_pBufferManager)
  2086.         {
  2087.             m_pBufferManager->EnterBufferedPlay();
  2088.         }
  2089.     }
  2090. #endif // (HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
  2091. }
  2092. void
  2093. HXNetSource::LeaveBufferedPlay(void)
  2094. {
  2095. #if !defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
  2096.     if (m_bBufferedPlay)
  2097.     {
  2098.         DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s,
  2099.             "(%p)Leave BufferedPlay", this));
  2100.         m_bBufferedPlay = FALSE;
  2101.         if (m_pBufferManager)
  2102.         {
  2103.             m_pBufferManager->LeaveBufferedPlay();
  2104.         }
  2105.     }
  2106. #endif // (HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
  2107. }
  2108. STDMETHODIMP
  2109. HXNetSource::GetCurrentBuffering (UINT16  uStreamNumber,
  2110.                                    REF(INT64)  llLowestTimestamp,
  2111.                                    REF(INT64)  llHighestTimestamp,
  2112.                                    REF(UINT32) ulNumBytes,
  2113.                                    REF(BOOL)   bDone)
  2114. {
  2115.     llLowestTimestamp   = 0;
  2116.     llHighestTimestamp  = 0;
  2117.     ulNumBytes          = 0;
  2118.     bDone               = FALSE;
  2119.     return m_pProto ? m_pProto->GetCurrentBuffering(uStreamNumber,
  2120.                                                     llLowestTimestamp,
  2121.                                                     llHighestTimestamp,
  2122.                                                     ulNumBytes,
  2123.                                                     bDone) : HXR_OK;
  2124. }
  2125. STDMETHODIMP
  2126. HXNetSource::GetProxyInfoDone(HX_RESULT    status,
  2127.                                char*        pszProxyInfo)
  2128. {
  2129.     HX_RESULT   rc = HXR_OK;
  2130.     PACInfo*    pPACInfo = NULL;
  2131. #if defined(HELIX_FEATURE_PAC)
  2132.     DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)GetProxyInfoDone: %s %lu", this, m_pszURL, status));
  2133.     if (HXR_OK == status && pszProxyInfo)
  2134.     {
  2135.         ::ParsePACInfo(pszProxyInfo, m_pPACInfoList);
  2136.         // at least one PAC entry
  2137.         HX_ASSERT(m_pPACInfoList && m_pPACInfoList->GetCount());
  2138.         m_PACInfoPosition = m_pPACInfoList->GetHeadPosition();
  2139.         pPACInfo = (PACInfo*)m_pPACInfoList->GetNext(m_PACInfoPosition);
  2140.         if (pPACInfo && pPACInfo->type != PAC_DIRECT)
  2141.         {
  2142.             DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)PAC: %s %lu", this, pPACInfo->pszHost, pPACInfo->ulPort));
  2143.             HX_ASSERT(pPACInfo->type == PAC_PROXY);
  2144.             set_proxy(pPACInfo->pszHost, (UINT16)pPACInfo->ulPort);
  2145.         }
  2146.         else if (pPACInfo)
  2147.         {
  2148.             DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)PAC: DIRECT", this));
  2149.         }
  2150.     }
  2151. #endif /* HELIX_FEATURE_PAC */
  2152.     if (m_state == NETSRC_PACPENDING)
  2153.     {
  2154.         m_state = NETSRC_PACREADY;
  2155.     }
  2156.     return rc;
  2157. }
  2158. void
  2159. HXNetSource::AdjustClipBandwidthStats(BOOL bActivate /* = FALSE */)
  2160. {
  2161.     if (!m_pProto)
  2162.     {
  2163.         return;
  2164.     }
  2165.     m_bIsActive = bActivate;
  2166. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2167.     CHXMapLongToObj::Iterator lStreamIterator = mStreamInfoTable->Begin();
  2168.     for (; lStreamIterator != mStreamInfoTable->End(); ++lStreamIterator)
  2169.     {
  2170.         ULONG32         ulStreamNumber = 0;
  2171.         STREAM_INFO*    pStreamInfo    = (STREAM_INFO*) (*lStreamIterator);
  2172.         STREAM_STATS*   pStreamStats   = NULL;
  2173.         if (m_pProto &&
  2174.             HXR_OK == m_pProto->GetStreamStatistics((ULONG32) pStreamInfo->m_uStreamNumber, &pStreamStats))
  2175.         {
  2176.             HX_ASSERT(pStreamStats && pStreamStats->m_bInitialized);
  2177.             if (!pStreamStats || !pStreamStats->m_bInitialized)
  2178.             {
  2179.                 continue;
  2180.             }
  2181. //          DEBUG_OUT(m_pPlayer, (s, "AdjustClipBandwidthStats: Source: %p Stream=%d On: %d, Bw=%d",
  2182. //              this, pStreamInfo->m_uStreamNumber, (int) bActivate, (bActivate? pStreamInfo->m_ulAvgBandwidth : 0)));
  2183.             if (bActivate)
  2184.             {
  2185. pStreamInfo->BufferingState().SetAvgBWToASMBw();
  2186.                 pStreamStats->m_pClipBandwidth->SetInt((INT32)pStreamInfo->BufferingState().AvgBandwidth());
  2187.             }
  2188.             else
  2189.             {
  2190.                 pStreamStats->m_pClipBandwidth->SetInt(0);
  2191.             }
  2192.         }
  2193.     }
  2194. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2195. }
  2196. BOOL
  2197. HXNetSource::CanBeResumed()
  2198. {
  2199.     BOOL    bResult = TRUE;
  2200.     UINT32  ulCurrentTime = 0;
  2201.     if (!m_bInitialized             ||
  2202.         !m_pProto                   ||
  2203.         !m_pPlayer->IsInitialized() ||
  2204.         m_bSourceEnd                ||
  2205.         (m_pSourceInfo && !m_pSourceInfo->AreStreamsSetup()))
  2206.     {
  2207.         bResult = FALSE;
  2208.     }
  2209. #if defined(HELIX_FEATURE_PREFETCH)
  2210.     else if (m_bPrefetch)
  2211.     {
  2212.         HX_ASSERT(m_pSourceInfo?(m_pPlayer->GetCurrentGroupID() == m_pSourceInfo->m_uGroupID):TRUE);
  2213.         // m_bDelayed could be turned off by pre-buffering in TryResume()
  2214.         if (m_bDelayed)
  2215.         {
  2216.             ulCurrentTime = m_pPlayer->GetInternalCurrentPlayTime();
  2217.             if (ulCurrentTime < m_ulPrefetchDelay)
  2218.             {
  2219.                 bResult = FALSE;
  2220.             }
  2221.         }
  2222.     }
  2223. #endif /* HELIX_FEATURE_PREFETCH */
  2224.     else if ((!m_bIsPreBufferingStarted && m_bDelayed) ||
  2225.              (m_bIsPreBufferingDone && ((!m_bPaused && !m_bFirstResume) || m_bDelayed)) ||
  2226.              // if the source is in the current group, don't resume till its renderers
  2227.              // have been initialized
  2228.              (m_pSourceInfo && !m_pSourceInfo->IsInitialized() &&
  2229.              m_pPlayer->GetCurrentGroupID() == m_pSourceInfo->m_uGroupID))
  2230.     {
  2231.         bResult = FALSE;
  2232.     }
  2233.     return bResult;
  2234. }
  2235. void
  2236. HXNetSource::ResetASMSource(void)
  2237. {
  2238.     HX_RELEASE(m_pBackChannel);
  2239.     HX_RELEASE(m_pASMSource);
  2240.     HX_ASSERT(m_pProto);
  2241.     m_pProto->QueryInterface(IID_IHXBackChannel, (void**) &m_pBackChannel);
  2242.     m_pProto->QueryInterface(IID_IHXASMSource, (void**) &m_pASMSource);
  2243. }
  2244. BOOL
  2245. HXNetSource::IsInCloakPortList(UINT16 uPort)
  2246. {
  2247.     BOOL bResult = FALSE;
  2248.     int  i = 0;
  2249.     if (m_pCloakPortList && m_nNumberOfCloakPorts)
  2250.     {
  2251.         for (i = 0; i < m_nNumberOfCloakPorts; i++)
  2252.         {
  2253.             if (m_pCloakPortList[i] == uPort)
  2254.             {
  2255.                 bResult = TRUE;
  2256.                 break;
  2257.             }
  2258.         }
  2259.     }
  2260.     return bResult;
  2261. }
  2262. void
  2263. HXNetSource::SetNoLatency()
  2264. {
  2265.     if (!m_bNoLatencySet && m_bNoLatency)
  2266.     {
  2267.         m_bNoLatencySet = TRUE;
  2268.         IHXResendBufferControl* pResendBufferControl = NULL;
  2269.         if (m_pProto &&
  2270.             HXR_OK == m_pProto->QueryInterface(IID_IHXResendBufferControl,
  2271.                                               (void**)&pResendBufferControl))
  2272.         {
  2273.             pResendBufferControl->SetResendBufferDepth(0);
  2274.         }
  2275.         HX_RELEASE(pResendBufferControl);
  2276.     }
  2277. }
  2278. BOOL
  2279. HXNetSource::IsPlaying()
  2280. {
  2281.     BOOL bIsPlaying = FALSE;
  2282.     if (m_pPlayer)
  2283.     {
  2284.         bIsPlaying = m_pPlayer->IsPlaying();
  2285.     }
  2286.     return bIsPlaying;
  2287. }
  2288. void
  2289. HXNetSource::WritePerfectPlayToRegistry()
  2290. {
  2291.     // JEBXXX: write out the perfect play registry item
  2292.     IHXRegistry* pRegistry = NULL;
  2293.     if (m_pEngine->QueryInterface(IID_IHXRegistry, (void**)&pRegistry) == HXR_OK)
  2294.     {
  2295.         UINT32 ulRegID = 0;
  2296.         if (HXR_OK == GetID(ulRegID) && ulRegID != 0)
  2297.         {
  2298.             IHXBuffer* pBuffer = NULL;
  2299.             char szRegistryEntry[256];  /* Flawfinder: ignore */
  2300.             if (HXR_OK == pRegistry->GetPropName(ulRegID, pBuffer))
  2301.             {
  2302.                 // now build key name
  2303.                 SafeSprintf (szRegistryEntry, 256, "%s.PerfectPlayAllowed", pBuffer->GetBuffer());
  2304.                 // if AddInt fails, set existing value instead
  2305.                 if (HXR_OK != pRegistry->AddInt(szRegistryEntry, (m_bPerfectPlayAllowed ?1 :0)))
  2306.                 {
  2307.                     INT32 val = (m_bPerfectPlayAllowed ?1 :0);
  2308.                     pRegistry->SetIntByName(szRegistryEntry, val);
  2309.                 }
  2310.                 HX_RELEASE(pBuffer);
  2311.             }
  2312.         }
  2313.         HX_RELEASE(pRegistry);
  2314.     }
  2315. }
  2316. void
  2317. HXNetSource::CreateCloakedPortList()
  2318. {
  2319.     // time to create cloak port list!
  2320.     if (!m_pCloakPortList)
  2321.     {
  2322.         m_pCloakPortList = new UINT16[MAX_CLOAK_PORTS];
  2323.         IHXValues* pOptions = NULL;
  2324.         IHXBuffer* pCloakPorts = NULL;
  2325.         UINT32      ulCloakPort = 0;
  2326.         BOOL    bShouldAddDefaultPort = TRUE;
  2327.         if (m_pURL)
  2328.         {
  2329.             pOptions = m_pURL->GetOptions();
  2330.         }
  2331.         if (pOptions)
  2332.         {
  2333.             // try the string and then the number!
  2334.             if (HXR_OK != pOptions->GetPropertyBuffer(CLOAKPORT_URL_OPTION, pCloakPorts))
  2335.             {
  2336.                 pOptions->GetPropertyULONG32(CLOAKPORT_URL_OPTION, ulCloakPort);
  2337.             }
  2338.         }
  2339.         if (pCloakPorts)
  2340.         {
  2341.             char* pPortString = ::new char[pCloakPorts->GetSize() + 1];
  2342.             ::strcpy(pPortString, (const char*) pCloakPorts->GetBuffer()); /* Flawfinder: ignore */
  2343.             char* pTok = ::strtok(pPortString, ", ");
  2344.             while (pTok && m_nNumberOfCloakPorts < MAX_CLOAK_PORTS)
  2345.             {
  2346.                 UINT16 uTmpCloakPort = ::atoi(pTok);
  2347.                 m_pCloakPortList[m_nNumberOfCloakPorts++] = uTmpCloakPort;
  2348.                 if (uTmpCloakPort == m_uPort)
  2349.                 {
  2350.                     bShouldAddDefaultPort = FALSE;
  2351.                 }
  2352.                 pTok = ::strtok(NULL, ", ");
  2353.             }
  2354.             HX_VECTOR_DELETE(pPortString);
  2355.         }
  2356.         else if (ulCloakPort > 0)
  2357.         {
  2358.             m_pCloakPortList[m_nNumberOfCloakPorts++] = (UINT16) ulCloakPort;
  2359.             if (ulCloakPort == m_uPort)
  2360.             {
  2361.                 bShouldAddDefaultPort = FALSE;
  2362.             }
  2363.         }
  2364.         if (pCloakPorts || (ulCloakPort > 0))
  2365.         {
  2366.             if (bShouldAddDefaultPort && m_nNumberOfCloakPorts < MAX_CLOAK_PORTS)
  2367.             {
  2368.                 m_pCloakPortList[m_nNumberOfCloakPorts++] = m_uPort;
  2369.             }
  2370.         }
  2371.         else
  2372.         {
  2373.             for (UINT16 i = 0; i < MAX_CLOAK_PORTS; i++)
  2374.             {
  2375.                 // use the port specified in the URL instead of using the
  2376.                 // standard ports!
  2377.                 if ((m_bRTSPProtocol && g_uCloakPorts[i] == 554) ||
  2378.                     (!m_bRTSPProtocol && g_uCloakPorts[i] == 7070))
  2379.                 {
  2380.                     m_pCloakPortList[i] = m_uPort;
  2381.                 }
  2382.                 else
  2383.                 {
  2384.                     m_pCloakPortList[i] = g_uCloakPorts[i];
  2385.                 }
  2386.             }
  2387.             m_nNumberOfCloakPorts = MAX_CLOAK_PORTS;
  2388.         }
  2389.         HX_RELEASE(pCloakPorts);
  2390.         HX_RELEASE(pOptions);
  2391.         HX_ASSERT(m_pCloakPortList && m_nNumberOfCloakPorts > 0);
  2392.         m_nCurrPortIdx = 0;
  2393.         m_uCurrCloakedPort = m_pCloakPortList[m_nCurrPortIdx];
  2394.     }
  2395. }
  2396. HX_RESULT
  2397. HXNetSource::ReportStats()
  2398. {
  2399. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2400.     HX_ASSERT(m_bSendStatistics && m_pProto);
  2401.     if (!m_bSendStatistics || !m_pProto)
  2402.     {
  2403.         return HXR_OK;
  2404.     }
  2405.     m_pProto->send_statistics(m_ulSendStatsMask);
  2406.     if (m_pStatsCallback && m_ulStatsInterval > 0)
  2407.     {
  2408.         m_pStatsCallback->ScheduleCallback(m_ulStatsInterval);
  2409.     }
  2410.     return HXR_OK;
  2411. #else
  2412.     return HXR_NOTIMPL;
  2413. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2414. }
  2415. HX_RESULT
  2416. HXNetSource::FillRecordControl()
  2417. {
  2418. #if defined(HELIX_FEATURE_RECORDCONTROL)
  2419.     if(m_state == NETSRC_RECONNECTPENDING)
  2420.         return HXR_OK;
  2421.     if(!m_bPlayFromRecordControl || m_bForcedSourceEnd || mLastError)
  2422.         return HXR_FAILED;
  2423.     if(!m_pRecordControl->CanAcceptPackets())
  2424.         return HXR_OK;
  2425.     // Try to time interleave packets of different stream for better playback performance.
  2426.     // Using 1 sec as pace for time-interleaving packets of different streams.
  2427.     BOOL bFillTimeSet = FALSE;
  2428.     UINT32 nFillTime = 0;
  2429.     BOOL bHasPackets = TRUE;
  2430.     while(bHasPackets)
  2431.     {
  2432.         bHasPackets = FALSE;
  2433.         if(bFillTimeSet)
  2434.             nFillTime += 1000;
  2435.         for(UINT16 nStream = 0; nStream < m_uNumStreams; nStream++)
  2436.         {
  2437.             CHXEvent* pProtocolEvent = NULL;
  2438.             while(GetEventFromProtocol(nStream, pProtocolEvent) == HXR_OK &&
  2439.                   pProtocolEvent)
  2440.             {
  2441.                 UINT32 nPacketTime = 0;
  2442.                 IHXPacket* pPacket = pProtocolEvent->GetPacket();
  2443.                 if (pPacket)
  2444.                 {
  2445.                     bHasPackets = TRUE;
  2446.                     m_pRecordControl->OnPacket(pPacket, pProtocolEvent->GetTimeOffset());
  2447.                     nPacketTime = pPacket->GetTime();
  2448.                 }
  2449.                 HX_DELETE(pProtocolEvent);
  2450.                 if(!bFillTimeSet)
  2451.                 {
  2452.                     bFillTimeSet = TRUE;
  2453.                     nFillTime = nPacketTime + 1000;
  2454.                 }
  2455.                 if(nPacketTime >= nFillTime && nPacketTime - nFillTime < MAX_TIMESTAMP_GAP ||
  2456.                    nPacketTime < nFillTime && nFillTime - nPacketTime > MAX_TIMESTAMP_GAP)
  2457.                     break;
  2458.             }
  2459.         }
  2460.         if(!bHasPackets) // No need to go any further.
  2461.             break;
  2462.     }
  2463.     return HXR_OK;
  2464. #else
  2465.     return HXR_NOTIMPL;
  2466. #endif /* HELIX_FEATURE_RECORDCONTROL */
  2467. }
  2468. ReconnectCallback::ReconnectCallback(HXNetSource*       pSource,
  2469.                                      BOOL bIsStatsCallback /*= FALSE*/) :
  2470.      m_lRefCount (0)
  2471.     ,m_pSource (pSource)
  2472.     ,m_PendingHandle (0)
  2473.     ,m_pScheduler(0)
  2474.     ,m_ulScheduleTime(0)
  2475.     ,m_ulTimeout(0)
  2476.     ,m_bPaused(FALSE)
  2477.     ,m_bIsStatsReportingCallback(bIsStatsCallback)
  2478. {
  2479.     m_pSource->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
  2480. }
  2481. ReconnectCallback::~ReconnectCallback()
  2482. {
  2483.     HX_RELEASE(m_pScheduler);
  2484. }
  2485. /*
  2486.  * IUnknown methods
  2487.  */
  2488. /////////////////////////////////////////////////////////////////////////
  2489. //      Method:
  2490. //              IUnknown::QueryInterface
  2491. //      Purpose:
  2492. //              Implement this to export the interfaces supported by your
  2493. //              object.
  2494. //
  2495. STDMETHODIMP ReconnectCallback::QueryInterface(REFIID riid, void** ppvObj)
  2496. {
  2497.     QInterfaceList qiList[] =
  2498.         {
  2499.             { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*)this },
  2500.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXCallback*)this },
  2501.         };
  2502.     
  2503.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  2504. }
  2505. /////////////////////////////////////////////////////////////////////////
  2506. //      Method:
  2507. //              IUnknown::AddRef
  2508. //      Purpose:
  2509. //              Everyone usually implements this the same... feel free to use
  2510. //              this implementation.
  2511. //
  2512. STDMETHODIMP_(ULONG32) ReconnectCallback::AddRef()
  2513. {
  2514.     return InterlockedIncrement(&m_lRefCount);
  2515. }
  2516. /////////////////////////////////////////////////////////////////////////
  2517. //      Method:
  2518. //              IUnknown::Release
  2519. //      Purpose:
  2520. //              Everyone usually implements this the same... feel free to use
  2521. //              this implementation.
  2522. //
  2523. STDMETHODIMP_(ULONG32) ReconnectCallback::Release()
  2524. {
  2525.     if (InterlockedDecrement(&m_lRefCount) > 0)
  2526.     {
  2527.         return m_lRefCount;
  2528.     }
  2529.     delete this;
  2530.     return 0;
  2531. }
  2532. /*
  2533.  *      IHXPlayerCallback methods
  2534.  */
  2535. STDMETHODIMP ReconnectCallback::Func(void)
  2536. {
  2537.     m_PendingHandle         = 0;
  2538.     if (m_pSource)
  2539.     {
  2540.         if (m_bIsStatsReportingCallback)
  2541.         {
  2542.             return m_pSource->ReportStats();
  2543.         }
  2544.         else
  2545.         {
  2546.             return m_pSource->StartReconnect();
  2547.         }
  2548.     }
  2549.     return HXR_OK;
  2550. }
  2551. HX_RESULT ReconnectCallback::ScheduleCallback(UINT32 ulTimeout)
  2552. {
  2553.     CancelCallback();
  2554.     m_bPaused = FALSE;
  2555.     m_ulScheduleTime = HX_GET_TICKCOUNT();
  2556.     m_ulTimeout      = ulTimeout;
  2557.     m_PendingHandle = m_pScheduler->RelativeEnter(this, m_ulTimeout);
  2558.     return HXR_OK;
  2559. }
  2560. HX_RESULT ReconnectCallback::PauseCallback()
  2561. {
  2562.     CancelCallback();
  2563.     UINT32 ulElapsed = CALCULATE_ELAPSED_TICKS(m_ulScheduleTime, HX_GET_TICKCOUNT());
  2564.     if (m_ulTimeout > ulElapsed)
  2565.     {
  2566.         m_ulTimeout -= ulElapsed;
  2567.     }
  2568.     else
  2569.     {
  2570.         // must be really close to sending stats, next time we will schedule for 0 timeout
  2571.         m_ulTimeout = 0;
  2572.     }
  2573.     m_bPaused = TRUE;
  2574.     return HXR_OK;
  2575. }
  2576. HX_RESULT ReconnectCallback::ResumeCallback()
  2577. {
  2578.     ScheduleCallback(m_ulTimeout);
  2579.     return HXR_OK;
  2580. }
  2581. HX_RESULT ReconnectCallback::CancelCallback()
  2582. {
  2583.     m_bPaused = FALSE;
  2584.     if (m_PendingHandle)
  2585.     {
  2586.         m_pScheduler->Remove(m_PendingHandle);
  2587.         m_PendingHandle = 0;
  2588.     }
  2589.     return HXR_OK;
  2590. }