Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/sipcc/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 189 kB image not shown  

Quelle  sdp_attr.c   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include <errno.h>
#include <limits.h>
#include <stdio.h>

#include "plstr.h"
#include "sdp_os_defs.h"
#include "sipcc_sdp.h"
#include "sdp_private.h"
#include "sdp_base64.h"

#include "sdp_log.h"

static const char* logTag = "sdp_attr";

/*
 * Macro for sdp_build_attr_fmtp
 * Adds name-value pair where value is char*
 */

#define FMTP_BUILD_STRING(condition, name, value) \
  if ((condition)) { \
    sdp_append_name_and_string(fs, (name), (value), semicolon); \
    semicolon = TRUE; \
  }

/*
 * Macro for sdp_build_attr_fmtp
 * Adds name-value pair where value is unsigned
 */

#define FMTP_BUILD_UNSIGNED(condition, name, value) \
  if ((condition)) { \
    sdp_append_name_and_unsigned(fs, (name), (value), semicolon); \
    semicolon = TRUE; \
  }

/*
 * Macro for sdp_build_attr_fmtp
 * Adds flag string on condition
 */

#define FMTP_BUILD_FLAG(condition, name) \
  if ((condition)) { \
    if (semicolon) { \
      flex_string_append(fs, ";"); \
    } \
    flex_string_append(fs, name); \
    semicolon = TRUE; \
  }

static int find_token_enum(const char *attr_name,
                           sdp_t *sdp_p,
                           const char **ptr,
                           const sdp_namearray_t *types,
                           int type_count,
                           int unknown_value)
{
    sdp_result_e  result = SDP_SUCCESS;
    char          tmp[SDP_MAX_STRING_LEN+1];
    int           i;

    *ptr = sdp_getnextstrtok(*ptr, tmp, sizeof(tmp), " \t", &result);
    if (result != SDP_SUCCESS) {
        sdp_parse_error(sdp_p,
            "%s Warning: problem parsing %s", sdp_p->debug_str, attr_name);
        sdp_p->conf_p->num_invalid_param++;
        return -1;
    }

    for (i=0; i < type_count; i++) {
        if (!cpr_strncasecmp(tmp, types[i].name, types[i].strlen)) {
            return i;
        }
    }
    return unknown_value;
}

/*
 * Helper function for adding nv-pair where value is string.
 */

static void sdp_append_name_and_string(flex_string *fs,
  const char *name,
  const char *value,
  tinybool semicolon)
{
  flex_string_sprintf(fs, "%s%s=%s",
    semicolon ? ";" : "",
    name,
    value);
}

/*
 * Helper function for adding nv-pair where value is unsigned.
 */

static void sdp_append_name_and_unsigned(flex_string *fs,
  const char *name,
  unsigned int value,
  tinybool semicolon)
{
  flex_string_sprintf(fs, "%s%s=%u",
    semicolon ? ";" : "",
    name,
    value);
}

/* Function:    sdp_parse_attribute
 * Description: Figure out the type of attribute and call the appropriate
 *              parsing routine.  If parsing errors are encountered,
 *              warnings will be printed and the attribute will be ignored.
 *              Unrecognized/invalid attributes do not cause overall parsing
 *              errors.  All errors detected are noted as warnings.
 * Parameters:  sdp_p       The SDP handle returned by sdp_init_description.
 *              level       The level to check for the attribute.
 *              ptr         Pointer to the attribute string to parse.
 */

sdp_result_e sdp_parse_attribute (sdp_t *sdp_p, uint16_t level, const char *ptr)
{
    int           i;
    uint8_t            xcpar_flag = FALSE;
    sdp_result_e  result;
    sdp_mca_t    *mca_p=NULL;
    sdp_attr_t   *attr_p;
    sdp_attr_t   *next_attr_p;
    sdp_attr_t   *prev_attr_p = NULL;
    char          tmp[SDP_MAX_STRING_LEN];

    /* Validate the level */
    if (level != SDP_SESSION_LEVEL) {
        mca_p = sdp_find_media_level(sdp_p, level);
        if (mca_p == NULL) {
            return (SDP_FAILURE);
        }
    }

    /* Find the attribute type. */
    ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
    if (ptr == NULL) {
        sdp_parse_error(sdp_p,
          "%s No attribute type specified, parse failed.", sdp_p->debug_str);
        sdp_p->conf_p->num_invalid_param++;
        return (SDP_INVALID_PARAMETER);
    }
    if (ptr[0] == ':') {
        /* Skip the ':' char for parsing attribute parameters. */
        ptr++;
    }
    if (result != SDP_SUCCESS) {
        sdp_parse_error(sdp_p,
          "%s No attribute type specified, parse failed.", sdp_p->debug_str);
        sdp_p->conf_p->num_invalid_param++;
        return (SDP_INVALID_PARAMETER);
    }

    attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
    if (attr_p == NULL) {
        sdp_p->conf_p->num_no_resource++;
        return (SDP_NO_RESOURCE);
    }
    attr_p->line_number = sdp_p->parse_line;
    attr_p->type = SDP_ATTR_INVALID;
    attr_p->next_p = NULL;
    for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
        if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
            attr_p->type = (sdp_attr_e)i;
            break;
        }
    }
    if (attr_p->type == SDP_ATTR_INVALID) {
        sdp_parse_error(sdp_p,
          "%s Warning: Unrecognized attribute (%s) ",
          sdp_p->debug_str, tmp);
        sdp_free_attr(attr_p);
        return (SDP_SUCCESS);
    }

    /* If this is an X-cpar or cpar attribute, set the flag.  The attribute
     * type will be changed by the parse. */

    if ((attr_p->type == SDP_ATTR_X_CPAR) ||
        (attr_p->type == SDP_ATTR_CPAR)) {
        xcpar_flag = TRUE;
    }

    /* Parse the attribute. */
    result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
    if (result != SDP_SUCCESS) {
        sdp_free_attr(attr_p);
        /* Return success so the parse won't fail.  We don't want to
         * fail on errors with attributes but just ignore them.
         */

        return (SDP_SUCCESS);
    }

    /* If this was an X-cpar/cpar attribute, it was hooked into the X-cap/cdsc
     * structure, so we're finished.
     */

    if (xcpar_flag == TRUE) {
        return (result);
    }

    /* Add the attribute in the appropriate place. */
    if (level == SDP_SESSION_LEVEL) {
        for (next_attr_p = sdp_p->sess_attrs_p; next_attr_p != NULL;
             prev_attr_p = next_attr_p,
                 next_attr_p = next_attr_p->next_p) {
            ; /* Empty for */
        }
        if (prev_attr_p == NULL) {
            sdp_p->sess_attrs_p = attr_p;
        } else {
            prev_attr_p->next_p = attr_p;
        }
    } else {
        for (next_attr_p = mca_p->media_attrs_p; next_attr_p != NULL;
             prev_attr_p = next_attr_p,
                 next_attr_p = next_attr_p->next_p) {
            ; /* Empty for */
        }
        if (prev_attr_p == NULL) {
            mca_p->media_attrs_p = attr_p;
        } else {
            prev_attr_p->next_p = attr_p;
        }
    }

    return (result);
}

