/* ------------------------------------------------------------------
 * 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 "sdp_parser.h"
#include "sdp_mediaparser_registry.h"
#include "oscl_string_utils.h"
#include "oscl_string_containers.h"
#include "oscl_str_ptr_len.h"
#include "base_media_info_parser.h"
#include "aac_media_info_parser.h"
#include "amr_media_info_parser.h"
#include "h263_media_info_parser.h"
#include "m4v_media_info_parser.h"
#include "still_image_media_info_parser.h"
#include "pcma_media_info_parser.h"
#include "pcmu_media_info_parser.h"
#include "oscl_vector.h"
#include "oscl_dll.h"

OSCL_DLL_ENTRY_POINT_DEFAULT()
struct mime_payload_pair
{
    OsclMemoryFragment mime;
    Oscl_Vector<int, SDPParserAlloc> payload_no;
};

OSCL_EXPORT_REF SDP_Parser::SDP_Parser(SDPMediaParserRegistry*& regTable, bool sipSdp):
        iLogger(NULL),
        _pSDPMediaParserRegistry(regTable),
        mediaArrayIndex(0),
        applicationFlag(false),
        isSipSdp(sipSdp)
{
    iLogger = PVLogger::GetLoggerObject("SDP_Parser");
}


OSCL_EXPORT_REF SDP_Parser::~SDP_Parser()
{
}

bool SDP_Parser::parse_rtpmap(const char *start, const char *end, int& rtp_payload,
                              OsclMemoryFragment& encoding_name)
{
    const int len_of_rtpmap = 9;

    // grab the endpoints
    const char *sptr = start + len_of_rtpmap;
    const char *eptr;

    // skip to the first whitespace character
    eptr = skip_to_whitespace(sptr, end);
    if (eptr < sptr)
    {
        return false;
    }
    uint32 rtpPayload;
    if (PV_atoi(sptr, 'd', (eptr - sptr), rtpPayload) == false)
    {
        return false;
    }
    rtp_payload = (int)rtpPayload;

    // now get the encoding name
    sptr = skip_whitespace(eptr, end);
    if (sptr >= end)
    {
        return false;
    }

    // now skip to end of the encoding name
    for (eptr = sptr; eptr < end &&
            (*eptr != ' ' && *eptr != '\t' && *eptr != '/');
            ++eptr);

    if (eptr >= end)
    {
        return false;
    }

    encoding_name.ptr = (void *) sptr;
    encoding_name.len = eptr - sptr;

    return true;
}


int SDP_Parser::validate_media_line(const char *start, const char *end, Oscl_Vector<int, SDPParserAlloc>& payload_type, uint32& portNumber)
{
    int len;
    const char *sptr, *eptr;

    sptr = start + 2;  // start after the "m="
    // skip to end of media type
    eptr = skip_to_whitespace(sptr, end);
    if (eptr >= end)
    {
        return 0;
    }


    len = eptr - sptr;
    // make sure type is supported
    if (!oscl_CIstrncmp(sptr, "audio", len) || !oscl_CIstrncmp(sptr, "video", len) ||
            !oscl_CIstrncmp(sptr, "application", len))
    {
        // the type is supported
        // make sure there is only one payload type in the format list

        // skip to start of port number
        sptr = skip_whitespace(eptr, end);
        if (sptr >= end)
        {
            return 0;
        }

        // skip to end of port number
        eptr = skip_to_whitespace(sptr, end);
        if (eptr <= sptr)
        {
            return 0;
        }

        const char *tmp_end_ptr = sptr;
        const char SDP_FWD_SLASH[] = "/";

        OSCL_HeapString<SDPParserAlloc> restOfLine(tmp_end_ptr, eptr - tmp_end_ptr);
        const char *slash = oscl_strstr(restOfLine.get_cstr(), SDP_FWD_SLASH);

        if (slash == NULL)
        {
            // Get the port number
            if (PV_atoi(sptr, 'd', (eptr - sptr), portNumber) == false)
            {
                return 0;
            }
        }
        else
        {
            // Get the port number
            if (PV_atoi(restOfLine.get_cstr(), 'd', (slash - restOfLine.get_cstr()), portNumber) == false)
            {
                return 0;
            }
        }

        // skip to start of transport
        sptr = skip_whitespace(eptr, end);
        if (sptr >= end)
        {
            return 0;
        }

        // skip to end of transport
        eptr = skip_to_whitespace(sptr, end);
        if (eptr <= sptr)
        {
            return 0;
        }

        // skip to start of format list
        sptr = skip_whitespace(eptr, end);
        if (sptr >= end)
        {
            return 0;
        }

        // skip to end of first payload arg
        eptr = skip_to_whitespace(sptr, end);
        if (eptr <= sptr)
        {
            return 0;
        }

        // record the payload type for non-application m= lines
        if (oscl_strncmp(start + 2, "application", len))
        {
            uint32 payloadType;

            while (sptr < end)
            {
                if (PV_atoi(sptr, 'd', (eptr - sptr), payloadType) == false)
                {
                    return 0;
                }

                payload_type.push_back(payloadType);

                sptr = skip_to_whitespace(sptr, end);
                sptr = skip_whitespace_and_line_term(eptr, end);
                eptr = skip_whitespace_and_line_term(eptr, end);
                eptr = skip_to_whitespace(eptr, end);
            }
        }
        else
        {
            uint32 len = OSCL_MIN((uint32)(eptr - start), oscl_strlen("IMAGE"));
            if (!oscl_strncmp(start, "IMAGE", len))
            {
                applicationFlag = true;
            }
            else    //don't support this media. so skip the section
                return 0;
        }

        if (sptr < end)
        {
            return 0;
        }

        return 1;
    }

    return 0;

}

OSCL_EXPORT_REF
SDP_ERROR_CODE SDP_Parser::parseSDP(const char *sdpText, int text_length, SDPInfo *sdp)
{
    int index = 0, sdpIndex = 0;

    const char *end_ptr = sdpText + text_length ; // Point just beyond the end
    const char *section_start_ptr;
    const char *section_end_ptr;
    const char *line_start_ptr, *line_end_ptr;
    bool session_info_parsed = false;

    /**************************************************************************/

    // The purpose of this outer loop is to partition the SDP into different
    // sections to be passed off to session-level parsers or media-level parsers.
    // We just need to find the boundaries and pass the appropriate sections
    // of code to the subparsers.

    sdpIndex = 0;
    index = 0;

    // these track whether media and session-level sections have already
    // been found
    int media_sections_found = 0;
    int session_section_found = 0;

    // skip any leading whitespace including line terminators
    section_start_ptr = skip_whitespace_and_line_term(sdpText, end_ptr);

    while ((section_start_ptr - sdpText) < text_length)
    {
        if (!get_next_line(section_start_ptr, end_ptr,
                           line_start_ptr, line_end_ptr))
        {
            break;
        }

        // figure out the type of section
        if (!oscl_strncmp(line_start_ptr, "v=", 2))
        {
            // this is the session-level
            if (media_sections_found || session_section_found)
            {
                // there were already media sections or already a session-level section
                // so a session-level section at this point is not allowed.
                PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Duplicate Session Sections"));
                return SDP_BAD_FORMAT;
            }

            section_end_ptr = line_end_ptr;

            // record that the session-level section has been found
            session_section_found = 1;

            while (get_next_line(section_end_ptr, end_ptr,
                                 line_start_ptr, line_end_ptr))
            {
                // check if this is the start of another section
                if (!oscl_strncmp(line_start_ptr, "v=", 2) ||
                        !oscl_strncmp(line_start_ptr, "m=", 2))
                {
                    break;
                }
                section_end_ptr = line_end_ptr;
            }


            OsclMemoryFragment session_frag;
            session_frag.ptr = (void *)section_start_ptr;
            session_frag.len = section_end_ptr - section_start_ptr;

            SDP_ERROR_CODE retval =
                parseSDPSessionInfo(section_start_ptr,
                                    section_end_ptr - section_start_ptr,
                                    sdp);
            if (retval != SDP_SUCCESS)
            {
                PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - parseSDPSessionInfo Failed=%d", retval));
                return retval;
            }
            else
            {
                session_info_parsed = true;
            }
        }
        else if (!oscl_strncmp(line_start_ptr, "m=", 2))
        {

            // now look for the end of the section
            section_end_ptr = line_end_ptr;
            bool supported_media = true;

            ++media_sections_found;
            sdp->setSegmentCount(media_sections_found);

            /* SUPPORTING MULTIPLE PAYLOAD TYPE PER MEDIA NOW */
            // check to see how many payload types are present
            Oscl_Vector<int, SDPParserAlloc> payload_type;
            Oscl_Vector<int, SDPParserAlloc> rtpmap_pt;
            Oscl_Vector<OsclMemoryFragment, SDPParserAlloc> encoding_name_vector;

            uint32 portNumber = 0;
            if (!validate_media_line(line_start_ptr, line_end_ptr, payload_type, portNumber))
            {
                // skip this section
                supported_media = false;
            }
            else
            {
                PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Validated MediaSection"));
            }

            int rtpmap_lines = 0;

            // get the next line
            OsclMemoryFragment encoding_name;
            encoding_name.ptr = NULL;
            encoding_name.len = 0;

            Oscl_Vector<int, SDPParserAlloc> AltId;
            while (get_next_line(section_end_ptr, end_ptr, line_start_ptr, line_end_ptr))
            {
                // check if this is the start of another section
                if (!oscl_strncmp(line_start_ptr, "v=", 2) ||
                        !oscl_strncmp(line_start_ptr, "m=", 2))
                {
                    break;
                }
                if (supported_media && (applicationFlag == false))
                {
                    // check for lines which will give the media type
                    // so the parser can be allocated. Simply look for
                    // the "a=rtpmap" lines which contain the MIME type.
                    StrPtrLen rtpmap_str("a=rtpmap:");
                    if (!oscl_strncmp(line_start_ptr, rtpmap_str.c_str(), rtpmap_str.length()))
                    {
                        ++rtpmap_lines;
                        int rtpmap_cu;
                        // get encoding name
                        if (!parse_rtpmap(line_start_ptr, line_end_ptr, rtpmap_cu, encoding_name))
                        {
                            // invalid format
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - parse_rtpmap Failed"));
                            return SDP_BAD_MEDIA_FORMAT;
                        }
                        rtpmap_pt.push_back(rtpmap_cu);
                        encoding_name_vector.push_back(encoding_name);
                        OSCL_StackString<15> mime((const char*)(encoding_name.ptr), encoding_name.len);
                        PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - a=rtpmap mime=%s", mime.get_cstr()));
                    }
                    StrPtrLen alt_def("a=alt-default-id:");
                    if (!oscl_strncmp(line_start_ptr, alt_def.c_str(), alt_def.length()))
                    {
                        uint32 id;
                        const char *sptr = line_start_ptr + alt_def.length();
                        sptr = skip_whitespace(sptr, line_end_ptr);
                        if (!PV_atoi(sptr, 'd', line_end_ptr - sptr, id))
                        {
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=alt-default-id: Failed"));
                            return SDP_BAD_MEDIA_ALT_ID;
                        }
                        AltId.push_back(id);
                    }
                    StrPtrLen alt_id("a=alt:");
                    if (!oscl_strncmp(line_start_ptr, alt_id.c_str(), alt_id.length()))
                    {
                        uint32 id;
                        const char *sptr = line_start_ptr + alt_id.length();
                        sptr = skip_whitespace(sptr, line_end_ptr);
                        const char *eptr = sptr;
                        for (; *eptr != ':'; eptr++);
                        if (!PV_atoi(sptr, 'd', eptr - sptr, id))
                        {
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=alt: Failed"));
                            return SDP_BAD_MEDIA_ALT_ID;
                        }
                        if (AltId.back() != (int)id)
                            AltId.push_back(id);
                    }

                    // fmtp and framesize payload check is provided below
                    // this is done to make sure that the payload coming in these fields
                    // is one of the payloads in the m= segment
                    StrPtrLen fmtp("a=fmtp:");
                    if (!oscl_strncmp(line_start_ptr, fmtp.c_str(), fmtp.length()))
                    {
                        uint32 payload;
                        const char *sptr = line_start_ptr + fmtp.length();
                        sptr = skip_whitespace(sptr, line_end_ptr);
                        const char* eptr = skip_to_whitespace(sptr, line_end_ptr);
                        if (!PV_atoi(sptr, 'd', eptr - sptr, payload))
                        {
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=fmtp: Failed"));
                            return SDP_BAD_MEDIA_FORMAT;
                        }
                        // The format is proper match the payload with payloads in m= segment
                        bool matched = false;
                        for (uint32 ii = 0; ii < payload_type.size(); ii++)
                        {
                            if (payload == (uint32)payload_type[ii])
                            {
                                matched = true;
                                break;
                            }
                        }
                        if (!matched)
                        {
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Payload Mismatch in fmtp line"));
                            return SDP_PAYLOAD_MISMATCH;
                        }
                    }
                    StrPtrLen framesize("a=framesize:");
                    if (!oscl_strncmp(line_start_ptr, framesize.c_str(), framesize.length()))
                    {
                        uint32 payload;
                        const char *sptr = line_start_ptr + framesize.length();
                        sptr = skip_whitespace(sptr, line_end_ptr);
                        const char* eptr = skip_to_whitespace(sptr, line_end_ptr);
                        if (!PV_atoi(sptr, 'd', eptr - sptr, payload))
                        {
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing a=framesize: Failed"));
                            return SDP_BAD_MEDIA_FORMAT;
                        }
                        // The format is proper match the payload with payloads in m= segment
                        bool matched = false;
                        for (uint32 ii = 0; ii < payload_type.size(); ii++)
                        {
                            if (payload == (uint32)payload_type[ii])
                            {
                                matched = true;
                                break;
                            }
                        }
                        if (!matched)
                        {
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Payload Mismatch in a=framesize: line"));
                            return SDP_PAYLOAD_MISMATCH;
                        }
                    }

                } // end if media is supported
                else
                {
                    PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Skipping over an entire m= section"));
                }

                section_end_ptr = line_end_ptr;
            } // end loop over the entire media section


            // The checking for rtpmap vs payloads is not required if the port number is 0 in case it is a sip sdp
            bool check_for_rtpmap = true;
            if (isSipSdp && portNumber == 0)
            {
                check_for_rtpmap = false;
            }

            // Checking for rtpmap with the payloads
            if (supported_media && check_for_rtpmap)
            {
                // Validate the payload type and rtpmap if required
                int static_payload_count = 0;
                int ii = 0;
                for (; ii < (int)payload_type.size(); ii++)
                {
                    // If any payload_type is in static range we do not care
                    // for the rtpmap field. We will process for this static payload type sdp
                    // the dynamic payload type if any will be ignored if it's rtpmap
                    // is missing
                    if ((payload_type[ii] >= FIRST_STATIC_PAYLOAD) &&
                            (payload_type[ii] <= LAST_STATIC_PAYLOAD))
                    {
                        PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - Static Payload =%d", payload_type[ii]));
                        static_payload_count++;
                    }
                }
                if (static_payload_count == 0)
                {
                    // The payload type present are all in the dynamic range
                    if (rtpmap_pt.size() != payload_type.size())
                    {
                        PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Mismatch between number of payloads and rtpmap lines"));
                        return SDP_BAD_MEDIA_FORMAT;
                    }
                    for (int ii = 0; ii < (int)rtpmap_pt.size(); ii++)
                    {
                        if (rtpmap_pt[ii] != payload_type[ii])
                        {
                            // this is an error
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Incorrect payload number  in rtpmap line"));
                            return SDP_PAYLOAD_MISMATCH;
                        }
                    }
                }
                else if (static_payload_count >= 1)
                {
                    // All of the payloads can either be static or one of them
                    // for every dynamic payload there should be matching rtpmap field
                    if (rtpmap_pt.size() != (payload_type.size() - static_payload_count))
                    {
                        PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Mismatch between number of payloads and rtpmap lines"));
                        return SDP_BAD_MEDIA_FORMAT;
                    }
                    for (uint32 rtpmap_count = 0; rtpmap_count < rtpmap_pt.size(); rtpmap_count++)
                    {
                        bool match_found = false;
                        for (int jj = 0; jj < (int)payload_type.size(); jj++)
                        {
                            if (rtpmap_pt[rtpmap_count] == payload_type[jj])
                            {
                                match_found = true;
                                break;
                            }
                        }
                        if (match_found == false)
                        {
                            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - No matching rtpmap line"));
                            // this is an error
                            return SDP_PAYLOAD_MISMATCH;
                        }
                    }
                }
            }

            if (session_info_parsed == false)
            {
                PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Missing Session Section"));
                return SDP_BAD_FORMAT;
            }

            if (supported_media)
            {
                StrPtrLen image("X-MP4V-IMAGE");
                if (applicationFlag == true)
                {
                    if (rtpmap_lines == 0)
                    {
                        rtpmap_lines++;
                        encoding_name.ptr = (void *) image.c_str();
                        encoding_name.len = image.length();
                        applicationFlag = false;
                        encoding_name_vector.push_back(encoding_name);
                    }
                }

                // Compose all media encoding names and put them in one vector
                // this will carry all encoding names including static and dynamic PT
                StrPtrLen pcma(PVMF_MIME_PCMA);
                StrPtrLen pcmu(PVMF_MIME_PCMU);
                StrPtrLen amr("AMR");
                Oscl_Vector<OsclMemoryFragment, SDPParserAlloc> all_media_encoding_names;
                uint32 ii = 0;
                uint32 jj = 0;
                for (; ii < payload_type.size(); ii++)
                {
                    if (payload_type[ii] == PVMF_PCMU)
                    {
                        rtpmap_lines++;
                        encoding_name.ptr = (void *) pcmu.c_str();
                        encoding_name.len = pcmu.length();
                    }
                    else if (payload_type[ii] == PVMF_PCMA)
                    {
                        rtpmap_lines++;
                        encoding_name.ptr = (void *) pcma.c_str();
                        encoding_name.len = pcma.length();
                    }
                    else if (check_for_rtpmap == false)
                    {
                        // This means that the port is 0 and they payload is in dynamic range
                        // rtpmap field is not present.
                        // To map it internally let's put it under PCMU again
                        rtpmap_lines++;
                        encoding_name.ptr = (void *) pcmu.c_str();
                        encoding_name.len = pcmu.length();
                    }
                    else
                    {
                        // All other payload encoding names are already present in the
                        // encoding_name_vector.
                        if (jj < encoding_name_vector.size())
                        {
                            encoding_name = encoding_name_vector[jj];
                            jj++;
                        }
                    }
                    all_media_encoding_names.push_back(encoding_name);
                }

                // compose all the above information in the following format
                // Any Mime type coming repeatedly with different payload numbers
                // Then club them together
                Oscl_Vector<mime_payload_pair, SDPParserAlloc> mime_payload_pair_vector;

                for (uint32 ll = 0; ll < payload_type.size(); ll++)
                {
                    if (check_for_rtpmap == true)
                    {
                        bool matched = false;
                        uint32 ii = 0;
                        for (; ii < mime_payload_pair_vector.size(); ii++)
                        {
                            if (oscl_strncmp((char*)mime_payload_pair_vector[ii].mime.ptr,
                                             (char*)all_media_encoding_names[ll].ptr,
                                             all_media_encoding_names[ll].len) == 0)
                            {
                                matched = true;
                                break;
                            }
                        }
                        if (matched)
                        {
                            mime_payload_pair_vector[ii].payload_no.push_back(payload_type[ll]);
                        }
                        else
                        {
                            mime_payload_pair mpp;
                            mpp.payload_no.push_back(payload_type[ll]);
                            mpp.mime.len = all_media_encoding_names[ll].len;
                            mpp.mime.ptr = all_media_encoding_names[ll].ptr;
                            mime_payload_pair_vector.push_back(mpp);
                        }
                    }
                    else
                    {
                        // It is a sip sdp with port = 0. Hence do not make specific checks
                        mime_payload_pair mpp;
                        mpp.payload_no.push_back(payload_type[ll]);
                        mpp.mime.len = all_media_encoding_names[ll].len;
                        mpp.mime.ptr = all_media_encoding_names[ll].ptr;
                        mime_payload_pair_vector.push_back(mpp);
                    }

                }

                if (rtpmap_lines >= 1)
                {
                    SDPMediaParserFactory  *mediaParserFactory;
                    SDPBaseMediaInfoParser *mediaParser;
                    SDP_ERROR_CODE retval;

                    for (uint32 kk = 0; kk < mime_payload_pair_vector.size(); kk++)
                    {
                        encoding_name = mime_payload_pair_vector[kk].mime;
                        if ((mediaParserFactory =
                                    _pSDPMediaParserRegistry->lookupSDPMediaParserFactory(encoding_name)) != NULL)
                        {
                            mediaParser = mediaParserFactory->createSDPMediaParserInstance();
                            if (mediaParser == NULL)
                            {
                                PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unable to create media parser"));
                                return SDP_FAILURE;
                            }
                            if (AltId.size() > 0)
                            {
                                int alt_id;
                                bool alt_def_id = false;
                                for (int ss = 0; ss < (int)AltId.size(); ss++)
                                {
                                    if (ss == 0) alt_def_id = true;
                                    else alt_def_id = false;

                                    alt_id = AltId[ss];

                                    if ((retval = mediaParser->parseMediaInfo(section_start_ptr, section_end_ptr - section_start_ptr, sdp, mime_payload_pair_vector[kk].payload_no, isSipSdp, alt_id, alt_def_id)) != SDP_SUCCESS)
                                    {
                                        OSCL_StackString<8> mime((const char*)(encoding_name.ptr), encoding_name.len);
                                        PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, mime=%s", mime.get_cstr()));
                                        OSCL_DELETE((mediaParser));
                                        sdp->freeLastMediaInfoObject();
                                        return retval;
                                    }

                                }
                            }
                            else
                            {
                                if ((retval = mediaParser->parseMediaInfo(section_start_ptr, section_end_ptr - section_start_ptr, sdp, mime_payload_pair_vector[kk].payload_no, isSipSdp)) != SDP_SUCCESS)
                                {
                                    OSCL_StackString<8> mime((const char*)(encoding_name.ptr), encoding_name.len);
                                    PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, mime=%s", mime.get_cstr()));
                                    OSCL_DELETE((mediaParser));
                                    sdp->freeLastMediaInfoObject();
                                    return retval;
                                }
                            }
                            sdp->IncrementAlternateMediaInfoVectorIndex();
                            OSCL_DELETE((mediaParser));
                        }
                        mediaParser = NULL;
                    }   // End of for
                }
                if (rtpmap_lines == 0) // no rtpmap found in media
                {
                    PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Parsing m= section failed, No rtpmap line"));
                    return SDP_BAD_MEDIA_MISSING_RTPMAP;
                }
            }
        } // end this is a media section
        else
        {
            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unrecognized Syntax"));
            // unknown section type -- this is an error
            return SDP_FAILURE;
        }

        section_start_ptr = skip_whitespace_and_line_term(section_end_ptr, end_ptr);

    }
    {
        //for SDP which doesn't have session level range, set the session level range
        //to be the MAX of media ranges.
        if (NULL == sdp->getSessionInfo())
        {
            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Missing Session Info"));
            return SDP_BAD_FORMAT;
        }
        RtspRangeType *mySdpRange = ((RtspRangeType *)sdp->getSessionInfo()->getRange());
        if (NULL == mySdpRange)
        {
            PVMF_SDP_PARSER_LOGERROR((0, "SDP_Parser::parseSDP - Unable to retrieve session range"));
            return SDP_BAD_FORMAT;
        }
        if (mySdpRange->format == RtspRangeType::INVALID_RANGE)
        {
            PVMF_SDP_PARSER_LOGINFO((0, "SDP_Parser::parseSDP - No Valid Session Range - Setting it to Max of all media ranges"));
            for (int32 i = sdp->getNumMediaObjects() - 1; i >= 0; i--)
            {
                Oscl_Vector<mediaInfo*, SDPParserAlloc> mediaInfoVec =
                    sdp->getMediaInfo(i);
                for (uint32 j = 0; j < mediaInfoVec.size(); j++)
                {
                    mediaInfo* mInfo = mediaInfoVec[j];
                    if (mInfo == NULL)
                    {
                        continue;
                    }
                    const RtspRangeType *mInfoSdpRange = mInfo->getRtspRange();
                    if (NULL == mInfoSdpRange)
                    {
                        continue;
                    }
                    if (mInfoSdpRange->format != RtspRangeType::NPT_RANGE)
                    {
                        continue;
                    }
                    if (mySdpRange->format == RtspRangeType::INVALID_RANGE)
                    {
                        *mySdpRange = *mInfoSdpRange;
                    }
                    if (!mInfoSdpRange->end_is_set)
                    {//live streaming
                        *mySdpRange = *mInfoSdpRange;
                        mySdpRange->start_is_set = true;//just to make sure
                        mySdpRange->npt_start.npt_format = NptTimeFormat::NOW;
                        return SDP_SUCCESS;
                    }
                    if (mInfoSdpRange->npt_start.npt_format == NptTimeFormat::NPT_SEC)
                    {
                        if (mInfoSdpRange->npt_start.npt_sec.sec < mySdpRange->npt_start.npt_sec.sec)
                        {
                            mySdpRange->npt_start.npt_sec = mInfoSdpRange->npt_start.npt_sec;
                        }
                        else if ((mInfoSdpRange->npt_start.npt_sec.sec == mySdpRange->npt_start.npt_sec.sec)
                                 && ((mInfoSdpRange->npt_start.npt_sec.milli_sec < mySdpRange->npt_start.npt_sec.milli_sec)))
                        {
                            mySdpRange->npt_start.npt_sec = mInfoSdpRange->npt_start.npt_sec;
                        }
                    }
                    if (mInfoSdpRange->npt_end.npt_format == NptTimeFormat::NPT_SEC)
                    {
                        if (mInfoSdpRange->npt_end.npt_sec.sec > mySdpRange->npt_end.npt_sec.sec)
                        {
                            mySdpRange->npt_end.npt_sec = mInfoSdpRange->npt_end.npt_sec;
                        }
                        else if ((mInfoSdpRange->npt_end.npt_sec.sec == mySdpRange->npt_end.npt_sec.sec)
                                 && ((mInfoSdpRange->npt_end.npt_sec.milli_sec > mySdpRange->npt_end.npt_sec.milli_sec)))
                        {
                            mySdpRange->npt_end.npt_sec = mInfoSdpRange->npt_end.npt_sec;
                        }
                    }
                }
            }
        }
    }
    return SDP_SUCCESS;
}

