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

Symbian

开发平台:

C/C++

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