/* Build all of the attributes defined for the specified level. */
sdp_result_e sdp_build_attribute (sdp_t *sdp_p, uint16_t level, flex_string *fs)
{
    sdp_attr_t   *attr_p;
    sdp_mca_t    *mca_p=NULL;
    sdp_result_e  result;

    if (level == SDP_SESSION_LEVEL) {
        attr_p = sdp_p->sess_attrs_p;
    } else {
        mca_p = sdp_find_media_level(sdp_p, level);
        if (mca_p == NULL) {
            return (SDP_FAILURE);
        }
        attr_p = mca_p->media_attrs_p;
    }
    /* Re-initialize the current capability number for this new level. */
    sdp_p->cur_cap_num = 1;

    /* Build all of the attributes for this level. Note that if there
     * is a problem building an attribute, we don't fail but just ignore it.*/

    while (attr_p != NULL) {
        if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
            if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
                SDPLogDebug(logTag, "%s Invalid attribute type to build (%u)",
                         sdp_p->debug_str, (unsigned)attr_p->type);
            }
        } else {
            result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);

            if (result != SDP_SUCCESS) {
              SDPLogError(logTag, "%s error building attribute %d", __FUNCTION__, result);
              return result;
            }

            if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
                SDP_PRINT("%s Built a=%s attribute line", sdp_p->debug_str,
                          sdp_get_attr_name(attr_p->type));
            }
        }
        attr_p = attr_p->next_p;
    }

    return SDP_SUCCESS;
}

sdp_result_e sdp_parse_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
                                           const char *ptr)
{
    sdp_result_e  result;

    ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
      sizeof(attr_p->attr.string_val), " \t", &result);

    if (result != SDP_SUCCESS) {
        sdp_parse_error(sdp_p,
            "%s Warning: No string token found for %s attribute",
            sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
        sdp_p->conf_p->num_invalid_param++;
        return (SDP_INVALID_PARAMETER);
    } else {
        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
                      sdp_get_attr_name(attr_p->type),
                      attr_p->attr.string_val);
        }
        return (SDP_SUCCESS);
    }
}

sdp_result_e sdp_build_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
  flex_string *fs)
{
  flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
    attr_p->attr.string_val);

  return SDP_SUCCESS;
}

sdp_result_e sdp_parse_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
                                        const char *ptr)
{
    sdp_result_e  result;

    attr_p->attr.u32_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);

    if (result != SDP_SUCCESS) {
        sdp_parse_error(sdp_p,
            "%s Warning: Numeric token for %s attribute not found",
            sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
        sdp_p->conf_p->num_invalid_param++;
        return (SDP_INVALID_PARAMETER);
    } else {
        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            SDP_PRINT("%s Parsed a=%s, %u", sdp_p->debug_str,
                      sdp_get_attr_name(attr_p->type), attr_p->attr.u32_val);
        }
        return (SDP_SUCCESS);
    }
}

sdp_result_e sdp_build_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
  flex_string *fs)
{
  flex_string_sprintf(fs, "a=%s:%u\r\n", sdp_attr[attr_p->type].name,
    attr_p->attr.u32_val);

  return SDP_SUCCESS;
}

sdp_result_e sdp_parse_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
                                         const char *ptr)
{
    sdp_result_e  result;

    if (sdp_getnextnumtok(ptr, &ptr, " \t", &result) == 0) {
        attr_p->attr.boolean_val = FALSE;
    } else {
        attr_p->attr.boolean_val= TRUE;
    }

    if (result != SDP_SUCCESS) {
        sdp_parse_error(sdp_p,
            "%s Warning: Boolean token for %s attribute not found",
            sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
        sdp_p->conf_p->num_invalid_param++;
        return (SDP_INVALID_PARAMETER);
    } else {
        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            if (attr_p->attr.boolean_val) {
                SDP_PRINT("%s Parsed a=%s, boolean is TRUE", sdp_p->debug_str,
                          sdp_get_attr_name(attr_p->type));
            } else {
                SDP_PRINT("%s Parsed a=%s, boolean is FALSE", sdp_p->debug_str,
                          sdp_get_attr_name(attr_p->type));
            }
        }
        return (SDP_SUCCESS);
    }
}

