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

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 "sdpmdgen.h"
  36. #include "sdptypes.h"
  37. #include "sdppyldinfo.h"
  38. #include "hxstrutl.h"
  39. #include "hxstring.h"
  40. #include "nptime.h"
  41. #include "netbyte.h"
  42. #include "rtsputil.h"
  43. #include "rtptypes.h"
  44. //#include "hlxclib/stdio.h"
  45. SDPMediaDescGenerator::SDPMediaDescGenerator(ULONG32 ulVersion) :
  46.     m_pContext(0),
  47.     m_pCCF(0),
  48.     m_pRegistry(0),
  49.     m_ulVersion(ulVersion),
  50.     m_bUseOldEOL(FALSE),
  51.     m_bUseSessionGUID(FALSE),
  52.     m_bUseAbsoluteURL(FALSE)
  53. {}
  54. SDPMediaDescGenerator::~SDPMediaDescGenerator()
  55. {
  56.     HX_RELEASE(m_pCCF);
  57.     HX_RELEASE(m_pContext);
  58.     HX_RELEASE(m_pRegistry);
  59. }
  60. HX_RESULT SDPMediaDescGenerator::Init(IUnknown* pContext)
  61. {
  62.     HX_RESULT res = HXR_FAILED;
  63.     HX_RELEASE(m_pContext);
  64.     HX_RELEASE(m_pCCF);
  65.     if (pContext)
  66.     {
  67.         pContext->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry);
  68.         res = pContext->QueryInterface(IID_IHXCommonClassFactory,
  69.                                        (void**)&m_pCCF);
  70.         if (SUCCEEDED(res) && m_pCCF)
  71.         {
  72.             m_pContext = pContext;
  73.             m_pContext->AddRef();
  74.         }
  75.     }
  76.     return res;
  77. }
  78. HX_RESULT SDPMediaDescGenerator::Generate(UINT16 nValues, 
  79.                                           IHXValues** pValueArray,
  80.                                           REF(IHXBuffer*) pDescription)
  81. {
  82.     CHXString mDesc;
  83.     char pszEOL[3]; /* Flawfinder: ignore */
  84.     HX_RESULT rc;
  85.     UINT32 propValue;
  86.     const char* pPropName = 0;
  87.     IHXBuffer* pPropBuffer = 0;
  88.     char psz256[256]; /* Flawfinder: ignore */
  89.     mDesc.SetMinBufSize(12000);
  90.     if (m_bUseOldEOL)
  91.     {
  92.         pszEOL[0] = 'n';
  93.         pszEOL[1] = '';
  94.     }
  95.     else
  96.     {
  97.         pszEOL[0] = 'r';
  98.         pszEOL[1] = 'n';
  99.         pszEOL[2] = '';
  100.     }
  101.     rc = SpecComplianceCheck(nValues, pValueArray);    
  102.     if (HXR_OK != rc)
  103.     {
  104.         return rc;
  105.     }
  106.     // get local host address from registry
  107.     //HX_RESULT hresult;
  108.     IHXRegistry* pRegistry = 0;
  109.     /*  XXX 
  110.      *  Interop:  Our old system is expecting a media type in m= to be either
  111.      *  "audio", "video", or "data" and anything else will be ignored.  
  112.      *  The spec dectates otherwise...It should be whatever the type of mimetype
  113.      *  is.  So, depending on the setting, we will have to change how we create 
  114.      *  m= line for interop and backward comp.
  115.      *
  116.      *  by default, we will do the spec complient way.
  117.      */    
  118.     BOOL bUseOldSdp = FALSE;
  119.     IHXBuffer* pHostIBuf = NULL;
  120.     if(m_pRegistry)
  121.     {
  122.         m_pRegistry->GetStrByName("server.sdpconfig.hostaddr", pHostIBuf);
  123.     }
  124.     const char* pszHost = "";
  125.     if (pHostIBuf)
  126.     {
  127.         pszHost = (const char *)pHostIBuf->GetBuffer();
  128.     }
  129.     UINT32 ulHostAddr = HXinet_addr(pszHost);
  130.     /*
  131.      * default sessionID, else get LastModified from optional values
  132.      */
  133.     char pszVersion[40]; /* Flawfinder: ignore */
  134.     UINT32 ulSessionIDBuffLen = 40;
  135.     IHXBuffer* pSessionGUIDBuff = NULL;
  136.     IHXBuffer* pControlStringBuff = NULL;
  137.     if(m_bUseSessionGUID && pValueArray[1])
  138.     {
  139.         rc = pValueArray[1]->GetPropertyCString("SessionGUID", pSessionGUIDBuff);
  140.         if((rc == HXR_OK) && pSessionGUIDBuff)
  141.         {
  142.             ulSessionIDBuffLen = pSessionGUIDBuff->GetSize();
  143.         }
  144.     }
  145.     NEW_FAST_TEMP_STR(pszSessionID, 256, ulSessionIDBuffLen);
  146.     // munge current time with IP
  147.     NPTime timeNow;
  148.     if (!pSessionGUIDBuff)
  149.     {
  150.         SafeSprintf(pszSessionID,ulSessionIDBuffLen,"%lu", ulHostAddr + timeNow.m_lMicroSecond); 
  151.     }
  152.     SafeSprintf(pszVersion, 40, "%lu", timeNow.m_lMicroSecond); 
  153.     IHXBuffer* pContentBase = NULL;
  154.     IHXBuffer* pQueryParams = NULL;
  155.     if(pValueArray[1])
  156.     {
  157.         ULONG32 ulLastMod;
  158.         rc = pValueArray[1]->GetPropertyULONG32("LastModified", ulLastMod);
  159.         SafeSprintf(pszVersion, 40,"%lu", ulLastMod);
  160.         if (pSessionGUIDBuff)
  161.         {
  162.             SafeSprintf(pszSessionID, ulSessionIDBuffLen, "%s", 
  163.                      pSessionGUIDBuff->GetBuffer());
  164.         }
  165.         else
  166.         {
  167.             SafeSprintf(pszSessionID, ulSessionIDBuffLen,"%lu", ulLastMod);
  168.         }
  169.         if (m_bUseAbsoluteURL)
  170.         {
  171.             rc = pValueArray[1]->GetPropertyCString("AbsoluteBaseURL",
  172.                                                     pContentBase);
  173.             if (HXR_OK != rc)
  174.             {
  175.                 HX_RELEASE(pContentBase);
  176.             }
  177.             
  178.             rc = pValueArray[1]->GetPropertyCString("URLQueryParams",
  179.                                                     pQueryParams);
  180.             if (HXR_OK != rc)
  181.             {
  182.                 HX_RELEASE(pQueryParams);
  183.             }
  184.         }
  185.         rc = pValueArray[1]->GetPropertyCString("Control", pControlStringBuff);
  186.         if(rc != HXR_OK)
  187.         {
  188.             HX_RELEASE(pControlStringBuff);
  189.         }
  190.     }
  191.     NEW_FAST_TEMP_STR(pszTmpString, 256, strlen(pszSessionID) + 
  192.                       strlen(pszVersion) + strlen(pszHost) + 64);
  193.     SafeSprintf(pszTmpString, 256, "v=0%so=- %s %s IN IP4 %s%s",
  194.         pszEOL, pszSessionID, pszVersion, pszHost, pszEOL);
  195.     HX_RELEASE(pHostIBuf);
  196.     HX_RELEASE(pSessionGUIDBuff);
  197.     DELETE_FAST_TEMP_STR(pszSessionID);
  198.     mDesc = pszTmpString;
  199.     DELETE_FAST_TEMP_STR(pszTmpString);
  200.     char* pszTitle = NULL;
  201.     char* pszAuthor = NULL;
  202.     char* pszCopyright = NULL;
  203.     CHXString headerAttributes;
  204.     headerAttributes.SetMinBufSize(8192);
  205.     char* pszSDPData=NULL;
  206.     char* pszInfo=NULL;
  207.     
  208.     char* pszConnAddr=NULL;
  209.     UINT32 avgBitRate = 0;
  210.     BOOL   bFoundAvgBitRate = FALSE;
  211.     UINT32 connTTL = 0;
  212.     BOOL   bFoundTTL = FALSE;
  213.     UINT32 connRange = 0;
  214.     BOOL   bFoundRange = FALSE;
  215.     BOOL   bAddToHeader = 0;
  216.     UINT32 ulDefaultDuration = 0;
  217.     BOOL   bDefaultDurationFound = FALSE;
  218.     BOOL   bIsLive = FALSE;
  219.     
  220.     /*
  221.      * Add session-level a=control field only for clients that can handle
  222.      * interop SDP.
  223.      */
  224.     // Figure out if the client can handle interop SDP
  225.     UINT32 ulSdpFileType = NONE_SDP;
  226.     if (HXR_OK == pValueArray[0]->GetPropertyULONG32("SdpFileType", ulSdpFileType))
  227.     {
  228.         // default for bUseOldSdp is FALSE
  229.         if (BACKWARD_COMP_SDP == ulSdpFileType)
  230.         {
  231.             bUseOldSdp = TRUE;
  232.         }
  233.     }
  234.     if(!bUseOldSdp) 
  235.     {
  236.         if (!pControlStringBuff)
  237.         {
  238.             const char* pszFieldPrefix = "a=control:";
  239.             UINT32 ulBuffLen = 0;
  240.             if (pContentBase)
  241.             {
  242.                 char *pszBaseURL = (char*)pContentBase->GetBuffer();
  243.                 UINT32 ulBaseLen = strlen(pszBaseURL);
  244.                 UINT32 ulBuffLen = strlen(pszFieldPrefix) + ulBaseLen +
  245.                                    ((pQueryParams) ? pQueryParams->GetSize() : 0);
  246.                 char cPathDelim = '';
  247.                 // Strip off the trailing slash from the aggregate control URL
  248.                 char *pszPathDelim = pszBaseURL + (ulBaseLen-1);
  249.                 if (*pszPathDelim == '/')
  250.                 {
  251.                     cPathDelim = *pszPathDelim;
  252.                     *pszPathDelim = '';
  253.                 }
  254.                 ulBuffLen += strlen(pszEOL) + 1;
  255.                 NEW_FAST_TEMP_STR(pszSessionCtrl, 512, ulBuffLen); 
  256.                 SafeSprintf(pszSessionCtrl, ulBuffLen, "%s%s%s%s", 
  257.                          pszFieldPrefix, pszBaseURL,
  258.                          (pQueryParams)?((char*)pQueryParams->GetBuffer()) : "",
  259.                          pszEOL);
  260.                 if (cPathDelim)
  261.                 {
  262.                     *pszPathDelim = cPathDelim;
  263.                 }
  264.                 headerAttributes += pszSessionCtrl;
  265.                 DELETE_FAST_TEMP_STR(pszSessionCtrl);
  266.             }
  267.             else 
  268.             {
  269.                 ulBuffLen = strlen(pszFieldPrefix) + strlen(pszEOL) + 2;
  270.                 NEW_FAST_TEMP_STR(pszSessionCtrl, 512, ulBuffLen); 
  271.                 SafeSprintf(pszSessionCtrl, ulBuffLen, "%s*%s", pszFieldPrefix, pszEOL);
  272.                 headerAttributes += pszSessionCtrl;
  273.                 DELETE_FAST_TEMP_STR(pszSessionCtrl);
  274.             }
  275.         }
  276.         else
  277.         {
  278.             UINT32 ulBuffLen = pControlStringBuff->GetSize();
  279.             ulBuffLen += (pContentBase) ? pContentBase->GetSize() : 0;
  280.             ulBuffLen += (pQueryParams) ? pQueryParams->GetSize() : 0;
  281.             ulBuffLen += 64;
  282.             NEW_FAST_TEMP_STR(pszControlString, 512, ulBuffLen); 
  283.             SafeSprintf(pszControlString, ulBuffLen, "a=control:%s%s%s%s",
  284.                      ((pContentBase) ? ((char*)pContentBase->GetBuffer()) : ""),
  285.                      pControlStringBuff->GetBuffer(),
  286.                      (pQueryParams) ?((char*)pQueryParams->GetBuffer()) : "", 
  287.                      pszEOL);
  288.             headerAttributes += pszControlString;
  289.             DELETE_FAST_TEMP_STR(pszControlString);
  290.         }
  291.     }
  292.     rc = pValueArray[0]->GetFirstPropertyULONG32(pPropName, propValue);
  293.     while(rc == HXR_OK)
  294.     {
  295.         bAddToHeader = FALSE;
  296.         if(strcasecmp(pPropName, "MulticastTTL") == 0)
  297.         {
  298.             connTTL = propValue;
  299.             bFoundTTL = TRUE;
  300.         }
  301.         else if(strcasecmp(pPropName, "MulticastRange") == 0)
  302.         {
  303.             connRange = propValue;
  304.             bFoundRange = TRUE;
  305.         }
  306.         else if(strcasecmp(pPropName, "Duration") == 0)
  307.         {
  308.             // save this off, so we can add an appropriate a=range depending
  309.             // on the value in "SdpFileType"
  310.             ulDefaultDuration = propValue;
  311.             bDefaultDurationFound = TRUE;
  312.         }
  313.         else if(strcasecmp(pPropName, "LiveStream") == 0)
  314.         {
  315.             // is this live?
  316.             bIsLive = propValue;
  317.             bAddToHeader = TRUE;
  318.         }
  319.         else if(strcasecmp(pPropName, "AvgBitRate") == 0)
  320.         {
  321.             avgBitRate = propValue;
  322.             // we need this in kbps
  323.             avgBitRate = (UINT32)((double)avgBitRate / 1000.0 + 0.5);
  324.             bFoundAvgBitRate = TRUE;
  325.             // add it to attribute as well.         
  326.             bAddToHeader = TRUE;    
  327.         }
  328.         else if(strcasecmp(pPropName, "SdpFileType") == 0)
  329.         {
  330.             // don't add it to attribute.
  331.             bAddToHeader = FALSE;    
  332.         }
  333.         else
  334.         {
  335.             bAddToHeader = TRUE;    
  336.         }
  337.         if(bAddToHeader)
  338.         {
  339.             NEW_FAST_TEMP_STR(pszAttBuf, 256, strlen(pPropName) + 64);
  340.             SafeSprintf(pszAttBuf, 256,"a=%s:integer;%d%s", pPropName, propValue,
  341.                                                     pszEOL);
  342.             headerAttributes += pszAttBuf;
  343.             DELETE_FAST_TEMP_STR(pszAttBuf);
  344.         }
  345.         /* make sure to reset SdpFileType header */
  346.         if (strcasecmp(pPropName, "SdpFileType") == 0)
  347.         {
  348.             pValueArray[0]->SetPropertyULONG32(pPropName, NONE_SDP);
  349.         }
  350.         rc = pValueArray[0]->GetNextPropertyULONG32(pPropName,
  351.             propValue);
  352.     }
  353.     /* 
  354.      * 3GPP compliance: session-level "b=" parameter is required.  If we
  355.      * it's not in the file header, then compute it from component streams.
  356.      */
  357.     if (!bFoundAvgBitRate)
  358.     {
  359.         UINT32 ulSessionBitRate = 0;
  360.         UINT32 ulStreamBitRate = 0;
  361.         
  362.         for(UINT16 i=2 ; i < nValues; ++i)
  363.         {
  364.             if (pValueArray[i])
  365.             {
  366.                 if (HXR_OK == pValueArray[i]->GetPropertyULONG32("AvgBitRate",
  367.                                                                ulStreamBitRate))
  368.                 {   
  369.                     bFoundAvgBitRate = TRUE;
  370.                     ulSessionBitRate += ulStreamBitRate;
  371.                 }
  372.             }
  373.         }
  374.         if (bFoundAvgBitRate) 
  375.         { 
  376.             // Convert bits/sec -> Kbits/sec (round up to nearest whole num)
  377.                 avgBitRate = (UINT32) ((double)ulSessionBitRate / 1000.0 + 0.5);
  378.         }
  379.     }
  380.     rc = pValueArray[0]->GetFirstPropertyBuffer(pPropName, pPropBuffer);
  381.     while(rc == HXR_OK)
  382.     {
  383.         INT32 dataSize = pPropBuffer->GetSize();
  384.         char* pString = (char*) pPropBuffer->GetBuffer();
  385.         bAddToHeader = TRUE;         // add it to attribute by default
  386.         if (dataSize > 0 && pString != NULL && *pString != '')
  387.         {
  388.             if(strcasecmp(pPropName, "Title") == 0)
  389.             {
  390.                 pszTitle = new char [ dataSize + 1 ];
  391.                 memcpy(pszTitle, (const char*)pPropBuffer->GetBuffer(), dataSize); /* Flawfinder: ignore */
  392.                 pszTitle[dataSize] = '';
  393.             }
  394.             else if(strcasecmp(pPropName, "Author") == 0)
  395.             {
  396.                 pszAuthor = new char [ dataSize + 1 ];
  397.                 memcpy(pszAuthor, (const char*)pPropBuffer->GetBuffer(), dataSize); /* Flawfinder: ignore */
  398.                 pszAuthor[dataSize] = '';
  399.             }
  400.             else if(strcasecmp(pPropName, "Copyright") == 0)
  401.             {
  402.                 pszCopyright = new char [ dataSize + 1 ];
  403.                 memcpy(pszCopyright, (const char*)pPropBuffer->GetBuffer(), dataSize); /* Flawfinder: ignore */
  404.                 pszCopyright[dataSize] = '';
  405.             }
  406.             if (bAddToHeader)
  407.             {
  408.                 NEW_FAST_TEMP_STR(pszAttBuf, 4096, dataSize * 2 + strlen(pPropName)
  409.                                                    + 64);
  410.                 NEW_FAST_TEMP_STR(pszPropString, 4096, dataSize * 2 + 64);
  411.                 (void)BinTo64((const BYTE*)pPropBuffer->GetBuffer(),
  412.                     dataSize, pszPropString);
  413.                 SafeSprintf(pszAttBuf, 4096, "a=%s:buffer;"%s"%s",pPropName, 
  414.                                                           pszPropString, pszEOL);
  415.                 headerAttributes += pszAttBuf;
  416.                 DELETE_FAST_TEMP_STR(pszPropString);
  417.                 DELETE_FAST_TEMP_STR(pszAttBuf);
  418.             }
  419.         }
  420.         HX_RELEASE(pPropBuffer);
  421.         rc = pValueArray[0]->GetNextPropertyBuffer(pPropName,
  422.             pPropBuffer);
  423.     }
  424.     rc = pValueArray[0]->GetFirstPropertyCString(pPropName,
  425.         pPropBuffer);
  426.     while(rc == HXR_OK)
  427.     {
  428.         char* pString = (char*) pPropBuffer->GetBuffer();
  429.         char* pszData=NULL;
  430.         BOOL bDeleteString=FALSE;
  431.         bAddToHeader = FALSE;
  432.         INT32 dataSize = pPropBuffer->GetSize();
  433.         if (dataSize > 0 && pString != NULL && *pString != '')
  434.         {
  435.             if(strcasecmp(pPropName, "Title") == 0)
  436.             {
  437.                 pszTitle = EscapeBuffer(pString, pPropBuffer->GetSize());
  438.                 pszData = pszTitle;
  439.                 bAddToHeader = TRUE;    
  440.             }
  441.             else if(strcasecmp(pPropName, "Author") == 0)
  442.             {
  443.                 pszAuthor = EscapeBuffer(pString, pPropBuffer->GetSize());
  444.                 pszData = pszAuthor;
  445.                 bAddToHeader = TRUE;    
  446.             }
  447.             else if(strcasecmp(pPropName, "Copyright") == 0)
  448.             {
  449.                 pszCopyright = EscapeBuffer(pString, pPropBuffer->GetSize());
  450.                 pszData = pszCopyright;
  451.                 bAddToHeader = TRUE;    
  452.             }
  453.             else if(strcasecmp(pPropName, "MulticastAddress") == 0)
  454.             {
  455.                 pszConnAddr = EscapeBuffer(pString, pPropBuffer->GetSize());
  456.             }
  457.             else if(strcasecmp(pPropName, "SDPData") == 0)
  458.             {
  459.                 pszSDPData = new char [ dataSize + 1 ];
  460.                 memcpy(pszSDPData, (const char*)pPropBuffer->GetBuffer(), dataSize); /* Flawfinder: ignore */
  461.                 pszSDPData[dataSize] = '';
  462. RemoveASLine(pszSDPData, dataSize);
  463.             }   
  464.             else if(strcasecmp(pPropName, "Information") == 0)
  465.             {
  466.                 // "i="
  467.                 pszInfo = EscapeBuffer(pString, pPropBuffer->GetSize());
  468.             }
  469.             else
  470.             {
  471.                 pszData = EscapeBuffer(pString, pPropBuffer->GetSize());
  472.                 bAddToHeader = TRUE;
  473.                 bDeleteString = TRUE;
  474.             }
  475.             if(bAddToHeader)
  476.             {
  477.                 HX_ASSERT(pszData);
  478.                 NEW_FAST_TEMP_STR(pszAttBuf, 4096, dataSize +
  479.                                                    strlen(pPropName) + 64);
  480.                 SafeSprintf(pszAttBuf, 4096,"a=%s:string;"%s"%s", pPropName, 
  481.                                                           pszData, pszEOL);
  482.                 headerAttributes += pszAttBuf;
  483.                 DELETE_FAST_TEMP_STR(pszAttBuf);
  484.             }
  485.             if (bDeleteString)
  486.             {
  487.                 HX_VECTOR_DELETE(pszData);
  488.             }
  489.         }
  490.         
  491.         HX_RELEASE(pPropBuffer);
  492.         rc = pValueArray[0]->GetNextPropertyCString(pPropName,
  493.                                                     pPropBuffer);
  494.     }
  495.     /*
  496.      *  Things in headerAttributes that depend on the value in "SdpFileType"
  497.      */
  498.     if (!bIsLive)
  499.     {
  500.         if (bDefaultDurationFound)
  501.         {
  502.                 NPTime npTime(ulDefaultDuration);
  503.             const char* pszTime = (const char*)npTime;
  504.             headerAttributes += "a=range:npt=0-";
  505.             headerAttributes += pszTime;
  506.             headerAttributes += pszEOL;
  507.         }               
  508.         else
  509.         {
  510.             /*
  511.              * error case - SpecComplianceCheck() should be taking care of it.
  512.              *
  513.              * let's just treat it as live.  When file is done, RTCP_BYE
  514.              * will be sent, and client TEARDOWN
  515.              */
  516.                 if (bUseOldSdp)
  517.                 {
  518.                     SafeSprintf(psz256, 256, "a=range:npt=0-0%s", pszEOL); 
  519.                         headerAttributes += psz256;             
  520.                 }
  521.                 else
  522.                 {
  523.                     SafeSprintf(psz256, 256,"a=range:npt=0-%s", pszEOL); 
  524.                         headerAttributes += psz256;             
  525.                 }
  526.         }
  527.     }   
  528.      
  529.     if (!pszTitle)
  530.     {
  531.        SafeSprintf(psz256, 256,"s=<No title>%s", pszEOL); 
  532.        mDesc += psz256;
  533.     }
  534.     else
  535.     {
  536.         NEW_FAST_TEMP_STR(pszTmpStr, 256, strlen(pszTitle) + 64);
  537.         SafeSprintf(pszTmpStr, 256, "s=%s%s", pszTitle, pszEOL); 
  538.         mDesc += pszTmpStr;
  539.         DELETE_FAST_TEMP_STR(pszTmpStr);
  540.     }
  541.     if (pszInfo)
  542.     {
  543.         NEW_FAST_TEMP_STR(pszTmpStr, 256, strlen(pszInfo) + 64);
  544.         SafeSprintf(pszTmpStr, 256,"i=%s%s", pszInfo, pszEOL); 
  545.         mDesc += pszTmpStr;
  546.         DELETE_FAST_TEMP_STR(pszTmpStr);
  547.         HX_VECTOR_DELETE(pszInfo);
  548.         pszInfo = NULL;
  549.     }
  550.     else
  551.     {
  552.         const char* pszDefaultAuthor = "<No author>";
  553.         const char* pszDefaultCopyright = "<No copyright>";
  554.         UINT32 len = 64;
  555.         len += pszAuthor ? strlen(pszAuthor) : 16;
  556.         len += pszCopyright ? strlen(pszCopyright) : 16;
  557.         NEW_FAST_TEMP_STR(pszTmpString, 512, len);
  558.         SafeSprintf(pszTmpString, 256, "i=%s %s%s",
  559.             pszAuthor ? pszAuthor : pszDefaultAuthor, 
  560.             pszCopyright ? pszCopyright : pszDefaultCopyright,
  561.             pszEOL);
  562.         mDesc += pszTmpString;
  563.         DELETE_FAST_TEMP_STR(pszTmpString);
  564.     }
  565.     if (pszTitle)
  566.         HX_VECTOR_DELETE(pszTitle);
  567.     if (pszAuthor)
  568.         HX_VECTOR_DELETE(pszAuthor);
  569.     if (pszCopyright)
  570.         HX_VECTOR_DELETE(pszCopyright);
  571.     /* Format the connection line only if MulticastAddress and MulticastTTL
  572.      * exist in the file header
  573.      */
  574.     if (pszConnAddr && strlen(pszConnAddr) && bFoundTTL)
  575.     {
  576.         NEW_FAST_TEMP_STR(pszTmpString, 256, strlen(pszConnAddr) + 64);
  577.         if (bFoundRange)
  578.         {
  579.             SafeSprintf(pszTmpString,256, "c=IN IP4 %s/%d/%d%s", 
  580.                 pszConnAddr, connTTL, connRange, pszEOL);
  581.         }
  582.         else
  583.         {
  584.             SafeSprintf(pszTmpString, 256, "c=IN IP4 %s/%d%s",
  585.                 pszConnAddr, connTTL, pszEOL);
  586.         }
  587.         mDesc += pszTmpString;
  588.         DELETE_FAST_TEMP_STR(pszTmpString);
  589.     }
  590.     else if (!bUseOldSdp)
  591.     {   
  592.         // we still need a c= line with a NULL value (RFC 2326 C.1.7)
  593.         // XXXGo
  594.         // Since adding this line w/o TTL (i.e. 0.0.0.0/ttl) will cause 
  595.         // older sdpplin to skip the next line (due to a wrong parsing), 
  596.         // add this only when we are using new sdp type.
  597.         mDesc += "c=IN IP4 0.0.0.0";
  598.         mDesc += pszEOL;
  599.     }    
  600.     if (bFoundAvgBitRate)
  601.     {
  602.         SafeSprintf(psz256, 256, "b=AS:%u%s", avgBitRate, pszEOL); 
  603.         mDesc += psz256;
  604.         bFoundAvgBitRate = FALSE;
  605.     }
  606.     mDesc += "t=0 0";
  607.     mDesc += pszEOL;
  608.     /* add sdpplin version */
  609.     SafeSprintf(psz256, 256, "a=SdpplinVersion:%u%s", m_ulVersion, pszEOL); 
  610.     mDesc += psz256;
  611.     
  612.     mDesc += headerAttributes;
  613.     // expand SDPData if it's there...
  614.     if (pszSDPData)
  615.     {
  616.         mDesc += pszSDPData;
  617.         HX_VECTOR_DELETE(pszSDPData);
  618.         pszSDPData = NULL;
  619.     }
  620.     for(UINT16 i=2;i<nValues;++i)
  621.     {
  622.         if(pValueArray[i])
  623.         {
  624.             CHXString streamAttributes;
  625.             streamAttributes.SetMinBufSize(8192);
  626.             UINT32 streamNumber = 0;
  627.             BOOL   bStreamNumberFound=FALSE;
  628.             UINT32 duration = 0;
  629.             BOOL   bDurationFound = FALSE;
  630.             UINT32 rtpPayloadType = 0;
  631.             BOOL   bRtpPayloadTypeFound=FALSE;
  632.             UINT32 samplesPerSecond = 0;
  633.             BOOL   bSamplesPerSecondFound=FALSE;
  634.             UINT32 nChannels = 0;
  635.             BOOL   bChannelsFound=FALSE;
  636.             UINT32 port = 0;
  637.             UINT32 ulPayloadType = 0;
  638.             BOOL   bFoundRTCPRR = FALSE;
  639.             UINT32 ulRTCPRR = 0;
  640.             BOOL   bFoundRTCPSR = FALSE;
  641.             UINT32 ulRTCPSR = 0;
  642.             BOOL   bFoundPreDecBufSize = FALSE;
  643.             UINT32 ulPreDecBufSize = 0;
  644.             BOOL   bFoundPreDecBufPeriod = FALSE;
  645.             UINT32 ulPreDecBufPeriod = 0;
  646.             BOOL   bFoundPostDecBufPeriod = FALSE;
  647.             UINT32 ulPostDecBufPeriod = 0;
  648.             BOOL   bFoundDecByteRate = FALSE;
  649.             UINT32 ulDecByteRate = 0;
  650.             char* pszMimeType=NULL;
  651.             char* pszMimeFirst=NULL;
  652.             UINT32 ulMimeFirstBufLen = 0;
  653.             char* pszMimeLast=NULL;
  654.             
  655.             UINT32 ptime=0;
  656.             BOOL bPtimeFound=FALSE;
  657.             char* pszFmtp=NULL;
  658.             // Reuse connection strings from file header
  659.             if (pszConnAddr)
  660.             {
  661.                 HX_VECTOR_DELETE(pszConnAddr);
  662.                 pszConnAddr = NULL;
  663.             }
  664.             bFoundTTL = FALSE;
  665.             bFoundRange = FALSE;
  666.             port = 0;
  667.             
  668.             rc = pValueArray[i]->GetFirstPropertyULONG32(pPropName, propValue);
  669.             while(rc == HXR_OK)
  670.             {
  671.                 bAddToHeader = FALSE;
  672.                 if(strcasecmp(pPropName, "StreamNumber") == 0)
  673.                 {
  674.                     streamNumber = propValue;
  675.                     bStreamNumberFound = TRUE;
  676.                 }
  677.                 else if(strcasecmp(pPropName, "Duration") == 0)
  678.                 {
  679.                     // don't use if 0 ( XXXJC we used to assert if the 
  680.                     // prop was not present).
  681.                     if (0 != propValue)
  682.                     {
  683.                         duration = propValue;
  684.                         bDurationFound = TRUE;
  685.                     }
  686.                 }
  687.                 else if(strcasecmp(pPropName, "RTPPayloadType") == 0)
  688.                 {
  689.                     rtpPayloadType = propValue;
  690.                     bRtpPayloadTypeFound = TRUE;
  691.                 }
  692.                 else if(strcasecmp(pPropName, "SamplesPerSecond") == 0)
  693.                 {
  694.                     samplesPerSecond = propValue;
  695.                     bSamplesPerSecondFound = TRUE;
  696.                 }
  697.                 else if(strcasecmp(pPropName, "Channels") == 0)
  698.                 {
  699.                     nChannels = propValue;
  700.                     bChannelsFound = TRUE;
  701.                 }
  702.                 else if(strcasecmp(pPropName, "MulticastTTL") == 0)
  703.                 {
  704.                     connTTL = propValue;
  705.                     bFoundTTL = TRUE;
  706.                 }
  707.                 else if(strcasecmp(pPropName, "MulticastRange") == 0)
  708.                 {
  709.                     connRange = propValue;
  710.                     bFoundRange = TRUE;
  711.                 }
  712.                 else if(strcasecmp(pPropName, "Port") == 0)
  713.                 {
  714.                     port = propValue;
  715.                 }
  716.                 else if(strcasecmp(pPropName, "ptime") == 0)
  717.                 {
  718.                     ptime = propValue;
  719.                     bPtimeFound = TRUE;
  720.                 }   
  721.                 else if(strcasecmp(pPropName, "AvgBitRate") == 0)
  722.                 {
  723.                     avgBitRate = propValue;
  724.                     
  725.                     // we need this in kbps
  726.                     avgBitRate = (UINT32)((double)avgBitRate / 1000.0 + 0.5);
  727.                     bFoundAvgBitRate = TRUE;
  728.                     // add it to attribute as well.         
  729.                     bAddToHeader = TRUE;    
  730.                 }
  731.                 else if(strcasecmp(pPropName, "RtcpRRRate") == 0)
  732.                 {
  733.                     bFoundRTCPRR = TRUE;
  734.                     ulRTCPRR = propValue;
  735.                 }
  736.                 else if(strcasecmp(pPropName, "RtcpRSRate") == 0)
  737.                 {
  738.                     bFoundRTCPSR = TRUE;
  739.                     ulRTCPSR = propValue;
  740.                 }
  741.                 else if(strcasecmp(pPropName, "PreDecBufSize") == 0)
  742.                 {
  743.                     bFoundPreDecBufSize = TRUE;
  744.                     ulPreDecBufSize = propValue;
  745.                 }
  746.                 else if(strcasecmp(pPropName, "InitPreDecBufPeriod") == 0)
  747.                 {
  748.                     bFoundPreDecBufPeriod = TRUE;
  749.                     ulPreDecBufPeriod = propValue;
  750.                 }
  751.                 else if(strcasecmp(pPropName, "InitPostDecBufPeriod") == 0)
  752.                 {
  753.                     bFoundPostDecBufPeriod = TRUE;
  754.                     ulPostDecBufPeriod = propValue;
  755.                 }
  756.                 else if(strcasecmp(pPropName, "DecByteRate") == 0)
  757.                 {
  758.                     bFoundDecByteRate = TRUE;
  759.                     ulDecByteRate = propValue;
  760.                 }
  761.                 else
  762.                 {
  763.                     bAddToHeader = TRUE;                    
  764.                 }
  765.         
  766.                 if (bAddToHeader)
  767.                 {
  768.                     NEW_FAST_TEMP_STR(pszAttBuf, 4096, strlen(pPropName) + 64);
  769.                     SafeSprintf(pszAttBuf, 4096, "a=%s:integer;%d%s", pPropName, 
  770.                                                             propValue, pszEOL);
  771.                     streamAttributes += pszAttBuf;
  772.                     DELETE_FAST_TEMP_STR(pszAttBuf);
  773.                 }
  774.                 
  775.                 /* make sure to reset SdpFileType header */
  776.                 if (strncasecmp(pPropName, "SdpFileType", 11) == 0)
  777.                 {
  778.                     pValueArray[i]->SetPropertyULONG32(pPropName, NONE_SDP);
  779.                 }
  780.                 rc = pValueArray[i]->GetNextPropertyULONG32(pPropName,
  781.                     propValue);
  782.             }
  783.             rc = pValueArray[i]->GetFirstPropertyBuffer(pPropName, pPropBuffer);
  784.             while(rc == HXR_OK)
  785.             {
  786.                 INT32 dataSize = pPropBuffer->GetSize();
  787.                 NEW_FAST_TEMP_STR(pszAttBuf, 4096, dataSize * 2 +
  788.                                                    strlen(pPropName) + 64);
  789.                 NEW_FAST_TEMP_STR(pszPropString, 4096, dataSize * 2 + 64);
  790.                 (void)BinTo64((const BYTE*)pPropBuffer->GetBuffer(),
  791.                     dataSize, pszPropString);
  792.                 SafeSprintf(pszAttBuf, 4096, "a=%s:buffer;"%s"%s", pPropName, 
  793.                                                       pszPropString, pszEOL);
  794.                 streamAttributes += pszAttBuf;
  795.                 DELETE_FAST_TEMP_STR(pszPropString);
  796.                 DELETE_FAST_TEMP_STR(pszAttBuf);
  797.                 HX_RELEASE(pPropBuffer);
  798.                 rc = pValueArray[i]->GetNextPropertyBuffer(pPropName,
  799.                     pPropBuffer);
  800.             }
  801.             rc = pValueArray[i]->GetFirstPropertyCString(pPropName,
  802.                 pPropBuffer);
  803.             while(rc == HXR_OK)
  804.             {
  805.                 char* pString = (char*) pPropBuffer->GetBuffer();
  806.                 char* pszData=NULL;
  807.                 BOOL bDeleteString = FALSE;
  808.                 int len = pPropBuffer->GetSize();
  809.                 bAddToHeader = FALSE;
  810.                 if(strcasecmp(pPropName, "MimeType") == 0)
  811.                 {
  812.                     pszMimeType = EscapeBuffer(pString, pPropBuffer->GetSize());
  813.                     pszMimeLast = strchr(pszMimeType, '/');
  814.                     if(pszMimeLast)
  815.                     {
  816.                         int MFLen = pszMimeLast-pszMimeType;
  817.                         pszMimeLast++;
  818.                         pszMimeFirst = new char [ MFLen+1 ];
  819.                         ulMimeFirstBufLen = MFLen + 1;
  820.                         memcpy(pszMimeFirst, pszMimeType, MFLen); /* Flawfinder: ignore */
  821.                         pszMimeFirst[MFLen] = '';
  822.                     }
  823.                     else
  824.                     {
  825.                         // mimetype is not in the right format...
  826.                     }
  827.                 }
  828.                 else if(strcasecmp(pPropName, "MulticastAddress") == 0)
  829.                 {
  830.                     pszConnAddr = EscapeBuffer(pString, pPropBuffer->GetSize());
  831.                 }
  832.                 else if(strcasecmp(pPropName, "Control") == 0)
  833.                 {
  834.                     if (pControlStringBuff)
  835.                     {
  836.                         HX_RELEASE(pControlStringBuff);
  837.                         pControlStringBuff = pPropBuffer;
  838.                         pControlStringBuff->AddRef(); 
  839.                     }
  840.                 }
  841.                 else if(strcasecmp(pPropName, "PayloadParameters") == 0)
  842.                 {
  843.                     pszFmtp = EscapeBuffer(pString, pPropBuffer->GetSize());
  844.                 }               
  845.                 else if(strcasecmp(pPropName, "SDPData") == 0)
  846.                 {
  847.                     pszSDPData = new char [ len + 1 ];
  848.                     memcpy(pszSDPData, (const char*)pPropBuffer->GetBuffer(), len); /* Flawfinder: ignore */
  849.                     pszSDPData[len] = '';
  850.     RemoveASLine(pszSDPData, len);
  851.                 }
  852.                 else if(strcasecmp(pPropName, "Information") == 0)
  853.                 {
  854.                     // "i="
  855.                     HX_ASSERT(!pszInfo);
  856.                     pszInfo = EscapeBuffer(pString, pPropBuffer->GetSize());
  857.                 }
  858.                 else
  859.                 {
  860.                     pszData = EscapeBuffer(pString, pPropBuffer->GetSize());
  861.                     bDeleteString = TRUE;
  862.                     bAddToHeader = TRUE;                
  863.                 }
  864.                 
  865.                 if(bAddToHeader)
  866.                 {
  867.                     NEW_FAST_TEMP_STR(pszAttBuf, 4096, strlen(pszData) +
  868.                                                        strlen(pPropName) + 64);
  869.                     SafeSprintf(pszAttBuf, 4096,"a=%s:string;"%s"%s", pPropName, 
  870.                                                               pszData, pszEOL);
  871.                     streamAttributes += pszAttBuf;
  872.                     DELETE_FAST_TEMP_STR(pszAttBuf);
  873.                 }
  874.                 if (bDeleteString)
  875.                 {
  876.                     HX_VECTOR_DELETE(pszData);
  877.                 }
  878.                 HX_RELEASE(pPropBuffer);
  879.                 rc = pValueArray[i]->GetNextPropertyCString(pPropName,
  880.                                                             pPropBuffer);
  881.             }
  882.             if(!bRtpPayloadTypeFound)
  883.             {
  884.                 ulPayloadType = RTP_PAYLOAD_RTSP;
  885.             }
  886.             else
  887.             {
  888.                 ulPayloadType = rtpPayloadType;
  889.             }
  890.             if (bUseOldSdp)
  891.             {   
  892.                 // our old sdpplin expects m= to have either "audio", 
  893.                 // "video", or "data", and anything else would be BAD!
  894.                 if (strcmp(pszMimeFirst, "audio") && strcmp(pszMimeFirst, "video"))
  895.                 {
  896.                     SafeStrCpy(pszMimeFirst, "data", ulMimeFirstBufLen);
  897.                 }
  898.             }
  899.             else if (!pszMimeFirst)
  900.             {
  901.                 pszMimeFirst = new char [ 5 ];
  902.                 strcpy(pszMimeFirst, "data"); /* Flawfinder: ignore */
  903.             }
  904.             // m=
  905.             NEW_FAST_TEMP_STR(pszTmpString, 256, strlen(pszMimeFirst) + 128);
  906.             SafeSprintf(pszTmpString, 256, "m=%s %d RTP/AVP %d%s", 
  907.                 pszMimeFirst, port, ulPayloadType, pszEOL);
  908.             mDesc += pszTmpString;
  909.             DELETE_FAST_TEMP_STR(pszTmpString);
  910.             // i= 
  911.             if (pszInfo)
  912.             {
  913.                 NEW_FAST_TEMP_STR(pszTmpStr, 256, strlen(pszInfo) + 64);
  914.                 SafeSprintf(pszTmpStr, 256,"i=%s%s", pszInfo, pszEOL);
  915.                 mDesc += pszTmpStr;
  916.                 DELETE_FAST_TEMP_STR(pszTmpStr);
  917.                 HX_VECTOR_DELETE(pszInfo);
  918.                 pszInfo = NULL;
  919.             }
  920.             /* Format the connection line only if MulticastAddress and 
  921.              * MulticastTTL exist in the stream header
  922.              */
  923.             if (pszConnAddr && strlen(pszConnAddr) && bFoundTTL)
  924.             {
  925.                 NEW_FAST_TEMP_STR(pszTmpString, 256, strlen(pszConnAddr) + 128);
  926.                 if (bFoundRange)
  927.                 {
  928.                     SafeSprintf(pszTmpString, 256,"c=IN IP4 %s/%d/%d%s", 
  929.                         pszConnAddr, connTTL, connRange, pszEOL);
  930.                 }
  931.                 else
  932.                 {
  933.                     SafeSprintf(pszTmpString, 256,"c=IN IP4 %s/%d%s", 
  934.                         pszConnAddr, connTTL, pszEOL);
  935.                 }
  936.                 mDesc += pszTmpString;
  937.                 DELETE_FAST_TEMP_STR(pszTmpString);
  938.             }
  939.             // b=
  940.             if (bFoundAvgBitRate)
  941.             {
  942.                 SafeSprintf(psz256, 256,"b=AS:%u%s", avgBitRate, pszEOL); 
  943.                 mDesc += psz256;
  944.                 bFoundAvgBitRate = FALSE;
  945.             }
  946.             if (bFoundRTCPRR)
  947.             {
  948.                 SafeSprintf(psz256, 256,"b=RR:%u%s", ulRTCPRR, pszEOL); 
  949.                 mDesc += psz256;
  950.                 bFoundRTCPRR = FALSE;
  951.             }
  952.             
  953.             if (bFoundRTCPSR)
  954.             {
  955.                 SafeSprintf(psz256, 256,"b=RS:%u%s", ulRTCPSR, pszEOL); 
  956.                 mDesc += psz256;
  957.                 bFoundRTCPSR = FALSE;
  958.             }
  959.                     
  960.             // a=control
  961.             if (pControlStringBuff)
  962.             {
  963.                 char* pString = (char*) pControlStringBuff->GetBuffer();
  964.                 char* pszData=NULL;
  965.                 pszData = EscapeBuffer(pString, pControlStringBuff->GetSize());
  966.                 if (pContentBase || pQueryParams)
  967.                 {
  968.                     UINT32 ulBuffLen = strlen(pszData);
  969.                     ulBuffLen += (pContentBase) ? pContentBase->GetSize() : 0;
  970.                     ulBuffLen += (pQueryParams) ? pQueryParams->GetSize() : 0;
  971.                     ulBuffLen +=64;
  972.                     NEW_FAST_TEMP_STR(pszControlString, 512, ulBuffLen); 
  973.                     SafeSprintf(pszControlString, 512, "a=control:%s%s%s%s",
  974.                     (pContentBase)? ((char*)pContentBase->GetBuffer()) : "",
  975.                     pControlStringBuff->GetBuffer(),
  976.                     (pQueryParams)?((char*)pQueryParams->GetBuffer()) : "",
  977.                     pszEOL);
  978.                     
  979.                     mDesc += pszControlString;
  980.                     DELETE_FAST_TEMP_STR(pszControlString);
  981.                 }
  982.                 else 
  983.                 {
  984.                     UINT32 ulBuffLen = strlen(pszData) + 64;
  985.                     NEW_FAST_TEMP_STR(pszControlString, 512, ulBuffLen); 
  986.                     SafeSprintf(pszControlString,512,"a=control:%s%s", pszData,
  987.                             pszEOL);
  988.                 
  989.                     mDesc += pszControlString;
  990.                     DELETE_FAST_TEMP_STR(pszControlString);
  991.                 }
  992.                 HX_VECTOR_DELETE(pszData);
  993.             }
  994.             else if (bStreamNumberFound)
  995.             {
  996.                 if (pContentBase || pQueryParams)
  997.                 {
  998.                     const char* pszFieldPrefix = "a=control:";
  999.                     const char* pszStreamLabel = "streamid=";
  1000.                     UINT32 ulBuffLen = strlen(pszFieldPrefix) + 
  1001.                                        strlen(pszStreamLabel);
  1002.                     ulBuffLen += (pContentBase) ? (pContentBase->GetSize()) : 0;
  1003.                     ulBuffLen += (pQueryParams) ? (pQueryParams->GetSize()) : 0;
  1004.                     ulBuffLen += 1;
  1005.                     NEW_FAST_TEMP_STR(pszControlField, 256, ulBuffLen);
  1006.                     SafeSprintf(pszControlField, 256,"%s%s%s%d%s%s", 
  1007.                             pszFieldPrefix, 
  1008.                             (pContentBase)? ((char*)pContentBase->GetBuffer()) : "",
  1009.                             pszStreamLabel, streamNumber, 
  1010.                             (pQueryParams)? ((char*)pQueryParams->GetBuffer()) : "",
  1011.                             pszEOL);
  1012.                     mDesc += pszControlField;
  1013.                     DELETE_FAST_TEMP_STR(pszControlField);
  1014.                 }
  1015.                 else
  1016.                 {
  1017.                     SafeSprintf(psz256, 256,"a=control:streamid=%d%s", streamNumber, pszEOL); 
  1018.                     mDesc += psz256;
  1019.                 }
  1020.             }
  1021.             // a=length && a=range
  1022.             if (bDurationFound)
  1023.             {
  1024.                 NPTime npTime(duration);
  1025.                 if (!bIsLive)
  1026.                 {
  1027.                     SafeSprintf(psz256,256, "a=range:npt=0-%s%s", (const char*)npTime, pszEOL);
  1028.                     mDesc += psz256;
  1029.                 }
  1030.                 
  1031.                 SafeSprintf(psz256, 256, "a=length:npt=%s%s", (const char*)npTime, pszEOL);
  1032.                 mDesc += psz256;
  1033.             }
  1034.             else if (bDefaultDurationFound)
  1035.             {
  1036.                 // take it from file header
  1037.                 NPTime npTime(ulDefaultDuration);
  1038.                 if (!bIsLive)
  1039.                 {
  1040.                     SafeSprintf(psz256, 256,"a=range:npt=0-%s%s", (const char*)npTime, pszEOL);
  1041.                     mDesc += psz256;
  1042.                 }                   
  1043.                 SafeSprintf(psz256,256, "a=length:npt=%s%s", (const char*)npTime,pszEOL);
  1044.                 mDesc += psz256;
  1045.             }
  1046.             else
  1047.             {
  1048.                 // if we put ntp=0-, old sdpplin is gonna freak out.
  1049.                 if (bUseOldSdp)
  1050.                 {
  1051.                     if (!bIsLive)
  1052.                     {
  1053.                         SafeSprintf(psz256, 256,"a=range:npt=0-0%s", pszEOL); 
  1054.                         mDesc += psz256;            
  1055.                     }
  1056.                     SafeSprintf(psz256, 256,"a=length:npt=0%s", pszEOL); 
  1057.                     mDesc += psz256;        
  1058.                 }
  1059.                 else
  1060.                 {
  1061.                     if (!bIsLive)
  1062.                     {
  1063.                         SafeSprintf(psz256, 256,"a=range:npt=0-%s", pszEOL); 
  1064.                         mDesc += psz256;            
  1065.                     }                   
  1066.                     SafeSprintf(psz256, 256,"a=length:npt=0%s", pszEOL);
  1067.                     mDesc += psz256;        
  1068.                 }
  1069.             }
  1070.             
  1071.             // a=rtpmap:
  1072.             if (!pszMimeLast)
  1073.             {
  1074.                 goto bail;
  1075.             }
  1076.             
  1077.             SafeSprintf(psz256, 256, "a=rtpmap:%d %s", ulPayloadType, pszMimeLast);
  1078.             mDesc += psz256;
  1079.             if (SDPIsStaticPayload(ulPayloadType))
  1080.             {
  1081.                 if (!bSamplesPerSecondFound)
  1082.                 {
  1083.                     samplesPerSecond = 
  1084.                         SDPMapPayloadToSamplesPerSecond(ulPayloadType);
  1085.                     if (samplesPerSecond)
  1086.                     {
  1087.                         bSamplesPerSecondFound = TRUE;
  1088.                     }
  1089.                 }
  1090.                 if (!bChannelsFound)
  1091.                 {
  1092.                     nChannels = SDPMapPayloadToChannels(ulPayloadType);
  1093.                     if (nChannels)
  1094.                     {
  1095.                         bChannelsFound = TRUE;
  1096.                     }
  1097.                 }
  1098.             }
  1099.             if (bSamplesPerSecondFound)
  1100.             {
  1101.                 SafeSprintf(psz256, 256,"/%d", samplesPerSecond); 
  1102.                 mDesc += psz256;
  1103.             }
  1104.             else
  1105.             {
  1106.                 mDesc += "/1000";
  1107.             }
  1108.             if (bChannelsFound)
  1109.             {
  1110.                 SafeSprintf(psz256, 256,"/%d", nChannels); 
  1111.                 mDesc += psz256;
  1112.             }
  1113.             mDesc += pszEOL;
  1114.             
  1115.             // a=fmtp
  1116.             if (pszFmtp)
  1117.             {
  1118.                 SafeSprintf(psz256, 256, "a=fmtp:%d %s%s", ulPayloadType, pszFmtp, pszEOL);
  1119.                 mDesc += psz256;
  1120.                 HX_VECTOR_DELETE(pszFmtp);
  1121.             }
  1122.             else if (!bUseOldSdp)
  1123.             {   
  1124.                 // 3GPP requires an fmtp field in every SDP file
  1125.                 // Include this only if the client supports interop SDP
  1126.                 // and SDPData doesn't already contain a=fmtp:
  1127.                 SafeSprintf(psz256, 256,"a=fmtp:%d ", ulPayloadType); 
  1128.                 if (!pszSDPData || !strstr(pszSDPData, psz256))
  1129.                 {
  1130.                     SafeSprintf(psz256,256, "a=fmtp:%d %s", ulPayloadType, pszEOL); 
  1131.                     mDesc += psz256;
  1132.                 }
  1133.             }
  1134.             // a=ptime
  1135.             if (bPtimeFound)
  1136.             {
  1137.                 SafeSprintf(psz256,256, "a=ptime:%d%s", ptime, pszEOL);
  1138.                 mDesc += psz256;
  1139.             }
  1140.             if (pszMimeType)
  1141.             {
  1142.                 // a=mimetype:string;xxx
  1143.                 NEW_FAST_TEMP_STR(pszTmpStr, 256, strlen(pszMimeType) + 128);
  1144.                 SafeSprintf(pszTmpString, 256, "a=mimetype:string;"%s"%s", pszMimeType, pszEOL);
  1145.                 mDesc += pszTmpString;
  1146.                 DELETE_FAST_TEMP_STR(pszTmpStr);
  1147.                 
  1148.                 HX_VECTOR_DELETE(pszMimeType);
  1149.             }
  1150.             // 3GPP AnnexG values
  1151.             if (bFoundPreDecBufSize)
  1152.             {
  1153.                 SafeSprintf(psz256, 256, "a=X-predecbufsize:%u%s", 
  1154.                     ulPreDecBufSize, pszEOL);
  1155.                 mDesc += psz256;
  1156.             }
  1157.             if (bFoundPreDecBufPeriod)
  1158.             {
  1159.                 SafeSprintf(psz256, 256, "a=X-initpredecbufperiod:%u%s", 
  1160.                     ulPreDecBufPeriod, pszEOL);
  1161.                 mDesc += psz256;
  1162.             }
  1163.             if (bFoundPostDecBufPeriod)
  1164.             {
  1165.                 SafeSprintf(psz256, 256, "a=X-initpostdecbufperiod:%u%s", 
  1166.                     ulPostDecBufPeriod, pszEOL);
  1167.                 mDesc += psz256;
  1168.             }
  1169.             if (bFoundDecByteRate)
  1170.             {
  1171.                 SafeSprintf(psz256, 256, "a=X-decbyterate:%u%s", 
  1172.                     ulDecByteRate, pszEOL);
  1173.                 mDesc += psz256;
  1174.             }
  1175.             if (pszMimeFirst)
  1176.             {
  1177.                 HX_VECTOR_DELETE(pszMimeFirst);
  1178.             }
  1179.             mDesc += streamAttributes;
  1180.             // expand SDPData if it's there...
  1181.             if (pszSDPData)
  1182.             {
  1183.                 mDesc += pszSDPData;
  1184.                 HX_VECTOR_DELETE(pszSDPData);
  1185.                 pszSDPData = NULL;
  1186.             }           
  1187.         }
  1188.     }
  1189. bail:
  1190.     if (pszConnAddr)
  1191.         HX_VECTOR_DELETE(pszConnAddr);
  1192.     HX_RELEASE(pControlStringBuff);
  1193.     HX_RELEASE(pContentBase);
  1194.     HX_RELEASE(pQueryParams);
  1195.     if (mDesc.IsEmpty())
  1196.     {
  1197.         pDescription = NULL;
  1198.         return HXR_FAIL;
  1199.     }
  1200.     IHXBuffer* pBuffer = NULL;
  1201.     m_pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pBuffer);
  1202.     pBuffer->Set((BYTE*)(const char*)mDesc, mDesc.GetLength());
  1203.     pDescription = pBuffer;
  1204.     return HXR_OK;
  1205. }
  1206. BOOL SDPMediaDescGenerator::GetUseOldEOL() const
  1207. {
  1208.     return m_bUseOldEOL;
  1209. }
  1210. void SDPMediaDescGenerator::SetUseOldEOL(BOOL bUseOldEOL)
  1211. {
  1212.     m_bUseOldEOL = bUseOldEOL;
  1213. }
  1214. /*
  1215.  *  If there is no Duration in a file header and all streams have the same 
  1216.  *  duration, put it in a file header.
  1217.  *  If live, it is 0.
  1218.  */
  1219. HX_RESULT
  1220. SDPMediaDescGenerator::SpecComplianceCheck(UINT16 nValues, 
  1221.                                         IHXValues** ppValueArray)
  1222. {
  1223.     HX_RESULT theErr;
  1224.     UINT32    ulDuration;
  1225.     // sanity check
  1226.     if (nValues < 3 || !ppValueArray)
  1227.     {
  1228.         HX_ASSERT(!"unexpected headers");
  1229.         return HXR_UNEXPECTED;
  1230.     }
  1231.     
  1232.     theErr = ppValueArray[0]->GetPropertyULONG32("Duration", ulDuration);
  1233.     if (SUCCEEDED(theErr))
  1234.     {
  1235.         return HXR_OK;
  1236.     }
  1237.     
  1238.     UINT32 ulTmp = 0;
  1239.     ulDuration = 0;
  1240.     
  1241.     /* find out if this is a live session */
  1242.     theErr = ppValueArray[0]->GetPropertyULONG32("LiveStream", ulTmp);
  1243.     if (SUCCEEDED(theErr) && 1 == ulTmp) 
  1244.     {
  1245.             ppValueArray[0]->SetPropertyULONG32("Duration", 0);
  1246.             return HXR_OK;
  1247.     }
  1248.     
  1249.     for (UINT16 i = 2; i < nValues; ++i)
  1250.     {
  1251.             theErr = 
  1252.                 ppValueArray[i]->GetPropertyULONG32("Duration", ulTmp);
  1253.             if (SUCCEEDED(theErr))
  1254.             {                
  1255.     // take the largest
  1256.     if (ulDuration < ulTmp)
  1257.                 {
  1258. ulDuration = ulTmp;
  1259.                 }
  1260.             }
  1261.     }
  1262.     
  1263.     if (ulDuration)
  1264.     {
  1265.             ppValueArray[0]->SetPropertyULONG32("Duration", ulDuration);        
  1266.     }            
  1267.     return HXR_OK;
  1268. }
  1269. char*
  1270. SDPMediaDescGenerator::EscapeBuffer(const char* pBuffer, UINT32 len)
  1271. {
  1272.     UCHAR* buf;
  1273.     UINT32 newlen;
  1274.     UINT32 i = 0;
  1275.     UCHAR* tmp;
  1276.     UCHAR* newbuf;
  1277.     if(!pBuffer)
  1278.     {
  1279.         return 0;
  1280.     }
  1281.     buf = (UCHAR*)pBuffer;
  1282.     newlen = len;
  1283.     /*
  1284.      *  We have to do this in two passes.  One to alloc new mem to 
  1285.      *  copy into, and the next to do the escape/ copy.
  1286.      *  First, count unescaped quotes and alloc.
  1287.      */
  1288.     tmp = buf;
  1289.     while(i < len)
  1290.     {
  1291.         if(*tmp == '"')
  1292.         {
  1293.             newlen++;
  1294.         }
  1295.         if(*tmp == '\')
  1296.         {
  1297.             tmp++;
  1298.             i++;
  1299.         }
  1300.         tmp++;
  1301.         i++;
  1302.     }
  1303.     newbuf = new UCHAR[newlen];
  1304.     tmp = newbuf;
  1305.     /*
  1306.      * Now copy into the new buffer and unescape as you go along.
  1307.      */
  1308.     i = 0;
  1309.     while(i < len)
  1310.     {
  1311.         if(*buf == '"')
  1312.         {
  1313.             *tmp++ = '\';
  1314.         }
  1315.         if(*buf == '\')
  1316.         {
  1317.             *tmp++ = *buf++;
  1318.             i++;
  1319.         }
  1320.         *tmp++ = *buf++;
  1321.         i++;
  1322.     }
  1323.     /*
  1324.      * Set the buffer and return.
  1325.      */
  1326.     return (char*)newbuf;
  1327. }
  1328. void
  1329. SDPMediaDescGenerator::RemoveASLine(char* pSDPData, UINT32 len)
  1330. {
  1331.     /* 
  1332.      * This method removes an extraneous b=AS line in place.
  1333.      */
  1334.     if (!pSDPData)
  1335.     {
  1336. return;
  1337.     }
  1338.     char* pWriteCursor = (char*)strstr((const char*)pSDPData, "b=AS");
  1339.     if (!pWriteCursor)
  1340.     {
  1341. return;
  1342.     }
  1343.     char* pReadCursor = pWriteCursor;
  1344.     UINT32 ulLength = (len - (pWriteCursor - pSDPData));
  1345.     //Find the end of the field
  1346.     while((ulLength != 0) &&
  1347.   (*pReadCursor != 0x0a) &&
  1348.   (*pReadCursor != 0x0d) &&
  1349.           (*pReadCursor != ' '))
  1350.     {
  1351.         pReadCursor++;
  1352.         ulLength--;
  1353.     }
  1354.     //Skip over the end of the field
  1355.     while((ulLength > 0) &&
  1356.           ((*pReadCursor == 0x0a) ||
  1357.            (*pReadCursor == 0x0d) ||
  1358.            (*pReadCursor == ' ')))
  1359.     {
  1360.         pReadCursor++;
  1361.         ulLength--;
  1362.     } 
  1363.     if (!pReadCursor)
  1364.     {
  1365. return;
  1366.     }
  1367.     if (ulLength == 0)
  1368.     {
  1369. /*
  1370.  * There's no more data beyond the b=AS line.
  1371.  * Terminate the SDPData after previous line
  1372.  */
  1373. *pWriteCursor = '';
  1374.     }
  1375.     else
  1376.     {
  1377. memmove(pWriteCursor, pReadCursor, len - (pReadCursor - pSDPData));
  1378.     }
  1379. }
  1380. BOOL SDPMediaDescGenerator::GetUseSessionGUID() const
  1381. {
  1382.     return m_bUseSessionGUID;
  1383. }
  1384. BOOL SDPMediaDescGenerator::GetUseAbsoluteURL() const
  1385. {
  1386.     return m_bUseAbsoluteURL;
  1387. }
  1388. void SDPMediaDescGenerator::SetUseSessionGUID(BOOL bOption)
  1389. {
  1390.     m_bUseSessionGUID = bOption;
  1391. }
  1392. void SDPMediaDescGenerator::SetUseAbsoluteURL(BOOL bOption)
  1393. {
  1394.     m_bUseAbsoluteURL= bOption;
  1395. }