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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: sdpmdparse.cpp,v 1.16.2.2 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 "sdpmdparse.h"
  50. #include "sdptypes.h"
  51. #include "sdppyldinfo.h"
  52. #include "rtptypes.h"
  53. #include "nptime.h"
  54. #include "rtsputil.h"
  55. #include "safestring.h"
  56. #include "chxfmtpparse.h"
  57. #include "chxcharstack.h"
  58. SDPMediaDescParser::SDPMediaDescParser(ULONG32 ulVersion) :
  59.     m_pContext(0),
  60.     m_pCCF(0),
  61.     m_ulVersion(ulVersion),
  62.     m_pFileHeader(0),
  63.     m_bDefiniteDuration(FALSE),
  64.     m_ulDefaultDuration(0)
  65. {
  66. }
  67. SDPMediaDescParser::~SDPMediaDescParser()
  68. {
  69.     HX_RELEASE(m_pCCF);
  70.     HX_RELEASE(m_pContext);
  71.     HX_RELEASE(m_pFileHeader);
  72.     clearStreamList();
  73. }
  74.     
  75. HX_RESULT SDPMediaDescParser::Init(IUnknown* pContext)
  76. {
  77.     HX_RESULT res = HXR_FAILED;
  78.     HX_RELEASE(m_pContext);
  79.     HX_RELEASE(m_pCCF);
  80.     if (pContext)
  81.     {
  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 SDPMediaDescParser::Parse(IHXBuffer* pDescription,
  93.                                     REF(UINT16) nValues, 
  94.                                     REF(IHXValues**) pValueArray)
  95. {    
  96.     HX_RESULT theErr = HXR_OK;
  97.     /*
  98.      * pDescription may not be NULL terminated, so don't do ->GetBuffer()
  99.      */
  100.     char* pDescString = NULL;
  101.     UINT32 ulDescStringLen = 0;
  102.     theErr = pDescription->Get((BYTE*&)pDescString, ulDescStringLen);
  103.     if (HXR_OK == theErr)
  104.         theErr = fromExternalRep(pDescString, ulDescStringLen);
  105.     
  106.     if (HXR_OK == theErr)
  107.     {    
  108.         nValues = m_streams.GetCount() + 1;
  109.         IHXValues** ppHeaders = new IHXValues*[nValues];
  110.         ppHeaders[0] = m_pFileHeader;
  111.         ppHeaders[0]->AddRef();
  112.         CHXSimpleList::Iterator i;
  113.         UINT16 j=1;
  114.         for(i = m_streams.Begin();i != m_streams.End();++i,++j)
  115.         {
  116.             ppHeaders[j] = (IHXValues*)(*i);
  117.             ppHeaders[j]->AddRef();
  118.             TakeCareOfDefaults(ppHeaders[j]);
  119.         }
  120.         pValueArray = ppHeaders;
  121.     }
  122.     return theErr;
  123. }
  124. /* right now there is only ASMRuleBook */
  125. void SDPMediaDescParser::TakeCareOfDefaults(IHXValues* pHeader)
  126. {
  127.     HX_ASSERT(pHeader);
  128.     IHXBuffer* pBuf = NULL;
  129.     if (pHeader->GetPropertyCString("ASMRuleBook", pBuf) != HXR_OK)
  130.     {
  131.         // there is no asmrulebook...
  132.         UINT32 ul = 0;
  133.         if (pHeader->GetPropertyULONG32("AvgBitRate", ul) == HXR_OK)
  134.         {
  135.             AddRuleBook(pHeader, ul);
  136.         }
  137.         else
  138.         {
  139.             AddRuleBook(pHeader, 0);
  140.             // add 0 bandwidth...
  141.             pHeader->SetPropertyULONG32("AvgBitRate", 0);
  142.         }
  143.     }
  144.     HX_RELEASE(pBuf);
  145. }
  146. /* if ulBW is 0, we will assume TSD */
  147. void SDPMediaDescParser::AddRuleBook(IHXValues* pHeader, UINT32 ulBW)
  148. {
  149.     IHXBuffer* pBuf = NULL;
  150.     m_pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pBuf);
  151.     if (!pBuf)
  152.     {
  153.         // nothing we can do...
  154.         return;
  155.     }
  156.     if (ulBW)
  157.     {    
  158.         char rulebook[256] = {0}; /* Flawfinder: ignore */
  159.         
  160.         UINT32 ulBWHalf = ulBW / 2;                            
  161.     
  162.         SafeSprintf(rulebook,256, "marker=0,AverageBandwidth=%d;marker=1,AverageBandwidth=%d;", 
  163.                     ulBW - ulBWHalf, ulBWHalf);
  164.         pBuf->Set((BYTE*)rulebook, strlen(rulebook) + 1);        
  165.     }
  166.     else
  167.     {
  168.         pBuf->Set((const BYTE*)"marker=0,timestampdelivery=1;marker=1,timestampdelivery=1;", 59);        
  169.     }    
  170.     pHeader->SetPropertyCString("ASMRuleBook", pBuf);
  171.     HX_RELEASE(pBuf);    
  172. }
  173. //
  174. //      This is to fix a problem that causes the optimized builds
  175. //      to cause the macintosh to crash!!!!!!!!!!!! <seanh>
  176. //
  177. #ifdef _MACINTOSH
  178. #pragma peephole off
  179. #pragma global_optimizer off
  180. #pragma scheduling off
  181. #endif
  182. /*
  183.  *  pData needs to be NULL terminated for we use strlen...
  184.  */
  185. HX_RESULT 
  186. SDPMediaDescParser::fromExternalRep(char* pData)
  187. {
  188.     return fromExternalRep(pData, strlen(pData));     
  189. }
  190. HX_RESULT
  191. SDPMediaDescParser::fromExternalRep(char* pData, UINT32 ulDataLen)
  192. {
  193.     const char* pCur = pData;
  194.     const char* pEnd = pData + ulDataLen;
  195.     ULONG32 nStreams = 0;
  196.     CHXString extraFields;
  197.     m_bDefiniteDuration = FALSE;
  198.     m_ulDefaultDuration = 0;
  199.     m_mediaType.Empty();
  200.     m_pFileHeader = CreateHeader();
  201.     IHXValues* pHdr = m_pFileHeader;
  202.     HX_RESULT res = (pHdr) ? HXR_OK : HXR_OUTOFMEMORY;
  203.     
  204.     while((HXR_OK == res) && *pCur && (pCur < pEnd))
  205.     {
  206.         // Skip n or 'r' characters
  207.         for(; *pCur && (pCur < pEnd) && strchr("rn", *pCur); pCur++)
  208.             ;
  209.         if (*pCur && (pCur < pEnd))
  210.         {
  211.             char lineType = *pCur++;
  212.             
  213.             if (*pCur == '=')
  214.             {
  215.                 pCur++; // skip '='
  216.                 IHXBuffer* pSDPLine = 0;
  217.                 res = GetLine(pCur, pEnd, pSDPLine);
  218.                 if (HXR_OK == res)
  219.                 {
  220.                     char* pLine = (char*)pSDPLine->GetBuffer();
  221.                     //printf ("line %c '%s'n", lineType, pLine);
  222.                     switch(lineType) {
  223.                     case 'v':
  224.                         res = HandleVLine(pLine);
  225.                         break;
  226.                     case 'm':
  227.                         if (!extraFields.IsEmpty())
  228.                         {
  229.                             AddString(pHdr, "SDPData",
  230.                                       (const char*)extraFields);
  231.                             extraFields.Empty();
  232.                         }
  233.                         pHdr = CreateHeader();
  234.                         m_streams.AddTail(pHdr);
  235.                         AddULONG32(pHdr, "StreamNumber", nStreams);
  236.                         nStreams++;
  237.                         // Propagate default duration to new stream
  238.                         if (0 != m_ulDefaultDuration)
  239.                         {
  240.                             AddULONG32(pHdr, "Duration", m_ulDefaultDuration);
  241.                         }   
  242.                         res = HandleMLine(pLine, pHdr);
  243.                         break;
  244.                     case 'a':
  245.                         res = HandleALine(pLine, pHdr);
  246.                         break;
  247.                     case 'c':
  248.                         res = HandleCLine(pLine, pHdr);
  249.                         break;
  250.                     case 'b':
  251.                         res = HandleBLine(pLine, pHdr);
  252.                         break;
  253.                     case 'i':
  254.                         AddString(pHdr, "Information", pLine);
  255.                         res = HXR_OK;
  256.                         break;
  257.                     case 'o':
  258.                     case 's':
  259.                     case 't':
  260.                         // ignore these lines
  261.                         res = HXR_OK;
  262.                         break;
  263.                     default:
  264.                         res = HXR_NOT_SUPPORTED;
  265.                         break;
  266.                     };
  267.                     if (HXR_NOT_SUPPORTED == res)
  268.                     {
  269.                         extraFields += lineType;
  270.                         extraFields += '=';
  271.                         extraFields += pLine;
  272.                         extraFields += "n";
  273.                         
  274.                         res = HXR_OK;
  275.                     }
  276.                     pSDPLine->Release();
  277.                     pSDPLine = 0;
  278.                 }
  279.             }
  280.             else
  281.             {
  282.                 res = HXR_FAILED;
  283.             }
  284.         }
  285.     }
  286.     if (HXR_OK == res)
  287.     {
  288.         if (!extraFields.IsEmpty())
  289.         {
  290.             AddString(pHdr, "SDPData",
  291.                       (const char*)extraFields);
  292.             extraFields.Empty();
  293.         }
  294.         /* Only add StreamCount and LiveStream fields
  295.          * if we have at least 1 stream. This prevents
  296.          * the fields from appearing when we are using 
  297.          * the SDP plugin to parse partial SDP chunks.
  298.          */
  299.         if (nStreams)
  300.         {
  301.             AddULONG32(m_pFileHeader, "StreamCount", nStreams);
  302.             
  303.             ULONG32 ulLive;
  304.             if (!m_bDefiniteDuration &&
  305.                 (m_ulDefaultDuration == 0) &&
  306.                 (!SUCCEEDED(m_pFileHeader->GetPropertyULONG32("LiveStream", 
  307.                                                               ulLive))))
  308.             {
  309.                 AddULONG32(m_pFileHeader, "LiveStream", 1);
  310.             }
  311.         }
  312.     }
  313.     
  314.     return res;
  315. }
  316. #ifdef _MACINTOSH
  317. #pragma peephole reset
  318. #pragma global_optimizer reset
  319. #pragma scheduling reset
  320. #endif
  321. /*
  322. * Payload table contains reserved/unassigned types as well.  So, this func
  323. * returns if the table contains a valid info
  324. */
  325. BOOL
  326. SDPMediaDescParser::IsPayloadTableValid(UINT32 ulPayloadType)
  327. {
  328.     HX_ASSERT(SDPIsStaticPayload(ulPayloadType));
  329.     if (!SDPMapPayloadToEncodingName(ulPayloadType))
  330.     {
  331.         return FALSE;
  332.     }
  333.     return TRUE;
  334. }
  335. HX_RESULT
  336. SDPMediaDescParser::getRTPMapInfo(const char* pMapInfo, 
  337.                                   REF(CHXString) strMimeType, 
  338.                                   IHXValues* pStream)
  339. {
  340.     if (!pMapInfo || !strMimeType.GetLength() || !pStream)
  341.     {
  342.         return HXR_FAIL;
  343.     }
  344.     
  345.     /* 
  346.      *  It could be either:
  347.      *  EncodingName
  348.      *  EncodingName/SamplesPerSecond
  349.      *  EncodingName/SamplesPerSecond/Channels
  350.      */   
  351.     strMimeType += "/";
  352.     char* pTok = strchr((char*)pMapInfo, ' ');
  353.     if (pTok)
  354.     {
  355.         *pTok = '';
  356.     }   
  357.     pTok = (char*)pMapInfo;    
  358.     char* pTokNext = strchr(pTok, '/');
  359.     if (pTokNext)
  360.     {
  361.         *pTokNext++ = '';
  362.         strMimeType += pTok;
  363.         pTok = pTokNext;
  364.         pTokNext = strchr((char*)pTok, '/');
  365.         if (pTokNext)
  366.         {
  367.             *pTokNext++ = '';
  368.             AddULONG32(pStream, "SamplesPerSecond", strtol(pTok, 0, 10));
  369.             AddULONG32(pStream, "Channels", strtol(pTokNext, 0, 10));
  370.         }
  371.         else
  372.         {
  373.             AddULONG32(pStream, "SamplesPerSecond", strtol(pTok, 0, 10));
  374.         }
  375.     }
  376.     else
  377.     {
  378.         // this is just an encoding name
  379.         strMimeType += pMapInfo;
  380.     }
  381.         
  382.     return HXR_OK;
  383. }
  384. /*
  385. *   Compare ulVersion against m_ulVersion.  and returns HXR_FAIL iff 
  386. *   ulVersion < m_ulVersion  ---> need auto update.
  387. */
  388. HX_RESULT
  389. SDPMediaDescParser::checkVersion(UINT32 ulVersion)
  390. {
  391.     HX_ASSERT(m_ulVersion);
  392.     UINT32 ulPluginMajor = HX_GET_MAJOR_VERSION(m_ulVersion);
  393.     UINT32 ulPluginMinor = HX_GET_MINOR_VERSION(m_ulVersion);
  394.     UINT32 ulDataMajor = HX_GET_MAJOR_VERSION(ulVersion);
  395.     UINT32 ulDataMinor = HX_GET_MINOR_VERSION(ulVersion);
  396.     if((ulDataMajor >  ulPluginMajor) ||
  397.        (ulDataMajor == ulPluginMajor && ulDataMinor > ulPluginMinor))
  398.     {
  399.         return HXR_FAIL;
  400.     }    
  401.     else
  402.     {
  403.         return HXR_OK;
  404.     }
  405. }
  406. void SDPMediaDescParser::clearStreamList()
  407. {
  408.     LISTPOSITION pos = m_streams.GetHeadPosition();
  409.     while(pos)
  410.     {
  411.         IHXValues* pStream = (IHXValues*)m_streams.GetNext(pos);
  412.         HX_RELEASE(pStream);
  413.     }
  414.     m_streams.RemoveAll();
  415. }
  416. IHXValues* SDPMediaDescParser::CreateHeader()
  417. {
  418.     IHXValues* pRet = 0;
  419.     if (m_pCCF)
  420.         m_pCCF->CreateInstance(IID_IHXValues, (void**)&pRet);
  421.     return pRet;
  422. }
  423. void SDPMediaDescParser::AddULONG32(IHXValues* pHeader, 
  424.                                     const char* pKey, ULONG32 ulValue)
  425. {
  426.     pHeader->SetPropertyULONG32(pKey, ulValue);
  427. }
  428. void SDPMediaDescParser::AddString(IHXValues* pHeader, 
  429.                                    const char* pKey,
  430.                                    const char* pValue)
  431. {
  432.     if ((pKey == NULL) || (pValue == NULL))
  433.     {
  434.         return;
  435.     }
  436.     IHXBuffer* pBuf = CopyBuffer((const UINT8*)pValue, strlen(pValue) + 1);
  437.     if (pBuf)
  438.         pHeader->SetPropertyCString(pKey, pBuf);
  439.     HX_RELEASE(pBuf);
  440. }
  441. void SDPMediaDescParser::AddBuffer(IHXValues* pHeader, 
  442.                                    const char* pKey,
  443.                                    const UINT8* pValue,
  444.                                    ULONG32 ulLength)
  445. {
  446.     IHXBuffer* pBuf = CopyBuffer(pValue, ulLength);
  447.     if (pBuf)
  448.         pHeader->SetPropertyBuffer(pKey, pBuf);
  449.     HX_RELEASE(pBuf);
  450. }
  451. IHXBuffer* SDPMediaDescParser::CopyBuffer(const UINT8* pBuf, ULONG32 ulLength)
  452. {
  453.     IHXBuffer* pRet = 0;
  454.     if (SUCCEEDED(m_pCCF->CreateInstance(IID_IHXBuffer, (void**)&pRet)))
  455.         pRet->Set(pBuf, ulLength);
  456.     return pRet;
  457. }
  458. HX_RESULT SDPMediaDescParser::GetLine(const char*& pData,
  459.                                       const char* pEnd,
  460.                                       IHXBuffer*& pLine) const
  461. {
  462.     HX_RESULT res = HXR_OK;
  463.     CHXCharStack tok(m_pCCF);
  464.     BOOL bInQuote = FALSE;
  465.     BOOL bLastWasEscape = FALSE;
  466.     for (; (HXR_OK == res) && *pData && (pData < pEnd) && (bInQuote || !strchr("rn", *pData)); pData++)
  467.     {
  468.         if (bLastWasEscape)
  469.         {
  470.             bLastWasEscape = FALSE;
  471.         }
  472.         else
  473.         {
  474.             if (*pData == '"')
  475.             {
  476.                 bInQuote = !bInQuote;
  477.             }
  478.             else if (*pData == '\')
  479.             {
  480.                 bLastWasEscape = TRUE;
  481.             }
  482.         }
  483.         res = tok.AddChar(*pData);
  484.     }
  485.     if (HXR_OK == res)
  486.     {
  487.         res = tok.Finish(pLine);
  488.     }
  489.     return res;
  490. }
  491. void SDPMediaDescParser::SkipSpaces(char*& pData) const
  492. {
  493.     for (; *pData && *pData == ' '; pData++)
  494.         ;
  495. }
  496. BOOL SDPMediaDescParser::ScanForDelim(char*& pData, char delim) const
  497. {
  498.     BOOL bRet = FALSE;
  499.     while(*pData && !bRet)
  500.     {
  501.         if (*pData == delim)
  502.         {
  503.             bRet = TRUE;
  504.         }
  505.         else
  506.         {
  507.             pData++;
  508.         }
  509.     }
  510.     return bRet;
  511. }
  512. HX_RESULT SDPMediaDescParser::HandleVLine(char* pLine)
  513. {
  514.     HX_RESULT res = HXR_FAILED;
  515.     
  516.     char* pEnd = 0;
  517.     unsigned long version = strtoul(pLine, &pEnd, 10);
  518.     if (*pLine && !*pEnd && (version == 0))
  519.     {
  520.         
  521.         res = HXR_OK;
  522.     }
  523.     return res;
  524. }
  525. HX_RESULT SDPMediaDescParser::HandleMLine(char* pLine, IHXValues* pHdr)
  526. {
  527.     HX_RESULT res = HXR_FAILED;
  528.     if (*pLine)
  529.     {
  530.         int state = 0;
  531.         const char* pMediaType = pLine;
  532.         ULONG32 ulPort = 0;
  533.         ULONG32 ulPayloadType = 0;
  534.         
  535.         if (ScanForDelim(pLine, ' '))
  536.         {
  537.             // Null terminate mimetype
  538.             *pLine++ = '';
  539.             // Save media type for later
  540.             m_mediaType = pMediaType;
  541.             res = HXR_OK;
  542.         }
  543.         while(*pLine && (HXR_OK == res))
  544.         {
  545.             char* pEnd = 0;
  546.             SkipSpaces(pLine);
  547.             
  548.             if (*pLine)
  549.             {
  550.                 switch(state) {
  551.                 case 0:
  552.                     // Grab port number
  553.                     ulPort = strtoul(pLine, &pEnd, 10);
  554.                     if (*pEnd == ' ')
  555.                     {
  556.                         pLine = pEnd;
  557.                         state = 1;
  558.                     }
  559.                     else
  560.                     {
  561.                         // No transport field or
  562.                         // invalid port character
  563.                         res = HXR_FAILED;
  564.                     }
  565.                     break;
  566.                 case 1:
  567.                     // Skip transport. Usually RTP/AVP
  568.                     if (ScanForDelim(pLine, ' '))
  569.                     {
  570.                         state = 2;
  571.                     }
  572.                     break;
  573.                 case 2:
  574.                     // Grab the first payload type
  575.                     ulPayloadType = strtoul(pLine, &pEnd, 10);
  576.                     if ((*pEnd == ' ') || !*pEnd )
  577.                     {
  578.                         state = 3;
  579.                     }
  580.                     else
  581.                     {
  582.                         // There was an unexpected character
  583.                         // the the payload type
  584.                         res = HXR_FAILED;
  585.                     }
  586.                 case 3:
  587.                     // Consume the rest of the payload types
  588.                     for (; *pLine; pLine++)
  589.                         ;
  590.                     break;
  591.                 }
  592.             }
  593.         }
  594.         if (state == 3)
  595.         {
  596.             AddULONG32(pHdr, "RTPPayloadType", ulPayloadType);
  597.             
  598.             if (ulPort)
  599.             {
  600.                 AddULONG32(pHdr, "Port", ulPort);
  601.             }
  602.             if (SDPIsStaticPayload(ulPayloadType))
  603.             {
  604.                 if (IsPayloadTableValid(ulPayloadType))
  605.                 {
  606.                     if (!SDPIsTimestampDeliverable(ulPayloadType))
  607.                     {
  608.                         ULONG32 ulBitrate = 
  609.                             SDPMapPayloadToBitrate(ulPayloadType);
  610.                         HX_ASSERT(ulBitrate);
  611.                         // we have a bandwidth info in a table...
  612.                         AddULONG32(pHdr, "AvgBitRate", ulBitrate);
  613.                     }
  614.                     // static payload type
  615.                     AddString(pHdr, "MimeType", 
  616.                               SDPMapPayloadToMimeType(ulPayloadType));
  617.                     AddULONG32(pHdr,
  618.                                "RTPTimestampConversionFactor", 
  619.                                SDPMapPayloadToRTPFactor(ulPayloadType));
  620.                     AddULONG32(pHdr,
  621.                                "HXTimestampConversionFactor", 
  622.                                SDPMapPayloadToRMAFactor(ulPayloadType));
  623.                     AddULONG32(pHdr,
  624.                                "SamplesPerSecond", 
  625.                                SDPMapPayloadToSamplesPerSecond(ulPayloadType));
  626.                     AddULONG32(pHdr,
  627.                                "Channels", 
  628.                                (ULONG32)SDPMapPayloadToChannels(ulPayloadType));
  629.                     // deal with opaque hack...
  630.                     const BYTE* pOpaqueData = NULL;
  631.                     ULONG32 ulOpaqueDataSize = 0;
  632.                     switch(ulPayloadType)
  633.                     {
  634.                     case RTP_PAYLOAD_GSM:
  635.                         pOpaqueData = 
  636.                             SDPMapPayloadToHeaderData(RTP_PAYLOAD_GSM,
  637.                                                       ulOpaqueDataSize);
  638.                         break;
  639.                     }   
  640.                     
  641.                     if (pOpaqueData)
  642.                     {
  643.                         AddBuffer(pHdr, "OpaqueData",
  644.                                   pOpaqueData, ulOpaqueDataSize);
  645.                     }           
  646.                 }
  647.                 else
  648.                 {
  649.                     res = HXR_REQUEST_UPGRADE;
  650.                 }
  651.             }
  652.         }
  653.         else if (HXR_OK == res)
  654.         {
  655.             res = HXR_FAILED;
  656.         }
  657.     }
  658.     return res;
  659. }
  660. HX_RESULT SDPMediaDescParser::HandleALine(char* pLine, IHXValues* pHdr)
  661. {
  662.     HX_RESULT res = HXR_FAILED;
  663.     
  664.     const char* pFieldName = pLine;
  665.     char* pFieldValue = 0;
  666.     FieldType fieldType = ftUnknown;
  667.     
  668.     if (*pLine)
  669.     {
  670.         // Collect the field name
  671.         if (ScanForDelim(pLine, ':'))
  672.         {
  673.             char* pColon = pLine;
  674.             // Must be the key/value form 
  675.             // a=foo:bar
  676.             
  677.             // Null terminate field name by replacing ':' with ''
  678.             *pLine++ = '';
  679.                     
  680.             pFieldValue = pLine;
  681.             if ((HXR_OK == (res = ParseFieldValue(pFieldValue, fieldType))))
  682.             {
  683.                 switch (fieldType) {
  684.                 case ftUnknown:
  685.                     res = HandleSpecialFields(pFieldName, pFieldValue, pHdr);
  686.                     break;
  687.                 case ftULONG32:
  688.                 {
  689.                     char* pEnd = 0;
  690.                     ULONG32 ulValue = strtoul(pFieldValue, &pEnd, 10);
  691.                     
  692.                     if (*pFieldValue && !*pEnd)
  693.                     {
  694.                         res = pHdr->SetPropertyULONG32(pFieldName, ulValue);
  695.                     }
  696.                 } break;
  697.                 case ftString:
  698.                     AddString(pHdr, pFieldName, pFieldValue);
  699.                     res = HXR_OK;
  700.                     break;
  701.                 case ftBuffer:
  702.                 {
  703.                     int length = strlen(pFieldValue);
  704.                     BYTE* pDecodeBuf = new BYTE[length];
  705.                     INT32 decodeLen = BinFrom64(pFieldValue, length, 
  706.                                                 pDecodeBuf);
  707.                     if( decodeLen != -1 )
  708.                     {
  709.                         AddBuffer(pHdr, pFieldName, pDecodeBuf, decodeLen);
  710.                     }
  711.                     res = HXR_OK;
  712.                     delete [] pDecodeBuf;
  713.                 }break;
  714.                 }
  715.             }
  716.             
  717.             if (HXR_OK != res)
  718.             {
  719.                 // Put back the ':'
  720.                 *pColon = ':';
  721.             }
  722.         }
  723.         else
  724.         {
  725.             // Must be the key only form
  726.             // a=foo
  727.             res = HXR_NOT_SUPPORTED;
  728.         }
  729.     }
  730.     return res;
  731. }
  732. HX_RESULT SDPMediaDescParser::HandleCLine(char* pLine, IHXValues* pHdr)
  733. {
  734.     // Handles the following forms
  735.     // c=IN IP4 xxx.xxx.xxx.xxx
  736.     // c=IN IP4 xxx.xxx.xxx.xxx/xxx
  737.     // c=IN IP4 xxx.xxx.xxx.xxx/xxx/xx
  738.     HX_RESULT res = HXR_FAILED;
  739.     
  740.     char* pCur = pLine;
  741.     if (ScanForDelim(pCur, ' '))
  742.     {
  743.         *pCur++ = '';
  744.         
  745.         SkipSpaces(pCur);
  746.         char* pAddrType = pCur;
  747.         if (!strcasecmp(pLine, "IN") && ScanForDelim(pCur, ' '))
  748.         {
  749.             *pCur++ = '';
  750.             SkipSpaces(pCur);
  751.             if (!strcasecmp(pAddrType, "IP4") && *pCur)
  752.             {
  753.                 char* pAddr = pCur;
  754.                 if (ScanForDelim(pCur, '/'))
  755.                 {
  756.                     *pCur++ = '';
  757.                     if (*pCur)
  758.                     {
  759.                         char* pEnd = 0;
  760.                         ULONG32 ulTTL = strtoul(pCur, &pEnd, 10);
  761.                         if (*pCur && ((*pEnd == '/') || (!*pEnd)))
  762.                         {
  763.                             AddULONG32(pHdr, "MulticastTTL", ulTTL);
  764.                             res = HXR_OK;
  765.                             pCur = pEnd;
  766.                             if (*pCur)
  767.                             {
  768.                                 pCur++; // skip '/'
  769.                                 ULONG32 ulRange = strtoul(pCur, &pEnd, 10);
  770.                                 
  771.                                 if (*pCur && !*pEnd)
  772.                                 {
  773.                                     // c=IN IP4 xxx.xxx.xxx.xxx/xxx/xx
  774.                                     AddULONG32(pHdr, "MulticastRange", ulRange);
  775.                                     res = HXR_OK;
  776.                                 }
  777.                             }
  778.                         }
  779.                     }
  780.                 }
  781.                 else
  782.                 {
  783.                     // c=IN IP4 xxx.xxx.xxx.xxx
  784.                     res = HXR_OK;
  785.                 }
  786.                 if (HXR_OK == res)
  787.                 {
  788.                     AddString(pHdr, "MulticastAddress", pAddr);
  789.                 }
  790.             }
  791.         }
  792.     }
  793.     return res;
  794. }
  795. HX_RESULT SDPMediaDescParser::HandleBLine(char* pLine, IHXValues* pHdr)
  796. {
  797.     HX_RESULT res = HXR_FAILED;
  798.     char* pCur = pLine;
  799.     if (ScanForDelim(pCur, ':'))
  800.     {
  801.         char* pColon = pCur;
  802.         *pCur++ = '';
  803.         
  804.         char* pEnd = 0;
  805.         ULONG32 ulBwValue = strtoul(pCur, &pEnd, 10);
  806.         if (*pCur && !*pEnd)
  807.         {
  808.             const char* pBwKey = 0;
  809.             res = HXR_OK;
  810.             if (!strcasecmp(pLine, "AS"))
  811.             {
  812.                 // a=AvgBitRate has the higher precedence...
  813.                 ULONG32 ulTmp;
  814.                 if (!SUCCEEDED(pHdr->GetPropertyULONG32("AvgBitRate",
  815.                                                         ulTmp)))
  816.                 {
  817.                                 // use this as a default.       
  818.                                 // it's kilobits per sec....
  819.                     pBwKey = "AvgBitRate";
  820.                     ulBwValue *= 1000;
  821.                 }
  822.             }
  823.             else if (!strcasecmp(pLine, "RR"))
  824.             {
  825.                 pBwKey = "RtcpRRRate";
  826.             }
  827.             else if (!strcasecmp(pLine, "RS"))
  828.             {
  829.                 pBwKey = "RtcpRSRate";
  830.             }
  831.             else
  832.             {
  833.                 res = HXR_NOT_SUPPORTED;
  834.             }
  835.             if (pBwKey)
  836.             {
  837.                 AddULONG32(pHdr, pBwKey, ulBwValue);
  838.             }
  839.         }
  840.         
  841.         *pColon = ':';
  842.     }
  843.     return res;
  844. }
  845. HX_RESULT SDPMediaDescParser::ParseFieldValue(char*& pValue, 
  846.                                               FieldType& fieldType) const
  847. {
  848.     HX_RESULT res = HXR_OK;
  849.     char* pCur = pValue;
  850.     // Look for the following forms
  851.     // a=anInt:integer;43
  852.     // a=aString:string;"this is a string"
  853.     // a=aBuffer:buffer;"TWFjIFRWAA=="
  854.     // Assume we don't know the type.
  855.     fieldType = ftUnknown;
  856.     if (ScanForDelim(pCur, ';'))
  857.     {
  858.         // Replace the ';' with a '' so we
  859.         // can check to see if it matches the known
  860.         // types
  861.         char* pSemiColon = pCur;
  862.         *pCur++ = '';
  863.         if (!strcmp(pValue, "integer"))
  864.         {
  865.             // Update the value pointer to the
  866.             // start of the integer value
  867.             pValue = pCur;
  868.             fieldType = ftULONG32;
  869.         }
  870.         else if (!strcmp(pValue, "string"))
  871.         {
  872.             fieldType = ftString;
  873.         }
  874.         else if (!strcmp(pValue, "buffer"))
  875.         {
  876.             fieldType = ftBuffer;
  877.         }
  878.         if ((fieldType == ftString) || (fieldType == ftBuffer))
  879.         {
  880.             BOOL bFailed = TRUE;
  881.             // Look for starting '"'
  882.             if (*pCur == '"')
  883.             {
  884.                 pCur++; // skip '"'
  885.                 if (*pCur)
  886.                 {
  887.                     // Store start of the string
  888.                     char* pStrStart = pCur;
  889.                     // Create temporary buffer for unescaping
  890.                     char* pTmpBuf = new char[strlen(pStrStart) + 1];
  891.                     if (pTmpBuf)
  892.                     {
  893.                         char* pDest = pTmpBuf;
  894.                         // Copy string into pTmpBuf and
  895.                         // unescape any escape sequences
  896.                         while (*pCur && *pCur != '"')
  897.                         {
  898.                             if (*pCur == '\')
  899.                             {
  900.                                 *pCur++; // skip '\'
  901.                             }
  902.                             
  903.                             *pDest++ = *pCur++;
  904.                         }
  905.                         
  906.                         // Make sure the last character is a '"'
  907.                         if (*pCur == '"')
  908.                         {
  909.                             // Replace ending '"' with ''
  910.                             *pDest = '';
  911.                             // Replace escaped string with
  912.                             // unescaped string.
  913.                             strcpy(pStrStart, pTmpBuf);
  914.                             // Update the value pointer to the 
  915.                             // start of the string value
  916.                             pValue = pStrStart;
  917.                             bFailed = FALSE;
  918.                         }
  919.                         delete [] pTmpBuf;
  920.                     }
  921.                 }
  922.             }
  923.             
  924.             if (bFailed)
  925.             {
  926.                 fieldType = ftUnknown;
  927.             }
  928.         }
  929.         
  930.         if (fieldType == ftUnknown)
  931.         {
  932.             // This is not a type we recognize.
  933.             // Replace the '' with a ';' so the
  934.             // value is the way it was before.
  935.             *pSemiColon = ';';
  936.         }
  937.     }
  938.     
  939.     return res;
  940. }
  941. HX_RESULT SDPMediaDescParser::HandleSpecialFields(const char* pFieldName, 
  942.                                                   char* pFieldValue, 
  943.                                                   IHXValues* pHdr)
  944. {
  945.     HX_RESULT res = HXR_FAILED;
  946.     if (!strcasecmp("Range", pFieldName))
  947.     {
  948.         res = HandleRangeField(pFieldValue, pHdr);
  949.     }
  950.     else if (!strcasecmp("length", pFieldName))
  951.     {
  952.         res = HandleLengthField(pFieldValue, pHdr);
  953.     }
  954.     else if (!strcasecmp("rtpmap", pFieldName))
  955.     {
  956.         res = HandleRTPMapField(pFieldValue, pHdr);
  957.     }
  958.     else if (!strcasecmp("fmtp", pFieldName))
  959.     {
  960.         res = HandleFMTPField(pFieldValue, pHdr);
  961.     }
  962.     else if (!strcasecmp("ptime", pFieldName))
  963.     {
  964.         // a=ptime:43
  965.         AddULONG32(pHdr, "Ptime", strtol(pFieldValue, 0, 10)); 
  966.         res = HXR_OK;
  967.     }
  968.     else if (!strcasecmp("x-bufferdelay", pFieldName))
  969.     {
  970.         // a=x-bufferdelay:234
  971.         // x-bufferdelay units are 1/1000 of a sec
  972.         res = HandlePrerollField(pFieldValue, 1000, pHdr);
  973.     }
  974.     else if (!strcasecmp("x-initpredecbufperiod", pFieldName))
  975.     {
  976.         // 3GPP 26.234 Annex G field
  977.         // a=x-initpredecbufperiod:45000
  978.         // x-initpredecbufperiod units are 1/90000 of a sec
  979.         res = HandlePrerollField(pFieldValue, 90000, pHdr);
  980.     }
  981.     else if (!strcasecmp("x-predecbufsize", pFieldName))
  982.     {
  983.         // 3GPP 26.234 Annex G field
  984.         // a=x-predecbufsize:45000
  985.         // x-predecbufsize units are bytes
  986.         AddULONG32(pHdr, "x-predecbufsize", strtoul(pFieldValue, 0, 10)); 
  987.         res = HXR_OK;
  988.     }
  989.     else if (!strcasecmp("SdpplinVersion", pFieldName))
  990.     {
  991.         res = checkVersion(strtol(pFieldValue, 0, 10));
  992.         
  993.         if (HXR_FAIL == res)
  994.         {
  995.             // need to update...
  996.             // this flag causes to exit in "m=" case
  997.             res = HXR_REQUEST_UPGRADE;
  998.         }
  999.     }
  1000.     else if (!strcasecmp("control", pFieldName))
  1001.     {
  1002.         AddString(pHdr, "Control", pFieldValue);
  1003.         res = HXR_OK;
  1004.     }
  1005.     else
  1006.     {
  1007.         res = HXR_NOT_SUPPORTED;
  1008.     }
  1009.     return res;
  1010. }
  1011. HX_RESULT SDPMediaDescParser::HandleRangeField(char* pFieldValue, 
  1012.                                                IHXValues* pHdr)
  1013. {
  1014.     char* pCur = pFieldValue;
  1015.     ULONG32 duration = 0;
  1016.     BOOL bIsLegal = TRUE;
  1017.     
  1018.     if (ScanForDelim(pCur, '='))
  1019.     {
  1020.         // replace '=' with ''
  1021.         *pCur++ = '';
  1022.         
  1023.         if (!strcasecmp(pFieldValue, "npt"))
  1024.         {
  1025.             // Look for the following npt forms
  1026.             // a=range:npt=-xxx
  1027.             // a=range:npt=xxx-
  1028.             // a=range:npt=xxx-xxx
  1029.             char* pLeftVal = pCur;
  1030.             
  1031.             if (ScanForDelim(pCur, '-'))
  1032.             {
  1033.                 // replace '-' with ''
  1034.                 
  1035.                 *pCur++ = '';
  1036.                 
  1037.                 NPTime left(pLeftVal);
  1038.                 NPTime right(pCur);
  1039.                 
  1040.                 if (*pCur)
  1041.                 {
  1042.                     // a=range:npt=xxx-xxx
  1043.                     duration = (UINT32)(right - left);
  1044.                     m_bDefiniteDuration = TRUE;
  1045.                 }
  1046.                 else
  1047.                 {
  1048.                     // a=range:npt=xxx-
  1049.                     // Treat open-ended play ranges as live streams 
  1050.                     // unless it is overridden by a media range.
  1051.                 }
  1052.             }
  1053.             else
  1054.             {
  1055.                 // This must be the following illegal form
  1056.                 // a=range:npt=xxx 
  1057.                 bIsLegal = FALSE;
  1058.             }
  1059.         }
  1060.     }
  1061.     else
  1062.     {
  1063.         duration = strtol(pFieldValue, 0, 10);
  1064.     }
  1065.     
  1066.     if (bIsLegal)
  1067.     {
  1068.         if (0 == m_ulDefaultDuration)
  1069.         {
  1070.             m_ulDefaultDuration = duration;
  1071.         }
  1072.         
  1073.         AddULONG32(pHdr, "Duration", duration);
  1074.     }
  1075.     return HXR_OK;
  1076. }
  1077. HX_RESULT SDPMediaDescParser::HandleLengthField(char* pFieldValue, 
  1078.                                                 IHXValues* pHdr)
  1079. {
  1080.     HX_RESULT res = HXR_FAILED;
  1081.     char* pCur = pFieldValue;
  1082.     ULONG32 duration = 0;
  1083.     BOOL bIsLegal = TRUE;
  1084.     // Look for the following npt form
  1085.     // a=length:npt=xxx
  1086.     if (ScanForDelim(pCur, '='))
  1087.     {
  1088.         char* pEqual = pCur;
  1089.         // replace '=' with ''
  1090.         *pCur++ = '';
  1091.         
  1092.         if (!strcasecmp(pFieldValue, "npt") && *pCur)
  1093.         {
  1094.             NPTime dTime(pCur);
  1095.             
  1096.             duration = (UINT32)dTime;
  1097.             res = HXR_OK;
  1098.         }
  1099.         else
  1100.         {
  1101.             // Put back '=' character
  1102.             *pEqual = '=';
  1103.         }
  1104.     }
  1105.     else
  1106.     {
  1107.         duration = strtol(pFieldValue, 0, 10);
  1108.         res = HXR_OK;
  1109.     }
  1110.     
  1111.     if (duration)
  1112.     {
  1113.         m_bDefiniteDuration = TRUE;
  1114.     }
  1115.     if (0 == m_ulDefaultDuration)
  1116.     {
  1117.         m_ulDefaultDuration = duration;
  1118.     }
  1119.         
  1120.     AddULONG32(pHdr, "Duration", duration);
  1121.     return res;
  1122. }
  1123. HX_RESULT SDPMediaDescParser::HandleRTPMapField(char* pFieldValue, 
  1124.                                                 IHXValues* pHdr)
  1125. {
  1126.     HX_RESULT res = HXR_FAILED;
  1127.     // e.g. a=rtpmap:101 xxx/90000/2
  1128.     char* pCur = 0;
  1129.     UINT32 payload = strtol(pFieldValue, &pCur, 10);
  1130.     ULONG32 rtpPayloadType = 0;
  1131.     res = pHdr->GetPropertyULONG32("RTPPayloadType", rtpPayloadType);
  1132.     if (*pFieldValue && (*pCur == ' '))
  1133.     {
  1134.         SkipSpaces(pCur);
  1135.         // there could be multiple of these...
  1136.         if (payload == rtpPayloadType)
  1137.         {    
  1138.             CHXString mimeType(m_mediaType);
  1139.             res = getRTPMapInfo(pCur, mimeType, pHdr);
  1140.             /* make sure there is no mime type set!
  1141.              *  MimeType from m= && a=rtpmap has the lowest precedence.
  1142.              *  a=mimetype -> mimetype table -> this mimetype
  1143.              */
  1144.             IHXBuffer* pMimeType = 0;
  1145.             if (!SUCCEEDED(pHdr->GetPropertyCString(
  1146.                 "MimeType", pMimeType)))
  1147.             {
  1148.                 AddString(pHdr, "MimeType", mimeType);
  1149.             }
  1150.             HX_RELEASE(pMimeType);
  1151.         }                
  1152.     }
  1153.                 
  1154.     return res;
  1155. }
  1156. HX_RESULT SDPMediaDescParser::HandleFMTPField(char* pFieldValue, 
  1157.                                               IHXValues* pHdr)
  1158. {
  1159.     // e.g. a=fmtp:101 emphasis=50/15;foo=bar
  1160.     char* pCur = 0;
  1161.     UINT32 payload = strtol(pFieldValue, &pCur, 10);
  1162.     ULONG32 rtpPayloadType = 0;
  1163.     HX_RESULT res = pHdr->GetPropertyULONG32("RTPPayloadType", rtpPayloadType);
  1164.     if (*pFieldValue && *pCur == ' ')
  1165.     {
  1166.         SkipSpaces(pCur);
  1167.         // If the RTPPayloadType field is present, compare it
  1168.         // to the value in the fmtp field.
  1169.         // There could be multiple of these...
  1170.         if ((HXR_OK != res) || (payload == rtpPayloadType))
  1171.         {    
  1172.             AddString(pHdr, "PayloadParameters", pCur);
  1173.         
  1174.             CHXFMTPParser fmtp(m_pCCF);
  1175.             res = fmtp.Parse(pCur, pHdr);
  1176.         }
  1177.     }
  1178.     return res;
  1179. }
  1180. HX_RESULT SDPMediaDescParser::HandlePrerollField(char* pFieldValue, 
  1181.                                                  ULONG32 ulPrerollUnits,
  1182.                                                  IHXValues* pHdr)
  1183. {
  1184.     ULONG32 ulPreroll = 0;
  1185.     
  1186.     if (HXR_OK != pHdr->GetPropertyULONG32("Preroll", ulPreroll))
  1187.     {
  1188.         ULONG32 ulValue = strtoul(pFieldValue, 0, 10);
  1189.         // Convert Preroll value to milliseconds
  1190.         ulPreroll = (ulValue / ulPrerollUnits) * 1000;
  1191.         ulPreroll += ((ulValue % ulPrerollUnits) * 1000) / ulPrerollUnits;
  1192.         
  1193.         AddULONG32(pHdr, "Preroll", ulPreroll); 
  1194.     }
  1195.     
  1196.     return HXR_OK;
  1197. }