OSCL_EXPORT_REF SDP_ERROR_CODE
SDP_Parser::parseSDPDownload(const char *sdpText,
                             int length,
                             SDPInfo *sdp,
                             movieInfo *mv)
{
    SDP_ERROR_CODE retval = parseSDP(sdpText, length, sdp);
    if (retval != SDP_SUCCESS)
    {
        mv->trackCount = 0;
        mv->movieName[0] = '\0';
        mv->creationDate[0] = '\0';
        return retval;
    }
    else
    {
        /*Get Movie name*/
        int len = oscl_strlen(sdp->getSessionInfo()->getSessionName());
        if (len >= MAX_STRING_LEN)
        {
            oscl_strncpy(mv->movieName, sdp->getSessionInfo()->getSessionName(), (MAX_STRING_LEN - 1));
            mv->movieName[MAX_STRING_LEN-1] = '\0';
        }
        else
        {
            oscl_strncpy(mv->movieName, sdp->getSessionInfo()->getSessionName(), len);
            mv->movieName[len] = '\0';
        }

        /*Get creation date*/
        len = oscl_strlen(sdp->getSessionInfo()->getCreationDate());
        if (len >= MAX_STRING_LEN)
        {
            oscl_strncpy(mv->creationDate, sdp->getSessionInfo()->getCreationDate(), (MAX_STRING_LEN - 1));
            mv->creationDate[MAX_STRING_LEN-1] = '\0';
        }
        else
        {
            oscl_strncpy(mv->creationDate, sdp->getSessionInfo()->getCreationDate(), len);
            mv->creationDate[len] = '\0';
        }

        /*Get number of tracks*/
        mv->trackCount = sdp->getNumMediaObjects();

        /*Get start stop times*/
        convertToMilliSec(*sdp->getSessionInfo()->getRange(), mv->duration.startTime, mv->duration.stopTime);

        /*Get MIMEType and other track info*/
        for (int ii = 0; ii < mv->trackCount; ii++)
        {
            Oscl_Vector<mediaInfo*, SDPParserAlloc> mediaInfoVec =
                sdp->getMediaInfo(ii);

            /*
             * There would only be one element in this vector
             * for fast track download content.
             */
            mediaInfo* minfo = mediaInfoVec[0];

            mv->TrackArray[ii].bitrate = minfo->getBitrate();
            len = oscl_strlen(minfo->getMIMEType());
            if (len >= MAX_STRING_LEN)
            {
                oscl_strncpy(mv->TrackArray[ii].codec_type,
                             minfo->getMIMEType(),
                             (MAX_STRING_LEN - 1));
                mv->TrackArray[ii].codec_type[MAX_STRING_LEN-1] = '\0';
            }
            else
            {
                oscl_strncpy(mv->TrackArray[ii].codec_type,
                             minfo->getMIMEType(),
                             len);
                mv->TrackArray[ii].codec_type[len] = '\0';
            }
            const char *trackID = minfo->getControlURL();
            int track = 0;
            if (trackID != NULL)
            {
                const char *locateID = oscl_strstr(trackID, "=");
                if (locateID != NULL)
                {
                    locateID += 1;
                    uint32 atoi_tmp;
                    PV_atoi(locateID, 'd', atoi_tmp);
                    track = atoi_tmp;
                }
            }
            mv->TrackArray[ii].trackID = track;
        }
    }
    return SDP_SUCCESS;
}


