sdpmdparse.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:37k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "sdpmdparse.h"
- #include "sdptypes.h"
- #include "sdppyldinfo.h"
- #include "rtptypes.h"
- #include "nptime.h"
- #include "rtsputil.h"
- #include "safestring.h"
- #include "chxfmtpparse.h"
- #include "chxcharstack.h"
- SDPMediaDescParser::SDPMediaDescParser(ULONG32 ulVersion) :
- m_pContext(0),
- m_pCCF(0),
- m_ulVersion(ulVersion),
- m_pFileHeader(0),
- m_bDefiniteDuration(FALSE),
- m_ulDefaultDuration(0)
- {
- }
- SDPMediaDescParser::~SDPMediaDescParser()
- {
- HX_RELEASE(m_pCCF);
- HX_RELEASE(m_pContext);
- HX_RELEASE(m_pFileHeader);
- clearStreamList();
- }
-
- HX_RESULT SDPMediaDescParser::Init(IUnknown* pContext)
- {
- HX_RESULT res = HXR_FAILED;
- HX_RELEASE(m_pContext);
- HX_RELEASE(m_pCCF);
- if (pContext)
- {
- res = pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&m_pCCF);
- if (SUCCEEDED(res) && m_pCCF)
- {
- m_pContext = pContext;
- m_pContext->AddRef();
- }
- }
- return res;
- }
- HX_RESULT SDPMediaDescParser::Parse(IHXBuffer* pDescription,
- REF(UINT16) nValues,
- REF(IHXValues**) pValueArray)
- {
- HX_RESULT theErr = HXR_OK;
- /*
- * pDescription may not be NULL terminated, so don't do ->GetBuffer()
- */
- char* pDescString = NULL;
- UINT32 ulDescStringLen = 0;
- theErr = pDescription->Get((BYTE*&)pDescString, ulDescStringLen);
- if (HXR_OK == theErr)
- theErr = fromExternalRep(pDescString, ulDescStringLen);
-
- if (HXR_OK == theErr)
- {
- nValues = m_streams.GetCount() + 1;
- IHXValues** ppHeaders = new IHXValues*[nValues];
- ppHeaders[0] = m_pFileHeader;
- ppHeaders[0]->AddRef();
- CHXSimpleList::Iterator i;
- UINT16 j=1;
- for(i = m_streams.Begin();i != m_streams.End();++i,++j)
- {
- ppHeaders[j] = (IHXValues*)(*i);
- ppHeaders[j]->AddRef();
- TakeCareOfDefaults(ppHeaders[j]);
- }
- pValueArray = ppHeaders;
- }
- return theErr;
- }
- /* right now there is only ASMRuleBook */
- void SDPMediaDescParser::TakeCareOfDefaults(IHXValues* pHeader)
- {
- HX_ASSERT(pHeader);
- IHXBuffer* pBuf = NULL;
- if (pHeader->GetPropertyCString("ASMRuleBook", pBuf) != HXR_OK)
- {
- // there is no asmrulebook...
- UINT32 ul = 0;
- if (pHeader->GetPropertyULONG32("AvgBitRate", ul) == HXR_OK)
- {
- AddRuleBook(pHeader, ul);
- }
- else
- {
- AddRuleBook(pHeader, 0);
- // add 0 bandwidth...
- pHeader->SetPropertyULONG32("AvgBitRate", 0);
- }
- }
- HX_RELEASE(pBuf);
- }
- /* if ulBW is 0, we will assume TSD */
- void SDPMediaDescParser::AddRuleBook(IHXValues* pHeader, UINT32 ulBW)
- {
- IHXBuffer* pBuf = NULL;
- m_pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pBuf);
- if (!pBuf)
- {
- // nothing we can do...
- return;
- }
- if (ulBW)
- {
- char rulebook[256] = {0}; /* Flawfinder: ignore */
-
- UINT32 ulBWHalf = ulBW / 2;
-
- SafeSprintf(rulebook,256, "marker=0,AverageBandwidth=%d;marker=1,AverageBandwidth=%d;",
- ulBW - ulBWHalf, ulBWHalf);
- pBuf->Set((BYTE*)rulebook, strlen(rulebook) + 1);
- }
- else
- {
- pBuf->Set((const BYTE*)"marker=0,timestampdelivery=1;marker=1,timestampdelivery=1;", 59);
- }
- pHeader->SetPropertyCString("ASMRuleBook", pBuf);
- HX_RELEASE(pBuf);
- }
- //
- // This is to fix a problem that causes the optimized builds
- // to cause the macintosh to crash!!!!!!!!!!!! <seanh>
- //
- #ifdef _MACINTOSH
- #pragma peephole off
- #pragma global_optimizer off
- #pragma scheduling off
- #endif
- /*
- * pData needs to be NULL terminated for we use strlen...
- */
- HX_RESULT
- SDPMediaDescParser::fromExternalRep(char* pData)
- {
- return fromExternalRep(pData, strlen(pData));
- }
- HX_RESULT
- SDPMediaDescParser::fromExternalRep(char* pData, UINT32 ulDataLen)
- {
- const char* pCur = pData;
- const char* pEnd = pData + ulDataLen;
- ULONG32 nStreams = 0;
- CHXString extraFields;
- m_bDefiniteDuration = FALSE;
- m_ulDefaultDuration = 0;
- m_mediaType.Empty();
- m_pFileHeader = CreateHeader();
- IHXValues* pHdr = m_pFileHeader;
- HX_RESULT res = (pHdr) ? HXR_OK : HXR_OUTOFMEMORY;
-
- while((HXR_OK == res) && *pCur && (pCur < pEnd))
- {
- // Skip n or 'r' characters
- for(; *pCur && (pCur < pEnd) && strchr("rn", *pCur); pCur++)
- ;
- if (*pCur && (pCur < pEnd))
- {
- char lineType = *pCur++;
-
- if (*pCur == '=')
- {
- pCur++; // skip '='
- IHXBuffer* pSDPLine = 0;
- res = GetLine(pCur, pEnd, pSDPLine);
- if (HXR_OK == res)
- {
- char* pLine = (char*)pSDPLine->GetBuffer();
- //printf ("line %c '%s'n", lineType, pLine);
- switch(lineType) {
- case 'v':
- res = HandleVLine(pLine);
- break;
- case 'm':
- if (!extraFields.IsEmpty())
- {
- AddString(pHdr, "SDPData",
- (const char*)extraFields);
- extraFields.Empty();
- }
- pHdr = CreateHeader();
- m_streams.AddTail(pHdr);
- AddULONG32(pHdr, "StreamNumber", nStreams);
- nStreams++;
- // Propagate default duration to new stream
- if (0 != m_ulDefaultDuration)
- {
- AddULONG32(pHdr, "Duration", m_ulDefaultDuration);
- }
- res = HandleMLine(pLine, pHdr);
- break;
- case 'a':
- res = HandleALine(pLine, pHdr);
- break;
- case 'c':
- res = HandleCLine(pLine, pHdr);
- break;
- case 'b':
- res = HandleBLine(pLine, pHdr);
- break;
- case 'i':
- AddString(pHdr, "Information", pLine);
- res = HXR_OK;
- break;
- case 'o':
- case 's':
- case 't':
- // ignore these lines
- res = HXR_OK;
- break;
- default:
- res = HXR_NOT_SUPPORTED;
- break;
- };
- if (HXR_NOT_SUPPORTED == res)
- {
- extraFields += lineType;
- extraFields += '=';
- extraFields += pLine;
- extraFields += "n";
-
- res = HXR_OK;
- }
- pSDPLine->Release();
- pSDPLine = 0;
- }
- }
- else
- {
- res = HXR_FAILED;
- }
- }
- }
- if (HXR_OK == res)
- {
- if (!extraFields.IsEmpty())
- {
- AddString(pHdr, "SDPData",
- (const char*)extraFields);
- extraFields.Empty();
- }
- /* Only add StreamCount and LiveStream fields
- * if we have at least 1 stream. This prevents
- * the fields from appearing when we are using
- * the SDP plugin to parse partial SDP chunks.
- */
- if (nStreams)
- {
- AddULONG32(m_pFileHeader, "StreamCount", nStreams);
-
- ULONG32 ulLive;
- if (!m_bDefiniteDuration &&
- (m_ulDefaultDuration == 0) &&
- (!SUCCEEDED(m_pFileHeader->GetPropertyULONG32("LiveStream",
- ulLive))))
- {
- AddULONG32(m_pFileHeader, "LiveStream", 1);
- }
- }
- }
-
- return res;
- }
- #ifdef _MACINTOSH
- #pragma peephole reset
- #pragma global_optimizer reset
- #pragma scheduling reset
- #endif
- /*
- * Payload table contains reserved/unassigned types as well. So, this func
- * returns if the table contains a valid info
- */
- BOOL
- SDPMediaDescParser::IsPayloadTableValid(UINT32 ulPayloadType)
- {
- HX_ASSERT(SDPIsStaticPayload(ulPayloadType));
- if (!SDPMapPayloadToEncodingName(ulPayloadType))
- {
- return FALSE;
- }
- return TRUE;
- }
- HX_RESULT
- SDPMediaDescParser::getRTPMapInfo(const char* pMapInfo,
- REF(CHXString) strMimeType,
- IHXValues* pStream)
- {
- if (!pMapInfo || !strMimeType.GetLength() || !pStream)
- {
- return HXR_FAIL;
- }
-
- /*
- * It could be either:
- * EncodingName
- * EncodingName/SamplesPerSecond
- * EncodingName/SamplesPerSecond/Channels
- */
- strMimeType += "/";
- char* pTok = strchr((char*)pMapInfo, ' ');
- if (pTok)
- {
- *pTok = ' ';
- }
- pTok = (char*)pMapInfo;
- char* pTokNext = strchr(pTok, '/');
- if (pTokNext)
- {
- *pTokNext++ = ' ';
- strMimeType += pTok;
- pTok = pTokNext;
- pTokNext = strchr((char*)pTok, '/');
- if (pTokNext)
- {
- *pTokNext++ = ' ';
- AddULONG32(pStream, "SamplesPerSecond", strtol(pTok, 0, 10));
- AddULONG32(pStream, "Channels", strtol(pTokNext, 0, 10));
- }
- else
- {
- AddULONG32(pStream, "SamplesPerSecond", strtol(pTok, 0, 10));
- }
- }
- else
- {
- // this is just an encoding name
- strMimeType += pMapInfo;
- }
-
- return HXR_OK;
- }
- /*
- * Compare ulVersion against m_ulVersion. and returns HXR_FAIL iff
- * ulVersion < m_ulVersion ---> need auto update.
- */
- HX_RESULT
- SDPMediaDescParser::checkVersion(UINT32 ulVersion)
- {
- HX_ASSERT(m_ulVersion);
- UINT32 ulPluginMajor = HX_GET_MAJOR_VERSION(m_ulVersion);
- UINT32 ulPluginMinor = HX_GET_MINOR_VERSION(m_ulVersion);
- UINT32 ulDataMajor = HX_GET_MAJOR_VERSION(ulVersion);
- UINT32 ulDataMinor = HX_GET_MINOR_VERSION(ulVersion);
- if((ulDataMajor > ulPluginMajor) ||
- (ulDataMajor == ulPluginMajor && ulDataMinor > ulPluginMinor))
- {
- return HXR_FAIL;
- }
- else
- {
- return HXR_OK;
- }
- }
- void SDPMediaDescParser::clearStreamList()
- {
- LISTPOSITION pos = m_streams.GetHeadPosition();
- while(pos)
- {
- IHXValues* pStream = (IHXValues*)m_streams.GetNext(pos);
- HX_RELEASE(pStream);
- }
- m_streams.RemoveAll();
- }
- IHXValues* SDPMediaDescParser::CreateHeader()
- {
- IHXValues* pRet = 0;
- if (m_pCCF)
- m_pCCF->CreateInstance(IID_IHXValues, (void**)&pRet);
- return pRet;
- }
- void SDPMediaDescParser::AddULONG32(IHXValues* pHeader,
- const char* pKey, ULONG32 ulValue)
- {
- pHeader->SetPropertyULONG32(pKey, ulValue);
- }
- void SDPMediaDescParser::AddString(IHXValues* pHeader,
- const char* pKey,
- const char* pValue)
- {
- if ((pKey == NULL) || (pValue == NULL))
- {
- return;
- }
- IHXBuffer* pBuf = CopyBuffer((const UINT8*)pValue, strlen(pValue) + 1);
- if (pBuf)
- pHeader->SetPropertyCString(pKey, pBuf);
- HX_RELEASE(pBuf);
- }
- void SDPMediaDescParser::AddBuffer(IHXValues* pHeader,
- const char* pKey,
- const UINT8* pValue,
- ULONG32 ulLength)
- {
- IHXBuffer* pBuf = CopyBuffer(pValue, ulLength);
- if (pBuf)
- pHeader->SetPropertyBuffer(pKey, pBuf);
- HX_RELEASE(pBuf);
- }
- IHXBuffer* SDPMediaDescParser::CopyBuffer(const UINT8* pBuf, ULONG32 ulLength)
- {
- IHXBuffer* pRet = 0;
- if (SUCCEEDED(m_pCCF->CreateInstance(IID_IHXBuffer, (void**)&pRet)))
- pRet->Set(pBuf, ulLength);
- return pRet;
- }
- HX_RESULT SDPMediaDescParser::GetLine(const char*& pData,
- const char* pEnd,
- IHXBuffer*& pLine) const
- {
- HX_RESULT res = HXR_OK;
- CHXCharStack tok(m_pCCF);
- BOOL bInQuote = FALSE;
- BOOL bLastWasEscape = FALSE;
- for (; (HXR_OK == res) && *pData && (pData < pEnd) && (bInQuote || !strchr("rn", *pData)); pData++)
- {
- if (bLastWasEscape)
- {
- bLastWasEscape = FALSE;
- }
- else
- {
- if (*pData == '"')
- {
- bInQuote = !bInQuote;
- }
- else if (*pData == '\')
- {
- bLastWasEscape = TRUE;
- }
- }
- res = tok.AddChar(*pData);
- }
- if (HXR_OK == res)
- {
- res = tok.Finish(pLine);
- }
- return res;
- }
- void SDPMediaDescParser::SkipSpaces(char*& pData) const
- {
- for (; *pData && *pData == ' '; pData++)
- ;
- }
- BOOL SDPMediaDescParser::ScanForDelim(char*& pData, char delim) const
- {
- BOOL bRet = FALSE;
- while(*pData && !bRet)
- {
- if (*pData == delim)
- {
- bRet = TRUE;
- }
- else
- {
- pData++;
- }
- }
- return bRet;
- }
- HX_RESULT SDPMediaDescParser::HandleVLine(char* pLine)
- {
- HX_RESULT res = HXR_FAILED;
-
- char* pEnd = 0;
- unsigned long version = strtoul(pLine, &pEnd, 10);
- if (*pLine && !*pEnd && (version == 0))
- {
-
- res = HXR_OK;
- }
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandleMLine(char* pLine, IHXValues* pHdr)
- {
- HX_RESULT res = HXR_FAILED;
- if (*pLine)
- {
- int state = 0;
- const char* pMediaType = pLine;
- ULONG32 ulPort = 0;
- ULONG32 ulPayloadType = 0;
-
- if (ScanForDelim(pLine, ' '))
- {
- // Null terminate mimetype
- *pLine++ = ' ';
- // Save media type for later
- m_mediaType = pMediaType;
- res = HXR_OK;
- }
- while(*pLine && (HXR_OK == res))
- {
- char* pEnd = 0;
- SkipSpaces(pLine);
-
- if (*pLine)
- {
- switch(state) {
- case 0:
- // Grab port number
- ulPort = strtoul(pLine, &pEnd, 10);
- if (*pEnd == ' ')
- {
- pLine = pEnd;
- state = 1;
- }
- else
- {
- // No transport field or
- // invalid port character
- res = HXR_FAILED;
- }
- break;
- case 1:
- // Skip transport. Usually RTP/AVP
- if (ScanForDelim(pLine, ' '))
- {
- state = 2;
- }
- break;
- case 2:
- // Grab the first payload type
- ulPayloadType = strtoul(pLine, &pEnd, 10);
- if ((*pEnd == ' ') || !*pEnd )
- {
- state = 3;
- }
- else
- {
- // There was an unexpected character
- // the the payload type
- res = HXR_FAILED;
- }
- case 3:
- // Consume the rest of the payload types
- for (; *pLine; pLine++)
- ;
- break;
- }
- }
- }
- if (state == 3)
- {
- AddULONG32(pHdr, "RTPPayloadType", ulPayloadType);
-
- if (ulPort)
- {
- AddULONG32(pHdr, "Port", ulPort);
- }
- if (SDPIsStaticPayload(ulPayloadType))
- {
- if (IsPayloadTableValid(ulPayloadType))
- {
- if (!SDPIsTimestampDeliverable(ulPayloadType))
- {
- ULONG32 ulBitrate =
- SDPMapPayloadToBitrate(ulPayloadType);
- HX_ASSERT(ulBitrate);
- // we have a bandwidth info in a table...
- AddULONG32(pHdr, "AvgBitRate", ulBitrate);
- }
- // static payload type
- AddString(pHdr, "MimeType",
- SDPMapPayloadToMimeType(ulPayloadType));
- AddULONG32(pHdr,
- "RTPTimestampConversionFactor",
- SDPMapPayloadToRTPFactor(ulPayloadType));
- AddULONG32(pHdr,
- "HXTimestampConversionFactor",
- SDPMapPayloadToRMAFactor(ulPayloadType));
- AddULONG32(pHdr,
- "SamplesPerSecond",
- SDPMapPayloadToSamplesPerSecond(ulPayloadType));
- AddULONG32(pHdr,
- "Channels",
- (ULONG32)SDPMapPayloadToChannels(ulPayloadType));
- // deal with opaque hack...
- const BYTE* pOpaqueData = NULL;
- ULONG32 ulOpaqueDataSize = 0;
- switch(ulPayloadType)
- {
- case RTP_PAYLOAD_GSM:
- pOpaqueData =
- SDPMapPayloadToHeaderData(RTP_PAYLOAD_GSM,
- ulOpaqueDataSize);
- break;
- }
-
- if (pOpaqueData)
- {
- AddBuffer(pHdr, "OpaqueData",
- pOpaqueData, ulOpaqueDataSize);
- }
- }
- else
- {
- res = HXR_REQUEST_UPGRADE;
- }
- }
- }
- else if (HXR_OK == res)
- {
- res = HXR_FAILED;
- }
- }
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandleALine(char* pLine, IHXValues* pHdr)
- {
- HX_RESULT res = HXR_FAILED;
-
- const char* pFieldName = pLine;
- char* pFieldValue = 0;
- FieldType fieldType = ftUnknown;
-
- if (*pLine)
- {
- // Collect the field name
- if (ScanForDelim(pLine, ':'))
- {
- char* pColon = pLine;
- // Must be the key/value form
- // a=foo:bar
-
- // Null terminate field name by replacing ':' with ' '
- *pLine++ = ' ';
-
- pFieldValue = pLine;
- if ((HXR_OK == (res = ParseFieldValue(pFieldValue, fieldType))))
- {
- switch (fieldType) {
- case ftUnknown:
- res = HandleSpecialFields(pFieldName, pFieldValue, pHdr);
- break;
- case ftULONG32:
- {
- char* pEnd = 0;
- ULONG32 ulValue = strtoul(pFieldValue, &pEnd, 10);
-
- if (*pFieldValue && !*pEnd)
- {
- res = pHdr->SetPropertyULONG32(pFieldName, ulValue);
- }
- } break;
- case ftString:
- AddString(pHdr, pFieldName, pFieldValue);
- res = HXR_OK;
- break;
- case ftBuffer:
- {
- int length = strlen(pFieldValue);
- BYTE* pDecodeBuf = new BYTE[length];
- INT32 decodeLen = BinFrom64(pFieldValue, length,
- pDecodeBuf);
- if( decodeLen != -1 )
- {
- AddBuffer(pHdr, pFieldName, pDecodeBuf, decodeLen);
- }
- res = HXR_OK;
- delete [] pDecodeBuf;
- }break;
- }
- }
-
- if (HXR_OK != res)
- {
- // Put back the ':'
- *pColon = ':';
- }
- }
- else
- {
- // Must be the key only form
- // a=foo
- res = HXR_NOT_SUPPORTED;
- }
- }
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandleCLine(char* pLine, IHXValues* pHdr)
- {
- // Handles the following forms
- // c=IN IP4 xxx.xxx.xxx.xxx
- // c=IN IP4 xxx.xxx.xxx.xxx/xxx
- // c=IN IP4 xxx.xxx.xxx.xxx/xxx/xx
- HX_RESULT res = HXR_FAILED;
-
- char* pCur = pLine;
- if (ScanForDelim(pCur, ' '))
- {
- *pCur++ = ' ';
-
- SkipSpaces(pCur);
- char* pAddrType = pCur;
- if (!strcasecmp(pLine, "IN") && ScanForDelim(pCur, ' '))
- {
- *pCur++ = ' ';
- SkipSpaces(pCur);
- if (!strcasecmp(pAddrType, "IP4") && *pCur)
- {
- char* pAddr = pCur;
- if (ScanForDelim(pCur, '/'))
- {
- *pCur++ = ' ';
- if (*pCur)
- {
- char* pEnd = 0;
- ULONG32 ulTTL = strtoul(pCur, &pEnd, 10);
- if (*pCur && ((*pEnd == '/') || (!*pEnd)))
- {
- AddULONG32(pHdr, "MulticastTTL", ulTTL);
- res = HXR_OK;
- pCur = pEnd;
- if (*pCur)
- {
- pCur++; // skip '/'
- ULONG32 ulRange = strtoul(pCur, &pEnd, 10);
-
- if (*pCur && !*pEnd)
- {
- // c=IN IP4 xxx.xxx.xxx.xxx/xxx/xx
- AddULONG32(pHdr, "MulticastRange", ulRange);
- res = HXR_OK;
- }
- }
- }
- }
- }
- else
- {
- // c=IN IP4 xxx.xxx.xxx.xxx
- res = HXR_OK;
- }
- if (HXR_OK == res)
- {
- AddString(pHdr, "MulticastAddress", pAddr);
- }
- }
- }
- }
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandleBLine(char* pLine, IHXValues* pHdr)
- {
- HX_RESULT res = HXR_FAILED;
- char* pCur = pLine;
- if (ScanForDelim(pCur, ':'))
- {
- char* pColon = pCur;
- *pCur++ = ' ';
-
- char* pEnd = 0;
- ULONG32 ulBwValue = strtoul(pCur, &pEnd, 10);
- if (*pCur && !*pEnd)
- {
- const char* pBwKey = 0;
- res = HXR_OK;
- if (!strcasecmp(pLine, "AS"))
- {
- // a=AvgBitRate has the higher precedence...
- ULONG32 ulTmp;
- if (!SUCCEEDED(pHdr->GetPropertyULONG32("AvgBitRate",
- ulTmp)))
- {
- // use this as a default.
- // it's kilobits per sec....
- pBwKey = "AvgBitRate";
- ulBwValue *= 1000;
- }
- }
- else if (!strcasecmp(pLine, "RR"))
- {
- pBwKey = "RtcpRRRate";
- }
- else if (!strcasecmp(pLine, "RS"))
- {
- pBwKey = "RtcpRSRate";
- }
- else
- {
- res = HXR_NOT_SUPPORTED;
- }
- if (pBwKey)
- {
- AddULONG32(pHdr, pBwKey, ulBwValue);
- }
- }
-
- *pColon = ':';
- }
- return res;
- }
- HX_RESULT SDPMediaDescParser::ParseFieldValue(char*& pValue,
- FieldType& fieldType) const
- {
- HX_RESULT res = HXR_OK;
- char* pCur = pValue;
- // Look for the following forms
- // a=anInt:integer;43
- // a=aString:string;"this is a string"
- // a=aBuffer:buffer;"TWFjIFRWAA=="
- // Assume we don't know the type.
- fieldType = ftUnknown;
- if (ScanForDelim(pCur, ';'))
- {
- // Replace the ';' with a ' ' so we
- // can check to see if it matches the known
- // types
- char* pSemiColon = pCur;
- *pCur++ = ' ';
- if (!strcmp(pValue, "integer"))
- {
- // Update the value pointer to the
- // start of the integer value
- pValue = pCur;
- fieldType = ftULONG32;
- }
- else if (!strcmp(pValue, "string"))
- {
- fieldType = ftString;
- }
- else if (!strcmp(pValue, "buffer"))
- {
- fieldType = ftBuffer;
- }
- if ((fieldType == ftString) || (fieldType == ftBuffer))
- {
- BOOL bFailed = TRUE;
- // Look for starting '"'
- if (*pCur == '"')
- {
- pCur++; // skip '"'
- if (*pCur)
- {
- // Store start of the string
- char* pStrStart = pCur;
- // Create temporary buffer for unescaping
- char* pTmpBuf = new char[strlen(pStrStart) + 1];
- if (pTmpBuf)
- {
- char* pDest = pTmpBuf;
- // Copy string into pTmpBuf and
- // unescape any escape sequences
- while (*pCur && *pCur != '"')
- {
- if (*pCur == '\')
- {
- *pCur++; // skip '\'
- }
-
- *pDest++ = *pCur++;
- }
-
- // Make sure the last character is a '"'
- if (*pCur == '"')
- {
- // Replace ending '"' with ' '
- *pDest = ' ';
- // Replace escaped string with
- // unescaped string.
- strcpy(pStrStart, pTmpBuf);
- // Update the value pointer to the
- // start of the string value
- pValue = pStrStart;
- bFailed = FALSE;
- }
- delete [] pTmpBuf;
- }
- }
- }
-
- if (bFailed)
- {
- fieldType = ftUnknown;
- }
- }
-
- if (fieldType == ftUnknown)
- {
- // This is not a type we recognize.
- // Replace the ' ' with a ';' so the
- // value is the way it was before.
- *pSemiColon = ';';
- }
- }
-
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandleSpecialFields(const char* pFieldName,
- char* pFieldValue,
- IHXValues* pHdr)
- {
- HX_RESULT res = HXR_FAILED;
- if (!strcasecmp("Range", pFieldName))
- {
- res = HandleRangeField(pFieldValue, pHdr);
- }
- else if (!strcasecmp("length", pFieldName))
- {
- res = HandleLengthField(pFieldValue, pHdr);
- }
- else if (!strcasecmp("rtpmap", pFieldName))
- {
- res = HandleRTPMapField(pFieldValue, pHdr);
- }
- else if (!strcasecmp("fmtp", pFieldName))
- {
- res = HandleFMTPField(pFieldValue, pHdr);
- }
- else if (!strcasecmp("ptime", pFieldName))
- {
- // a=ptime:43
- AddULONG32(pHdr, "Ptime", strtol(pFieldValue, 0, 10));
- res = HXR_OK;
- }
- else if (!strcasecmp("x-bufferdelay", pFieldName))
- {
- // a=x-bufferdelay:234
- // x-bufferdelay units are 1/1000 of a sec
- res = HandlePrerollField(pFieldValue, 1000, pHdr);
- }
- else if (!strcasecmp("x-initpredecbufperiod", pFieldName))
- {
- // 3GPP 26.234 Annex G field
- // a=x-initpredecbufperiod:45000
- // x-initpredecbufperiod units are 1/90000 of a sec
- res = HandlePrerollField(pFieldValue, 90000, pHdr);
- }
- else if (!strcasecmp("x-predecbufsize", pFieldName))
- {
- // 3GPP 26.234 Annex G field
- // a=x-predecbufsize:45000
- // x-predecbufsize units are bytes
- AddULONG32(pHdr, "x-predecbufsize", strtoul(pFieldValue, 0, 10));
- res = HXR_OK;
- }
- else if (!strcasecmp("SdpplinVersion", pFieldName))
- {
- res = checkVersion(strtol(pFieldValue, 0, 10));
-
- if (HXR_FAIL == res)
- {
- // need to update...
- // this flag causes to exit in "m=" case
- res = HXR_REQUEST_UPGRADE;
- }
- }
- else if (!strcasecmp("control", pFieldName))
- {
- AddString(pHdr, "Control", pFieldValue);
- res = HXR_OK;
- }
- else
- {
- res = HXR_NOT_SUPPORTED;
- }
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandleRangeField(char* pFieldValue,
- IHXValues* pHdr)
- {
- char* pCur = pFieldValue;
- ULONG32 duration = 0;
- BOOL bIsLegal = TRUE;
-
- if (ScanForDelim(pCur, '='))
- {
- // replace '=' with ' '
- *pCur++ = ' ';
-
- if (!strcasecmp(pFieldValue, "npt"))
- {
- // Look for the following npt forms
- // a=range:npt=-xxx
- // a=range:npt=xxx-
- // a=range:npt=xxx-xxx
- char* pLeftVal = pCur;
-
- if (ScanForDelim(pCur, '-'))
- {
- // replace '-' with ' '
-
- *pCur++ = ' ';
-
- NPTime left(pLeftVal);
- NPTime right(pCur);
-
- if (*pCur)
- {
- // a=range:npt=xxx-xxx
- duration = (UINT32)(right - left);
- m_bDefiniteDuration = TRUE;
- }
- else
- {
- // a=range:npt=xxx-
- // Treat open-ended play ranges as live streams
- // unless it is overridden by a media range.
- }
- }
- else
- {
- // This must be the following illegal form
- // a=range:npt=xxx
- bIsLegal = FALSE;
- }
- }
- }
- else
- {
- duration = strtol(pFieldValue, 0, 10);
- }
-
- if (bIsLegal)
- {
- if (0 == m_ulDefaultDuration)
- {
- m_ulDefaultDuration = duration;
- }
-
- AddULONG32(pHdr, "Duration", duration);
- }
- return HXR_OK;
- }
- HX_RESULT SDPMediaDescParser::HandleLengthField(char* pFieldValue,
- IHXValues* pHdr)
- {
- HX_RESULT res = HXR_FAILED;
- char* pCur = pFieldValue;
- ULONG32 duration = 0;
- BOOL bIsLegal = TRUE;
- // Look for the following npt form
- // a=length:npt=xxx
- if (ScanForDelim(pCur, '='))
- {
- char* pEqual = pCur;
- // replace '=' with ' '
- *pCur++ = ' ';
-
- if (!strcasecmp(pFieldValue, "npt") && *pCur)
- {
- NPTime dTime(pCur);
-
- duration = (UINT32)dTime;
- res = HXR_OK;
- }
- else
- {
- // Put back '=' character
- *pEqual = '=';
- }
- }
- else
- {
- duration = strtol(pFieldValue, 0, 10);
- res = HXR_OK;
- }
-
- if (duration)
- {
- m_bDefiniteDuration = TRUE;
- }
- if (0 == m_ulDefaultDuration)
- {
- m_ulDefaultDuration = duration;
- }
-
- AddULONG32(pHdr, "Duration", duration);
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandleRTPMapField(char* pFieldValue,
- IHXValues* pHdr)
- {
- HX_RESULT res = HXR_FAILED;
- // e.g. a=rtpmap:101 xxx/90000/2
- char* pCur = 0;
- UINT32 payload = strtol(pFieldValue, &pCur, 10);
- ULONG32 rtpPayloadType = 0;
- res = pHdr->GetPropertyULONG32("RTPPayloadType", rtpPayloadType);
- if (*pFieldValue && (*pCur == ' '))
- {
- SkipSpaces(pCur);
- // there could be multiple of these...
- if (payload == rtpPayloadType)
- {
- CHXString mimeType(m_mediaType);
- res = getRTPMapInfo(pCur, mimeType, pHdr);
- /* make sure there is no mime type set!
- * MimeType from m= && a=rtpmap has the lowest precedence.
- * a=mimetype -> mimetype table -> this mimetype
- */
- IHXBuffer* pMimeType = 0;
- if (!SUCCEEDED(pHdr->GetPropertyCString(
- "MimeType", pMimeType)))
- {
- AddString(pHdr, "MimeType", mimeType);
- }
- HX_RELEASE(pMimeType);
- }
- }
-
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandleFMTPField(char* pFieldValue,
- IHXValues* pHdr)
- {
- // e.g. a=fmtp:101 emphasis=50/15;foo=bar
- char* pCur = 0;
- UINT32 payload = strtol(pFieldValue, &pCur, 10);
- ULONG32 rtpPayloadType = 0;
- HX_RESULT res = pHdr->GetPropertyULONG32("RTPPayloadType", rtpPayloadType);
- if (*pFieldValue && *pCur == ' ')
- {
- SkipSpaces(pCur);
- // If the RTPPayloadType field is present, compare it
- // to the value in the fmtp field.
- // There could be multiple of these...
- if ((HXR_OK != res) || (payload == rtpPayloadType))
- {
- AddString(pHdr, "PayloadParameters", pCur);
-
- CHXFMTPParser fmtp(m_pCCF);
- res = fmtp.Parse(pCur, pHdr);
- }
- }
- return res;
- }
- HX_RESULT SDPMediaDescParser::HandlePrerollField(char* pFieldValue,
- ULONG32 ulPrerollUnits,
- IHXValues* pHdr)
- {
- ULONG32 ulPreroll = 0;
-
- if (HXR_OK != pHdr->GetPropertyULONG32("Preroll", ulPreroll))
- {
- ULONG32 ulValue = strtoul(pFieldValue, 0, 10);
- // Convert Preroll value to milliseconds
- ulPreroll = (ulValue / ulPrerollUnits) * 1000;
- ulPreroll += ((ulValue % ulPrerollUnits) * 1000) / ulPrerollUnits;
-
- AddULONG32(pHdr, "Preroll", ulPreroll);
- }
-
- return HXR_OK;
- }