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

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: RCSL 1.0/RPSL 1.0
  3.  *
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
  5.  *
  6.  * The contents of this file, and the files included with this file, are
  7.  * subject to the current version of the RealNetworks Public Source License
  8.  * Version 1.0 (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the RealNetworks Community Source License Version 1.0
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
  12.  * in which case the RCSL will apply. You may also obtain the license terms
  13.  * directly from RealNetworks.  You may not use this file except in
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or
  16.  * RCSL for the rights, obligations and limitations governing use of the
  17.  * contents of the file.
  18.  *
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the
  20.  * developer of the Original Code and owns the copyrights in the portions
  21.  * it created.
  22.  *
  23.  * This file, and the files included with this file, is distributed and made
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  28.  *
  29.  * Technology Compatibility Kit Test Suite(s) Location:
  30.  *    http://www.helixcommunity.org/content/tck
  31.  *
  32.  * Contributor(s):
  33.  *
  34.  * ***** END LICENSE BLOCK ***** */
  35. #include "hxcom.h"
  36. #include "hlxclib/stdio.h"
  37. #include "hlxclib/stdlib.h"
  38. #include "hxver.h"
  39. #include "hxtypes.h"
  40. #include "hxresult.h"
  41. #include "hxstrutl.h"
  42. #include "hxcomm.h"
  43. #include "ihxpckts.h"
  44. #include "hxfiles.h"
  45. #include "hxengin.h"
  46. #include "hxasm.h"
  47. #include "hxsdesc.h"
  48. #include "chxpckts.h"
  49. #include "hxcore.h"
  50. #include "hxprefs.h" 
  51. #include "hxpref.h"
  52. #include "hxsdesc.h"
  53. #include "hxpends.h"
  54. #include "hxrsdbf.h"
  55. #include "hxengin.h"
  56. #include "hxstring.h"
  57. #include "hxslist.h"
  58. #include "hxstat.h"
  59. #include "hxtick.h"
  60. #include "chxeven.h"
  61. #include "hxcleng.h"
  62. //#include "rtmlpars.h"
  63. #include "rtspclnt.h"
  64. #include "rtspclntext.h"
  65. #include "rtsputil.h"
  66. #include "mimehead.h"
  67. #include "rtspmsg.h"
  68. #include "rtsppars.h"
  69. #include "rtspmdsc.h"
  70. #include "statinfo.h"
  71. #include "hxntsrc.h"
  72. #include "hxprotocol.h"
  73. #include "hxauthn.h"
  74. #include "hxplgns.h"
  75. #include "hxauth.h"
  76. #include "hxdate.h"
  77. #include "hxurl.h"
  78. #include "platform.h"
  79. #include "clntcore.ver"
  80. #include "hxplugn.h"
  81. #include "dtrvtcon.h"
  82. #include "rmfftype.h"
  83. #include "rtspprotocol.h"
  84. #include "hxcomsp.h"
  85. #include "hxpktsp.h"
  86. #include "hxplnsp.h"
  87. #include "miscsp.h"
  88. #include "hxxrsmg.h"
  89. #include "hxresmgr.h"
  90. #include "dcoreres.h"
  91. #ifdef _MACINTOSH
  92. #include "hxmm.h"
  93. #endif
  94. #include "hxheap.h"
  95. #ifdef _DEBUG
  96. #undef HX_THIS_FILE
  97. static const char HX_THIS_FILE[] = __FILE__;
  98. #endif
  99. #define PRAGMA  "initiate-session"
  100. #define MINIMUM_STATS_INTERVAL      15000 // 15 seconds
  101. #define MAX_DEFAULT_STATS_SIZE      512
  102. #define MAX_TRANSPORT               10
  103. RTSPProtocol::RTSPProtocol(HXNetSource* owner, ULONG32 ulPlatformSpecific)
  104. : HXProtocol (owner, ulPlatformSpecific)
  105. , m_lRefCount(0)
  106. , m_uSecurityKey(0)
  107. , m_uStreamCount(0)
  108. , m_uCurrentStreamCount(0)
  109. , m_pProtocolLib(0)
  110. , m_pPendingStatus(0)
  111. , m_pStatistics(0)
  112. , m_bPlaying(FALSE)
  113. , m_bIsASMSource(FALSE)
  114. , m_bUseRTP(FALSE)
  115. , m_bReceivedData(FALSE)
  116. , m_bMulticastOnly(FALSE)
  117. , m_idleState(NULL_STATE)
  118. , m_pIDInfo(NULL)
  119. , m_pRequest(NULL)
  120. , m_bFirstAuthAttempt(TRUE)
  121. , mReceivedControl(FALSE)
  122. , m_bPendingSeek(FALSE)
  123. , m_ulSeekPos1(0)
  124. , m_ulSeekPos2(0)
  125. , m_bHandleWWWAuthentication(FALSE)
  126. , m_WWWResult(HXR_OK)
  127. , m_pWWWValues(NULL)
  128. #if defined(HELIX_FEATURE_REVERTER)
  129. , m_pDataRevert(0)
  130. #endif /* HELIX_FEATURE_REVERTER */
  131. {
  132.     m_pStreamInfoList = new CHXMapLongToObj;
  133.     
  134.     if (owner)
  135.     {
  136.         IHXPlayer* pPlayer = NULL;
  137.         IUnknown*   pUnknown = NULL;
  138.         owner->GetPlayer(pPlayer);
  139.         if (pPlayer)
  140.         {
  141.             pUnknown = (IUnknown*)pPlayer;
  142.         }
  143.         // auto. config doesn't have the player object
  144.         // use IHXClientEngine instead
  145.         else
  146.         {
  147.             owner->GetContext(pUnknown);
  148.         }
  149. #if defined(HELIX_FEATURE_REVERTER)
  150.         m_pDataRevert = new DataRevertController(pUnknown);
  151.         m_pDataRevert->AddRef();
  152.         m_pDataRevert->SetControlResponse(this);
  153. #endif /* HELIX_FEATURE_REVERTER */
  154.         HX_RELEASE(pUnknown);
  155.     }
  156.     /* Always allowed in RTSP - till we add some code to file format
  157.      * plugins to set this value in file header - XXXRA
  158.      */
  159.     m_bPerfectPlayAllowed = TRUE;
  160.     //
  161.     // get proxy info for RTSP protocol
  162.     //
  163.     initialize_members();
  164.     ReadPrefBOOL(m_pPreferences, "NonRS", m_bUseRTP);    
  165.     if (!m_bUseRTP)
  166.     {
  167.         ReadPrefBOOL(m_pPreferences, "UseRTP", m_bUseRTP);
  168.     }
  169. }
  170. RTSPProtocol::~RTSPProtocol ()
  171. {
  172.     if (m_pProtocolLib)
  173.     {
  174.         m_pProtocolLib->Done();
  175.         HX_RELEASE(m_pProtocolLib);
  176.     }
  177.     HX_RELEASE(m_pRequest);
  178.     HX_RELEASE(m_pPendingStatus);
  179.     HX_RELEASE(m_pStatistics);
  180.     HX_RELEASE(m_pIDInfo);
  181.     HX_RELEASE(m_pWWWValues);
  182. #if defined(HELIX_FEATURE_REVERTER)
  183.     HX_RELEASE(m_pDataRevert);
  184. #endif /* HELIX_FEATURE_REVERTER */
  185.     
  186.     HX_DELETE(m_pStreamInfoList);
  187. }
  188. /* IUnknown methods */
  189. STDMETHODIMP
  190. RTSPProtocol::QueryInterface(REFIID riid, void** ppvObj)
  191. {
  192.     QInterfaceList qiList[] =
  193.         {
  194.             { GET_IIDHANDLE(IID_IHXPendingStatus), (IHXPendingStatus*)this },
  195.             { GET_IIDHANDLE(IID_IHXStatistics), (IHXStatistics*)this },
  196.             { GET_IIDHANDLE(IID_IHXBackChannel), (IHXBackChannel*)this },
  197.             { GET_IIDHANDLE(IID_IHXAtomicRuleChange), (IHXAtomicRuleChange*)this },
  198.             { GET_IIDHANDLE(IID_IHXPreferredTransportSink), (IHXPreferredTransportSink*)this },
  199.             { GET_IIDHANDLE(IID_IUnknown), this },
  200.         };
  201.     
  202.     if (HXR_OK == ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj))
  203.     {
  204.         return HXR_OK;
  205.     }    
  206.     else if (IsEqualIID(riid, IID_IHXASMSource) && m_bIsASMSource)
  207.     {
  208.         AddRef();
  209.         *ppvObj = (IHXASMSource*)this;
  210.         return HXR_OK;
  211.     }
  212.     else if (m_pProtocolLib &&
  213.             (HXR_OK == m_pProtocolLib->QueryInterface(riid, ppvObj)))
  214.     {
  215.         return HXR_OK;
  216.     }
  217.     *ppvObj = NULL;
  218.     return HXR_NOINTERFACE;
  219. }
  220. /////////////////////////////////////////////////////////////////////////
  221. //  Method:
  222. //      IUnknown::AddRef
  223. //  Purpose:
  224. //      Everyone usually implements this the same... feel free to use
  225. //      this implementation.
  226. //
  227. STDMETHODIMP_(ULONG32) RTSPProtocol::AddRef()
  228. {
  229.     return InterlockedIncrement(&m_lRefCount);
  230. }
  231. /////////////////////////////////////////////////////////////////////////
  232. //  Method:
  233. //      IUnknown::Release
  234. //  Purpose:
  235. //      Everyone usually implements this the same... feel free to use
  236. //      this implementation.
  237. //
  238. STDMETHODIMP_(ULONG32) RTSPProtocol::Release()
  239. {
  240.     if (InterlockedDecrement(&m_lRefCount) > 0)
  241.     {
  242.         return m_lRefCount;
  243.     }
  244.     delete this;
  245.     return 0;
  246. }
  247. /* IHXRTSPClientProtocolResponse methods */
  248. STDMETHODIMP
  249. RTSPProtocol::InitDone
  250. (
  251.     HX_RESULT status
  252. )
  253. {
  254.     if (status != HXR_OK)
  255.     {
  256.         /*
  257.          * XXX...Need to get proper errors from protocol library
  258.          */
  259.         mOwner->ReportError(status); //ConvertHResultToHXError(status));
  260.     }
  261.     if (m_pProtocolLib->HttpOnly())
  262.     {
  263.         mCurrentTransport = TCPMode;
  264.     }
  265.     return HXR_OK;
  266. }
  267. STDMETHODIMP
  268. RTSPProtocol::HandleWWWAuthentication
  269. (
  270.     HX_RESULT HX_RESULTStatus,
  271.     IHXValues* pIHXValuesHeaders
  272. )
  273. {
  274. #if defined(HELIX_FEATURE_AUTHENTICATION)
  275. #ifdef _MACINTOSH
  276.     /*
  277.      * We load a plugin for authetication. Can't do this at interrupt
  278.      * time on Mac
  279.      */
  280.     if (HXMM_ATINTERRUPT())
  281.     {
  282.         m_bHandleWWWAuthentication  = TRUE;
  283.         m_WWWResult                 = HX_RESULTStatus;
  284.         HX_RELEASE(m_pWWWValues);
  285.         m_pWWWValues                = pIHXValuesHeaders;
  286.         if (m_pWWWValues)
  287.         {
  288.             m_pWWWValues->AddRef();
  289.         }
  290.         if (mOwner)
  291.         {
  292.             mOwner->ScheduleProcessCallback();
  293.         }
  294.         return HXR_OK;
  295.     }
  296. #endif
  297.     return (handlePendingWWWAuthentication(HX_RESULTStatus, pIHXValuesHeaders));
  298. #else
  299.     return HXR_NOTIMPL;
  300. #endif /* HELIX_FEATURE_AUTHENTICATION */
  301. }
  302. #if defined(HELIX_FEATURE_AUTHENTICATION)
  303. // IHXClientAuthResponse
  304. STDMETHODIMP
  305. RTSPProtocol::ResponseReady
  306. (
  307.     HX_RESULT   HX_RESULTStatus,
  308.     IHXRequest* pIHXRequestResponse
  309. )
  310. {
  311.     HX_RESULT HX_RESULTErr;
  312.     IHXValues* pIHXValuesRequestHeaders = NULL;
  313.     if(SUCCEEDED(HX_RESULTStatus))
  314.     {
  315.         if (!m_pProtocolLib)
  316.         {
  317.             return HXR_OUTOFMEMORY;
  318.         }
  319.         pIHXRequestResponse->GetRequestHeaders
  320.         (
  321.             pIHXValuesRequestHeaders
  322.         );
  323.         if(!m_uStreamCount)
  324.         {
  325.             // We haven't received a successful Describe..
  326.             //
  327.             CHXHeader::mergeHeaders
  328.             (
  329.                 pIHXValuesRequestHeaders,
  330.                 m_spIHXValuesStoredHeaders
  331.             );
  332.             HX_RESULTErr = m_pProtocolLib->SendStreamDescriptionRequest
  333.             (
  334.                 mPath,
  335.                 pIHXValuesRequestHeaders
  336.             );
  337.         }
  338.         else if (m_uCurrentStreamCount == m_uStreamCount)
  339.         {
  340.             // We haven't received a successful Setup..
  341.             //
  342.             HX_RESULTErr = m_pProtocolLib->SendSetupRequest
  343.             (
  344.                 NULL,
  345.                 0,
  346.                 pIHXValuesRequestHeaders
  347.             );
  348.         }
  349.         HX_RELEASE(pIHXValuesRequestHeaders);
  350.     }
  351.     else
  352.     {
  353.         if (HXR_FAIL == HX_RESULTStatus)
  354.         {
  355.             HX_RESULTStatus = HXR_NOT_AUTHORIZED;
  356.         }
  357.         mOwner->ReportError(HX_RESULTStatus);
  358.     }
  359.     return HXR_OK;
  360. }
  361. HX_RESULT
  362. RTSPProtocol::handlePendingWWWAuthentication
  363. (
  364.     HX_RESULT HX_RESULTStatus,
  365.     IHXValues* pIHXValuesHeaders
  366. )
  367. {
  368.     HX_RESULT HX_RESULTRet = HXR_FAIL;
  369.     if(HXR_NOT_AUTHORIZED == HX_RESULTStatus)
  370.     {
  371.         IUnknown*   pIUnknownContext = NULL;
  372.         IHXPlayer* pIHXPlayerPlayer = NULL;
  373.         IHXAuthenticationManager* pIHXAuthenticationManager = NULL;
  374.         // Don't transport switch while we are waiting for authentication
  375.         mOwner->StopDataWait();
  376.         if
  377.         (
  378.             m_spIHXClientAuthConversationAuthenticator.IsValid()
  379.             &&
  380.             m_spIHXClientAuthConversationAuthenticator->IsDone()
  381.         )
  382.         {
  383.             // Well we tried to authenticate already,
  384.             // so it must have failed
  385.             m_spIHXClientAuthConversationAuthenticator->Authenticated(FALSE);
  386.             // Cleanup so that we can re-auth
  387.             m_spIHXClientAuthConversationAuthenticator.Release();
  388.         }
  389.         mOwner->GetPlayer(pIHXPlayerPlayer);
  390.         if (NULL == pIHXPlayerPlayer)
  391.         {
  392.             // in case of the Auto. Config
  393.             mOwner->GetContext(pIUnknownContext);
  394.         }
  395.         else
  396.         {
  397.             pIUnknownContext = (IUnknown*)pIHXPlayerPlayer;
  398.         }
  399.         if (!m_spIHXClientAuthConversationAuthenticator.IsValid())
  400.         {
  401.             DECLARE_SMART_POINTER_UNKNOWN spIUnknownAuthenticator;
  402.             DECLARE_SMART_POINTER
  403.             (
  404.                 IHXObjectConfiguration
  405.             ) spIHXObjectConfigurationAuthenticator;
  406.             DECLARE_SMART_POINTER
  407.             (
  408.                 IHXCommonClassFactory
  409.             ) spIHXCommonClassFactoryHXCore;
  410.             spIHXCommonClassFactoryHXCore = pIUnknownContext;
  411.             // Starting conversation
  412.             HX_RESULTRet = spIHXCommonClassFactoryHXCore->CreateInstance
  413.             (
  414.                 CLSID_CHXClientAuthenticator,
  415.                 (void**)&spIUnknownAuthenticator
  416.             );
  417.             if
  418.             (
  419.                 SUCCEEDED(HX_RESULTRet)
  420.                 &&
  421.                 spIUnknownAuthenticator.IsValid()
  422.             )
  423.             {
  424.                 spIHXObjectConfigurationAuthenticator =
  425.                 (
  426.                     spIUnknownAuthenticator
  427.                 );
  428.                 spIHXObjectConfigurationAuthenticator->SetContext
  429.                 (
  430.                     pIUnknownContext
  431.                 );
  432.                 m_spIHXClientAuthConversationAuthenticator =
  433.                 (
  434.                     spIUnknownAuthenticator
  435.                 );
  436.             }
  437.         }
  438.         if
  439.         (
  440.             m_spIHXClientAuthConversationAuthenticator.IsValid()
  441.             &&
  442.             !m_spIHXClientAuthConversationAuthenticator->IsDone()
  443.         )
  444.         {
  445.             HX_ASSERT(m_pRequest);
  446.             if (m_pRequest)
  447.             {
  448.                 m_pRequest->SetResponseHeaders
  449.                 (
  450.                     pIHXValuesHeaders
  451.                 );
  452.                 HX_RESULTRet =
  453.                 (
  454.                     m_spIHXClientAuthConversationAuthenticator->MakeResponse
  455.                     (
  456.                         this,
  457.                         m_pRequest
  458.                     )
  459.                 );
  460.             }
  461.             else
  462.             {
  463.                 // Auth Failed!
  464.                 m_spIHXClientAuthConversationAuthenticator->Authenticated(FALSE);
  465.                 mOwner->ReportError(HXR_NOT_AUTHORIZED);
  466.             }
  467.             // Flow continues in ResponseReady()
  468.         }
  469.         else
  470.         {
  471.             // Auth Failed!
  472.             if (m_spIHXClientAuthConversationAuthenticator.IsValid())
  473.             {
  474.                 m_spIHXClientAuthConversationAuthenticator->Authenticated(FALSE);
  475.             }
  476.             mOwner->ReportError(HXR_NOT_AUTHORIZED);
  477.         }
  478.         HX_RELEASE(pIUnknownContext);
  479.         return HXR_OK;
  480.     }
  481.     return HXR_OK;
  482. }
  483. STDMETHODIMP
  484. RTSPProtocol::AuthenticationRequestDone(HX_RESULT result,
  485.                                         const char* user,
  486.                                         const char* password)
  487. {
  488.     return HXR_NOTIMPL;
  489. }
  490. #endif /* HELIX_FEATURE_AUTHENTICATION */
  491. // XXXGo - IPTV_HACK
  492. void
  493. RTSPProtocol::hackCookie(IHXBuffer* pCookie)
  494. {
  495.     HX_ASSERT(m_bUseRTP);
  496.     // XXXGo - Interop Hack
  497.     // IP/TV send a spec incomplient cookie...take care of it for now while
  498.     // we get them to fix it.
  499.     // we will assume Set-Cookie has just NAME=VALUE paris.
  500.     IHXBuffer* pBuffer = new CHXBuffer();
  501.     pBuffer->AddRef();
  502.     pBuffer->Set((const BYTE*)pCookie->GetBuffer(),
  503.             strlen((const char*)pCookie->GetBuffer()) +1);
  504.     IHXBuffer* pBuf = NULL;
  505.     char* pcOneCookie = (char*)pBuffer->GetBuffer();
  506.     char* pc = pcOneCookie;
  507.     char* pcKey = NULL;
  508.     // go thorough each ';'
  509.     for (;;)
  510.     {
  511.         pc = strchr(pc, ';');
  512.         if (pc)
  513.         {
  514.             pBuf = new CHXBuffer();
  515.             pBuf->AddRef();
  516.             *pc = NULL;
  517.             pBuf->Set((const BYTE*)pcOneCookie, strlen(pcOneCookie) + 1);
  518.             mOwner->SetCookie(pBuf);
  519.             HX_RELEASE(pBuf);
  520.             pcOneCookie = ++pc;
  521.         }
  522.         else
  523.         {
  524.             // just set it
  525.             pBuf = new CHXBuffer();
  526.             pBuf->AddRef();
  527.             pBuf->Set((const BYTE*)pcOneCookie, strlen(pcOneCookie) + 1);
  528.             mOwner->SetCookie(pBuf);
  529.             HX_RELEASE(pBuf);
  530.             break;
  531.         }
  532.     }
  533. }
  534. HX_RESULT
  535. RTSPProtocol::SwitchToUnicast(void)
  536. {
  537.     HX_RESULT   rc = HXR_FAILED;
  538.     IHXBuffer* pBuffer = NULL;
  539.     if (mOwner && mOwner->m_pFileHeader)
  540.     {
  541.         // get a URL from the file header.  No URL, no Unicast!
  542.         if (HXR_OK == mOwner->m_pFileHeader->GetPropertyCString("UnicastURL", pBuffer) &&
  543.             pBuffer)
  544.         {
  545.             rc = HandleRedirectRequest((const char*)pBuffer->GetBuffer(), 0);
  546.         }
  547.         HX_RELEASE(pBuffer);
  548.     }
  549.     return rc;
  550. }
  551. STDMETHODIMP
  552. RTSPProtocol::HandleOptionsResponse(HX_RESULT status,
  553.     IHXValues* pHeader)
  554. {
  555.     if (FAILED(status))
  556.     {
  557.         mOwner->ReportError(status);
  558.         return status;
  559.     }
  560.     else if (HXR_REDIRECTION == status)
  561.     {
  562.         // expect a redirection message soon!
  563.         m_idleState = NULL_STATE;
  564.         BOOL bHackCookie = FALSE;
  565.         IHXBuffer* pAgent = NULL;
  566.         if (pHeader->GetPropertyCString("User-Agent", pAgent) == HXR_OK)
  567.         {
  568.             if (strncasecmp((const char*)pAgent->GetBuffer(), "Cisco IP/TV",
  569.                 11) == 0)
  570.             {
  571.                 bHackCookie = TRUE;
  572.             }
  573.         }
  574.         HX_RELEASE(pAgent);
  575.         // retrieve cookies from the response header
  576.         IHXKeyValueList* pKeyValueList = NULL;
  577.         if (HXR_OK == pHeader->QueryInterface(IID_IHXKeyValueList,
  578.                                         (void**)&pKeyValueList))
  579.         {
  580.             IHXKeyValueListIterOneKey* pListIter = NULL;
  581.             IHXBuffer* pCookie = NULL;
  582.             pKeyValueList->GetIterOneKey("Set-Cookie",pListIter);
  583.             while (pListIter->GetNextString(pCookie) == HXR_OK)
  584.             {
  585.                 // XXXGo - IPTV_HACK
  586.                 if (bHackCookie)
  587.                 {
  588.                     hackCookie(pCookie);
  589.                 }
  590.                 else
  591.                 {
  592.                     mOwner->SetCookie(pCookie);
  593.                 }
  594.                 HX_RELEASE(pCookie);
  595.             }
  596.             HX_RELEASE(pListIter);
  597.         }
  598.         HX_RELEASE(pKeyValueList);
  599.         return HXR_OK;
  600.     }
  601.     m_bConnectDone = TRUE;
  602.     HX_RESULT result = HXR_OK;
  603.     result = m_pProtocolLib->SendStreamDescriptionRequest
  604.     (
  605.         mPath,
  606.         m_spIHXValuesStoredHeaders
  607.     );
  608.     return result;
  609. }
  610. STDMETHODIMP
  611. RTSPProtocol::HandleStreamDescriptionResponse(HX_RESULT      status,
  612.                                                 IHXValues*    pFileHeader,
  613.                                                 CHXSimpleList* pHeaderList,
  614.                                                 IHXValues*    pResponseHeaders)
  615. {
  616.     HX_RESULT   hr = HXR_OK;
  617.     if (FAILED(status))
  618.     {
  619.         if (!pFileHeader || !pHeaderList)
  620.         {
  621.             /*
  622.              * XXX...Need to get proper errors from protocol library
  623.              */
  624.             mOwner->ReportError(status);//ConvertHResultToHXError(status));
  625.             return (status != (UINT32)HXR_OK) ? status : (UINT32)HXR_FAIL;
  626.         }
  627.     }
  628.     else if (!pFileHeader || !pHeaderList)
  629.     {
  630.         // Not a severe failure, need to try again.
  631.         return m_pProtocolLib->SendStreamDescriptionRequest(mPath,
  632.                                                 m_spIHXValuesStoredHeaders);
  633.     }
  634. #if defined(HELIX_FEATURE_REVERTER)
  635.     // DESCRIBE Succeeded!
  636.     //
  637.     m_pDataRevert->RevertHeaders(pFileHeader, pHeaderList, pResponseHeaders);
  638. #else
  639.     RevertHeadersDone(pFileHeader,
  640.                       pHeaderList,
  641.                       pResponseHeaders,
  642.                       FALSE);
  643. #endif /* HELIX_FEATURE_REVERTER */
  644.     return HXR_OK;
  645. }
  646. /*
  647.  * IHXPreferredTransportSink methods
  648.  */
  649. STDMETHODIMP
  650. RTSPProtocol::TransportSucceeded(TransportMode  /* IN */   prefTransportType,
  651.                                  UINT16         /* IN */   uCloakPort)
  652. {
  653.     if (m_bHTTPOnly)
  654.     {
  655.         return mOwner->TransportSucceeded(HTTPCloakMode, uCloakPort);
  656.     }
  657.     // we ignore the TCP control channel succeeded message if we are attempting
  658.     // Multicast or UDP
  659.     else if (mCurrentTransport == prefTransportType)
  660.     {
  661.         return mOwner->TransportSucceeded(prefTransportType, uCloakPort);
  662.     }
  663.     else
  664.     {
  665.         HX_ASSERT(mCurrentTransport == UDPMode || mCurrentTransport == MulticastMode);
  666.     }
  667.     return HXR_OK;
  668. }
  669. STDMETHODIMP
  670. RTSPProtocol::TransportFailed()
  671. {
  672.     return mOwner->TransportFailed();
  673. }
  674. void
  675. RTSPProtocol::RevertHeadersDone(IHXValues* pFileHeader,
  676.                                 CHXSimpleList* pHeaderList,
  677.                                 IHXValues* pResponseHeaders,
  678.                                 BOOL bUseReverter)
  679. {
  680.     HX_RESULT status = HXR_OK;
  681.     ULONG32 tempLiveStream = 0;
  682.     pFileHeader->GetPropertyULONG32("LiveStream", tempLiveStream);
  683.     mLiveStream = (tempLiveStream > 0)?TRUE:FALSE;
  684. #if defined(HELIX_FEATURE_REVERTER)
  685.     if (bUseReverter && m_pDataRevert)
  686.     {
  687.         m_pProtocolLib->InitPacketFilter(m_pDataRevert);
  688.     }
  689. #endif /* HELIX_FEATURE_REVERTER */
  690.     ULONG32 ulFlags = 0;
  691.     pFileHeader->GetPropertyULONG32("Flags", ulFlags);
  692.     mSaveAsAllowed = ulFlags & HX_SAVE_ENABLED ? TRUE : FALSE;
  693.     IHXBuffer* pBuffer = NULL;
  694.     if (HXR_OK == pResponseHeaders->GetPropertyCString("StatsMask", pBuffer))
  695.     {
  696.         mSendStatsMask = atoi((const char*)pBuffer->GetBuffer());
  697.         mOwner->SetOption(HX_STATS_MASK, &mSendStatsMask);
  698.     }
  699.     HX_RELEASE(pBuffer);
  700.     if (HXR_OK == pResponseHeaders->GetPropertyCString("StatsInterval", pBuffer))
  701.     {
  702.         UINT32 ulStatsInterval = 1000* atoi((const char*)pBuffer->GetBuffer());
  703.         // ulStatsInterval = 0 to disable the stats
  704.         if (ulStatsInterval && ulStatsInterval < MINIMUM_STATS_INTERVAL)
  705.         {
  706.             ulStatsInterval = MINIMUM_STATS_INTERVAL;
  707.         }
  708.         mOwner->SetOption(HX_STATS_INTERVAL, &ulStatsInterval);
  709.     }
  710.     HX_RELEASE(pBuffer);
  711.     if (HXR_OK == pResponseHeaders->GetPropertyCString("MaxBandwidth", pBuffer))
  712.     {
  713.         UINT32 ulMaxBandwidth = atoi((const char*)pBuffer->GetBuffer());
  714.         // ulMaxBandwidth = 0 to disable the faststart
  715.         mOwner->SetOption(HX_MAX_BANDWIDTH, &ulMaxBandwidth);
  716.     }
  717.     HX_RELEASE(pBuffer);
  718.     if (HXR_OK == pResponseHeaders->GetPropertyCString("TurboPlay", pBuffer))
  719.     {
  720.         BOOL bTurboPlay = (BOOL)atoi((const char*)pBuffer->GetBuffer());
  721.         mOwner->SetOption(HX_TURBO_PLAY, &bTurboPlay);
  722.     }
  723.     HX_RELEASE(pBuffer);
  724.     // UseRTP was set from RTSPClientProtocol::handleDescribeResponse when
  725.     // it detected we were not playing a stream from a RealServer.
  726.     ULONG32 ulTemp = 0;
  727.     if (HXR_OK == pResponseHeaders->GetPropertyULONG32("UseRTP", ulTemp))
  728.     {
  729.         m_bUseRTP = ulTemp;
  730.     }
  731.     // retrieve cookies from the response header
  732.     IHXKeyValueList* pKeyValueList = NULL;
  733.     if (HXR_OK == pResponseHeaders->QueryInterface(IID_IHXKeyValueList,
  734.                                                     (void**)&pKeyValueList))
  735.     {
  736.         IHXKeyValueListIterOneKey* pListIter = NULL;
  737.         IHXBuffer* pCookie = NULL;
  738.         pKeyValueList->GetIterOneKey("Set-Cookie",pListIter);
  739.         while (pListIter->GetNextString(pCookie) == HXR_OK)
  740.         {
  741.             mOwner->SetCookie(pCookie);
  742.             HX_RELEASE(pCookie);
  743.         }
  744.         HX_RELEASE(pListIter);
  745.     }
  746.     HX_RELEASE(pKeyValueList);
  747.     m_pRequest->SetResponseHeaders(pResponseHeaders);
  748.     // notify the source file header is ready
  749.     mOwner->FileHeaderReady(pFileHeader);
  750.     UINT32 ulNumHeaders = (UINT32) pHeaderList->GetCount();
  751.     HX_ASSERT(m_pStreamInfoList->IsEmpty() == TRUE);
  752.     if (m_pStreamInfoList->IsEmpty() && ulNumHeaders > 0 &&
  753.         ulNumHeaders < m_pStreamInfoList->GetHashTableSize())
  754.     {
  755.         m_pStreamInfoList->InitHashTable(ulNumHeaders);
  756.     }
  757.     CHXSimpleList::Iterator i;
  758.     for (i = pHeaderList->Begin(); i != pHeaderList->End(); ++i)
  759.     {
  760.         IHXValues* pHeader = (IHXValues*)(*i);
  761.         mOwner->HeaderCallback(pHeader);
  762.         if(!m_bIsASMSource)
  763.         {
  764.             // see if there's an ASMRuleBook in the stream header and set
  765.             //flag for QI. only need to get one rulebook to make this TRUE
  766.             IHXBuffer* pRuleBook = NULL;
  767.             pHeader->GetPropertyCString("ASMRuleBook", pRuleBook);
  768.             if(pRuleBook)
  769.             {
  770.                 m_bIsASMSource = TRUE;
  771.                 pRuleBook->Release();
  772.             }
  773.         }
  774.         /*
  775.          * Need to maintain status for the streams
  776.          */
  777.         HX_RESULT result;
  778.         UINT32 ulStreamNumber = 0;
  779.         UINT32 ulClipBandwidth = 0;
  780.         IHXBuffer* pMimeType = NULL;
  781.         result = pHeader->GetPropertyULONG32("StreamNumber", ulStreamNumber);
  782.         if (result != HXR_OK)
  783.         {
  784.             return;
  785.         }
  786.         pHeader->GetPropertyCString("MimeType", pMimeType);
  787.         pHeader->GetPropertyULONG32("AvgBitRate", ulClipBandwidth);
  788.         RTSP_STREAM_INFO* pStreamInfo = new RTSP_STREAM_INFO;
  789.         pStreamInfo->m_uStreamNumber = (UINT16)ulStreamNumber;
  790.         pStreamInfo->m_ulClipBandwidth = ulClipBandwidth;
  791. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  792.         pStreamInfo->m_pStreamStats = create_statistics((UINT16)ulStreamNumber);
  793.         if (pStreamInfo->m_pStreamStats)
  794.         {
  795.             pStreamInfo->m_pStreamStats->m_pClipBandwidth->SetInt(0);
  796.             if (pMimeType)
  797.             {
  798.                 pStreamInfo->m_pStreamStats->m_pMimeType->SetStr((char*)pMimeType->GetBuffer());
  799.             }
  800.         }
  801. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  802.         HX_RELEASE(pMimeType);
  803.         (*m_pStreamInfoList)[ulStreamNumber] = pStreamInfo;
  804.         m_uStreamCount++;
  805.     }
  806.     mReceivedControl        = TRUE;
  807.     m_uCurrentStreamCount   = m_uStreamCount;
  808.     m_idleState             = INIT_SOCKETS_STATE;
  809. }
  810. void
  811. RTSPProtocol::SendControlBuffer(IHXBuffer* pBuffer)
  812. {
  813.     char* p64Buf = new char[pBuffer->GetSize() * 2 + 4];
  814.     BinTo64((const unsigned char*)pBuffer->GetBuffer(),
  815.             pBuffer->GetSize(), p64Buf);
  816.     m_pProtocolLib->SendSetParameterRequest("DataConvertBuffer", "1",
  817.             "base64", p64Buf);
  818.     delete[] p64Buf;
  819. }
  820. UINT16
  821. RTSPProtocol::GetRDTFeatureLevel(void)
  822. {
  823. #if defined(HELIX_FEATURE_RDT)
  824.     if (m_pProtocolLib)
  825.     {
  826.         return ((RTSPClientProtocolExt*)m_pProtocolLib)->GetRDTFeatureLevel();
  827.     }
  828.     else
  829. #endif /* HELIX_FEATURE_RDT */
  830.     {
  831.         return 0;
  832.     }
  833. }
  834. void
  835. RTSPProtocol::LeavePrefetch(void)
  836. {
  837.     m_bPrefetch = FALSE;
  838.     if (m_pProtocolLib)
  839.     {
  840.         ((RTSPClientProtocol*)m_pProtocolLib)->LeavePrefetch();
  841.     }
  842.     return;
  843. }
  844. void
  845. RTSPProtocol::EnterFastStart(void)
  846. {
  847.     m_bFastStart = TRUE;
  848.     if (m_pProtocolLib)
  849.     {
  850.         ((RTSPClientProtocol*)m_pProtocolLib)->EnterFastStart();
  851.     }
  852.     return;
  853. }
  854. void
  855. RTSPProtocol::LeaveFastStart(void)
  856. {
  857.     m_bFastStart = FALSE;
  858.     if (m_pProtocolLib)
  859.     {
  860.         ((RTSPClientProtocol*)m_pProtocolLib)->LeaveFastStart();
  861.     }
  862.     return;
  863. }
  864. /*
  865.  *  If this is multicast, make sure to send subscribe msg
  866.  */
  867. HX_RESULT
  868. RTSPProtocol::handle_multicast(void)
  869. {
  870. #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
  871.     HX_ASSERT(mCurrentTransport == MulticastMode);
  872.     STREAM_INFO* pStreamInfo = NULL;
  873.     IHXBuffer* pRuleBook = NULL;
  874.     for (UINT16 uStrmNum = 0; uStrmNum < m_uStreamCount; uStrmNum++)
  875.     {
  876.         pStreamInfo = NULL;
  877.         if (FAILED(mOwner->GetStreamInfo(uStrmNum, pStreamInfo)))
  878.         {
  879.             return HXR_OK;
  880.         }
  881.         HX_ASSERT(pStreamInfo);
  882.         // If there is an ASMRuleBook, subscription will be done eventually
  883.         // through RTSPClientProtocol::RuleChange()...
  884.         pRuleBook = NULL;
  885.         if (FAILED(pStreamInfo->m_pHeader->GetPropertyCString("ASMRuleBook", pRuleBook)))
  886.         {
  887.             HX_ASSERT(!pRuleBook);
  888.             Subscribe(uStrmNum, 0);
  889.         }
  890.         HX_RELEASE(pRuleBook);
  891.     }
  892.     return HXR_OK;
  893. #else
  894.     return HXR_NOTIMPL;
  895. #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
  896. }
  897. HX_RESULT
  898. RTSPProtocol::send_setup_request()
  899. {
  900.     HX_RESULT   rc = HXR_OK;
  901.     RTSPTransportType* pTransport = new RTSPTransportType[MAX_TRANSPORT];
  902.     int nTransports = 0;
  903.     switch (mCurrentTransport)
  904.     {
  905.         /*
  906.          * Port is omitted here, the transport layer will pick it.
  907.          */
  908. #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
  909.         case MulticastMode:
  910.             if (!m_bUseRTP)
  911.             {
  912.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_MCAST;
  913.                 pTransport[nTransports++].m_sPort = 0;
  914.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_UDP;
  915.                 pTransport[nTransports++].m_sPort = 0;
  916.                 pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_UDP;
  917.                 pTransport[nTransports++].m_sPort = 0;
  918.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_UDP;
  919.                 pTransport[nTransports++].m_sPort = 0;
  920.                 if (m_ulTransportPrefMask & ATTEMPT_TCP)
  921.                 {
  922.                     pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_TCP;
  923.                     pTransport[nTransports++].m_sPort = 0;
  924.                     pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_TCP;
  925.                     pTransport[nTransports++].m_sPort = 0;
  926.                     pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
  927.                     pTransport[nTransports++].m_sPort = 0;
  928.                 }
  929.             }
  930.             else
  931.             {
  932.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_UDP;
  933.                 pTransport[nTransports++].m_sPort = 0;
  934.                 if (m_ulTransportPrefMask & ATTEMPT_TCP)
  935.                 {
  936.                     pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
  937.                     pTransport[nTransports++].m_sPort = 0;
  938.                 }
  939.             }
  940.             // tell the owner that we are using multicast...
  941.             // this is needed to display it on the stats dialog...
  942.             mOwner->TransportStarted(MulticastMode);
  943.             break;
  944. #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
  945.         case UDPMode:
  946.             if(!m_bUseRTP)
  947.             {
  948.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_UDP;
  949.                 pTransport[nTransports++].m_sPort = 0;
  950.                 pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_UDP;
  951.                 pTransport[nTransports++].m_sPort = 0;
  952.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_UDP;
  953.                 pTransport[nTransports++].m_sPort = 0;
  954.                 if (m_ulTransportPrefMask & ATTEMPT_TCP)
  955.                 {
  956.                     pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_TCP;
  957.                     pTransport[nTransports++].m_sPort = 0;
  958.                     pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_TCP;
  959.                     pTransport[nTransports++].m_sPort = 0;
  960.                     pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
  961.                     pTransport[nTransports++].m_sPort = 0;
  962.                 }
  963.             }
  964.             else
  965.             {
  966.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_UDP;
  967.                 pTransport[nTransports++].m_sPort = 0;
  968.                 if (m_ulTransportPrefMask & ATTEMPT_TCP)
  969.                 {
  970.                     pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
  971.                     pTransport[nTransports++].m_sPort = 0;
  972.                 }
  973.             }
  974.             // tell the owner that we are using UDP...
  975.             // this is needed to display it on the stats dialog...
  976.             mOwner->TransportStarted(UDPMode);
  977.             break;
  978.         case TCPMode:
  979.             if(!m_bUseRTP)
  980.             {
  981.                 pTransport[nTransports].m_lTransportType = RTSP_TR_TNG_TCP;
  982.                 pTransport[nTransports++].m_sPort = 0;
  983.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RDT_TCP;
  984.                 pTransport[nTransports++].m_sPort = 0;
  985.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
  986.                 pTransport[nTransports++].m_sPort = 0;
  987.             }
  988.             else
  989.             {
  990.                 pTransport[nTransports].m_lTransportType = RTSP_TR_RTP_TCP;
  991.                 pTransport[nTransports++].m_sPort = 0;
  992.             }
  993.             // tell the owner that we are using TCPt...
  994.             // this is needed to display it on the stats dialog...
  995.             if (m_bHTTPOnly)
  996.             {
  997.                 mOwner->TransportStarted(HTTPCloakMode);
  998.             }
  999.             else
  1000.             {
  1001.                 mOwner->TransportStarted(TCPMode);
  1002.             }
  1003.             break;
  1004.         default:
  1005.             HX_VECTOR_DELETE(pTransport);
  1006. #if defined(_DEBUG) && defined(DEBUG_LOG_INFO)
  1007.             HXStaticStatLog::StatPrintf("SetTransport::wrong mode %dn", mCurrentTransport);
  1008. #endif
  1009.             return HXR_FAIL;
  1010.     }
  1011.     HX_ASSERT(nTransports <= MAX_TRANSPORT);
  1012.     // look for a cookie...
  1013.     // If we use pRequsetHeaders straight from m_pRequest, it will contain a
  1014.     // whole bunch of stuff that we don't need.  SO, just extract the "Cookie"
  1015.     // and create a new header right here.  If you need other headers, we might
  1016.     // need to come up with a better loginc.
  1017.     IHXValues* pRequestHeaders = NULL;
  1018.     IHXBuffer* pCookie = NULL;
  1019.     if (SUCCEEDED(m_pRequest->GetRequestHeaders(pRequestHeaders)))
  1020.     {
  1021.         pRequestHeaders->GetPropertyCString("Cookie", pCookie);
  1022.         HX_RELEASE(pRequestHeaders);
  1023.         if (pCookie)
  1024.         {
  1025.             pRequestHeaders = new CHXHeader();
  1026.             pRequestHeaders->AddRef();
  1027.             pRequestHeaders->SetPropertyCString("Cookie", pCookie);
  1028.             HX_RELEASE(pCookie);
  1029.         }
  1030.     }
  1031.     rc = m_pProtocolLib->SendSetupRequest(pTransport, nTransports, pRequestHeaders);
  1032.     HX_RELEASE(pRequestHeaders);
  1033.     HX_VECTOR_DELETE(pTransport);
  1034.     return rc;
  1035. }
  1036. STDMETHODIMP
  1037. RTSPProtocol::HandleStreamRecordDescriptionResponse
  1038. (
  1039.     HX_RESULT   status,
  1040.     IHXValues* pResponseHeaders
  1041. )
  1042. {
  1043.     return HXR_NOTIMPL;
  1044. }
  1045. STDMETHODIMP
  1046. RTSPProtocol::HandleSetupResponse
  1047. (
  1048.     HX_RESULT status
  1049. )
  1050. {
  1051.     if (status != HXR_OK)
  1052.     {
  1053.         /*
  1054.          * XXX...Need to get proper errors from protocol library
  1055.          */
  1056.         mOwner->ReportError(status);
  1057.         return status;
  1058.     }
  1059.     switch(m_pProtocolLib->GetProtocolType())
  1060.     {
  1061.         case 1:
  1062.             mOwner->TransportStarted(MulticastMode);
  1063. #if defined(HELIX_FEATURE_TRANSPORT_MULTICAST)
  1064.             // OK, this is multicast for sure...Make sure to send subscription.
  1065.             handle_multicast();
  1066. #endif /* HELIX_FEATURE_TRANSPORT_MULTICAST */
  1067.             break;
  1068.         case 2:
  1069.             mOwner->TransportStarted(UDPMode);
  1070.             break;
  1071.         case 3:
  1072.             // notify that the server has selected TCP over UDP
  1073.             // when the player supports both
  1074.             if (!m_bHTTPOnly                        &&
  1075.                 mCurrentTransport != TCPMode        &&
  1076.                 HXR_OK == mOwner->TransportStarted(TCPMode))
  1077.             {
  1078.                 mOwner->TransportSucceeded(TCPMode, 0);
  1079.             }
  1080.             /* No need to report TCP success
  1081.              * We may be in TCP/HTTP Cloaking mode
  1082.              */
  1083.             break;
  1084.         default:
  1085.             HX_ASSERT(FALSE);
  1086.             break;
  1087.     }
  1088. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1089.     /*
  1090.      * Must wait until transport is established before initializing
  1091.      * statistics
  1092.      */
  1093.     CHXMapLongToObj::Iterator i;
  1094.     for (i = m_pStreamInfoList->Begin(); i != m_pStreamInfoList->End(); ++i)
  1095.     {
  1096.         RTSP_STREAM_INFO* pStreamInfo = (RTSP_STREAM_INFO*)(*i);
  1097.         if (m_pProtocolLib)
  1098.         {
  1099.             ((RTSPClientProtocol*)m_pProtocolLib)->SetStatistics(pStreamInfo->m_uStreamNumber,
  1100.                                                                  pStreamInfo->m_pStreamStats);
  1101.         }
  1102.     }
  1103. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1104.     mOwner->Initialize();
  1105. //    return m_pProtocolLib->SendPlayRequest(RTSP_PLAY_RANGE_BLANK, RTSP_PLAY_RANGE_BLANK, 0);
  1106.     return HXR_OK;
  1107. }
  1108. STDMETHODIMP
  1109. RTSPProtocol::HandlePlayResponse
  1110. (
  1111.     HX_RESULT status
  1112. )
  1113. {
  1114.     if (status != HXR_OK)
  1115.     {
  1116.         /*
  1117.          * XXX...Need to get proper errors from protocol library
  1118.          */
  1119.         mOwner->ReportError(status); //ConvertHResultToHXError(status));
  1120.         return status;
  1121.     }
  1122.     /* Mark the current state as Playing ONLY if we have called resume */
  1123.     if (!m_bIsFirstResume)
  1124.     {
  1125.         m_bPlaying = TRUE;
  1126.         // Start Waiting for data..
  1127.         mOwner->StartDataWait();
  1128.     }
  1129.     return HXR_OK;
  1130. }
  1131. STDMETHODIMP
  1132. RTSPProtocol::HandleRecordResponse
  1133. (
  1134.     HX_RESULT status
  1135. )
  1136. {
  1137.     return HXR_NOTIMPL;
  1138. }
  1139. STDMETHODIMP
  1140. RTSPProtocol::HandleTeardownResponse
  1141. (
  1142.     HX_RESULT status
  1143. )
  1144. {
  1145.     AddRef();
  1146.     if (m_pProtocolLib)
  1147.     {
  1148.         m_pProtocolLib->Done();
  1149.         m_pProtocolLib->Release();
  1150.         m_pProtocolLib = 0;
  1151.     }
  1152.     Release();
  1153.     return HXR_OK;
  1154. }
  1155. STDMETHODIMP
  1156. RTSPProtocol::HandleSetParameterRequest
  1157. (
  1158.     UINT32 lParamType,
  1159.     const char* pParamName,
  1160.     IHXBuffer* pParamValue
  1161. )
  1162. {
  1163.     IHXPlayer* pPlayer;
  1164.     IHXBandwidthManager * pBWM;
  1165.     if(!strcmp(pParamName,"MaximumASMBandwidth") &&
  1166.        (HXR_OK == mOwner->GetPlayer(pPlayer)) &&
  1167.        (HXR_OK == pPlayer->QueryInterface(IID_IHXBandwidthManager,
  1168.                                                   (void **)&pBWM)))
  1169.     {
  1170.         pBWM->ChangeBW((UINT32)atoi((const char *)pParamValue->GetBuffer()),
  1171.                 mOwner);
  1172.         return HXR_OK;
  1173.     }
  1174. #if defined(HELIX_FEATURE_REVERTER)
  1175.     else if (!strcmp(pParamName, "DataConvertBuffer"))
  1176.     {
  1177.         m_pDataRevert->ControlBufferReady(pParamValue);
  1178.         return HXR_OK;
  1179.     }
  1180. #endif /* HELIX_FEATURE_REVERTER */
  1181.     return HXR_NOTIMPL;
  1182. }
  1183. STDMETHODIMP
  1184. RTSPProtocol::HandleSetParameterRequest(const char* pParamName,
  1185.         const char* pParamValue, const char* pContent)
  1186. {
  1187. #if defined(HELIX_FEATURE_REVERTER)
  1188.     if (!strcmp(pParamName, "DataConvertBuffer"))
  1189.     {
  1190.         IHXBuffer* pBuffer = new CHXBuffer();
  1191.         int contentLen = strlen(pContent);
  1192.         pBuffer->SetSize(contentLen);
  1193.         int offset = BinFrom64(pContent, contentLen,
  1194.                 (unsigned char*)pBuffer->GetBuffer());
  1195.         pBuffer->SetSize(offset);
  1196.         pBuffer->AddRef();
  1197.         m_pDataRevert->ControlBufferReady(pBuffer);
  1198.         pBuffer->Release();
  1199.         return HXR_OK;
  1200.     }
  1201. #endif /* HELIX_FEATURE_REVERTER */
  1202.     return HXR_NOTIMPL;
  1203. }
  1204. STDMETHODIMP
  1205. RTSPProtocol::HandleSetParameterResponse
  1206. (
  1207.     HX_RESULT status
  1208. )
  1209. {
  1210.     return HXR_OK; // XXXSMP Just return OK for now.
  1211. }
  1212. STDMETHODIMP
  1213. RTSPProtocol::HandleSetParameterResponseWithValues
  1214. (
  1215.     HX_RESULT status,
  1216.     IHXValues* pValues
  1217. )
  1218. {
  1219.     if (status == HXR_OK && pValues)
  1220.     {
  1221.         UINT32 ulStatsInterval = 0;
  1222.         UINT32 ulValue = 0;
  1223.         if (pValues->GetPropertyULONG32("UpdateStatsInterval", ulStatsInterval) == HXR_OK)
  1224.         {
  1225.             ulStatsInterval = ulStatsInterval * 1000;
  1226.             // ulStatsInterval = 0 to disable the stats
  1227.             if (ulStatsInterval && ulStatsInterval < MINIMUM_STATS_INTERVAL)
  1228.             {
  1229.                 ulStatsInterval = MINIMUM_STATS_INTERVAL;
  1230.             }
  1231.             mOwner->SetOption(HX_STATS_INTERVAL, &ulStatsInterval);
  1232.         }
  1233.         if (pValues->GetPropertyULONG32("Reconnect", ulValue) == HXR_OK)
  1234.         {
  1235.             mOwner->SetReconnectInfo(pValues);
  1236.         }
  1237.     }
  1238.     return HandleSetParameterResponse(status);
  1239. }
  1240. STDMETHODIMP
  1241. RTSPProtocol::HandleGetParameterRequest
  1242. (
  1243.     UINT32 lParamType,
  1244.     const char* pParamName,
  1245.     IHXBuffer** pParamValue
  1246. )
  1247. {
  1248.     /*
  1249.      * XXX...Need to implement
  1250.      */
  1251.     return HXR_NOTIMPL;
  1252. }
  1253. STDMETHODIMP
  1254. RTSPProtocol::HandleGetParameterResponse
  1255. (
  1256.     HX_RESULT status,
  1257.     IHXBuffer* pParamValue
  1258. )
  1259. {
  1260.     /*
  1261.      * XXX...Need to implement
  1262.      */
  1263.     return HXR_NOTIMPL;
  1264. }
  1265. STDMETHODIMP
  1266. RTSPProtocol::HandleAlertRequest
  1267. (
  1268.     HX_RESULT status,
  1269.     INT32 lAlertNumber,
  1270.     const char* pAlertText
  1271. )
  1272. {
  1273.     HX_RESULT   theErr = HXR_OK;
  1274.     m_idleState = ALERT_STATE;
  1275.     m_ulLastAlert = (UINT32)lAlertNumber;
  1276.     HX_VECTOR_DELETE(m_pTextBuf);
  1277.     if (pAlertText)
  1278.     {
  1279.         m_pTextBuf = new char[::strlen(pAlertText) + 1];
  1280.         if(!m_pTextBuf)
  1281.         {
  1282.             theErr = HXR_OUTOFMEMORY;
  1283.             goto cleanup;
  1284.         }
  1285.         strcpy(m_pTextBuf, pAlertText); /* Flawfinder: ignore */
  1286.     }
  1287. cleanup:
  1288.     // Clear the authentication cache
  1289.     if (m_pRegistry)
  1290.     {
  1291.         m_pRegistry->DeleteByName("CredCache");
  1292.     }
  1293.     return theErr;
  1294. }
  1295. STDMETHODIMP
  1296. RTSPProtocol::HandleUseProxyRequest
  1297. (
  1298.     const char* pProxyURL
  1299. )
  1300. {
  1301.     HX_RESULT rc = HXR_OK;
  1302.     if(!pProxyURL)
  1303.     {
  1304.         mOwner->ReportError(HXR_DNR);
  1305.     }
  1306.     else
  1307.     {
  1308.         char* pProxyHost = NULL;
  1309.         UINT32 ulProxyPort = 0;
  1310.         // parse host name, port
  1311.         CHXURL proxyURL(pProxyURL);
  1312.         IHXValues* pProxyURLProps = proxyURL.GetProperties();
  1313.         IHXBuffer* pBuffer = NULL;
  1314.         if(HXR_OK == pProxyURLProps->GetPropertyBuffer(PROPERTY_HOST, pBuffer))
  1315.         {
  1316.             pProxyHost = new char[pBuffer->GetSize()+1];
  1317.             strcpy(pProxyHost, (char*)pBuffer->GetBuffer()); /* Flawfinder: ignore */
  1318.             HX_RELEASE(pBuffer);
  1319.         }
  1320.         pProxyURLProps->GetPropertyULONG32(PROPERTY_PORT, ulProxyPort);
  1321.         HX_RELEASE(pProxyURLProps);
  1322.         if(pProxyHost)
  1323.         {
  1324.             initialize_members();
  1325.             set_proxy(pProxyHost, (UINT16)ulProxyPort);
  1326.             // copy host/path so setup doesn't override
  1327.             char* pHost = new_string(mHost);
  1328.             char* pPath = new_string(mPath);
  1329.             rc = setup(pHost, pPath, mPort, mLossCorrection,
  1330.                        m_bHTTPOnly, m_bSDPInitiated, mCloakPort);
  1331.             delete[] pHost;
  1332.             delete[] pPath;
  1333.         }
  1334.         delete[] pProxyHost;
  1335.     }
  1336.     return rc;
  1337. }
  1338. STDMETHODIMP
  1339. RTSPProtocol::HandleRedirectRequest
  1340. (
  1341.     const char* pURL,
  1342.     UINT32 msFromNow
  1343. )
  1344. {
  1345.     HX_RESULT   rc = HXR_OK;
  1346.     char*       pHostStr = NULL;
  1347.     char*       pResource = NULL;
  1348.     UINT32      ulPort = 0;
  1349.     IHXValues*  pHeader = NULL;
  1350.     if(pURL)
  1351.     {
  1352.         CHXURL urlObj(pURL);
  1353.         pHeader = urlObj.GetProperties();
  1354.         IHXBuffer* pBuffer = 0;
  1355.         if (HXR_OK != pHeader->GetPropertyBuffer(PROPERTY_HOST, pBuffer))
  1356.         {
  1357.             rc = HXR_FAILED;
  1358.             goto cleanup;
  1359.         }
  1360.         pHostStr = new char[pBuffer->GetSize()+1];
  1361.         strcpy(pHostStr, (char*)pBuffer->GetBuffer()); /* Flawfinder: ignore */
  1362.         pBuffer->Release();
  1363.         if (HXR_OK != pHeader->GetPropertyBuffer(PROPERTY_RESOURCE, pBuffer))
  1364.         {
  1365.             rc = HXR_FAILED;
  1366.             goto cleanup;
  1367.         }
  1368.         pResource = (char*)pBuffer->GetBuffer();
  1369.         ulPort = 0;
  1370.         pHeader->GetPropertyULONG32(PROPERTY_PORT, ulPort);
  1371.         mOwner->SetRedirectURL(pHostStr, (UINT16)ulPort, pResource, &urlObj);
  1372.         m_LastError = HXR_REDIRECTION;
  1373.         pBuffer->Release();
  1374.         delete[] pHostStr;
  1375.     }
  1376.     else
  1377.     {
  1378.         mOwner->ReportError(HXR_DNR);
  1379.     }
  1380. cleanup:
  1381.     HX_RELEASE(pHeader);
  1382.     return rc;
  1383. }
  1384. STDMETHODIMP
  1385. RTSPProtocol::HandlePacket
  1386. (
  1387.     HX_RESULT   status,
  1388.     const char* pSessionID,
  1389.     IHXPacket* pPacket
  1390. )
  1391. {
  1392.     /*
  1393.      * These are flushed pre-seek packets
  1394.      */
  1395.     if (HXR_OK == status)
  1396.     {
  1397.         CHXEvent* pEvent = new CHXEvent(pPacket);
  1398.         pEvent->SetPreSeekEvent();
  1399.         mOwner->EventReady(pEvent);
  1400.     }
  1401.     return HXR_OK;
  1402. }
  1403. STDMETHODIMP
  1404. RTSPProtocol::HandleProtocolError
  1405. (
  1406.     HX_RESULT status
  1407. )
  1408. {
  1409.     /*
  1410.      * XXX...Need to get proper errors from protocol library
  1411.      */
  1412.     mOwner->ReportError(status);//ConvertHResultToHXError(status));
  1413.     m_bPlaying = FALSE;
  1414.     return status;
  1415. }
  1416. STDMETHODIMP
  1417. RTSPProtocol::HandleRTTResponse
  1418. (
  1419.     HX_RESULT status,
  1420.     const char* pSessionID,
  1421.     UINT32    ulSecs,
  1422.     UINT32    ulUSecs
  1423. )
  1424. {
  1425.     // we handle RTT response in order to detect
  1426.     // whether the UDP channel is still alive during PAUSE/RESUME
  1427.     return HXR_OK;
  1428. }
  1429. STDMETHODIMP
  1430. RTSPProtocol::HandleCongestion
  1431. (
  1432.     HX_RESULT status,
  1433.     const char* pSessionID,
  1434.     INT32     xmitMultiplier,
  1435.     INT32     recvMultiplier
  1436. )
  1437. {
  1438.     return HXR_NOTIMPL;
  1439. }
  1440. STDMETHODIMP
  1441. RTSPProtocol::HandleSourceDone(void)
  1442. {
  1443.     mSourceEnd = TRUE;
  1444.     if (mOwner)
  1445.     {
  1446.         mOwner->SetEndOfClip();
  1447.     }
  1448.     return HXR_OK;
  1449. }
  1450. STDMETHODIMP
  1451. RTSPProtocol::HandlePrerollChange(THIS_ 
  1452.   RTSPPrerollTypeEnum prerollType,
  1453.   UINT32 ulPreroll)
  1454. {
  1455.     if (RTSP_PREROLL_PREDECBUFPERIOD == prerollType)
  1456.     {
  1457. // Handle 3GPP 26.234 Annex G x-initpredecbufperiod field
  1458. // This field only updates the preroll for video streams
  1459. // Look through all the streams
  1460. for (UINT16 uStrmNum = 0; uStrmNum < m_uStreamCount; uStrmNum++)
  1461. {
  1462.     STREAM_INFO* pStreamInfo = NULL;
  1463.     IHXBuffer* pMimeType = NULL;
  1464.     // Look for video streams
  1465.     if ((HXR_OK == mOwner->GetStreamInfo(uStrmNum, pStreamInfo)) &&
  1466. (pStreamInfo->m_pHeader) &&
  1467. (HXR_OK == pStreamInfo->m_pHeader->GetPropertyCString("Mimetype",
  1468.       pMimeType)) &&
  1469. (!strncasecmp("video/", (char*)pMimeType->GetBuffer(), 6)))
  1470.     {
  1471. // Update the preroll value
  1472. pStreamInfo->BufferingState().UpdatePreroll(ulPreroll);
  1473.     }
  1474.     HX_RELEASE(pMimeType);
  1475. }
  1476.     }
  1477.     return HXR_OK;
  1478. }
  1479. STDMETHODIMP
  1480. RTSPProtocol::HandleStreamDone
  1481. (
  1482.     HX_RESULT status,
  1483.     UINT16    uStreamNumber
  1484. )
  1485. {
  1486.     STREAM_INFO* pStreamInfo;
  1487.     if (HXR_OK != mOwner->GetStreamInfo(uStreamNumber, pStreamInfo))
  1488.     {
  1489.         return HXR_FAIL;
  1490.     }
  1491.     HX_ASSERT(!pStreamInfo->m_bSrcStreamDone);
  1492.     if (!pStreamInfo->m_bSrcStreamDone)
  1493.     {
  1494.         pStreamInfo->m_bSrcStreamDone = TRUE;
  1495.         m_uCurrentStreamCount--;
  1496.         if (!m_uCurrentStreamCount)
  1497.         {
  1498.             mOwner->SetEndOfClip();
  1499.         }
  1500.     }
  1501.     return HXR_OK;
  1502. }
  1503. STDMETHODIMP
  1504. RTSPProtocol::GetStatus
  1505. (
  1506.     REF(UINT16) uStatusCode,
  1507.     REF(IHXBuffer*) pStatusDesc,
  1508.     REF(UINT16) ulPercentDone
  1509. )
  1510. {
  1511. // XXX HP
  1512. // we no longer care about the buffering at the transport layer
  1513. // playback starts as soon as we get enough data at BufferManager
  1514. #if 0
  1515.     /*
  1516.      * XXX...This needs to be properly implemented
  1517.      */
  1518.     CHXBuffer*          pStatus = NULL;
  1519.     IUnknown*           pContext = NULL;
  1520.     IHXClientEngine*    pEngine = NULL;
  1521.     uStatusCode = HX_STATUS_READY;
  1522.     ulPercentDone = 100;
  1523.     pStatusDesc = NULL;
  1524.     if (!m_bConnectDone)
  1525.     {
  1526.         uStatusCode     = HX_STATUS_CONTACTING;
  1527.         ulPercentDone   = 0;
  1528.         mOwner->GetContext(pContext);
  1529. #if defined(HELIX_FEATURE_RESOURCEMGR)
  1530.         if (pContext &&
  1531.             HXR_OK == pContext->QueryInterface(IID_IHXClientEngine, (void**)&pEngine))
  1532.         {
  1533.             pStatus = ((HXClientEngine *)pEngine)->GetResMgr()->GetMiscString(IDS_STATUS_CONTACTING);
  1534.         }
  1535.         pStatusDesc     = new CHXBuffer;
  1536.         if (!pStatusDesc)
  1537.         {
  1538.             return HXR_OUTOFMEMORY;
  1539.         }
  1540.         pStatusDesc->AddRef();
  1541.         CHXString statusDesc = "";
  1542.         if (pStatus)
  1543.         {
  1544.             statusDesc += (const char*) pStatus->GetBuffer();
  1545.             statusDesc += " ";
  1546.         }
  1547.         statusDesc += mHost;
  1548.         statusDesc += "...";
  1549.         pStatusDesc->Set((UCHAR*)(const char*) statusDesc,
  1550.                          strlen((const char*)statusDesc)+1);
  1551.         HX_RELEASE(pStatus);
  1552.         HX_RELEASE(pEngine);
  1553. #endif /* HELIX_FEATURE_RESOURCEMGR */
  1554.         HX_RELEASE(pContext);
  1555.         return HXR_OK;
  1556.     }
  1557.     else if (m_pPendingStatus)
  1558.     {
  1559.         return m_pPendingStatus->GetStatus(uStatusCode,
  1560.                                            pStatusDesc,
  1561.                                            ulPercentDone);
  1562.     }
  1563.     else
  1564.     {
  1565.         uStatusCode = HX_STATUS_BUFFERING;
  1566.         ulPercentDone = 0;
  1567.     }
  1568.     return HXR_OK;
  1569. #else
  1570.     return HXR_NOTIMPL;
  1571. #endif
  1572. }
  1573. #if defined(HELIX_FEATURE_STATS)
  1574. /************************************************************************
  1575.  *      Method:
  1576.  *          IHXStatistics::InitializeStatistics
  1577.  *      Purpose:
  1578.  *          Pass registry ID to the caller
  1579.  */
  1580. STDMETHODIMP
  1581. RTSPProtocol::InitializeStatistics
  1582. (
  1583.     UINT32      /*IN*/ ulRegistryID
  1584. )
  1585. {
  1586.     m_ulRegistryID = ulRegistryID;
  1587.     return HXR_OK;
  1588. }
  1589. /************************************************************************
  1590.  *      Method:
  1591.  *          IHXStatistics::UpdateStatistics
  1592.  *      Purpose:
  1593.  *          Notify the user to updates its statistics registry
  1594.  */
  1595. STDMETHODIMP
  1596. RTSPProtocol::UpdateStatistics()
  1597. {
  1598.     if (!m_pStatistics)
  1599.     {
  1600.         return HXR_FAIL;
  1601.     }
  1602.     return m_pStatistics->UpdateStatistics();
  1603. }
  1604. #endif /* HELIX_FEATURE_STATS */
  1605. HX_RESULT
  1606. RTSPProtocol::GetStreamStatistics
  1607. (
  1608.     ULONG32 ulStreamNumber,
  1609.     STREAM_STATS** ppStreamStats
  1610. )
  1611. {
  1612. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1613.     RTSP_STREAM_INFO* pStreamInfo;
  1614.     if (!m_pStreamInfoList->Lookup(ulStreamNumber, (void*&)pStreamInfo))
  1615.     {
  1616.         *ppStreamStats = NULL;
  1617.         return HXR_FAIL;
  1618.     }
  1619.     *ppStreamStats = pStreamInfo->m_pStreamStats;
  1620.     return HXR_OK;
  1621. #else
  1622.     return HXR_NOTIMPL;
  1623. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1624. }
  1625. HX_RESULT
  1626. RTSPProtocol::UpdateRegistry(UINT32 ulStreamNumber,
  1627.                              UINT32 ulRegistryID)
  1628. {
  1629. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  1630.     HX_RESULT result = HXR_OK;
  1631.     if (!m_pRegistry)
  1632.     {
  1633.         return HXR_FAIL;
  1634.     }
  1635.     CHXMapLongToObj::Iterator i;
  1636.     for (i = m_pStreamInfoList->Begin(); i != m_pStreamInfoList->End(); ++i)
  1637.     {
  1638.         RTSP_STREAM_INFO* pStreamInfo = (RTSP_STREAM_INFO*)(*i);
  1639.         if (pStreamInfo->m_uStreamNumber == (UINT16)ulStreamNumber)
  1640.         {
  1641.             STREAM_STATS* pTmpStreamStats = new STREAM_STATS(m_pRegistry, ulRegistryID);
  1642.             *pTmpStreamStats = *pStreamInfo->m_pStreamStats;
  1643.             HX_DELETE(pStreamInfo->m_pStreamStats);
  1644.             pStreamInfo->m_pStreamStats = pTmpStreamStats;
  1645.             if (m_pProtocolLib)
  1646.             {
  1647.                 ((RTSPClientProtocol*)m_pProtocolLib)->SetStatistics(pStreamInfo->m_uStreamNumber,
  1648.                                                                      pStreamInfo->m_pStreamStats);
  1649.             }
  1650.             break;
  1651.         }
  1652.     }
  1653.     return result;
  1654. #else
  1655.     return HXR_NOTIMPL;
  1656. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  1657. }
  1658. STDMETHODIMP
  1659. RTSPProtocol::RuleChange(REF(CHXSimpleList) pList)
  1660. {
  1661.     return m_pProtocolLib->RuleChange(&pList);
  1662. }
  1663. /*
  1664.  * IHXASMSource methods
  1665.  */
  1666. /************************************************************************
  1667.  *      Method:
  1668.  *          IHXASMSource::Subscribe
  1669.  *      Purpose:
  1670.  *          Subscribe to a stream
  1671.  */
  1672. STDMETHODIMP
  1673. RTSPProtocol::Subscribe
  1674. (
  1675.     UINT16 streamNumber,
  1676.     UINT16 ruleNumber
  1677. )
  1678. {
  1679.     RTSPSubscription sub;
  1680.     sub.m_streamNumber = streamNumber;
  1681.     sub.m_ruleNumber = ruleNumber;
  1682.     sub.m_bIsSubscribe = TRUE;
  1683.     CHXSimpleList subList;
  1684.     subList.AddTail(&sub);
  1685.     return m_pProtocolLib->Subscribe(&subList);
  1686. }
  1687. /************************************************************************
  1688.  *      Method:
  1689.  *          IHXASMSource::Unsubscribe
  1690.  *      Purpose:
  1691.  *          Unsubscribe from a stream
  1692.  */
  1693. STDMETHODIMP
  1694. RTSPProtocol::Unsubscribe
  1695. (
  1696.     UINT16 streamNumber,
  1697.     UINT16 ruleNumber
  1698. )
  1699. {
  1700.     RTSPSubscription sub;
  1701.     sub.m_streamNumber = streamNumber;
  1702.     sub.m_ruleNumber = ruleNumber;
  1703.     sub.m_bIsSubscribe = FALSE;
  1704.     CHXSimpleList subList;
  1705.     subList.AddTail(&sub);
  1706.     return m_pProtocolLib->Unsubscribe(&subList);
  1707. }
  1708. /*
  1709.  * IHXBackChannel methods
  1710.  */
  1711. /************************************************************************
  1712.  *      Method:
  1713.  *          IHXBackChannel::PacketReady
  1714.  *      Purpose:
  1715.  *          Send a packet from renderer back to file format
  1716.  */
  1717. STDMETHODIMP
  1718. RTSPProtocol::PacketReady
  1719. (
  1720.     IHXPacket* pPacket
  1721. )
  1722. {
  1723.     /*
  1724.      * XXXSMP - We'll use the transport when available eventually, but
  1725.      * Control messages will do for now.
  1726.      */
  1727.     if(m_pProtocolLib)
  1728.     {
  1729.         return m_pProtocolLib->BackChannelPacketReady(pPacket);
  1730.     }
  1731.     return HXR_FAIL;
  1732. }
  1733. /* HXProtocol methods */
  1734. HX_RESULT
  1735. RTSPProtocol::server_hello(void)
  1736. {
  1737.     HX_RESULT   theErr = HXR_OK;
  1738.     IUnknown*   pContext = NULL;
  1739.     IHXBuffer*  pBuffer = NULL;
  1740.     IHXValues*  pInfo = NULL;
  1741.     pContext = (IUnknown*)(IHXStreamSource*)mOwner;
  1742.     pContext->AddRef();
  1743.     if (m_bSDPInitiated)
  1744.     {
  1745.         pInfo = new CHXHeader();
  1746.         if (pInfo)
  1747.         {
  1748.             pInfo->AddRef();
  1749.             pBuffer = new CHXBuffer();
  1750.             if (pBuffer)
  1751.             {
  1752.                 pBuffer->AddRef();
  1753.                 pBuffer->Set((UCHAR*)mPath, strlen(mPath) + 1);
  1754.                 pInfo->SetPropertyCString("helix-sdp", pBuffer);
  1755.                 pBuffer->Release();
  1756.             }
  1757.         }
  1758.     }
  1759.     theErr = m_pProtocolLib->Init((IUnknown*)pContext,
  1760.                                   mHost,
  1761.                                   mPort,
  1762.                                   (IHXRTSPClientProtocolResponse*)this,
  1763.                                   mUseProxy?RTSP_INIT_HXPRIVATE_AUTHORIZATION:0,
  1764.                                   m_pIDInfo,
  1765.                                   pInfo,
  1766.                                   m_bHTTPOnly,
  1767.                                   mCloakPort,
  1768.                                   FALSE);
  1769.     if (pInfo)
  1770.     {
  1771.         UINT32  ulMulticastOnly = 0;
  1772.         // "MulticastOnly" is set by the RTSPClientProtocol when it's scalable
  1773.         // multicast via SDP file.
  1774.         //
  1775.         // If "MulticastOnly" is set and the current transport is not multicast then
  1776.         // we will returns error immediately and won't waste time in transport switching
  1777.         pInfo->GetPropertyULONG32("MulticastOnly", ulMulticastOnly);
  1778.         m_bMulticastOnly = (ulMulticastOnly > 0)?TRUE:FALSE;
  1779.         if (m_bMulticastOnly && mCurrentTransport != MulticastMode)
  1780.         {
  1781.             theErr = HXR_SE_MULTICAST_DELIVERY_ONLY;
  1782.         }
  1783.     }
  1784.     HX_RELEASE(pInfo);
  1785.     HX_RELEASE(pContext);
  1786.     return theErr;
  1787. }
  1788. HX_RESULT
  1789. RTSPProtocol::proxy_hello(void)
  1790. {
  1791.     m_pProtocolLib->SetProxy(mProxy, mProxyPort);
  1792.     return server_hello();
  1793. }
  1794.     
  1795. HX_RESULT
  1796. RTSPProtocol::process(void)
  1797. {
  1798.     HX_RESULT theErr = HXR_OK;
  1799.     if (m_LastError != HXR_OK)
  1800.     {
  1801.         return m_LastError;
  1802.     }
  1803. #ifdef _MACINTOSH
  1804. #if defined(HELIX_FEATURE_AUTHENTICATION)
  1805.     if (m_bHandleWWWAuthentication)
  1806.     {
  1807.         /* Need to wait for system time */
  1808.         if (HXMM_ATINTERRUPT())
  1809.         {
  1810.             return HXR_OK;
  1811.         }
  1812.         m_bHandleWWWAuthentication = FALSE;
  1813.         handlePendingWWWAuthentication(m_WWWResult, m_pWWWValues);
  1814.         HX_RELEASE(m_pWWWValues);
  1815.     }
  1816. #endif
  1817. #endif
  1818.     switch(m_idleState)
  1819.     {
  1820.         case INIT_SOCKETS_STATE:
  1821.         {
  1822.             IUnknown*           pContext = NULL;
  1823.             IHXInterruptState*  pInterruptState = NULL;
  1824.             mOwner->GetContext(pContext);
  1825.             if (pContext)
  1826.             {
  1827.                 pContext->QueryInterface(IID_IHXInterruptState, (void**) &pInterruptState);
  1828.             }
  1829.             HX_RELEASE(pContext);
  1830.             /* We want to initialize sockets ONLY at system time */
  1831.             if (!pInterruptState ||
  1832.                 !pInterruptState->AtInterruptTime())
  1833.             {
  1834.                 // XXX HP: we should find better way to handle this
  1835.                 //             when the UseUDPPort option is selected
  1836.                 if (UDPMode == mCurrentTransport ||
  1837.                     MulticastMode == mCurrentTransport)
  1838.                 {
  1839.                     theErr = m_pProtocolLib->InitSockets();
  1840.                 }
  1841.                 m_idleState = SEND_SETUP_REQUEST_STATE;
  1842.             }
  1843.             HX_RELEASE(pInterruptState);
  1844.         }
  1845.         break;
  1846.         case SEND_SETUP_REQUEST_STATE:
  1847.         {
  1848.             // Make sure we are finished with the file header
  1849.             if (!mOwner->m_bContinueWithHeaders)
  1850.             {
  1851.                 theErr = send_setup_request();
  1852.                 m_idleState = NULL_STATE;
  1853.             }
  1854.         }
  1855.         break;
  1856.         case ALERT_STATE:
  1857.         {
  1858.             // Set theErr to the correct ServerAlert HXR_ code.
  1859.             theErr = MAKE_SA(m_ulLastAlert);
  1860.             if (!IS_SERVER_ALERT(theErr))
  1861.             {
  1862.                 theErr = HXR_SERVER_ALERT;
  1863.             }
  1864.             m_idleState = NULL_STATE;
  1865.         }
  1866.         break;
  1867.         default:
  1868.         break;
  1869.     }
  1870.     // check whether the connection has timed out
  1871.     if (!theErr && !m_bPaused)
  1872.     {
  1873.         ULONG32 ulNow = HX_GET_TICKCOUNT();
  1874.         if ((!mReceivedControl || (!m_bReceivedData && m_bPlaying))
  1875.             && mOwner->CheckTransportTimeout(ulNow))
  1876.         {
  1877.             /* Make sure that we have really not receioved any data.
  1878.              * If it is a sparse stream, transport may hold onto initial
  1879.              * data for around 2 seconds before releasing it to the next
  1880.              * layer.
  1881.              */
  1882.             if (!mReceivedControl)
  1883.             {
  1884.                 theErr = HXR_NET_CONNECT;
  1885.             }
  1886.             else
  1887.             {
  1888.                 if (m_pProtocolLib && m_pProtocolLib->IsDataReceived())
  1889.                 {
  1890.                     /* We haver received the data.. Transport will
  1891.                     * eventually give it to use (hopefully!)
  1892.                     */
  1893.                     m_bReceivedData = TRUE;
  1894.                 }
  1895.                 else
  1896.                 {
  1897.                     switch (mCurrentTransport)
  1898.                     {
  1899.                     case MulticastMode:
  1900.                         theErr = HXR_MULTICAST_UDP;
  1901.                         break;
  1902.                     case UDPMode:
  1903.                         theErr = HXR_NET_UDP;
  1904.                         break;
  1905.                     case TCPMode:
  1906.                         if (!m_bHTTPOnly)
  1907.                         {
  1908.                             theErr = HXR_NET_TCP;
  1909.                         }
  1910.                         else
  1911.                         {
  1912.                             theErr = HXR_DNR;
  1913.                         }
  1914.                         break;
  1915.                     default:
  1916.                         break;
  1917.                     }
  1918.                 }
  1919.             }
  1920.         }
  1921.         // The following logic is to force reconnect when in certain cases, the UDP
  1922.         // channel would be closed after a long pause. This solves the 50% phenomenon.
  1923.         if (HXR_OK == theErr && m_bReceivedData && m_bAreResuming && mCurrentTransport == UDPMode)
  1924.         {
  1925.             if (mSourceEnd || (m_pProtocolLib && m_pProtocolLib->IsDataReceived()))
  1926.             {
  1927.                 m_bAreResuming = FALSE;
  1928.             }
  1929.             else if (mOwner->CheckTransportTimeout(ulNow))
  1930.             {
  1931.                 m_bAreResuming = FALSE;
  1932.                 theErr = HXR_SERVER_TIMEOUT;
  1933.             }
  1934.         }
  1935.         // fallback to unicast if scalable multicast fails
  1936.         if (m_bSDPInitiated && HXR_MULTICAST_UDP == theErr && mLiveStream)
  1937.         {
  1938.             if (HXR_OK == SwitchToUnicast())
  1939.             {
  1940.                 theErr = HXR_OK;
  1941.             }
  1942.             else
  1943.             {
  1944.                 theErr = HXR_MULTICAST_JOIN;
  1945.             }
  1946.         }
  1947.     }
  1948.     // remember the last error so we won't proceed to the next
  1949.     // RTSP state in subsequent process() calls
  1950.     if (HXR_OK == m_LastError && HXR_OK != theErr)
  1951.     {
  1952.         m_LastError = theErr;
  1953.     }
  1954.     return theErr;
  1955. }
  1956. HX_RESULT
  1957. RTSPProtocol::abort(void)
  1958. {
  1959.     HX_RESULT theErr = HXR_OK;
  1960. //XXX...Currently unimplemented
  1961.     return theErr;
  1962. }
  1963. HX_RESULT
  1964. RTSPProtocol::GetEvent
  1965. (
  1966.     UINT16 uStreamNumber,
  1967.     CHXEvent*& pEvent
  1968. )
  1969. {
  1970.     HX_TRACE("RTSPProtocol::GetPacket");
  1971.     HX_RESULT result;
  1972.     IHXPacket* pPacket = NULL;
  1973.     pEvent = NULL;
  1974.     result = m_pProtocolLib->GetPacket(uStreamNumber, pPacket);
  1975. #ifdef _DEBUG
  1976.     if (result == HXR_AT_END)
  1977.     {
  1978.         STREAM_INFO* pStreamInfo;
  1979.         if (HXR_OK != mOwner->GetStreamInfo(uStreamNumber, pStreamInfo))
  1980.         {
  1981.             return HXR_FAIL;
  1982.         }
  1983.         HX_ASSERT(pStreamInfo->m_bSrcStreamDone);
  1984.     }
  1985. #endif
  1986.     if (pPacket)
  1987.     {
  1988.         // signal the raw data is received
  1989.         m_bReceivedData = TRUE;
  1990.         pEvent = new CHXEvent(pPacket);
  1991.         pPacket->Release();
  1992.     }
  1993.     return result;
  1994. }
  1995. HX_RESULT
  1996. RTSPProtocol::setup(const char* host, const char* path, UINT16 port,
  1997.                     BOOL LossCorrection, BOOL bHTTPCloak, 
  1998.                     BOOL bSDPInitiated, UINT16 cloakPort)
  1999. {
  2000.     HX_RESULT   theErr  = HXR_OK;
  2001.     IHXValues*  pRequestHeaders = NULL;
  2002.     IHXValues* pCloakValues = NULL;
  2003.     IHXBuffer*  pRegionData = NULL;
  2004.     m_bSDPInitiated = bSDPInitiated;
  2005.     mOwner->GetRequest(m_pRequest);
  2006.     // XXXkshoop store origional headers for use
  2007.     // in replaying Describe's.  This supports
  2008.     // authentication.
  2009.     HX_ASSERT(m_pRequest);
  2010.     if (m_pRequest)
  2011.     {
  2012.         m_spIHXValuesStoredHeaders.Release();
  2013.         theErr = m_pRequest->GetRequestHeaders(
  2014.             m_spIHXValuesStoredHeaders.ptr_reference());
  2015.         HX_VERIFY(SUCCEEDED(theErr) && m_spIHXValuesStoredHeaders.IsValid());
  2016.     }
  2017.     // setup base class members
  2018.     theErr = HXProtocol::setup(host, path, port, LossCorrection, bHTTPCloak,
  2019.                                m_bSDPInitiated, cloakPort);
  2020.     if (theErr)
  2021.     {
  2022.         return theErr;
  2023.     }
  2024.     if
  2025.     (
  2026.         m_pRequest
  2027.         &&
  2028.         SUCCEEDED(m_pRequest->GetRequestHeaders(pRequestHeaders))
  2029.         &&
  2030.         pRequestHeaders
  2031.     )
  2032.     {
  2033.         pRequestHeaders->GetPropertyCString("RegionData", pRegionData);
  2034.     }
  2035.     HX_RELEASE(pRequestHeaders);
  2036.     // construct the IHXValues
  2037.     m_pIDInfo = new CHXHeader();
  2038.     m_pIDInfo->AddRef();
  2039.     IHXBuffer*  pGUID = new CHXBuffer();
  2040.     IHXBuffer*  pClientID = new CHXBuffer();
  2041.     IHXBuffer*  pPragma = new CHXBuffer();
  2042.     pGUID->AddRef();
  2043.     pClientID->AddRef();
  2044.     pPragma->AddRef();
  2045.     pGUID->Set((const UCHAR*)m_pszGUID, strlen(m_pszGUID)+1);
  2046.     pClientID->Set((const UCHAR*)m_pszClientID, strlen(m_pszClientID)+1);
  2047.     pPragma->Set((const UCHAR*)PRAGMA, strlen(PRAGMA)+1);
  2048.     m_pIDInfo->SetPropertyCString("GUID", pGUID);
  2049.     m_pIDInfo->SetPropertyCString("ClientID", pClientID);
  2050.     // server doesn't like this in SDP initiated playback
  2051.     if (!m_bSDPInitiated)
  2052.     {
  2053.         m_pIDInfo->SetPropertyCString("Pragma", pPragma);
  2054.     }
  2055. #if 0
  2056.     IHXBuffer* pPasswordBuffer;
  2057.     if (m_pPreferences && m_pPreferences->ReadPref("LoadTestPassword",
  2058.        pPasswordBuffer) == HXR_OK)
  2059.     {
  2060.         char szLoadTestPasswordKey[HX_COMPANY_ID_KEY_SIZE] = {0}; /* Flawfinder: ignore */
  2061.         // create the encrypted key
  2062.         CalcCompanyIDKey((const char*)pPasswordBuffer->GetBuffer(),
  2063.                         (const char*)szStarttime,
  2064.                         (const char*)"LoadTestID",
  2065.                         (const char*)pRCMagic1,
  2066.                         (const char*)pMagic2,
  2067.                         (UCHAR*) &szLoadTestPasswordKey[0]);
  2068.         char szEncodedLTP[HX_COMPANY_ID_KEY_SIZE * 2]; // probably overkill /* Flawfinder: ignore */
  2069.         BinTo64((const BYTE*)szLoadTestPasswordKey, HX_COMPANY_ID_KEY_SIZE,
  2070.             szEncodedLTP);
  2071.         IHXBuffer* pEncodedLTPBuffer = new CHXBuffer();
  2072.         pEncodedLTPBuffer->AddRef();
  2073.         pEncodedLTPBuffer->Set((const UCHAR*)szEncodedLTP,
  2074.             strlen(szEncodedLTP)+1);
  2075.         m_pIDInfo->SetPropertyCString("LoadTestPassword", pEncodedLTPBuffer);
  2076.         pEncodedLTPBuffer->Release();
  2077.         HX_RELEASE(pPasswordBuffer);
  2078.         /*
  2079.          * XXXSMP Very poor way to set a requirement.  This won't work
  2080.          * as soon rmartsp needs to send other requirements.  Comment
  2081.          * in rmartsp about this.
  2082.          */
  2083.         const UINT8 pRequireStr[] = "com.real.load-test-password-enabled";
  2084.         IHXBuffer* pReq = new CHXBuffer();
  2085.         pReq->AddRef();
  2086.         pReq->Set(pRequireStr, sizeof(pRequireStr) + 1);
  2087.         m_pIDInfo->SetPropertyCString("Require", pReq);
  2088.         pReq->Release();
  2089.     }
  2090. #endif
  2091.     if (pRegionData)
  2092.     {
  2093.         m_pIDInfo->SetPropertyCString("RegionData", pRegionData);
  2094.     }
  2095.     HX_RELEASE(pGUID);
  2096.     HX_RELEASE(pClientID);
  2097.     HX_RELEASE(pRegionData);
  2098.     HX_RELEASE(pPragma);
  2099.     /*
  2100.      * XXX...This had better get fixed under full IRMA (should
  2101.      *       be done with QueryInterface)
  2102.      */
  2103.     RTSPClientProtocol* pClientProtocol = NULL;
  2104. #if defined(HELIX_FEATURE_RDT)
  2105.     pClientProtocol = new RTSPClientProtocolExt();
  2106. #else
  2107.     pClientProtocol = new RTSPClientProtocol();
  2108. #endif /* HELIX_FEATURE_RDT */
  2109.     m_pProtocolLib = (IHXRTSPClientProtocol*)pClientProtocol;
  2110.     if (!m_pProtocolLib)
  2111.     {
  2112.         return HXR_OUTOFMEMORY;
  2113.     }
  2114.     m_pProtocolLib->AddRef();
  2115.     if (m_bHTTPOnly)
  2116.     {
  2117.         IHXBuffer* pBuffer = NULL;
  2118.         const char* pszURL = NULL;
  2119.         pCloakValues = new CHXHeader();
  2120.         pCloakValues->AddRef();
  2121.         if (HXR_OK == m_pIDInfo->GetPropertyCString("ClientID", pBuffer))
  2122.         {
  2123.             pCloakValues->SetPropertyCString("ClientID", pBuffer);
  2124.         }
  2125.         HX_RELEASE(pBuffer);
  2126.         if (m_pRequest)
  2127.         {
  2128.             if (HXR_OK == m_pRequest->GetURL(pszURL))
  2129.             {
  2130.                 pBuffer = new CHXBuffer();
  2131.                 pBuffer->AddRef();
  2132.                 pBuffer->Set((const UCHAR*)pszURL, strlen(pszURL)+1);
  2133.                 pCloakValues->SetPropertyCString("url", pBuffer);
  2134.                 HX_RELEASE(pBuffer);
  2135.             }
  2136.             if (HXR_OK == m_pRequest->GetRequestHeaders(pRequestHeaders))
  2137.             {
  2138.                 if (HXR_OK == pRequestHeaders->GetPropertyCString("Cookie", pBuffer))
  2139.                 {
  2140.                     pCloakValues->SetPropertyCString("Cookie", pBuffer);
  2141.                 }
  2142.                 HX_RELEASE(pBuffer);
  2143.             }
  2144.             HX_RELEASE(pRequestHeaders);
  2145.         }
  2146.         pClientProtocol->InitCloak(m_pCloakPorts, m_nCloakPorts, pCloakValues);
  2147.         HX_RELEASE(pCloakValues);
  2148.     }
  2149.     if (m_bPrefetch)
  2150.     {
  2151.         pClientProtocol->EnterPrefetch();
  2152.     }
  2153.     //USER_AGENT_STRING defined in hxver.h
  2154.     CHXString buildVersion = USER_AGENT_STRING +
  2155.         CHXString(TARVER_STRING_VERSION) + " (" +
  2156.         CHXString(TARVER_STR_PLATFORM) + ")";
  2157.     m_pProtocolLib->SetBuildVersion((const char*)buildVersion);
  2158.     m_pPendingStatus = m_pProtocolLib->GetPendingStatus();
  2159.     m_pStatistics = m_pProtocolLib->GetStatistics();
  2160.     // start communication with server
  2161.     if(mUseProxy)
  2162.     { 
  2163.         theErr = proxy_hello();
  2164.     }
  2165.     else
  2166.     {
  2167.         theErr = server_hello();
  2168.     }
  2169.     // Start Waiting for control channel..
  2170.     mOwner->StartDataWait(TRUE);
  2171.     return theErr;
  2172. }
  2173. // these get initialized every time we make a new connection with
  2174. // the server
  2175. void
  2176. RTSPProtocol::initialize_members(void)
  2177. {
  2178.     // intialize base class members
  2179.     HXProtocol::initialize_members();
  2180.     m_bPerfectPlayAllowed   = TRUE;
  2181.     // release any allocated local resources
  2182.     HX_RELEASE(m_pPendingStatus);
  2183.     HX_RELEASE(m_pStatistics);
  2184.     HX_RELEASE(m_pIDInfo);
  2185.     if (m_pProtocolLib)
  2186.     {
  2187.         m_pProtocolLib->Done();
  2188.         HX_RELEASE(m_pProtocolLib);
  2189.     }
  2190.     CHXMapLongToObj::Iterator i;
  2191.     for (i = m_pStreamInfoList->Begin(); i != m_pStreamInfoList->End(); ++i)
  2192.     {
  2193.         RTSP_STREAM_INFO* pStreamInfo = (RTSP_STREAM_INFO*)(*i);
  2194.         HX_DELETE(pStreamInfo);
  2195.     }
  2196.     m_pStreamInfoList->RemoveAll();
  2197. }
  2198. HX_RESULT
  2199. RTSPProtocol::seek
  2200. (
  2201.     ULONG32 posArg,
  2202.     ULONG32 posArg2,
  2203.     UINT16 seekFrom
  2204. )
  2205. {
  2206.     if (IsLive())
  2207.     {
  2208.         return m_pProtocolLib->SeekFlush();
  2209.     }
  2210.     HX_RESULT theErr = HXR_OK;
  2211.     m_uCurrentStreamCount = m_uStreamCount;
  2212.     mSourceEnd = FALSE;
  2213.     m_bPendingSeek = TRUE;
  2214.     m_ulSeekPos1 = posArg;
  2215.     m_ulSeekPos2 = posArg2;
  2216.     return theErr;
  2217. }
  2218. HX_RESULT
  2219. RTSPProtocol::resume(UINT32 ulEndTime)
  2220. {
  2221.     if (m_bPendingSeek)
  2222.     {
  2223.         m_bPendingSeek = FALSE;
  2224.         m_bIsFirstResume = FALSE;
  2225.         m_bPaused = FALSE;
  2226.         if (mCurrentTransport == UDPMode)
  2227.         {
  2228.             m_bAreResuming = TRUE;
  2229.             mOwner->StartDataWait();
  2230.         }
  2231.         return m_pProtocolLib->SendPlayRequest(m_ulSeekPos1, (!mLiveStream && ulEndTime > 0) ? ulEndTime : m_ulSeekPos2, 0);
  2232.     }
  2233.     if (m_bIsFirstResume)
  2234.     {
  2235.         m_bIsFirstResume = FALSE;
  2236.         return m_pProtocolLib->SendPlayRequest(0, (!mLiveStream && ulEndTime > 0) ? ulEndTime : RTSP_PLAY_RANGE_BLANK, 0);
  2237.     }
  2238.     else if (mCurrentTransport == UDPMode)
  2239.     {
  2240.         m_bAreResuming = TRUE;
  2241.         mOwner->StartDataWait();
  2242.     }
  2243.     if (!m_bPaused)
  2244.     {
  2245.         return HXR_OK;
  2246.     }
  2247.     m_bPaused = FALSE;
  2248.     return m_pProtocolLib->SendResumeRequest();
  2249. }
  2250. HX_RESULT
  2251. RTSPProtocol::stop(void)
  2252. {
  2253.     if (m_pProtocolLib)
  2254.     {
  2255.         m_pProtocolLib->SendTeardownRequest();
  2256.         m_pProtocolLib->Done();
  2257.         m_pProtocolLib->Release();
  2258.         m_pProtocolLib = 0;
  2259.     }
  2260.     HXProtocol::stop();
  2261. #if defined(HELIX_FEATURE_REVERTER)
  2262.     if (m_pDataRevert)
  2263.     {
  2264.         m_pDataRevert->Done();
  2265.         HX_RELEASE(m_pDataRevert);
  2266.     }
  2267. #endif /* HELIX_FEATURE_REVERTER */
  2268.     CHXMapLongToObj::Iterator i;
  2269.     for (i = m_pStreamInfoList->Begin(); i != m_pStreamInfoList->End(); ++i)
  2270.     {
  2271.         RTSP_STREAM_INFO* pStreamInfo = (RTSP_STREAM_INFO*)(*i);
  2272.         HX_DELETE(pStreamInfo);
  2273.     }
  2274.     m_pStreamInfoList->RemoveAll();
  2275.     m_bReceivedData = FALSE;
  2276.     m_bPlaying = FALSE;
  2277.     m_uStreamCount = 0;
  2278.     return HXR_OK;
  2279. }
  2280. HX_RESULT
  2281. RTSPProtocol::pause(void)
  2282. {
  2283.     if (m_bPaused || m_bIsFirstResume)
  2284.     {
  2285.         return HXR_OK;
  2286.     }
  2287.     m_bPaused = TRUE;
  2288.     return m_pProtocolLib->SendPauseRequest();
  2289. }
  2290. #if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
  2291. void
  2292. RTSPProtocol::send_statistics
  2293. (
  2294.     UINT32      ulStatsMask
  2295. )
  2296. {
  2297.     UINT32  ulStats123 = 0;
  2298.     UINT32  ulStats4 = 0;
  2299.     char*   pszStats123 = NULL;
  2300.     char*   pszStats4 = NULL;
  2301.     char*   pszStats = NULL;
  2302.     prepare_statistics(ulStatsMask, pszStats123);
  2303.     if (pszStats123)
  2304.     {
  2305.         ulStats123 = strlen(pszStats123);
  2306.     }
  2307.     if (ulStatsMask & 8UL)
  2308.     {
  2309.         prepare_stats4(pszStats4, ulStats4);
  2310.     }
  2311.     if (pszStats123 && pszStats4)
  2312.     {
  2313.         pszStats = new char[ulStats123 + ulStats4 + 1];
  2314.         strcpy(pszStats, pszStats123); /* Flawfinder: ignore */
  2315.         strcat(pszStats, pszStats4); /* Flawfinder: ignore */
  2316.         HX_VECTOR_DELETE(pszStats123);
  2317.         HX_VECTOR_DELETE(pszStats4);
  2318.     }
  2319.     else if (pszStats123 && !pszStats4)
  2320.     {
  2321.         pszStats = pszStats123;
  2322.     }
  2323.     else if (!pszStats123 && pszStats4)
  2324.     {
  2325.         pszStats = pszStats4;
  2326.     }
  2327.     if (pszStats)
  2328.     {
  2329.         m_pProtocolLib->SendPlayerStats(pszStats);
  2330.     }
  2331.     HX_VECTOR_DELETE(pszStats);
  2332.     return;
  2333. }
  2334. HX_RESULT
  2335. RTSPProtocol::prepare_stats4(char*& pszStats, UINT32& ulStats)
  2336. {
  2337.     HX_RESULT           rc = HXR_OK;
  2338.     UINT32              i = 0;
  2339.     UINT32              ulAllocatedBufferSize = MAX_DEFAULT_STATS_SIZE;
  2340.     UINT32              ulValue = 0;
  2341.     char                szRegKeyName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
  2342.     char*               pszValue = NULL;
  2343.     char*               pszTempStats = NULL;
  2344.     RTSP_STREAM_INFO*   pStreamInfo = NULL;
  2345.     STREAM_STATS*       pStreamStats = NULL;
  2346.     IHXBuffer*          pParentName = NULL;
  2347.     IHXBuffer*          pValue = NULL;
  2348.     CHXMapLongToObj::Iterator j;
  2349.     pszStats = new char[ulAllocatedBufferSize];
  2350.     ulStats = 0;
  2351.     SafeStrCpy(pszStats, "[Stat4:", MAX_DISPLAY_NAME);
  2352.     ulStats += 7;
  2353.     statistics_cat_ext(pszStats, ulAllocatedBufferSize, m_uStreamCount, " ", ulStats);
  2354.     // per stream stats
  2355.     if (m_pStreamInfoList->GetCount())
  2356.     {
  2357.         for (j = m_pStreamInfoList->Begin(); j != m_pStreamInfoList->End(); ++j)
  2358.         {
  2359.             pStreamInfo = (RTSP_STREAM_INFO*)(*j);
  2360.             pStreamStats = pStreamInfo->m_pStreamStats;
  2361.             if (!pStreamStats || !pStreamStats->m_bInitialized)
  2362.             {
  2363.                 continue;
  2364.             }
  2365.             // mime type
  2366.             if (pStreamStats->m_pMimeType &&
  2367.                 (pszValue = pStreamStats->m_pMimeType->GetStr()))
  2368.             {
  2369.                 ulStats += strlen(pszValue);
  2370.                 if (ulStats > (ulAllocatedBufferSize - MAX_DISPLAY_NAME))
  2371.                 {
  2372.                     ulAllocatedBufferSize += MAX_DEFAULT_STATS_SIZE;
  2373.                     pszTempStats = new char[ulAllocatedBufferSize];
  2374.                     SafeStrCpy(pszTempStats, pszStats, ulAllocatedBufferSize);
  2375.                     HX_VECTOR_DELETE(pszStats);
  2376.                     pszStats = pszTempStats;
  2377.                 }
  2378.                 SafeStrCat(pszStats, pszValue, ulAllocatedBufferSize);
  2379.                 HX_VECTOR_DELETE(pszValue);
  2380.             }
  2381.             else
  2382.             {
  2383.                 SafeStrCat(pszStats, "N/A", ulAllocatedBufferSize);
  2384.                 ulStats += 3;
  2385.             }
  2386.             SafeStrCat(pszStats, "|", ulAllocatedBufferSize);
  2387.             ulStats++;
  2388.             // codec
  2389.             if (HXR_OK == m_pRegistry->GetPropName(pStreamStats->m_pRenderer->m_ulRegistryID, pParentName))
  2390.             {
  2391.                 SafeSprintf(szRegKeyName, MAX_DISPLAY_NAME, "%s.Codec", pParentName->GetBuffer());
  2392.                 if (HXR_OK == m_pRegistry->GetStrByName(szRegKeyName, pValue) && pValue)
  2393.                 {
  2394.                     ulValue = pValue->GetSize();
  2395.                     pszValue = new char[ulValue+1];
  2396.                     strcpy(pszValue, (const char*)pValue->GetBuffer()); /* Flawfinder: ignore */
  2397.                     // replace space with underscore
  2398.                     for (i = 0; i < ulValue; i++)
  2399.                     {
  2400.                         if (pszValue[i] == ' ')
  2401.                         {
  2402.                             pszValue[i] = '_';
  2403.                         }
  2404.                     }
  2405.                 }
  2406.                 HX_RELEASE(pValue);
  2407.             }
  2408.             HX_RELEASE(pParentName);
  2409.             if (pszValue)
  2410.             {
  2411.                 ulStats += strlen(pszValue);
  2412.                 if (ulStats > (ulAllocatedBufferSize - MAX_DISPLAY_NAME))
  2413.                 {
  2414.                     ulAllocatedBufferSize += MAX_DEFAULT_STATS_SIZE;
  2415.                     pszTempStats = new char[ulAllocatedBufferSize];
  2416.                     SafeStrCpy(pszTempStats, pszStats, ulAllocatedBufferSize);
  2417.                     HX_VECTOR_DELETE(pszStats);
  2418.                     pszStats = pszTempStats;
  2419.                 }
  2420.                 SafeStrCat(pszStats, pszValue, ulAllocatedBufferSize);
  2421.                 HX_VECTOR_DELETE(pszValue);
  2422.             }
  2423.             else
  2424.             {
  2425.                 SafeStrCat(pszStats, "N/A", ulAllocatedBufferSize);
  2426.                 ulStats += 3;
  2427.             }
  2428.             SafeStrCat(pszStats, "|", ulAllocatedBufferSize);
  2429.             ulStats++;
  2430.             // bandwidth stats
  2431.             statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pReceived->GetInt(), "|", ulStats);
  2432.             statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pLost->GetInt(), "|", ulStats);
  2433.             statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pReceived->GetInt() - pStreamStats->m_pNormal->GetInt(), "|", ulStats);
  2434.             statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pAvgBandwidth->GetInt(), "|", ulStats);
  2435.             statistics_cat_ext(pszStats, ulAllocatedBufferSize, pStreamStats->m_pCurBandwidth->GetInt(), "|", ulStats);
  2436.             SafeStrCat(pszStats, ";", ulAllocatedBufferSize);
  2437.             ulStats++;
  2438.         }
  2439.     }
  2440.     else
  2441.     {
  2442.         statistics_cat_ext(pszStats, ulAllocatedBufferSize, 0, " ", ulStats);
  2443.     }
  2444.     pszStats[ulStats-1] = ' ';
  2445.     // Transport
  2446.     statistics_cat_ext(pszStats, ulAllocatedBufferSize, mCurrentTransport, " ", ulStats);
  2447.     // TurboPlay
  2448.     statistics_cat_ext(pszStats, ulAllocatedBufferSize, m_bFastStart, "|", ulStats);
  2449.     if (m_bFastStart)
  2450.     {
  2451.         statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->m_turboPlayStats.ulAcceleratedBW, "|", ulStats);
  2452.         statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->m_turboPlayStats.ulBufferedTime, "|", ulStats);
  2453.     }
  2454.     else
  2455.     {
  2456.         statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->m_turboPlayStats.tpOffReason, "|", ulStats);
  2457.         statistics_cat_ext(pszStats, ulAllocatedBufferSize, 0, "|", ulStats);
  2458.     }
  2459.     SafeStrCat(pszStats, " ", ulAllocatedBufferSize);
  2460.     ulStats++;
  2461.     // Startup latency, first data packet arrives!
  2462.     statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->GetFirstDataArriveTime(), " ", ulStats);
  2463.     // Reason of clip end
  2464.     statistics_cat_ext(pszStats, ulAllocatedBufferSize, mOwner->m_srcEndCode, NULL, ulStats);
  2465.     SafeStrCat(pszStats, "]", ulAllocatedBufferSize);
  2466.     ulStats++;
  2467.     return rc;
  2468. }
  2469. STREAM_STATS*
  2470. RTSPProtocol::create_statistics(UINT16 uStreamNumber)
  2471. {
  2472.     HX_RESULT       result = HXR_OK;
  2473.     STREAM_STATS*   pStats = NULL;
  2474.     IHXBuffer*      pParentName = NULL;
  2475.     CHAR            RegKeyName[MAX_DISPLAY_NAME] = {0};
  2476.     if (!m_pRegistry)
  2477.     {
  2478.         goto cleanup;
  2479.     }
  2480.     if (HXR_OK == m_pRegistry->GetPropName(m_ulRegistryID, pParentName) && pParentName)
  2481.     {
  2482.         SafeSprintf(RegKeyName, MAX_DISPLAY_NAME, "%s.Stream%d", pParentName->GetBuffer(), uStreamNumber);
  2483.         /*
  2484.          * This the location where the first STREAM_STATS for the stream
  2485.          * is instantiated. The protocol library may make another to fill
  2486.          * the fields in the registry, but it must use the keys created
  2487.          * here
  2488.          */
  2489.         //ASSERT(!m_pRegistry->GetId(RegKeyName));
  2490.         UINT32 uStreamId = 0;
  2491.         if (!m_pRegistry->GetId(RegKeyName))
  2492.         {
  2493.             uStreamId = m_pRegistry->AddComp(RegKeyName);
  2494.         }
  2495.         else
  2496.         {
  2497.             uStreamId = m_pRegistry->GetId(RegKeyName);
  2498.         }
  2499.         pStats = new STREAM_STATS(m_pRegistry, uStreamId);
  2500.     }
  2501.     HX_RELEASE(pParentName);
  2502. cleanup:
  2503.     return pStats;
  2504. }
  2505. #endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
  2506. BOOL
  2507. RTSPProtocol::IsSourceDone(void)
  2508. {
  2509.     return mSourceEnd;
  2510. }
  2511. HX_RESULT
  2512. RTSPProtocol::GetCurrentBuffering(UINT16  uStreamNumber,
  2513.                                   INT64&  llLowestTimestamp,
  2514.                                   INT64&  llHighestTimestamp,
  2515.                                   UINT32& ulNumBytes,
  2516.                                   BOOL&   bDone)
  2517. {
  2518.     HX_RESULT   theErr  = HXR_OK;
  2519.     llLowestTimestamp   = 0;
  2520.     llHighestTimestamp  = 0;
  2521.     ulNumBytes          = 0;
  2522.     bDone               = FALSE;
  2523.     if (m_pProtocolLib)
  2524.     {
  2525.         theErr = m_pProtocolLib->GetCurrentBuffering(uStreamNumber,
  2526.                                                      llLowestTimestamp,
  2527.                                                      llHighestTimestamp,
  2528.                                                      ulNumBytes,
  2529.                                                      bDone);
  2530.         if (!theErr && ulNumBytes > 0)
  2531.         {
  2532.             m_bReceivedData = TRUE;
  2533.         }
  2534.     }
  2535.     return theErr;
  2536. }