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

Symbian

开发平台:

Visual C++

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