/* ------------------------------------------------------------------
 * 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;
}

