/* ------------------------------------------------------------------ * 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 "amr_media_info_parser.h" #include "oscl_string_utils.h" #include "oscl_string_containers.h" SDP_ERROR_CODE SDPAMRMediaInfoParser::parseMediaInfo(const char *buff, const int index, SDPInfo *sdp, payloadVector payload_vec, bool isSipSdp, int alt_id, bool alt_def_id) { 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; int modes[] = {1, 2, 4, 8, 16, 32, 64, 128}; int fmtp_cnt = 0; bool altMedia = false; if (!alt_id || (alt_def_id == true)) altMedia = false; else altMedia = true; void *memory = NULL; memory = sdp->alloc(sizeof(amr_mediaInfo), altMedia); if (NULL == memory) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - No Memory allocated")); return SDP_NO_MEMORY; } else { amr_mediaInfo *amrA = OSCL_PLACEMENT_NEW(memory, amr_mediaInfo()); amrA->setMediaInfoID(sdp->getMediaObjectIndex()); // Allocate memory to the payload specific objects for (uint32 ii = 0; ii < payload_vec.size(); ii++) { void* mem = amrA->alloc(sizeof(AmrPayloadSpecificInfoType)); if (mem == NULL) { return SDP_NO_MEMORY; } else { AmrPayloadSpecificInfoType* amrPayload = OSCL_PLACEMENT_NEW(mem, AmrPayloadSpecificInfoType(payload_vec[ii])); (void) amrPayload; } } if (alt_id && !alt_def_id) { sdp->copyFmDefMedia(amrA); //empty alternate & default track ID vectors. amrA->resetAlternateTrackId(); amrA->resetDependentTrackId(); } SDP_ERROR_CODE status = baseMediaInfoParser(buff, amrA, index , alt_id, alt_def_id, isSipSdp); if (status != SDP_SUCCESS) { return status; } while (get_next_line(current_start, end, line_start_ptr, line_end_ptr)) { switch (*line_start_ptr) { case 'a': { const char *sptr; if ((!oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:"))) && (alt_def_id == false)) { line_start_ptr += oscl_strlen("a=alt:"); for (; *line_start_ptr != ':'; line_start_ptr++); line_start_ptr = line_start_ptr + 1; } if (!oscl_strncmp(line_start_ptr, "a=lang:", oscl_strlen("a=lang:"))) { sptr = line_start_ptr + oscl_strlen("a=lang:"); sptr = skip_whitespace(sptr, line_end_ptr); if (sptr >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=lang field bad")); return SDP_BAD_MEDIA_LANG_FIELD; } OsclMemoryFragment memFrag; memFrag.ptr = (void*)sptr; memFrag.len = (line_end_ptr - sptr); ((amr_mediaInfo*)amrA)->setLang(memFrag); } if (!oscl_strncmp(line_start_ptr, "a=maxptime:", oscl_strlen("a=maxptime:"))) { sptr = line_start_ptr + oscl_strlen("a=maxptime:"); sptr = skip_whitespace(sptr, line_end_ptr); if (sptr >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=maxptime field bad")); return SDP_BAD_MEDIA_MAXPTIME; } uint32 maxptime = 0; if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), maxptime) == true) { ((amr_mediaInfo*)amrA)->setMaximumPTime(maxptime); } } if (!oscl_strncmp(line_start_ptr, "a=fmtp:", oscl_strlen("a=fmtp:"))) { const char *tmp_start_line, *tmp_end_line; fmtp_cnt++; tmp_start_line = line_start_ptr + oscl_strlen("a=fmtp:"); tmp_start_line = skip_whitespace(tmp_start_line, line_end_ptr); if (tmp_start_line >= line_end_ptr) { break; } tmp_end_line = skip_to_whitespace(tmp_start_line, line_end_ptr); if (tmp_end_line < tmp_start_line) { break; } uint32 payloadNumber; if (PV_atoi(tmp_start_line, 'd', (tmp_end_line - tmp_start_line), payloadNumber) == false) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=fmtp field bad for payload number")); return SDP_BAD_MEDIA_FMTP; } else { int p; if (!amrA->lookupPayloadNumber(payloadNumber, p)) { fmtp_cnt--; break; } } // payloadNumber is present in the mediaInfo. get the payload // Specific pointer corresponding to this payload AmrPayloadSpecificInfoType* payloadPtr = (AmrPayloadSpecificInfoType*)amrA->getPayloadSpecificInfoTypePtr(payloadNumber); if (payloadPtr == NULL) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - unable to find payload ptr for payload number")); return SDP_PAYLOAD_MISMATCH; } PVMF_SDP_PARSER_LOGINFO((0, "SDPAmrMediaInfoParser::parseMediaInfo - processing payload number : %d", payloadNumber)); tmp_start_line = tmp_end_line + 1; tmp_start_line = skip_whitespace(tmp_start_line, line_end_ptr); if (tmp_start_line >= line_end_ptr) { break; } int ii = 0; const char *temp = tmp_start_line; for (ii = 0; ii < (line_end_ptr - tmp_start_line); ii++) { if ((tmp_start_line[ii] == ';') || (ii == (line_end_ptr - tmp_start_line) - 1)) { tmp_end_line = tmp_start_line + ii; if (ii == (line_end_ptr - tmp_start_line) - 1) { tmp_end_line += 1; } if (!oscl_strncmp(temp, "maxptime=", oscl_strlen("maxptime="))) { temp += oscl_strlen("maxptime="); temp = skip_whitespace(temp, tmp_end_line); if (temp >= tmp_end_line) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=fmtp field format is bad for maxptime=")); return SDP_BAD_MEDIA_MAXPTIME; } uint32 maxPTime; if (PV_atoi(temp, 'd', (tmp_end_line - temp), maxPTime) == true) payloadPtr->setMaximumPTime(maxPTime); } if (!oscl_strncmp(temp, "crc", oscl_strlen("crc"))) { if (!oscl_strncmp(temp, "crc=0", oscl_strlen("crc=0"))) payloadPtr->setCRC(false); else payloadPtr->setCRC(true); } if (!oscl_strncmp(temp, "robust-sorting", oscl_strlen("robust-sorting"))) { //We need to make sure that we do not read beyond valid memory if ((line_end_ptr - temp) >= (int)oscl_strlen("robust-sorting=0")) { if (oscl_strncmp(temp, "robust-sorting=0", oscl_strlen("robust-sorting=0"))) { payloadPtr->setRobustSorting(true); } } else { payloadPtr->setRobustSorting(false); } } if (!oscl_strncmp(temp, "octet-align", oscl_strlen("octet-align"))) { //We need to make sure that we do not read beyond valid memory if ((line_end_ptr - temp) >= (int) oscl_strlen("octet-align=0")) { if (oscl_strncmp(temp, "octet-align=0", oscl_strlen("octet-align=0"))) { payloadPtr->setOctetAlign(true); } } else { payloadPtr->setOctetAlign(false); } } if (!oscl_strncmp(temp, "interleaving=", oscl_strlen("interleaving="))) { temp += oscl_strlen("interleaving="); temp = (char *)skip_whitespace(temp, tmp_end_line); if (temp > tmp_end_line) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=fmtp field format is bad for interleaving=")); return SDP_BAD_MEDIA_FMTP; } uint32 interleave; if (PV_atoi(temp, 'd', (tmp_end_line - temp), interleave) == true) payloadPtr->setInterLeaving(interleave); } if (!oscl_strncmp(temp, "decode_buf=", oscl_strlen("decode_buf="))) { temp += oscl_strlen("decode_buf="); temp = skip_whitespace(temp, tmp_end_line); if (temp > tmp_end_line) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=fmtp field format is bad for decode_buf=")); return SDP_BAD_MEDIA_FMTP; } uint32 dec; if (PV_atoi(temp, 'd', (tmp_end_line - temp), dec) == true) payloadPtr->setMaxBufferSize(dec); } if (!oscl_strncmp(temp, "mode-change-period=", oscl_strlen("mode-change-period="))) { temp += oscl_strlen("mode-change-period="); temp = skip_whitespace(temp, tmp_end_line); if (temp > tmp_end_line) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=fmtp field format is bad for mode-change-period=")); return SDP_BAD_MEDIA_FMTP; } uint32 mcp; if (PV_atoi(temp, 'd', (tmp_end_line - temp), mcp) == true) payloadPtr->setModeChangePeriod(mcp); } if (!oscl_strncmp(temp, "mode-change-neighbor", oscl_strlen("mode-change-neighbor"))) { //We need to make sure that we do not read beyond valid memory if ((line_end_ptr - temp) >= (int)oscl_strlen("mode-change-neighbor=0")) { if (oscl_strncmp(temp, "mode-change-neighbor=0", oscl_strlen("mode-change-neighbor=0"))) { payloadPtr->setModeChangeNeighbor(true); } } else { payloadPtr->setModeChangeNeighbor(false); } } if (!oscl_strncmp(temp, "mode-change-neighbor=1", oscl_strlen("mode-change-neighbor=1"))) { payloadPtr->setModeChangeNeighbor(true); } if (!oscl_strncmp(temp, "mode-set=", oscl_strlen("mode-set="))) { temp += oscl_strlen("mode-set="); temp = skip_whitespace(temp, tmp_end_line); if (temp > tmp_end_line) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=fmtp field format is bad for mode-set=")); return SDP_BAD_MEDIA_FMTP; } int idx = 0; int cModeList = 0; const char *begin = temp, *end; for (idx = 0; idx < (tmp_end_line - temp); idx++) { if ((temp[idx] == ',') || ((tmp_end_line - temp) - 1 == idx)) { { end = temp + idx; } if ((tmp_end_line - temp) - 1 == idx) { end++; } uint32 temp_idx; if (PV_atoi(begin, 'd', (end - begin), temp_idx) == true) cModeList += modes[temp_idx]; begin = end + 1; } } payloadPtr->setCodecModeList(cModeList); } if (tmp_end_line != line_end_ptr) temp = tmp_end_line + 1; temp = skip_whitespace(temp, line_end_ptr); if (temp >= line_end_ptr) { PVMF_SDP_PARSER_LOGERROR((0, "SDPAMRMediaInfoParser::parseMediaInfo - a=fmtp field format is bad")); return SDP_BAD_MEDIA_FMTP; } } } } } break; default: break; } current_start = line_end_ptr; } sessionDescription *session = sdp->getSessionInfo(); if (fmtp_cnt != amrA->getMediaPayloadNumberCount() && isSipSdp == false) return SDP_PAYLOAD_MISMATCH; const char *altGroupBW = session->getAltGroupBW(); int length = session->getAltGroupBWLength(); if (length > 0) { status = setDependentMediaId(altGroupBW, length, amrA, alt_id); if (status != SDP_SUCCESS) return SDP_BAD_MEDIA_ALT_ID; } const char *altGroupLANG = session->getAltGroupLANG(); length = session->getAltGroupLANGLength(); if (length > 0) { status = setDependentMediaId(altGroupLANG, length, amrA, alt_id); if (status != SDP_SUCCESS) return SDP_BAD_MEDIA_ALT_ID; } if (amrA->getCFieldStatus() || session->getCFieldStatus()) { //if sample rate is zero override with defaults Oscl_Vector<PayloadSpecificInfoTypeBase*, SDPParserAlloc> payloadSpecificInfoVector = amrA->getPayloadSpecificInfoVector(); for (int ii = 0; ii < (int)payloadSpecificInfoVector.size(); ii++) { if (payloadSpecificInfoVector[ii]->getSampleRate() == 0) { payloadSpecificInfoVector[ii]->sampleRate = PVMF_SDP_DEFAULT_AMR_SAMPLE_RATE; } } return SDP_SUCCESS; } else { return SDP_FAILURE_NO_C_FIELD; } } }