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