hxntsrc.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:179k
源码类别:

Symbian

开发平台:

C/C++

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