sdp_result_e sdp_build_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
  flex_string *fs)
{
  flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
    attr_p->attr.boolean_val ? "1" : "0");

  return SDP_SUCCESS;
}

/*
 * sdp_parse_attr_maxprate
 *
 * This function parses maxprate attribute lines. The ABNF for this a=
 * line is:
 *    max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF
 *    packet-rate = 1*DIGIT ["." 1*DIGIT]
 *
 * Returns:
 * SDP_INVALID_PARAMETER - If we are unable to parse the string OR if
 *                         packet-rate is not in the right format as per
 *                         the ABNF.
 *
 * SDP_SUCCESS - If we are able to successfully parse the a= line.
 */

sdp_result_e sdp_parse_attr_maxprate (sdp_t *sdp_p, sdp_attr_t *attr_p,
                                      const char *ptr)
{
    sdp_result_e  result;

    ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
      sizeof(attr_p->attr.string_val), " \t", &result);

    if (result != SDP_SUCCESS) {
        sdp_parse_error(sdp_p,
            "%s Warning: No string token found for %s attribute",
            sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
        sdp_p->conf_p->num_invalid_param++;
        return (SDP_INVALID_PARAMETER);
    } else {
        if (!sdp_validate_maxprate(attr_p->attr.string_val)) {
            sdp_parse_error(sdp_p,
                "%s is not a valid maxprate value.",
                attr_p->attr.string_val);
            sdp_p->conf_p->num_invalid_param++;
            return (SDP_INVALID_PARAMETER);
        }

        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
                      sdp_get_attr_name(attr_p->type),
                      attr_p->attr.string_val);
        }
        return (SDP_SUCCESS);
    }
}

/*
 * sdp_attr_fmtp_no_value
 * Helper function for sending the warning when a parameter value is
 * missing.
 *
 */

static void sdp_attr_fmtp_no_value(sdp_t *sdp, const char *param_name)
{
  sdp_parse_error(sdp,
    "%s Warning: No %s value specified for fmtp attribute",
    sdp->debug_str, param_name);
  sdp->conf_p->num_invalid_param++;
}

/*
 * sdp_attr_fmtp_invalid_value
 * Helper function for sending the warning when a parameter value is
 * incorrect.
 *
 */

static void sdp_attr_fmtp_invalid_value(sdp_t *sdp, const char *param_name,
  const char* param_value)
{
  sdp_parse_error(sdp,
    "%s Warning: Invalid %s: %s specified for fmtp attribute",
    sdp->debug_str, param_name, param_value);
  sdp->conf_p->num_invalid_param++;
}

/*
 * sdp_verify_attr_fmtp_telephone_event
 * Helper function for verifying the telephone-event fmtp format
 */

static sdp_result_e sdp_verify_attr_fmtp_telephone_event(char *fmtpVal)
{
  size_t len = fmtpVal ? strlen(fmtpVal) : 0;

  // make sure the basics are good:
  // - at least 1 character
  // - no illegal chars
  // - first char is a number
  if (len < 1
      || strspn(fmtpVal, "0123456789,-") != len
      || PL_strstr(fmtpVal, ",,")
      || fmtpVal[len-1] == ','
      || !('0' <= fmtpVal[0] && fmtpVal[0] <= '9')) {
    return SDP_INVALID_PARAMETER;
  }

  // Now that we've passed the basic sanity test, copy the string so we
  // can tokenize and check the format of the tokens without disturbing
  // the input string.
  char dtmf_tones[SDP_MAX_STRING_LEN+1];
  PL_strncpyz(dtmf_tones, fmtpVal, sizeof(dtmf_tones));

  char *strtok_state;
  char *temp = PL_strtok_r(dtmf_tones, ",", &strtok_state);

  while (temp != NULL) {
    len = strlen(temp);
    if (len > 5) {
      // an example of a max size token is "11-15", so if the
      // token is longer than 5 it is bad
      return SDP_INVALID_PARAMETER;
    }

    // case where we have 1 or 2 characters, example 4 or 23
    if (len < 3 && strspn(temp, "0123456789") != len) {
      return SDP_INVALID_PARAMETER;
    } else if (len >= 3) {
      // case where we have 3-5 characters, ex 3-5, 2-33, or 10-20
      sdp_result_e result1 = SDP_SUCCESS;
      sdp_result_e result2 = SDP_SUCCESS;
      uint8_t low_val;
      uint8_t high_val;
      low_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
                                           "-", &result1);
      high_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
                                            "-", &result2);
      if (temp[0] // we don't want to find a second hyphen
          || result1 != SDP_SUCCESS
          || result2 != SDP_SUCCESS) {
        return SDP_INVALID_PARAMETER;
      }

      if (low_val > 99
          || high_val > 99
          || high_val <= low_val) {
        return SDP_INVALID_PARAMETER;
      }
    }

    temp=PL_strtok_r(NULL, ",", &strtok_state);
  }

  return SDP_SUCCESS;
}

/* Note:  The fmtp attribute formats currently handled are:
 *        fmtp:<payload type> <event>,<event>...
 *        fmtp:<payload_type> [annexa=yes/no] [annexb=yes/no] [bitrate=<value>]
 *        [QCIF =<value>] [CIF =<value>] [MaxBR = <value>] one or more
 *        Other FMTP params as per H.263, H.263+, H.264 codec support.
 *        Note -"value" is a numeric value > 0 and each event is a
 *        single number or a range separated by a '-'.
 *        Example:  fmtp:101 1,3-15,20
 * Video codecs have annexes that can be listed in the following legal formats:
 * a) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3
 * b) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3;T
 * c) a=fmtp:34 param1=token;D;I;J
 *
 */

