blob: 6adb425196371ec3d494d3a919b27f684448569e [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "base_media_info_parser.h"
#include "oscl_string_utils.h"
#include "oscl_string_containers.h"
#include "rtsp_range_utils.h"
/* Function to allocate temporary buffer, OSCL_TRY() put here to avoid */
/* compiler warnings */
static void newTmpBuf(uint32 len, char** buf)
{
int32 err;
*buf = NULL;
OSCL_TRY(err, *buf = OSCL_ARRAY_NEW(char, len));
if (err != OsclErrNone)
{
*buf = NULL;
}
}
SDP_ERROR_CODE
SDPBaseMediaInfoParser::baseMediaInfoParser(const char* buff,
mediaInfo* mediaStr,
const int index,
const int alt_id,
bool alt_def_id,
bool isSipSdp)
{
const char *current_start = buff; //Pointer to the beginning of the media text
const char *end = buff + index; //Pointer to the end of the media text
const char *line_start_ptr, *line_end_ptr;
bool a_range_found = false;
bool a_rtpmap_found = false;
bool a_control_found = false;
bool a_control_set = false;
OsclMemoryFragment memFrag;
while (get_next_line(current_start, end,
line_start_ptr, line_end_ptr))
{
if ((!alt_def_id && !alt_id) || (alt_def_id) ||
((!alt_def_id) && !oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:"))))
{
if (!alt_def_id && !oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:")))
{
line_start_ptr += oscl_strlen("a=alt:");
const char *end1 = line_start_ptr;
for (; *end1 != ':'; end1++);
uint32 id;
if (!PV_atoi(line_start_ptr, 'd' , end1 - line_start_ptr, id))
return SDP_BAD_MEDIA_ALT_ID;
if ((int)id != alt_id)
{
//check if id is already present
Oscl_Vector<int, SDPParserAlloc> alt_track = mediaStr->getalternateTrackId();
bool found = false;
for (int ss = 0; ss < (int)alt_track.size(); ss++)
{
if (alt_track[ss] == (int)id)
found = true;
}
if (!found)
mediaStr->setalternateTrackId(id);
current_start = line_end_ptr;
continue;
}
line_start_ptr = end1 + 1;
line_start_ptr = skip_whitespace(line_start_ptr, line_end_ptr);
}
switch (*line_start_ptr)
{
case 'm':
{
if (*(line_start_ptr + 1) != '=')
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format"));
return SDP_BAD_MEDIA_FORMAT;
}
// parse through each field
const char *sptr, *eptr;
//line_start_ptr+2 since we need to start looking beyond the '=' sign
//get the media type (audio, video, application)
sptr = skip_whitespace(line_start_ptr + 2, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for media type"));
return SDP_BAD_MEDIA_FORMAT;
}
eptr = skip_to_whitespace(sptr, line_end_ptr);
if (eptr <= sptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format"));
return SDP_BAD_MEDIA_FORMAT;
}
memFrag.ptr = (void*)sptr;
memFrag.len = (eptr - sptr);
mediaStr->setType(memFrag);
//get the suggested port number
sptr = skip_whitespace(eptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for suggested port"));
return SDP_BAD_MEDIA_FORMAT;
}
eptr = skip_to_whitespace(sptr, line_end_ptr);
if (eptr <= sptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format"));
return SDP_BAD_MEDIA_FORMAT;
}
uint32 suggestedPort;
OSCL_HeapString<SDPParserAlloc> restOfLine(sptr, eptr - sptr);
const char *slash = oscl_strstr(restOfLine.get_cstr(), "/");
if (slash)
{
if (PV_atoi(restOfLine.get_cstr(), 'd', (slash - restOfLine.get_cstr()), suggestedPort) == true)
{
mediaStr->setSuggestedPort(suggestedPort);
// There must be number of ports info after the slash
uint32 numOfPorts;
const char *ports = oscl_strstr(sptr, "/");
ports++;
if (ports == NULL)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for ports info"));
return SDP_BAD_MEDIA_FORMAT;
}
if (PV_atoi(ports, 'd', (eptr - ports), numOfPorts) == true)
{
mediaStr->setNumOfPorts(numOfPorts);
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for ports info"));
return SDP_BAD_MEDIA_FORMAT;
}
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for ports info"));
return SDP_BAD_MEDIA_FORMAT;
}
}
else
{
if (PV_atoi(sptr, 'd', (eptr - sptr), suggestedPort) == true)
{
mediaStr->setSuggestedPort(suggestedPort);
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for ports info"));
return SDP_BAD_MEDIA_FORMAT;
}
}
//get the transport profile
sptr = skip_whitespace(eptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for tranport profile"));
return SDP_BAD_MEDIA_FORMAT;
}
eptr = skip_to_whitespace(sptr, line_end_ptr);
if (eptr <= sptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for tranport profile"));
return SDP_BAD_MEDIA_FORMAT;
}
memFrag.ptr = (void*)sptr;
memFrag.len = (eptr - sptr);
if (oscl_strncmp(sptr, "RTP/AVP", (eptr - sptr)) && oscl_strncmp(sptr, "RTP/AVPF", (eptr - sptr)) && oscl_strncmp(sptr, "RTP/SAVP", (eptr - sptr)))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for tranport profile"));
return SDP_BAD_MEDIA_FORMAT;
}
else if ((suggestedPort % 2)) // port number should be even
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format - port number is not even"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setTransportProfile(memFrag);
//get the payload number
sptr = skip_whitespace(eptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for payload number"));
return SDP_BAD_MEDIA_FORMAT;
}
while (eptr < line_end_ptr)
{
eptr = skip_to_whitespace(sptr, line_end_ptr);
if (eptr <= sptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for payload number"));
return SDP_BAD_MEDIA_FORMAT;
}
uint32 payloadNumber; ;
if (PV_atoi(sptr, 'd', (eptr - sptr), payloadNumber) == true)
{
// Parse the payload number info only and see if there
// is any payload number in static range if yes rtpmap
// field may not be present for this
for (uint32 ii = 0; ii < mediaStr->getPayloadSpecificInfoVector().size(); ii++)
{
if (payloadNumber == mediaStr->getPayloadSpecificInfoVector()[ii]->getPayloadNumber())
{
// check if (FIRST_STATIC_PAYLOAD <= payloadNumber <= LAST_STATIC_PAYLOAD)
// since payloadNumber is unsigned and FIRST_STATIC_PAYLOAD == 0, only the upper
// boundary needs to be checked. Adding the lower boundary causes compiler warning.
if (payloadNumber <= LAST_STATIC_PAYLOAD)
a_rtpmap_found = true;
}
}
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for payload number"));
return SDP_BAD_MEDIA_FORMAT;
}
sptr = skip_whitespace(eptr, line_end_ptr);
eptr = sptr;
}
// No rtpmap will come if port is 0 in sip sdp
if (isSipSdp && suggestedPort == 0)
{
a_rtpmap_found = true;
}
}
break;
case 'a':
{
if (*(line_start_ptr + 1) != '=')
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a= line format - '=' missing"));
return SDP_BAD_MEDIA_FORMAT;
}
// parse through each field
const char *sptr1, *eptr1;
if (!oscl_strncmp(line_start_ptr, "a=rtpmap:", oscl_strlen("a=rtpmap:")))
{
//get the payload number
sptr1 = line_start_ptr + oscl_strlen("a=rtpmap:");
sptr1 = skip_whitespace(sptr1, line_end_ptr);
a_rtpmap_found = true;
if (sptr1 >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format"));
return SDP_BAD_MEDIA_RTP_MAP;
}
eptr1 = skip_to_whitespace(sptr1, line_end_ptr);
if (eptr1 <= sptr1)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format"));
return SDP_BAD_MEDIA_RTP_MAP;
}
uint32 payloadNumber;
if (PV_atoi(sptr1, 'd', (eptr1 - sptr1), payloadNumber) == true)
{
int p;
if (!mediaStr->lookupPayloadNumber(payloadNumber, p))
{
break;
}
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for payload number"));
return SDP_BAD_MEDIA_RTP_MAP;
}
// payloadNumber is present in the mediaInfo. get the payload
// Specific pointer corresponding to this payload
PayloadSpecificInfoTypeBase* payloadPtr =
mediaStr->getPayloadSpecificInfoTypePtr(payloadNumber);
if (payloadPtr == NULL)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Unable to get payload pointer for the payload"));
return SDP_PAYLOAD_MISMATCH;
}
PVMF_SDP_PARSER_LOGINFO((0, "SDPBaseMediaInfoParser::parseMediaInfo - processing payload number : %d", payloadNumber));
//get the MIME type and sample rate
sptr1 = skip_whitespace(eptr1, line_end_ptr);
if (sptr1 >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for MIME Type & Sample rate"));
return SDP_BAD_MEDIA_RTP_MAP;
}
eptr1 = skip_to_whitespace(sptr1, line_end_ptr);
if (eptr1 <= sptr1)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format"));
return SDP_BAD_MEDIA_RTP_MAP;
}
//int ii = 0;
const char *tmp_end_ptr = NULL;
/*
for( ii = 0; ii < (eptr1-sptr1); ii++ )
{
if(sptr1[ii] == '/')
{
tmp_end_ptr = sptr1 + ii;
break;
}
}
*/
const char SDP_FWD_SLASH[] = "/";
tmp_end_ptr = oscl_strstr(sptr1, SDP_FWD_SLASH);
if (tmp_end_ptr == NULL)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format - nothing after '/' "));
return SDP_BAD_MEDIA_RTP_MAP;
}
//The below mentioned code converts the non standard MIME type to standard MIME type.
//For eg. earlier we have MIME type "AMR" and according to standard it should be
//like "audio/AMR". so tho whole logic implements the same.
uint32 tempBufLen = 0;
char *tmpBuf = NULL;
const char SDP_NULL[] = "\0";
tempBufLen = oscl_strlen(mediaStr->getType()) + (tmp_end_ptr - sptr1) + 2;
// "OSCL_TRY(err, OSCL_ARRAY_NEW(char, tempBufLen)" is in separate function to avoid warnings
newTmpBuf(tempBufLen, &tmpBuf);
if (NULL == tmpBuf)
{
return SDP_NO_MEMORY;
}
oscl_strncpy(tmpBuf, mediaStr->getType(), (oscl_strlen(mediaStr->getType()) + 1));
oscl_strcat(tmpBuf, SDP_FWD_SLASH);
oscl_strncat(tmpBuf, sptr1, (tmp_end_ptr - sptr1));
oscl_strcat(tmpBuf, SDP_NULL);
memFrag.ptr = (void*)tmpBuf;
memFrag.len = oscl_strlen(tmpBuf);
mediaStr->setMIMEType(memFrag);
OSCL_ARRAY_DELETE(tmpBuf);
tmpBuf = NULL;
//Till here
tmp_end_ptr++;
if (tmp_end_ptr >= eptr1)
{
return SDP_BAD_MEDIA_RTP_MAP;
}
tmp_end_ptr = skip_whitespace(tmp_end_ptr, eptr1);
if (tmp_end_ptr >= eptr1)
{
return SDP_BAD_MEDIA_RTP_MAP;
}
OSCL_HeapString<SDPParserAlloc> restOfLine(tmp_end_ptr, eptr1 - tmp_end_ptr);
const char *another_slash = oscl_strstr(restOfLine.get_cstr(), SDP_FWD_SLASH);
uint32 sampleRate;
if (another_slash)
{
if (PV_atoi(restOfLine.get_cstr(), 'd', (another_slash - restOfLine.get_cstr()), sampleRate) == true)
{
payloadPtr->setSampleRate(sampleRate);
// There must be channel numbers after the 2nd forward slash
uint32 channels;
tmp_end_ptr = oscl_strstr(tmp_end_ptr, SDP_FWD_SLASH);
if (tmp_end_ptr == NULL)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for channel info"));
return SDP_BAD_MEDIA_RTP_MAP;
}
tmp_end_ptr++;
if (PV_atoi(tmp_end_ptr, 'd', (eptr1 - tmp_end_ptr), channels) == true)
{
payloadPtr->setNoOfChannels(channels);
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for channel info"));
return SDP_BAD_MEDIA_RTP_MAP;
}
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for channel info"));
return SDP_BAD_MEDIA_RTP_MAP;
}
}
else
{
if (PV_atoi(tmp_end_ptr, 'd', (eptr1 - tmp_end_ptr), sampleRate) == true)
{
payloadPtr->setSampleRate(sampleRate);
}
else
{
return SDP_BAD_MEDIA_RTP_MAP;
}
}
}
if (!oscl_strncmp(line_start_ptr, "a=control:", oscl_strlen("a=control:")))
{
sptr1 = line_start_ptr + oscl_strlen("a=control:");
sptr1 = skip_whitespace(sptr1, line_end_ptr);
a_control_found = true;
if (sptr1 >= line_end_ptr)
{
return SDP_BAD_MEDIA_CONTROL_FIELD;
}
memFrag.ptr = (void*)sptr1;
memFrag.len = (line_end_ptr - sptr1);
mediaStr->setControlURL(memFrag);
for (int ii = 0; ii < (line_end_ptr - sptr1); ii++)
{
if (sptr1[ii] == '=')
{
uint32 trackID;
sptr1 = skip_whitespace((sptr1 + ii + 1), line_end_ptr);
if (sptr1 >= line_end_ptr)
{
break;
}
if ((PV_atoi(sptr1, 'd', 1, trackID) == true))
{
mediaStr->setControlTrackID(trackID);
}
break;
}
}
}
if (!oscl_strncmp(line_start_ptr, "a=range:", oscl_strlen("a=range:")))
{
sptr1 = line_start_ptr + oscl_strlen("a=range:");
sptr1 = skip_whitespace(sptr1, line_end_ptr);
a_range_found = true;
if (sptr1 >= line_end_ptr)
{
return SDP_BAD_MEDIA_RANGE_FIELD;
}
parseRtspRange(sptr1, line_end_ptr - sptr1, *(mediaStr->getRtspRange()));
}
if (!oscl_strncmp(line_start_ptr, "a=depends_on:", oscl_strlen("a=depends_on:")))
{
sptr1 = line_start_ptr + oscl_strlen("a=depends_on:");
memFrag.ptr = (void*)sptr1;
memFrag.len = (line_end_ptr - sptr1);
mediaStr->setDependsonURL(memFrag);
for (int ii = 0; ii < (line_end_ptr - sptr1); ii++)
{
if (sptr1[ii] == '=')
{
uint32 trackID;
sptr1 = skip_whitespace((sptr1 + ii + 1), line_end_ptr);
if (sptr1 >= line_end_ptr)
{
break;
}
if ((PV_atoi(sptr1, 'd', 1, trackID) == true))
{
mediaStr->setDependsOnTrackID(trackID);
}
break;
}
}
}
//Random access denied added for 3rd party content random positioning - 01/08/02
StrPtrLen random_access("a=random_access_denied");
if (!oscl_strncmp(line_start_ptr, random_access.c_str(), random_access.length()))
{
mediaStr->setRandomAccessDenied(true);
}
StrPtrLen qoe_metrics("a=3GPP-QoE-Metrics:");
if (!oscl_strncmp(line_start_ptr, qoe_metrics.c_str(), qoe_metrics.length()))
{
const char *sptr;
sptr = line_start_ptr + qoe_metrics.length();
QoEMetricsType qMetrics;
oscl_memset(qMetrics.name, 0, 7);
qMetrics.rateFmt = QoEMetricsType::VAL;
qMetrics.rateVal = 0;
qMetrics.paramFmt = QoEMetricsType::IDIGIT;
qMetrics.paramExtIdigit = 0;
if (!parseQoEMetrics(sptr, line_end_ptr, qMetrics))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-QoE-Metrics: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setQoEMetrics(qMetrics);
}
StrPtrLen predec("a=X-predecbufsize:");
if (!oscl_strncmp(line_start_ptr, predec.c_str(), predec.length()))
{
const char *sptr;
sptr = line_start_ptr + predec.length();
uint32 size;
if (!PV_atoi(sptr, 'd', (line_end_ptr - sptr), size))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=X-predecbufsize: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setPreDecBuffSize(size);
}
StrPtrLen initpredec("a=X-initpredecbufperiod:");
if (!oscl_strncmp(line_start_ptr, initpredec.c_str(), initpredec.length()))
{
const char *sptr;
sptr = line_start_ptr + initpredec.length();
uint32 period;
if (!PV_atoi(sptr, 'd', (line_end_ptr - sptr), period))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=X-initpredecbufperiod: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setInitPreDecBuffPeriod(period);
}
StrPtrLen initpostdec("a=X-initpostdecbufperiod:");
if (!oscl_strncmp(line_start_ptr, initpostdec.c_str(), initpostdec.length()))
{
const char *sptr;
sptr = line_start_ptr + initpostdec.length();
uint32 period;
if (!PV_atoi(sptr, 'd', (line_end_ptr - sptr), period))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=X-initpostdecbufperiod: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setInitPostDecBuffPeriod(period);
}
StrPtrLen decbyterate("a=X-decbyterate:");
if (!oscl_strncmp(line_start_ptr, decbyterate.c_str(),
decbyterate.length()))
{
const char *sptr;
sptr = line_start_ptr + decbyterate.length();
uint32 rate;
if (!PV_atoi(sptr, 'd', (line_end_ptr - sptr), rate))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=X-decbyterate: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setDecByteRate(rate);
}
StrPtrLen adapt_supp("a=3GPP-Adaptation-Support:");
if (!oscl_strncmp(line_start_ptr, adapt_supp.c_str(),
adapt_supp.length()))
{
const char *sptr = line_start_ptr + adapt_supp.length();
sptr = skip_whitespace_and_line_term(sptr, line_end_ptr);
uint32 frequency;
if (!PV_atoi(sptr, 'd', line_end_ptr - sptr, frequency))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-Adaptation-Support: line format - frequency not correct"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setReportFrequency(frequency);
}
StrPtrLen asset_info("a=3GPP-Asset-Information:");
if (!oscl_strncmp(line_start_ptr, asset_info.c_str(),
asset_info.length()))
{
const char *sptr = line_start_ptr + asset_info.length();
AssetInfoType assetInfo;
if (!parseAssetInfo(sptr, line_end_ptr, assetInfo))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-Asset-Information: line format"));
return SDP_BAD_SESSION_FORMAT;
}
mediaStr->setAssetInfo(assetInfo);
}
StrPtrLen srtp("a=3GPP-SRTP-Config:");
if (!oscl_strncmp(line_start_ptr, srtp.c_str(),
srtp.length()))
{
const char *sptr = line_start_ptr + srtp.length();
const char *eptr;
sptr = skip_whitespace(sptr, line_end_ptr);
eptr = skip_to_whitespace(sptr, line_end_ptr);
memFrag.ptr = (void *)sptr;
memFrag.len = eptr - sptr;
mediaStr->setSRTPintg_nonce(memFrag);
eptr = eptr + 1;
sptr = eptr;
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-SRTP-Config: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
eptr = skip_to_whitespace(eptr, line_end_ptr);
if (eptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-SRTP-Config: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
memFrag.ptr = (void *)sptr;
memFrag.len = eptr - sptr;
mediaStr->setSRTPkey_salt(memFrag);
eptr = eptr + 1;
sptr = eptr;
if (!oscl_strncmp(sptr, "auth-tag-len=", oscl_strlen("auth-tag-len=")))
{
sptr = sptr + oscl_strlen("auth-tag-len=");
uint32 length;
if (!PV_atoi(sptr, 'd', 2, length))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-SRTP-Config: line format for auth-tag-len= field"));
return SDP_BAD_MEDIA_FORMAT;
}
if ((length != 32) && (length != 80))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-SRTP-Config: line format for auth-tag-len= field"));
return SDP_BAD_MEDIA_FORMAT;
}
else
mediaStr->setSRTPauth_tag_len(length);
}
else
{
memFrag.ptr = (void *)sptr;
memFrag.len = line_end_ptr - sptr;
mediaStr->setSRTPparam_ext(memFrag);
}
}
StrPtrLen rtcp_fb("a=rtcp-fb:");
if (!oscl_strncmp(line_start_ptr, rtcp_fb.c_str(), rtcp_fb.length()))
{
const char *sptr = line_start_ptr + rtcp_fb.length();
const char *eptr = skip_to_whitespace(sptr, line_end_ptr);
if (eptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtcp-fb: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
memFrag.ptr = (void *)sptr;
memFrag.len = eptr - sptr;
mediaStr->setrtcp_fb_pt(memFrag);
sptr = skip_whitespace(eptr, line_end_ptr);
eptr = skip_to_whitespace(sptr, line_end_ptr);
memFrag.ptr = (void *)sptr;
memFrag.len = eptr - sptr;
mediaStr->setrtcp_fb_val(memFrag);
if (eptr >= line_end_ptr)
break;
if (!oscl_strncmp(sptr, "trr-int", eptr - sptr))
{
sptr = skip_whitespace(eptr, line_end_ptr);
eptr = skip_to_line_term(sptr, line_end_ptr);
uint32 trr;
if (!PV_atoi(sptr, 'd', eptr - sptr, trr))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtcp-fb: line format for trr-int field"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setrtcp_fb_trr_val(trr);
}
else
{
sptr = skip_whitespace(eptr, line_end_ptr);
eptr = skip_to_line_term(sptr, line_end_ptr);
memFrag.ptr = (void *)sptr;
memFrag.len = eptr - sptr;
mediaStr->setrtcp_fb_val_param(memFrag);
}
}
if (!oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:")))
{
line_start_ptr += oscl_strlen("a=alt:");
const char *end1 = line_start_ptr;
for (; *end1 != ':'; end1++);
uint32 id;
if (!PV_atoi(line_start_ptr, 'd' , end1 - line_start_ptr, id))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad ID in a=alt: line format"));
return SDP_BAD_MEDIA_ALT_ID;
}
//check if id is already present
Oscl_Vector<int, SDPParserAlloc> alt_track = mediaStr->getalternateTrackId();
bool found = false;
for (int ss = 0; ss < (int)alt_track.size(); ss++)
{
if (alt_track[ss] == (int)id)
found = true;
}
if (!found)
mediaStr->setalternateTrackId(id);
}
if (!oscl_strncmp(line_start_ptr, "a=maxprate:", oscl_strlen("a=maxprate:")))
{
line_start_ptr += oscl_strlen("a=maxprate:");
OsclFloat rate;
if (!PV_atof(line_start_ptr, line_end_ptr - line_start_ptr, rate))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=maxprate: line format for rate field"));
return SDP_BAD_MEDIA_FORMAT;
}
mediaStr->setMaxprate(rate);
}
if (!oscl_strncmp(line_start_ptr, "a=X-allowrecord", oscl_strlen("a=X-allowrecord")))
{
mediaStr->setAllowRecord(true);
}
}
break;
case 'b':
{
if (!oscl_strncmp(line_start_ptr, "b=AS:", oscl_strlen("b=AS:")))
{
const char *sptr;
sptr = line_start_ptr + oscl_strlen("b=AS:");
sptr = skip_whitespace(sptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=AS: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
uint32 bitRate;
if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), bitRate) == true)
{
mediaStr->setBitrate(1000*bitRate);
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=AS: line format - bitrate incorrect"));
return SDP_BAD_MEDIA_FORMAT;
}
}
else if (!oscl_strncmp(line_start_ptr, "b=RS:", oscl_strlen("b=RS:")))
{
const char *sptr;
sptr = line_start_ptr + oscl_strlen("b=AS:");
sptr = skip_whitespace(sptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=RS: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
uint32 rtcpBWSender;
if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), rtcpBWSender) == true)
{
mediaStr->setRTCPSenderBitRate(rtcpBWSender);
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=RS: line format - Sender Bitrate incorrect"));
return SDP_BAD_MEDIA_FORMAT;
}
}
else if (!oscl_strncmp(line_start_ptr, "b=RR:", oscl_strlen("b=RR:")))
{
const char *sptr;
sptr = line_start_ptr + oscl_strlen("b=AS:");
sptr = skip_whitespace(sptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=RR: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
uint32 rtcpBWReceiver;
if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), rtcpBWReceiver) == true)
{
mediaStr->setRTCPReceiverBitRate(rtcpBWReceiver);
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=RR: line format - Receiver Bit rate incorrect"));
return SDP_BAD_MEDIA_FORMAT;
}
}
else if (!oscl_strncmp(line_start_ptr, "b=TIAS:", oscl_strlen("b=TIAS:")))
{
const char *sptr;
sptr = line_start_ptr + oscl_strlen("b=TIAS:");
sptr = skip_whitespace(sptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=T1AS: line format"));
return SDP_BAD_MEDIA_FORMAT;
}
uint32 bMod;
if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), bMod) == true)
{
mediaStr->setBWtias(1000 * bMod);
}
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=T1AS: line format - bMod incorrect"));
return SDP_BAD_MEDIA_FORMAT;
}
}
}
break;
case 'u':
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - u field not supported"));
return SDP_BAD_MEDIA_FORMAT;
}
case 'c':
{
if (*(line_start_ptr + 1) != '=')
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - '=' missing after c"));
return SDP_BAD_SESSION_FORMAT;
}
mediaStr->setCFieldStatus(true);
// parse through each field
const char *sptr, *eptr;
// get the connection network type
sptr = skip_whitespace(line_start_ptr + 2, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - connection network type missing"));
return SDP_BAD_SESSION_FORMAT;
}
eptr = skip_to_whitespace(sptr, line_end_ptr);
if (eptr <= sptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - part after connection network type missing"));
return SDP_BAD_SESSION_FORMAT;
}
memFrag.ptr = (void*)sptr;
memFrag.len = (eptr - sptr);
mediaStr->setCNetworkType(memFrag);
// get the address type
sptr = skip_whitespace(eptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - address type missing"));
return SDP_BAD_SESSION_FORMAT;
}
eptr = skip_to_whitespace(sptr, line_end_ptr);
if (eptr <= sptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - part after address type missing"));
return SDP_BAD_SESSION_FORMAT;
}
memFrag.ptr = (void*)sptr;
memFrag.len = (eptr - sptr);
mediaStr->setCAddressType(memFrag);
// get the address
sptr = skip_whitespace(eptr, line_end_ptr);
if (sptr >= line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - address missing"));
return SDP_BAD_SESSION_FORMAT;
}
eptr = skip_to_whitespace(sptr, line_end_ptr);
if (eptr < sptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - part after address missing"));
return SDP_BAD_SESSION_FORMAT;
}
memFrag.ptr = (void*)sptr;
memFrag.len = (eptr - sptr);
mediaStr->setCAddress(memFrag);
uint32 len = OSCL_MIN((uint32)(eptr - sptr), oscl_strlen("IP4"));
if (oscl_strncmp(sptr, "IP4", len) == 0)
{
uint32 address;
const char *addrend = sptr;
for (; *addrend != '.'; ++addrend);
if (!PV_atoi(sptr, 'd', addrend - sptr, address))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
return SDP_BAD_SESSION_FORMAT;
}
if (address >= 224 && address <= 239) //multicast address look for TTL
{
for (; (*sptr != '/') && (sptr < eptr); ++sptr);
if (sptr == eptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
return SDP_BAD_SESSION_FORMAT; // no TTL found in multicast address.
}
else
{
uint32 ttl;
sptr = sptr + 1;
if (!PV_atoi(sptr, 'd', eptr - sptr, ttl))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
return SDP_BAD_SESSION_FORMAT;
}
if (!(ttl <= 255))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
return SDP_BAD_SESSION_FORMAT; // ttl out of range.
}
}
}
else // unicast address
{
for (; (*sptr != '/') && (sptr < eptr); ++sptr);
if (!oscl_strncmp(sptr, "/", 1))
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
return SDP_BAD_SESSION_FORMAT; //unicast address can not have TTL.
}
}
if (eptr < line_end_ptr)
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
return SDP_BAD_SESSION_FORMAT;
}
}
//use "len" here since "IP4" and "IP6" have same lengths
else if (oscl_strncmp(sptr, "IP6", len) == 0)
{
//TBD
}
break;
}
default:
{
//skip a line we don't understand
}
break;
}
}
current_start = line_end_ptr;
}
mediaStr->setmediaTrackId(alt_id);
if (!alt_def_id && alt_id)
{
uint32 defaultId;
getAltDefaultId(buff, buff + index, defaultId);
if (defaultId != 0)
mediaStr->setalternateTrackId(defaultId);
else
return SDP_BAD_MEDIA_ALT_ID;
}
if (!a_control_found)
{
uint32 addr;
connectionInfo ci;
mediaStr->getConnectionInformation(&ci);
PV_atoi(ci.connectionAddress.get_cstr(), 'd', addr);
//224.0.0.0 through 239.255.255.255 represent class D network addresses
//reserved for multicasting, which indicate a DVB connection
if (addr >= 224 && addr <= 239)
{
uint32 id = mediaStr->getMediaInfoID();
mediaStr->setControlTrackID(id);
a_control_set = true;
}
}
/*
* cannot assume that range is always going to be set at media level
*/
if ((isSipSdp && a_rtpmap_found) || (!alt_def_id && alt_id))
return SDP_SUCCESS;
else if ((a_rtpmap_found && a_control_found) || (!alt_def_id && alt_id) || (a_control_set))
return SDP_SUCCESS;
else
{
PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad Media - no rtpmap and control present"));
return SDP_BAD_MEDIA_FORMAT;
}
}
SDP_ERROR_CODE SDPBaseMediaInfoParser::getAltDefaultId(const char* start, const char *end, uint32 &defaultId)
{
const char *current_start = start;
const char *line_start_ptr, *line_end_ptr;
defaultId = 0;
while (get_next_line(current_start, end,
line_start_ptr, line_end_ptr))
{
switch (*line_start_ptr)
{
case 'a':
{
if (!oscl_strncmp(line_start_ptr, "a=alt-default-id:", oscl_strlen("a=alt-default-id:")))
{
line_start_ptr += oscl_strlen("a=alt-default-id:");
if (!PV_atoi(line_start_ptr, 'd', line_end_ptr - line_start_ptr, defaultId))
return SDP_BAD_MEDIA_ALT_ID;
else
return SDP_SUCCESS;
}
}
break;
default:
break;
}
current_start = line_end_ptr;
}
return SDP_SUCCESS;
}
SDP_ERROR_CODE SDPBaseMediaInfoParser::setDependentMediaId(const char *start, int length, mediaInfo *mediaPtr, int mediaId)
{
const char *startPtr = start;
const char *endLine = start + length;
while (startPtr < endLine)
{
for (; *startPtr != '='; ++startPtr);
startPtr = startPtr + 1;
if (startPtr > endLine)
return SDP_BAD_MEDIA_ALT_ID;
const char *endPtr = startPtr;
for (; (*endPtr != ';') && (endPtr != endLine); ++endPtr);
if (endPtr > endLine)
return SDP_BAD_MEDIA_ALT_ID;
if (lookForMediaId(startPtr, endPtr, mediaId))
{
while (startPtr < endPtr)
{
const char *end = startPtr;
for (; (*end != ',') && (end < endPtr) ; ++end);
uint32 id;
if (!PV_atoi(startPtr, 'd', end - startPtr, id))
return SDP_BAD_MEDIA_ALT_ID;
if ((int)id != mediaId)
mediaPtr->setdependentTrackId(id);
startPtr = end + 1;
}
}
else
startPtr = endPtr + 1;
}
return SDP_SUCCESS;
}
bool SDPBaseMediaInfoParser::lookForMediaId(const char *startPtr, const char* endPtr, int mediaId)
{
const char *end = startPtr;
while (startPtr < endPtr)
{
for (; (*end != ',') && (end < endPtr); ++end);
uint32 id;
PV_atoi(startPtr, 'd' , end - startPtr, id);
if ((int)id == mediaId)
return true;
end = end + 1;
startPtr = end;
}
return false;
}