int
SDP_Parser::convertToMilliSec(RtspRangeType range , int &startTime, int &stopTime)
{
    switch (range.format)
    {
        case RtspRangeType::NPT_RANGE:
        {
            if (range.start_is_set)
            {
                switch (range.npt_start.npt_format)
                {
                    case NptTimeFormat::NOW:
                    {
                        startTime = 0;
                    }
                    break;
                    case NptTimeFormat::NPT_SEC:
                    {
                        startTime = (int)(1000 * ((float)range.npt_start.npt_sec.sec + range.npt_start.npt_sec.milli_sec));
                    }
                    break;
                    case NptTimeFormat::NPT_HHMMSS:
                    {
                        startTime = 3600000 * range.npt_start.npt_hhmmss.hours + 60000 * range.npt_start.npt_hhmmss.min + 1000 * range.npt_start.npt_hhmmss.sec + (int)(10 * range.npt_start.npt_hhmmss.frac_sec);
                    }
                    break;
                }
            }
            else
            {
                startTime = 0;
            }
            if (range.end_is_set)
            {
                switch (range.npt_end.npt_format)
                {
                    case NptTimeFormat::NOW:
                    {
                        stopTime = 0;
                    }
                    break;
                    case NptTimeFormat::NPT_SEC:
                    {
                        stopTime = (int)(1000 * ((float)range.npt_end.npt_sec.sec + range.npt_end.npt_sec.milli_sec));
                    }
                    break;
                    case NptTimeFormat::NPT_HHMMSS:
                    {
                        stopTime = 3600000 * range.npt_end.npt_hhmmss.hours + 60000 * range.npt_end.npt_hhmmss.min + 1000 * range.npt_end.npt_hhmmss.sec + (int)(100 * range.npt_end.npt_hhmmss.frac_sec);
                    }
                    break;
                }
            }
            else
            {
                stopTime = false;
            }
        }
        break;
        case RtspRangeType::SMPTE_RANGE:
        case RtspRangeType::SMPTE_25_RANGE:
        case RtspRangeType::SMPTE_30_RANGE:
        {
            if (range.start_is_set)
            {
                startTime = 3600000 * range.smpte_start.hours + 60000 * range.smpte_start.minutes + 1000 * range.smpte_start.seconds;
            }
            else
            {
                startTime = 0;
            }
            if (range.end_is_set)
            {
                stopTime = 3600000 * range.smpte_end.hours + 60000 * range.smpte_end.minutes + 1000 * range.smpte_end.seconds;
            }
            else
            {
                stopTime = 0;
            }
        }
        break;
        case RtspRangeType::ABS_RANGE:
        {
            startTime = 0;
            stopTime = 0;
        }
        break;
        case RtspRangeType::UNKNOWN_RANGE:
        case RtspRangeType::INVALID_RANGE:
        {
            startTime = 0;
            stopTime = 0;
            return -1;
        }
        // break;   This statement was removed to avoid compiler warning for Unreachable Code

        default:
        {
            startTime = 0;
            stopTime = 0;
            return -1;
        }
        // break;   This statement was removed to avoid compiler warning for Unreachable Code
    }
    return 0;
}

OSCL_EXPORT_REF int SDP_Parser::getNumberOfTracks()
{
    return mediaArrayIndex;
}

OSCL_EXPORT_REF int SDP_Parser::setNumberOfTracks(int tracks)
{
    return (mediaArrayIndex = tracks);
}