sdp_result_e sdp_get_fmtp_tok(sdp_t *sdp_p,
                              const char** fmtp_ptr,
                              const char* fmtp_name,
                              char* buf,
                              size_t buf_size,
                              char** tok)
{
    sdp_result_e result1 = SDP_SUCCESS;

    *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, "; \t", &result1);
    if (result1 != SDP_SUCCESS) {
        *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, " \t", &result1);
        if (result1 != SDP_SUCCESS) {
            sdp_attr_fmtp_no_value(sdp_p, fmtp_name);
            return SDP_INVALID_PARAMETER;
        }
    }
    *tok = buf;
    (*tok)++;

    return SDP_SUCCESS;
}

sdp_result_e sdp_get_fmtp_tok_val(sdp_t *sdp_p,
                              const char** fmtp_ptr,
                              const char* fmtp_name,
                              char* buf,
                              size_t buf_size,
                              char** tok,
                              unsigned long* strtoul_result,
                              unsigned long illegal_value,
                              unsigned long min_limit,
                              unsigned long max_limit)
{
  sdp_result_e result1 = SDP_SUCCESS;
  unsigned long value;
  char* strtoul_end;

  result1 = sdp_get_fmtp_tok(sdp_p, fmtp_ptr, fmtp_name, buf, buf_size, tok);
  if (result1 != SDP_SUCCESS) return result1;

  errno = 0;
  value = strtoul(*tok, &strtoul_end, 10);

  if (errno
      || (*tok == strtoul_end)
      || (illegal_value != ULONG_MAX && value == illegal_value)
      || (min_limit != ULONG_MAX && value < min_limit)
      || (max_limit != ULONG_MAX && value > max_limit)) {
    sdp_attr_fmtp_invalid_value(sdp_p, fmtp_name, *tok);
    return SDP_INVALID_PARAMETER;
  }
  *strtoul_result = value;

  return SDP_SUCCESS;
}

sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
                                  const char *ptr)
{
    uint16_t           i;
    uint32_t           mapword;
    uint32_t           bmap;
    uint8_t            low_val;
    uint8_t            high_val;
    const char    *ptr2;
    const char    *fmtp_ptr;
    sdp_result_e  result1 = SDP_SUCCESS;
    sdp_result_e  result2 = SDP_SUCCESS;
    tinybool      done = FALSE;
    tinybool      codec_info_found = FALSE;
    sdp_fmtp_t   *fmtp_p;
    char          tmp[SDP_MAX_STRING_LEN];
    char          *src_ptr;
    char          *temp_ptr = NULL;
    char         *tok=NULL;
    char         *temp=NULL;
    uint16_t          custom_x=0;
    uint16_t          custom_y=0;
    uint16_t          custom_mpi=0;
    uint16_t          par_height=0;
    uint16_t          par_width=0;
    uint16_t          cpcf=0;
    uint16_t          iter=0;

    ulong        l_val = 0;
    char*        strtok_state;
    unsigned long strtoul_result;
    char*        strtoul_end;

    /* Find the payload type number. */
    attr_p->attr.fmtp.payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
                                                      " \t", &result1);
    if (result1 != SDP_SUCCESS) {
        sdp_attr_fmtp_no_value(sdp_p, "payload type");
        return SDP_INVALID_PARAMETER;
    }
    fmtp_p = &(attr_p->attr.fmtp);
    fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE;
    fmtp_p->parameter_add = 1;
    fmtp_p->flag = 0;

    /*
     * set default value of packetization mode and level-asymmetry-allowed. If
     * remote sdp does not specify any value for these two parameters, then the
     * default value will be assumed for remote sdp. If remote sdp does specify
     * any value for these parameters, then default value will be overridden.
    */

    fmtp_p->packetization_mode = SDP_DEFAULT_PACKETIZATION_MODE_VALUE;
    fmtp_p->level_asymmetry_allowed = SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE;

    temp_ptr = cpr_strdup(ptr);
    if (temp_ptr == NULL) {
        return (SDP_FAILURE);
    }
    fmtp_ptr = src_ptr = temp_ptr;

    src_ptr = temp_ptr;
    while (!done) {
      fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "= \t", &result1);
      if (result1 == SDP_SUCCESS) {
        if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[1].name,
                        sdp_fmtp_codec_param[1].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexb", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
                            sdp_fmtp_codec_param_val[0].strlen) == 0) {
                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->annexb_required = TRUE;
                fmtp_p->annexb = TRUE;
            } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
                                   sdp_fmtp_codec_param_val[1].strlen) == 0) {
                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->annexb_required = TRUE;
                fmtp_p->annexb = FALSE;
            } else {
                sdp_attr_fmtp_invalid_value(sdp_p, "annexb", tok);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[0].name,
                               sdp_fmtp_codec_param[0].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexa", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
                            sdp_fmtp_codec_param_val[0].strlen) == 0) {
                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->annexa = TRUE;
                fmtp_p->annexa_required = TRUE;
            } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
                                   sdp_fmtp_codec_param_val[1].strlen) == 0) {
                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->annexa = FALSE;
                fmtp_p->annexa_required = TRUE;
            } else {
                sdp_attr_fmtp_invalid_value(sdp_p, "annexa", tok);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[2].name,
                               sdp_fmtp_codec_param[2].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bitrate", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->bitrate = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

         } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[41].name,
                               sdp_fmtp_codec_param[41].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "mode", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_MODE;
            fmtp_p->mode = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[3].name,
                               sdp_fmtp_codec_param[3].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "qcif", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->qcif = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[4].name,
                               sdp_fmtp_codec_param[4].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->cif = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[5].name,
                               sdp_fmtp_codec_param[5].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxbr", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->maxbr = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[6].name,
                               sdp_fmtp_codec_param[6].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "sqcif", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->sqcif = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[7].name,
                               sdp_fmtp_codec_param[7].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif4", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->cif4 = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[8].name,
                               sdp_fmtp_codec_param[8].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif16", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->cif16 = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[9].name,
                               sdp_fmtp_codec_param[9].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "custom", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            temp=PL_strtok_r(tok, ",", &strtok_state);
            iter++;
        if (temp) {
            iter=1;
            while (temp != NULL) {
                errno = 0;
                strtoul_result = strtoul(temp, &strtoul_end, 10);

                if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX){
                    custom_x = custom_y = custom_mpi = 0;
                    break;
                }

                if (iter == 1)
                    custom_x = (uint16_t) strtoul_result;
                if (iter == 2)
                    custom_y = (uint16_t) strtoul_result;
                if (iter == 3)
                    custom_mpi = (uint16_t) strtoul_result;

                temp=PL_strtok_r(NULL, ",", &strtok_state);
                iter++;
            }
        }

        /* custom x,y and mpi values from tmp */
            if (!custom_x || !custom_y || !custom_mpi) {
                sdp_attr_fmtp_invalid_value(sdp_p, "x/y/MPI", temp);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->custom_x = custom_x;
            fmtp_p->custom_y = custom_y;
            fmtp_p->custom_mpi = custom_mpi;
            codec_info_found = TRUE;

        } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[10].name,
                               sdp_fmtp_codec_param[10].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "par", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            temp=PL_strtok_r(tok, ":", &strtok_state);
        if (temp) {
            iter=1;
            /* get par width and par height for the aspect ratio */
            while (temp != NULL) {
                errno = 0;
                strtoul_result = strtoul(temp, &strtoul_end, 10);

                if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
                    par_width = par_height = 0;
                    break;
                }

                if (iter == 1)
                    par_width = (uint16_t) strtoul_result;
                else
                    par_height = (uint16_t) strtoul_result;

                temp=PL_strtok_r(NULL, ",", &strtok_state);
                iter++;
            }
        }
            if (!par_width || !par_height) {
                sdp_attr_fmtp_invalid_value(sdp_p, "par_width or par_height", temp);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->par_width = par_width;
            fmtp_p->par_height = par_height;
            codec_info_found = TRUE;

        } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[11].name,
                               sdp_fmtp_codec_param[11].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "cpcf", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            temp=PL_strtok_r(tok, ".", &strtok_state);
        if ( temp != NULL  ) {
            errno = 0;
            strtoul_result = strtoul(temp, &strtoul_end, 10);

            if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
                cpcf = 0;
            } else {
                cpcf = (uint16_t) strtoul_result;
            }
        }

            if (!cpcf) {
                sdp_attr_fmtp_invalid_value(sdp_p, "cpcf", tok);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->cpcf = cpcf;
            codec_info_found = TRUE;

        } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[12].name,
                               sdp_fmtp_codec_param[12].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bpp", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
        fmtp_p->bpp = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else  if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[13].name,
                               sdp_fmtp_codec_param[13].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "hrd", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->hrd = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[14].name,
                               sdp_fmtp_codec_param[14].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "profile", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, SDP_MAX_PROFILE_VALUE);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->profile = (short) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[15].name,
                               sdp_fmtp_codec_param[15].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_VALUE);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->level = (short) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name,
                               sdp_fmtp_codec_param[16].strlen) == 0) {
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->is_interlace = TRUE;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[17].name,
                               sdp_fmtp_codec_param[17].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "profile_level_id", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            sstrncpy(fmtp_p->profile_level_id , tok, sizeof(fmtp_p->profile_level_id));
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[18].name,
                               sdp_fmtp_codec_param[18].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "parameter_sets", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            sstrncpy(fmtp_p->parameter_sets , tok, sizeof(fmtp_p->parameter_sets));
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[19].name,
                               sdp_fmtp_codec_param[19].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "packetization_mode", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, 2);
            // this one is different for some reason. Most others don't increment
            // the num_invalid_param field. (mjf)
            if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->packetization_mode = (int16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[20].name,
                               sdp_fmtp_codec_param[20].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "interleaving_depth", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->interleaving_depth = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[21].name,
                               sdp_fmtp_codec_param[21].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->deint_buf_req = (uint32_t) l_val;
                fmtp_p->flag |= SDP_DEINT_BUF_REQ_FLAG;
                codec_info_found = TRUE;
            } else {
                sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_req", tok);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[22].name,
                               sdp_fmtp_codec_param[22].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_don_diff", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->max_don_diff = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[23].name,
                               sdp_fmtp_codec_param[23].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "init_buf_time", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->init_buf_time = (uint32_t) l_val;
                fmtp_p->flag |= SDP_INIT_BUF_TIME_FLAG;
                codec_info_found = TRUE;
            } else {
                sdp_attr_fmtp_invalid_value(sdp_p, "init_buf_time", tok);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[24].name,
                               sdp_fmtp_codec_param[24].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_mbps", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
        fmtp_p->max_mbps = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[25].name,
                               sdp_fmtp_codec_param[25].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fs", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->max_fs = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[26].name,
                               sdp_fmtp_codec_param[26].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_cbp", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->max_cpb = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[27].name,
                               sdp_fmtp_codec_param[27].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_dpb", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->max_dpb = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[28].name,
                               sdp_fmtp_codec_param[28].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_br", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->max_br = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[29].name,
                               sdp_fmtp_codec_param[29].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "redundant_pic_cap", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, 1);
            fmtp_p->redundant_pic_cap = (result1 == SDP_SUCCESS);
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[30].name,
                               sdp_fmtp_codec_param[30].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf_cap", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->deint_buf_cap = (uint32_t) l_val;
                fmtp_p->flag |= SDP_DEINT_BUF_CAP_FLAG;
                codec_info_found = TRUE;
            } else {
                sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_cap", tok);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }

        }  else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[31].name,
                               sdp_fmtp_codec_param[31].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "max_rcmd_nalu_size", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->max_rcmd_nalu_size = (uint32_t) l_val;
                fmtp_p->flag |= SDP_MAX_RCMD_NALU_SIZE_FLAG;
                codec_info_found = TRUE;
            } else {
                sdp_attr_fmtp_invalid_value(sdp_p, "max_rcmd_nalu_size", tok);
                SDP_FREE(temp_ptr);
                return SDP_INVALID_PARAMETER;
            }

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[32].name,
                               sdp_fmtp_codec_param[32].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "parameter_add", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, 1);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->parameter_add = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[33].name,
                               sdp_fmtp_codec_param[33].strlen) == 0) {
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->annex_d = TRUE;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[34].name,
                               sdp_fmtp_codec_param[34].strlen) == 0) {
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->annex_f = TRUE;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[35].name,
                               sdp_fmtp_codec_param[35].strlen) == 0) {
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->annex_i = TRUE;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[36].name,
                               sdp_fmtp_codec_param[36].strlen) == 0) {
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->annex_j = TRUE;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[37].name,
                               sdp_fmtp_codec_param[36].strlen) == 0) {
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->annex_t = TRUE;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[38].name,
                             sdp_fmtp_codec_param[38].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_k", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

                fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                fmtp_p->annex_k_val = (uint16_t) strtoul_result;
                codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[39].name,
                               sdp_fmtp_codec_param[39].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_n", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, USHRT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->annex_n_val = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[40].name,
                               sdp_fmtp_codec_param[40].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annex_p", tmp, sizeof(tmp), &tok);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->annex_p_val_picture_resize = 0;
            fmtp_p->annex_p_val_warp = 0;
            temp = PL_strtok_r(tok, ",", &strtok_state);
            if (temp) {
                iter=1;
                while (temp != NULL) {
                    errno = 0;
                    strtoul_result = strtoul(temp, &strtoul_end, 10);

                    if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
                        break;
                    }

                    if (iter == 1)
                        fmtp_p->annex_p_val_picture_resize = (uint16_t) strtoul_result;
                    else if (iter == 2)
                        fmtp_p->annex_p_val_warp = (uint16_t) strtoul_result;

                    temp = PL_strtok_r(NULL, ",", &strtok_state);
                    iter++;
                }
            } else {
              SDP_FREE(temp_ptr);
              return SDP_INVALID_PARAMETER;
            }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[42].name,
                               sdp_fmtp_codec_param[42].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level_asymmetry_allowed", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->level_asymmetry_allowed = (int) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[43].name,
                                   sdp_fmtp_codec_param[43].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxaveragebitrate", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->maxaveragebitrate = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[44].name,
                                   sdp_fmtp_codec_param[44].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "usedtx", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, 1);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->usedtx = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[45].name,
                                   sdp_fmtp_codec_param[45].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "stereo", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, 1);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->stereo = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[46].name,
                                   sdp_fmtp_codec_param[46].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "useinbandfec", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, 1);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->useinbandfec = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[47].name,
                                       sdp_fmtp_codec_param[47].strlen) == 0) {
            result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "maxcodedaudiobandwidth", tmp, sizeof(tmp), &tok);
            // this one is different for some reason. Most others don't increment
            // the num_invalid_param field. (mjf)
            if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

                    fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
                    sstrncpy(fmtp_p->maxcodedaudiobandwidth , tok, sizeof(fmtp_p->maxcodedaudiobandwidth));
                    codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[48].name,
                                   sdp_fmtp_codec_param[48].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cbr", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, -1, 1);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->cbr = (uint16_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[49].name,
                                   sdp_fmtp_codec_param[49].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fr", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->max_fr = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[50].name,
                                   sdp_fmtp_codec_param[50].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxplaybackrate", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, 0, -1, UINT_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }

            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->maxplaybackrate = (uint32_t) strtoul_result;
            codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[51].name,
                                   sdp_fmtp_codec_param[51].strlen) == 0) {
          result1 =
              sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "apt", tmp, sizeof(tmp),
                                   &tok, &strtoul_result, -1, 0, UINT8_MAX);
          if (result1 != SDP_SUCCESS) {
              SDP_FREE(temp_ptr);
              return result1;
          }

          fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
          fmtp_p->apt = (uint8_t)strtoul_result;

          codec_info_found = TRUE;

        } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[52].name,
                                   sdp_fmtp_codec_param[52].strlen) == 0) {

          result1 =
              sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "rtx_time", tmp, sizeof(tmp),
                                   &tok, &strtoul_result, -1, 0, UINT_MAX);
          if (result1 != SDP_SUCCESS) {
              SDP_FREE(temp_ptr);
              return result1;
          }

          fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
          fmtp_p->has_rtx_time = TRUE;
          fmtp_p->rtx_time = (uint32_t)strtoul_result;

          codec_info_found = TRUE;
        } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[53].name,
                                   sdp_fmtp_codec_param[53].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level-idx", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, 0, UINT8_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->av1_has_level_idx = TRUE;
            fmtp_p->av1_level_idx = (uint8_t)strtoul_result;
            codec_info_found = TRUE;
        } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[54].name,
                                   sdp_fmtp_codec_param[54].strlen) == 0) {
            result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "tier", tmp, sizeof(tmp),
                                           &tok, &strtoul_result, -1, 0, UINT8_MAX);
            if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
            fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
            fmtp_p->av1_has_tier = TRUE;
            fmtp_p->av1_tier = (uint8_t)strtoul_result;
            codec_info_found = TRUE;
        } else if (strchr(tmp, '/')) {
            // XXX Note that because RFC 5109 so conveniently specified
            // this fmtp with no param names, we hope that nothing else
            // has a slash in the string because otherwise we won't know
            // how to differentiate.
            temp=PL_strtok_r(tmp, "/", &strtok_state);
            if (temp) {
                iter = 0;
                while (temp != NULL) {
                    errno = 0;
                    strtoul_result = strtoul(temp, &strtoul_end, 10);

                    if (errno ||
                       temp == strtoul_end || strtoul_result > USHRT_MAX) {
                      temp = NULL;
                      continue;
                    }
                    fmtp_p->redundant_encodings[iter++] =
                        (uint8_t)strtoul_result;
                    temp=PL_strtok_r(NULL, "/", &strtok_state);
                }
            } /* if (temp) */
        } else if (SDP_SUCCESS == sdp_verify_attr_fmtp_telephone_event(tmp)) {
          // XXX Note that DTMF fmtp will fall into here:
          // a=fmtp:101 0-15 (or 0-15,NN,NN etc)
          sstrncpy(fmtp_p->dtmf_tones , tmp, sizeof(fmtp_p->dtmf_tones));
          codec_info_found = TRUE;
        } else if (fmtp_ptr != NULL && *fmtp_ptr == '\n') {
            temp=PL_strtok_r(tmp, ";", &strtok_state);
            if (temp) {
                if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
                    SDP_PRINT("%s Annexes are possibly there for this fmtp %s tmp: %s line\n",
                              sdp_p->debug_str, fmtp_ptr, tmp);
                }
                while (temp != NULL) {
                    if (strchr(temp, 'D') !=NULL) {
                        attr_p->attr.fmtp.annex_d = TRUE;
                    }
                    if (strchr(temp, 'F') !=NULL) {
                        attr_p->attr.fmtp.annex_f = TRUE;
                    }
                    if (strchr(temp, 'I') !=NULL) {
                        attr_p->attr.fmtp.annex_i = TRUE;
                    }
                    if (strchr(temp, 'J') !=NULL) {
                        attr_p->attr.fmtp.annex_j = TRUE;
                    }
                    if (strchr(temp, 'T') !=NULL) {
                        attr_p->attr.fmtp.annex_t = TRUE;
                    }
                    temp=PL_strtok_r(NULL, ";", &strtok_state);
                }
            } /* if (temp) */
            done = TRUE;
        } else {
          // unknown parameter - eat chars until ';'
          SDPLogDebug(logTag, "%s Unknown fmtp type (%s) - ignoring", __FUNCTION__,
                      tmp);
          fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t",
                                       &result1);
          if (result1 != SDP_SUCCESS) {
            fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
            if (result1 != SDP_SUCCESS) {
              // hmmm, no ; or spaces or tabs; continue on
            }
          }
        }
        if (*fmtp_ptr == '\n') {
          // reached end of line, stop parsing
          done = TRUE;
        } else {
          fmtp_ptr++;
        }
      } else {
          done = TRUE;
      }
    } /* while  - done loop*/

    if (codec_info_found) {

        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            SDP_PRINT("%s Parsed a=%s, payload type %u, bitrate %u, mode %u QCIF = %u, CIF = %u, MAXBR= %u, SQCIF=%u, CIF4= %u, CIF16=%u, CUSTOM=%u,%u,%u , PAR=%u:%u,CPCF=%u, BPP=%u, HRD=%u \n",
                      sdp_p->debug_str,
                      sdp_get_attr_name(attr_p->type),
                      attr_p->attr.fmtp.payload_num,
                      attr_p->attr.fmtp.bitrate,
                      attr_p->attr.fmtp.mode,
                      attr_p->attr.fmtp.qcif,
                      attr_p->attr.fmtp.cif,
                      attr_p->attr.fmtp.maxbr,
                      attr_p->attr.fmtp.sqcif,
                      attr_p->attr.fmtp.cif4,
                      attr_p->attr.fmtp.cif16,
                      attr_p->attr.fmtp.custom_x,attr_p->attr.fmtp.custom_y,
                      attr_p->attr.fmtp.custom_mpi,
                      attr_p->attr.fmtp.par_width,
                      attr_p->attr.fmtp.par_height,
                      attr_p->attr.fmtp.cpcf,
                      attr_p->attr.fmtp.bpp,
                      attr_p->attr.fmtp.hrd
                      );
        }

        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            SDP_PRINT("%s Parsed a=%s, payload type %u,PROFILE=%u,LEVEL=%u, INTERLACE - %s",
                      sdp_p->debug_str,
                      sdp_get_attr_name(attr_p->type),
                      attr_p->attr.fmtp.payload_num,
                      attr_p->attr.fmtp.profile,
                      attr_p->attr.fmtp.level,
                      attr_p->attr.fmtp.is_interlace ? "YES":"NO");
        }

        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            SDP_PRINT("%s Parsed H.264 attributes: profile-level-id=%s, parameter-sets=%s, packetization-mode=%d level-asymmetry-allowed=%d interleaving-depth=%d deint-buf-req=%u max-don-diff=%u, init_buf-time=%u\n",
                      sdp_p->debug_str,
                      attr_p->attr.fmtp.profile_level_id,
                      attr_p->attr.fmtp.parameter_sets,
                      attr_p->attr.fmtp.packetization_mode,
                      attr_p->attr.fmtp.level_asymmetry_allowed,
                      attr_p->attr.fmtp.interleaving_depth,
                      attr_p->attr.fmtp.deint_buf_req,
                      attr_p->attr.fmtp.max_don_diff,
                      attr_p->attr.fmtp.init_buf_time
                      );
        }

        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            SDP_PRINT("\n%s Parsed H.264 opt attributes: max-mbps=%u, max-fs=%u, max-cpb=%u max-dpb=%u max-br=%u redundant-pic-cap=%d, deint-buf-cap=%u, max-rcmd-nalu-size=%u , parameter-add=%d\n",
                      sdp_p->debug_str,
                      attr_p->attr.fmtp.max_mbps,
                      attr_p->attr.fmtp.max_fs,
                      attr_p->attr.fmtp.max_cpb,
                      attr_p->attr.fmtp.max_dpb,
                      attr_p->attr.fmtp.max_br,
                      attr_p->attr.fmtp.redundant_pic_cap,
                      attr_p->attr.fmtp.deint_buf_cap,
                      attr_p->attr.fmtp.max_rcmd_nalu_size,
                      attr_p->attr.fmtp.parameter_add);

        }
        if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
            SDP_PRINT("%s Parsed annexes are : D=%d F=%d I=%d J=%d T=%d, K=%d N=%d P=%d,%d\n",
                      sdp_p->debug_str,
                      attr_p->attr.fmtp.annex_d,
                      attr_p->attr.fmtp.annex_f,  attr_p->attr.fmtp.annex_i,
                      attr_p->attr.fmtp.annex_j,  attr_p->attr.fmtp.annex_t,
                      attr_p->attr.fmtp.annex_k_val,
                      attr_p->attr.fmtp.annex_n_val,
                      attr_p->attr.fmtp.annex_p_val_picture_resize,
                      attr_p->attr.fmtp.annex_p_val_warp);

        }
        SDP_FREE(temp_ptr);
        return (SDP_SUCCESS);
    } else {
        done = FALSE;
        fmtp_ptr = src_ptr;
        tmp[0] = '\0';
    }

    for (i=0; !done; i++) {
        fmtp_p->fmtp_format = SDP_FMTP_NTE;
        /* Look for comma separated events */
        fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), ", \t", &result1);
        if (result1 != SDP_SUCCESS) {
            done = TRUE;
            continue;
        }
        /* Now look for '-' separated range */
        ptr2 = tmp;
        low_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
                                    "- \t", &result1);
        if (*ptr2 == '-') {
            high_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
                                         "- \t", &result2);
        } else {
            high_val = low_val;
        }

        if ((result1 != SDP_SUCCESS) || (result2 != SDP_SUCCESS)) {
            sdp_parse_error(sdp_p,
                "%s Warning: Invalid named events specified for fmtp attribute.",
                sdp_p->debug_str);
            sdp_p->conf_p->num_invalid_param++;
            SDP_FREE(temp_ptr);
            return (SDP_INVALID_PARAMETER);
        }

        for (i = low_val; i <= high_val; i++) {
            mapword = i/SDP_NE_BITS_PER_WORD;
            bmap = ((unsigned)SDP_NE_BIT_0) << (i%32);
            fmtp_p->bmap[mapword] |= bmap;
        }
        if (high_val > fmtp_p->maxval) {
            fmtp_p->maxval = high_val;
        }
    }

    if (fmtp_p->maxval == 0) {
        sdp_parse_error(sdp_p,
            "%s Warning: No named events specified for fmtp attribute.",
            sdp_p->debug_str);
        sdp_p->conf_p->num_invalid_param++;
        SDP_FREE(temp_ptr);
        return (SDP_INVALID_PARAMETER);
    }

    if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
        SDP_PRINT("%s Parsed a=%s, payload type %u, ", sdp_p->debug_str,
                  sdp_get_attr_name(attr_p->type),
                  attr_p->attr.fmtp.payload_num);
    }
    SDP_FREE(temp_ptr);
    return (SDP_SUCCESS);
}

sdp_result_e
sdp_build_attr_fmtp_params (sdp_t *sdp_p, sdp_fmtp_t *fmtp_p, flex_string *fs)
{
  uint16_t         event_id;
  uint32_t         mask;
  uint32_t         mapword;
  uint8_t          min = 0;
  uint8_t          max = 0;
  tinybool    range_start = FALSE;
  tinybool    range_end = FALSE;
  tinybool    semicolon = FALSE;

  switch (fmtp_p->fmtp_format) {
    case SDP_FMTP_MODE:
      sdp_append_name_and_unsigned(fs, "mode", fmtp_p->mode, FALSE);
      break;

    case SDP_FMTP_CODEC_INFO:
      FMTP_BUILD_UNSIGNED(fmtp_p->bitrate > 0, "bitrate", fmtp_p->bitrate)

      FMTP_BUILD_STRING(fmtp_p->annexa_required,
        "annexa", (fmtp_p->annexa ? "yes" : "no"))

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=91 G=93

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.