1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "sdp_os_defs.h"
11 #include "sipcc_sdp.h"
12 #include "sdp_private.h"
13 #include "sdp_base64.h"
17 static const char* logTag
= "sdp_attr";
20 * Macro for sdp_build_attr_fmtp
21 * Adds name-value pair where value is char*
23 #define FMTP_BUILD_STRING(condition, name, value) \
25 sdp_append_name_and_string(fs, (name), (value), semicolon); \
30 * Macro for sdp_build_attr_fmtp
31 * Adds name-value pair where value is unsigned
33 #define FMTP_BUILD_UNSIGNED(condition, name, value) \
35 sdp_append_name_and_unsigned(fs, (name), (value), semicolon); \
40 * Macro for sdp_build_attr_fmtp
41 * Adds flag string on condition
43 #define FMTP_BUILD_FLAG(condition, name) \
46 flex_string_append(fs, ";"); \
48 flex_string_append(fs, name); \
52 static int find_token_enum(const char *attr_name
,
55 const sdp_namearray_t
*types
,
59 sdp_result_e result
= SDP_SUCCESS
;
60 char tmp
[SDP_MAX_STRING_LEN
+1];
63 *ptr
= sdp_getnextstrtok(*ptr
, tmp
, sizeof(tmp
), " \t", &result
);
64 if (result
!= SDP_SUCCESS
) {
65 sdp_parse_error(sdp_p
,
66 "%s Warning: problem parsing %s", sdp_p
->debug_str
, attr_name
);
67 sdp_p
->conf_p
->num_invalid_param
++;
71 for (i
=0; i
< type_count
; i
++) {
72 if (!cpr_strncasecmp(tmp
, types
[i
].name
, types
[i
].strlen
)) {
80 * Helper function for adding nv-pair where value is string.
82 static void sdp_append_name_and_string(flex_string
*fs
,
87 flex_string_sprintf(fs
, "%s%s=%s",
94 * Helper function for adding nv-pair where value is unsigned.
96 static void sdp_append_name_and_unsigned(flex_string
*fs
,
101 flex_string_sprintf(fs
, "%s%s=%u",
102 semicolon
? ";" : "",
107 /* Function: sdp_parse_attribute
108 * Description: Figure out the type of attribute and call the appropriate
109 * parsing routine. If parsing errors are encountered,
110 * warnings will be printed and the attribute will be ignored.
111 * Unrecognized/invalid attributes do not cause overall parsing
112 * errors. All errors detected are noted as warnings.
113 * Parameters: sdp_p The SDP handle returned by sdp_init_description.
114 * level The level to check for the attribute.
115 * ptr Pointer to the attribute string to parse.
117 sdp_result_e
sdp_parse_attribute (sdp_t
*sdp_p
, uint16_t level
, const char *ptr
)
120 uint8_t xcpar_flag
= FALSE
;
122 sdp_mca_t
*mca_p
=NULL
;
124 sdp_attr_t
*next_attr_p
;
125 sdp_attr_t
*prev_attr_p
= NULL
;
126 char tmp
[SDP_MAX_STRING_LEN
];
128 /* Validate the level */
129 if (level
!= SDP_SESSION_LEVEL
) {
130 mca_p
= sdp_find_media_level(sdp_p
, level
);
132 return (SDP_FAILURE
);
136 /* Find the attribute type. */
137 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), ": \t", &result
);
139 sdp_parse_error(sdp_p
,
140 "%s No attribute type specified, parse failed.", sdp_p
->debug_str
);
141 sdp_p
->conf_p
->num_invalid_param
++;
142 return (SDP_INVALID_PARAMETER
);
145 /* Skip the ':' char for parsing attribute parameters. */
148 if (result
!= SDP_SUCCESS
) {
149 sdp_parse_error(sdp_p
,
150 "%s No attribute type specified, parse failed.", sdp_p
->debug_str
);
151 sdp_p
->conf_p
->num_invalid_param
++;
152 return (SDP_INVALID_PARAMETER
);
155 attr_p
= (sdp_attr_t
*)SDP_MALLOC(sizeof(sdp_attr_t
));
156 if (attr_p
== NULL
) {
157 sdp_p
->conf_p
->num_no_resource
++;
158 return (SDP_NO_RESOURCE
);
160 attr_p
->line_number
= sdp_p
->parse_line
;
161 attr_p
->type
= SDP_ATTR_INVALID
;
162 attr_p
->next_p
= NULL
;
163 for (i
=0; i
< SDP_MAX_ATTR_TYPES
; i
++) {
164 if (cpr_strncasecmp(tmp
, sdp_attr
[i
].name
, sdp_attr
[i
].strlen
) == 0) {
165 attr_p
->type
= (sdp_attr_e
)i
;
169 if (attr_p
->type
== SDP_ATTR_INVALID
) {
170 sdp_parse_error(sdp_p
,
171 "%s Warning: Unrecognized attribute (%s) ",
172 sdp_p
->debug_str
, tmp
);
173 sdp_free_attr(attr_p
);
174 return (SDP_SUCCESS
);
177 /* If this is an X-cpar or cpar attribute, set the flag. The attribute
178 * type will be changed by the parse. */
179 if ((attr_p
->type
== SDP_ATTR_X_CPAR
) ||
180 (attr_p
->type
== SDP_ATTR_CPAR
)) {
184 /* Parse the attribute. */
185 result
= sdp_attr
[attr_p
->type
].parse_func(sdp_p
, attr_p
, ptr
);
186 if (result
!= SDP_SUCCESS
) {
187 sdp_free_attr(attr_p
);
188 /* Return success so the parse won't fail. We don't want to
189 * fail on errors with attributes but just ignore them.
191 return (SDP_SUCCESS
);
194 /* If this was an X-cpar/cpar attribute, it was hooked into the X-cap/cdsc
195 * structure, so we're finished.
197 if (xcpar_flag
== TRUE
) {
201 /* Add the attribute in the appropriate place. */
202 if (level
== SDP_SESSION_LEVEL
) {
203 for (next_attr_p
= sdp_p
->sess_attrs_p
; next_attr_p
!= NULL
;
204 prev_attr_p
= next_attr_p
,
205 next_attr_p
= next_attr_p
->next_p
) {
208 if (prev_attr_p
== NULL
) {
209 sdp_p
->sess_attrs_p
= attr_p
;
211 prev_attr_p
->next_p
= attr_p
;
214 for (next_attr_p
= mca_p
->media_attrs_p
; next_attr_p
!= NULL
;
215 prev_attr_p
= next_attr_p
,
216 next_attr_p
= next_attr_p
->next_p
) {
219 if (prev_attr_p
== NULL
) {
220 mca_p
->media_attrs_p
= attr_p
;
222 prev_attr_p
->next_p
= attr_p
;
229 /* Build all of the attributes defined for the specified level. */
230 sdp_result_e
sdp_build_attribute (sdp_t
*sdp_p
, uint16_t level
, flex_string
*fs
)
233 sdp_mca_t
*mca_p
=NULL
;
236 if (level
== SDP_SESSION_LEVEL
) {
237 attr_p
= sdp_p
->sess_attrs_p
;
239 mca_p
= sdp_find_media_level(sdp_p
, level
);
241 return (SDP_FAILURE
);
243 attr_p
= mca_p
->media_attrs_p
;
245 /* Re-initialize the current capability number for this new level. */
246 sdp_p
->cur_cap_num
= 1;
248 /* Build all of the attributes for this level. Note that if there
249 * is a problem building an attribute, we don't fail but just ignore it.*/
250 while (attr_p
!= NULL
) {
251 if (attr_p
->type
>= SDP_MAX_ATTR_TYPES
) {
252 if (sdp_p
->debug_flag
[SDP_DEBUG_WARNINGS
]) {
253 SDPLogDebug(logTag
, "%s Invalid attribute type to build (%u)",
254 sdp_p
->debug_str
, (unsigned)attr_p
->type
);
257 result
= sdp_attr
[attr_p
->type
].build_func(sdp_p
, attr_p
, fs
);
259 if (result
!= SDP_SUCCESS
) {
260 SDPLogError(logTag
, "%s error building attribute %d", __FUNCTION__
, result
);
264 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
265 SDP_PRINT("%s Built a=%s attribute line", sdp_p
->debug_str
,
266 sdp_get_attr_name(attr_p
->type
));
269 attr_p
= attr_p
->next_p
;
275 sdp_result_e
sdp_parse_attr_simple_string (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
280 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.string_val
,
281 sizeof(attr_p
->attr
.string_val
), " \t", &result
);
283 if (result
!= SDP_SUCCESS
) {
284 sdp_parse_error(sdp_p
,
285 "%s Warning: No string token found for %s attribute",
286 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
287 sdp_p
->conf_p
->num_invalid_param
++;
288 return (SDP_INVALID_PARAMETER
);
290 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
291 SDP_PRINT("%s Parsed a=%s, %s", sdp_p
->debug_str
,
292 sdp_get_attr_name(attr_p
->type
),
293 attr_p
->attr
.string_val
);
295 return (SDP_SUCCESS
);
299 sdp_result_e
sdp_build_attr_simple_string (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
302 flex_string_sprintf(fs
, "a=%s:%s\r\n", sdp_attr
[attr_p
->type
].name
,
303 attr_p
->attr
.string_val
);
308 sdp_result_e
sdp_parse_attr_simple_u32 (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
313 attr_p
->attr
.u32_val
= sdp_getnextnumtok(ptr
, &ptr
, " \t", &result
);
315 if (result
!= SDP_SUCCESS
) {
316 sdp_parse_error(sdp_p
,
317 "%s Warning: Numeric token for %s attribute not found",
318 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
319 sdp_p
->conf_p
->num_invalid_param
++;
320 return (SDP_INVALID_PARAMETER
);
322 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
323 SDP_PRINT("%s Parsed a=%s, %u", sdp_p
->debug_str
,
324 sdp_get_attr_name(attr_p
->type
), attr_p
->attr
.u32_val
);
326 return (SDP_SUCCESS
);
330 sdp_result_e
sdp_build_attr_simple_u32 (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
333 flex_string_sprintf(fs
, "a=%s:%u\r\n", sdp_attr
[attr_p
->type
].name
,
334 attr_p
->attr
.u32_val
);
339 sdp_result_e
sdp_parse_attr_simple_bool (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
344 if (sdp_getnextnumtok(ptr
, &ptr
, " \t", &result
) == 0) {
345 attr_p
->attr
.boolean_val
= FALSE
;
347 attr_p
->attr
.boolean_val
= TRUE
;
350 if (result
!= SDP_SUCCESS
) {
351 sdp_parse_error(sdp_p
,
352 "%s Warning: Boolean token for %s attribute not found",
353 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
354 sdp_p
->conf_p
->num_invalid_param
++;
355 return (SDP_INVALID_PARAMETER
);
357 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
358 if (attr_p
->attr
.boolean_val
) {
359 SDP_PRINT("%s Parsed a=%s, boolean is TRUE", sdp_p
->debug_str
,
360 sdp_get_attr_name(attr_p
->type
));
362 SDP_PRINT("%s Parsed a=%s, boolean is FALSE", sdp_p
->debug_str
,
363 sdp_get_attr_name(attr_p
->type
));
366 return (SDP_SUCCESS
);
370 sdp_result_e
sdp_build_attr_simple_bool (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
373 flex_string_sprintf(fs
, "a=%s:%s\r\n", sdp_attr
[attr_p
->type
].name
,
374 attr_p
->attr
.boolean_val
? "1" : "0");
380 * sdp_parse_attr_maxprate
382 * This function parses maxprate attribute lines. The ABNF for this a=
384 * max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF
385 * packet-rate = 1*DIGIT ["." 1*DIGIT]
388 * SDP_INVALID_PARAMETER - If we are unable to parse the string OR if
389 * packet-rate is not in the right format as per
392 * SDP_SUCCESS - If we are able to successfully parse the a= line.
394 sdp_result_e
sdp_parse_attr_maxprate (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
399 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.string_val
,
400 sizeof(attr_p
->attr
.string_val
), " \t", &result
);
402 if (result
!= SDP_SUCCESS
) {
403 sdp_parse_error(sdp_p
,
404 "%s Warning: No string token found for %s attribute",
405 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
406 sdp_p
->conf_p
->num_invalid_param
++;
407 return (SDP_INVALID_PARAMETER
);
409 if (!sdp_validate_maxprate(attr_p
->attr
.string_val
)) {
410 sdp_parse_error(sdp_p
,
411 "%s is not a valid maxprate value.",
412 attr_p
->attr
.string_val
);
413 sdp_p
->conf_p
->num_invalid_param
++;
414 return (SDP_INVALID_PARAMETER
);
417 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
418 SDP_PRINT("%s Parsed a=%s, %s", sdp_p
->debug_str
,
419 sdp_get_attr_name(attr_p
->type
),
420 attr_p
->attr
.string_val
);
422 return (SDP_SUCCESS
);
427 * sdp_attr_fmtp_no_value
428 * Helper function for sending the warning when a parameter value is
432 static void sdp_attr_fmtp_no_value(sdp_t
*sdp
, const char *param_name
)
435 "%s Warning: No %s value specified for fmtp attribute",
436 sdp
->debug_str
, param_name
);
437 sdp
->conf_p
->num_invalid_param
++;
441 * sdp_attr_fmtp_invalid_value
442 * Helper function for sending the warning when a parameter value is
446 static void sdp_attr_fmtp_invalid_value(sdp_t
*sdp
, const char *param_name
,
447 const char* param_value
)
450 "%s Warning: Invalid %s: %s specified for fmtp attribute",
451 sdp
->debug_str
, param_name
, param_value
);
452 sdp
->conf_p
->num_invalid_param
++;
456 * sdp_verify_attr_fmtp_telephone_event
457 * Helper function for verifying the telephone-event fmtp format
459 static sdp_result_e
sdp_verify_attr_fmtp_telephone_event(char *fmtpVal
)
461 size_t len
= fmtpVal
? strlen(fmtpVal
) : 0;
463 // make sure the basics are good:
464 // - at least 1 character
465 // - no illegal chars
466 // - first char is a number
468 || strspn(fmtpVal
, "0123456789,-") != len
469 || PL_strstr(fmtpVal
, ",,")
470 || fmtpVal
[len
-1] == ','
471 || !('0' <= fmtpVal
[0] && fmtpVal
[0] <= '9')) {
472 return SDP_INVALID_PARAMETER
;
475 // Now that we've passed the basic sanity test, copy the string so we
476 // can tokenize and check the format of the tokens without disturbing
478 char dtmf_tones
[SDP_MAX_STRING_LEN
+1];
479 PL_strncpyz(dtmf_tones
, fmtpVal
, sizeof(dtmf_tones
));
482 char *temp
= PL_strtok_r(dtmf_tones
, ",", &strtok_state
);
484 while (temp
!= NULL
) {
487 // an example of a max size token is "11-15", so if the
488 // token is longer than 5 it is bad
489 return SDP_INVALID_PARAMETER
;
492 // case where we have 1 or 2 characters, example 4 or 23
493 if (len
< 3 && strspn(temp
, "0123456789") != len
) {
494 return SDP_INVALID_PARAMETER
;
495 } else if (len
>= 3) {
496 // case where we have 3-5 characters, ex 3-5, 2-33, or 10-20
497 sdp_result_e result1
= SDP_SUCCESS
;
498 sdp_result_e result2
= SDP_SUCCESS
;
501 low_val
= (uint8_t)sdp_getnextnumtok(temp
, (const char **)&temp
,
503 high_val
= (uint8_t)sdp_getnextnumtok(temp
, (const char **)&temp
,
505 if (temp
[0] // we don't want to find a second hyphen
506 || result1
!= SDP_SUCCESS
507 || result2
!= SDP_SUCCESS
) {
508 return SDP_INVALID_PARAMETER
;
513 || high_val
<= low_val
) {
514 return SDP_INVALID_PARAMETER
;
518 temp
=PL_strtok_r(NULL
, ",", &strtok_state
);
524 /* Note: The fmtp attribute formats currently handled are:
525 * fmtp:<payload type> <event>,<event>...
526 * fmtp:<payload_type> [annexa=yes/no] [annexb=yes/no] [bitrate=<value>]
527 * [QCIF =<value>] [CIF =<value>] [MaxBR = <value>] one or more
528 * Other FMTP params as per H.263, H.263+, H.264 codec support.
529 * Note -"value" is a numeric value > 0 and each event is a
530 * single number or a range separated by a '-'.
531 * Example: fmtp:101 1,3-15,20
532 * Video codecs have annexes that can be listed in the following legal formats:
533 * a) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3
534 * b) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3;T
535 * c) a=fmtp:34 param1=token;D;I;J
538 sdp_result_e
sdp_get_fmtp_tok(sdp_t
*sdp_p
,
539 const char** fmtp_ptr
,
540 const char* fmtp_name
,
545 sdp_result_e result1
= SDP_SUCCESS
;
547 *fmtp_ptr
= sdp_getnextstrtok(*fmtp_ptr
, buf
, buf_size
, "; \t", &result1
);
548 if (result1
!= SDP_SUCCESS
) {
549 *fmtp_ptr
= sdp_getnextstrtok(*fmtp_ptr
, buf
, buf_size
, " \t", &result1
);
550 if (result1
!= SDP_SUCCESS
) {
551 sdp_attr_fmtp_no_value(sdp_p
, fmtp_name
);
552 return SDP_INVALID_PARAMETER
;
561 sdp_result_e
sdp_get_fmtp_tok_val(sdp_t
*sdp_p
,
562 const char** fmtp_ptr
,
563 const char* fmtp_name
,
567 unsigned long* strtoul_result
,
568 unsigned long illegal_value
,
569 unsigned long min_limit
,
570 unsigned long max_limit
)
572 sdp_result_e result1
= SDP_SUCCESS
;
576 result1
= sdp_get_fmtp_tok(sdp_p
, fmtp_ptr
, fmtp_name
, buf
, buf_size
, tok
);
577 if (result1
!= SDP_SUCCESS
) return result1
;
580 value
= strtoul(*tok
, &strtoul_end
, 10);
583 || (*tok
== strtoul_end
)
584 || (illegal_value
!= ULONG_MAX
&& value
== illegal_value
)
585 || (min_limit
!= ULONG_MAX
&& value
< min_limit
)
586 || (max_limit
!= ULONG_MAX
&& value
> max_limit
)) {
587 sdp_attr_fmtp_invalid_value(sdp_p
, fmtp_name
, *tok
);
588 return SDP_INVALID_PARAMETER
;
590 *strtoul_result
= value
;
595 sdp_result_e
sdp_parse_attr_fmtp (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
604 const char *fmtp_ptr
;
605 sdp_result_e result1
= SDP_SUCCESS
;
606 sdp_result_e result2
= SDP_SUCCESS
;
607 tinybool done
= FALSE
;
608 tinybool codec_info_found
= FALSE
;
610 char tmp
[SDP_MAX_STRING_LEN
];
612 char *temp_ptr
= NULL
;
617 uint16_t custom_mpi
=0;
618 uint16_t par_height
=0;
619 uint16_t par_width
=0;
625 unsigned long strtoul_result
;
628 /* Find the payload type number. */
629 attr_p
->attr
.fmtp
.payload_num
= (uint16_t)sdp_getnextnumtok(ptr
, &ptr
,
631 if (result1
!= SDP_SUCCESS
) {
632 sdp_attr_fmtp_no_value(sdp_p
, "payload type");
633 return SDP_INVALID_PARAMETER
;
635 fmtp_p
= &(attr_p
->attr
.fmtp
);
636 fmtp_p
->fmtp_format
= SDP_FMTP_UNKNOWN_TYPE
;
637 fmtp_p
->parameter_add
= 1;
641 * set default value of packetization mode and level-asymmetry-allowed. If
642 * remote sdp does not specify any value for these two parameters, then the
643 * default value will be assumed for remote sdp. If remote sdp does specify
644 * any value for these parameters, then default value will be overridden.
646 fmtp_p
->packetization_mode
= SDP_DEFAULT_PACKETIZATION_MODE_VALUE
;
647 fmtp_p
->level_asymmetry_allowed
= SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE
;
649 temp_ptr
= cpr_strdup(ptr
);
650 if (temp_ptr
== NULL
) {
651 return (SDP_FAILURE
);
653 fmtp_ptr
= src_ptr
= temp_ptr
;
657 fmtp_ptr
= sdp_getnextstrtok(fmtp_ptr
, tmp
, sizeof(tmp
), "= \t", &result1
);
658 if (result1
== SDP_SUCCESS
) {
659 if (cpr_strncasecmp(tmp
, sdp_fmtp_codec_param
[1].name
,
660 sdp_fmtp_codec_param
[1].strlen
) == 0) {
661 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "annexb", tmp
, sizeof(tmp
), &tok
);
662 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
664 if (cpr_strncasecmp(tok
,sdp_fmtp_codec_param_val
[0].name
,
665 sdp_fmtp_codec_param_val
[0].strlen
) == 0) {
666 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
667 fmtp_p
->annexb_required
= TRUE
;
668 fmtp_p
->annexb
= TRUE
;
669 } else if (cpr_strncasecmp(tok
,sdp_fmtp_codec_param_val
[1].name
,
670 sdp_fmtp_codec_param_val
[1].strlen
) == 0) {
671 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
672 fmtp_p
->annexb_required
= TRUE
;
673 fmtp_p
->annexb
= FALSE
;
675 sdp_attr_fmtp_invalid_value(sdp_p
, "annexb", tok
);
677 return SDP_INVALID_PARAMETER
;
679 codec_info_found
= TRUE
;
681 } else if (cpr_strncasecmp(tmp
, sdp_fmtp_codec_param
[0].name
,
682 sdp_fmtp_codec_param
[0].strlen
) == 0) {
683 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "annexa", tmp
, sizeof(tmp
), &tok
);
684 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
686 if (cpr_strncasecmp(tok
,sdp_fmtp_codec_param_val
[0].name
,
687 sdp_fmtp_codec_param_val
[0].strlen
) == 0) {
688 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
689 fmtp_p
->annexa
= TRUE
;
690 fmtp_p
->annexa_required
= TRUE
;
691 } else if (cpr_strncasecmp(tok
,sdp_fmtp_codec_param_val
[1].name
,
692 sdp_fmtp_codec_param_val
[1].strlen
) == 0) {
693 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
694 fmtp_p
->annexa
= FALSE
;
695 fmtp_p
->annexa_required
= TRUE
;
697 sdp_attr_fmtp_invalid_value(sdp_p
, "annexa", tok
);
699 return SDP_INVALID_PARAMETER
;
701 codec_info_found
= TRUE
;
703 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[2].name
,
704 sdp_fmtp_codec_param
[2].strlen
) == 0) {
705 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "bitrate", tmp
, sizeof(tmp
),
706 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
707 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
709 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
710 fmtp_p
->bitrate
= (uint32_t) strtoul_result
;
711 codec_info_found
= TRUE
;
713 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[41].name
,
714 sdp_fmtp_codec_param
[41].strlen
) == 0) {
715 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "mode", tmp
, sizeof(tmp
),
716 &tok
, &strtoul_result
, -1, -1, UINT_MAX
);
717 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
719 fmtp_p
->fmtp_format
= SDP_FMTP_MODE
;
720 fmtp_p
->mode
= (uint32_t) strtoul_result
;
721 codec_info_found
= TRUE
;
723 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[3].name
,
724 sdp_fmtp_codec_param
[3].strlen
) == 0) {
725 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "qcif", tmp
, sizeof(tmp
),
726 &tok
, &strtoul_result
, -1, SDP_MIN_CIF_VALUE
, SDP_MAX_CIF_VALUE
);
727 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
729 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
730 fmtp_p
->qcif
= (uint16_t) strtoul_result
;
731 codec_info_found
= TRUE
;
733 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[4].name
,
734 sdp_fmtp_codec_param
[4].strlen
) == 0) {
735 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "cif", tmp
, sizeof(tmp
),
736 &tok
, &strtoul_result
, -1, SDP_MIN_CIF_VALUE
, SDP_MAX_CIF_VALUE
);
737 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
739 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
740 fmtp_p
->cif
= (uint16_t) strtoul_result
;
741 codec_info_found
= TRUE
;
743 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[5].name
,
744 sdp_fmtp_codec_param
[5].strlen
) == 0) {
745 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "maxbr", tmp
, sizeof(tmp
),
746 &tok
, &strtoul_result
, 0, -1, USHRT_MAX
);
747 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
749 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
750 fmtp_p
->maxbr
= (uint16_t) strtoul_result
;
751 codec_info_found
= TRUE
;
753 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[6].name
,
754 sdp_fmtp_codec_param
[6].strlen
) == 0) {
755 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "sqcif", tmp
, sizeof(tmp
),
756 &tok
, &strtoul_result
, -1, SDP_MIN_CIF_VALUE
, SDP_MAX_CIF_VALUE
);
757 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
759 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
760 fmtp_p
->sqcif
= (uint16_t) strtoul_result
;
761 codec_info_found
= TRUE
;
763 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[7].name
,
764 sdp_fmtp_codec_param
[7].strlen
) == 0) {
765 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "cif4", tmp
, sizeof(tmp
),
766 &tok
, &strtoul_result
, -1, SDP_MIN_CIF_VALUE
, SDP_MAX_CIF_VALUE
);
767 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
769 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
770 fmtp_p
->cif4
= (uint16_t) strtoul_result
;
771 codec_info_found
= TRUE
;
773 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[8].name
,
774 sdp_fmtp_codec_param
[8].strlen
) == 0) {
775 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "cif16", tmp
, sizeof(tmp
),
776 &tok
, &strtoul_result
, -1, SDP_MIN_CIF_VALUE
, SDP_MAX_CIF_VALUE
);
777 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
779 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
780 fmtp_p
->cif16
= (uint16_t) strtoul_result
;
781 codec_info_found
= TRUE
;
783 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[9].name
,
784 sdp_fmtp_codec_param
[9].strlen
) == 0) {
785 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "custom", tmp
, sizeof(tmp
), &tok
);
786 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
788 temp
=PL_strtok_r(tok
, ",", &strtok_state
);
792 while (temp
!= NULL
) {
794 strtoul_result
= strtoul(temp
, &strtoul_end
, 10);
796 if (errno
|| temp
== strtoul_end
|| strtoul_result
> USHRT_MAX
){
797 custom_x
= custom_y
= custom_mpi
= 0;
802 custom_x
= (uint16_t) strtoul_result
;
804 custom_y
= (uint16_t) strtoul_result
;
806 custom_mpi
= (uint16_t) strtoul_result
;
808 temp
=PL_strtok_r(NULL
, ",", &strtok_state
);
813 /* custom x,y and mpi values from tmp */
814 if (!custom_x
|| !custom_y
|| !custom_mpi
) {
815 sdp_attr_fmtp_invalid_value(sdp_p
, "x/y/MPI", temp
);
817 return SDP_INVALID_PARAMETER
;
819 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
820 fmtp_p
->custom_x
= custom_x
;
821 fmtp_p
->custom_y
= custom_y
;
822 fmtp_p
->custom_mpi
= custom_mpi
;
823 codec_info_found
= TRUE
;
825 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[10].name
,
826 sdp_fmtp_codec_param
[10].strlen
) == 0) {
827 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "par", tmp
, sizeof(tmp
), &tok
);
828 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
830 temp
=PL_strtok_r(tok
, ":", &strtok_state
);
833 /* get par width and par height for the aspect ratio */
834 while (temp
!= NULL
) {
836 strtoul_result
= strtoul(temp
, &strtoul_end
, 10);
838 if (errno
|| temp
== strtoul_end
|| strtoul_result
> USHRT_MAX
) {
839 par_width
= par_height
= 0;
844 par_width
= (uint16_t) strtoul_result
;
846 par_height
= (uint16_t) strtoul_result
;
848 temp
=PL_strtok_r(NULL
, ",", &strtok_state
);
852 if (!par_width
|| !par_height
) {
853 sdp_attr_fmtp_invalid_value(sdp_p
, "par_width or par_height", temp
);
855 return SDP_INVALID_PARAMETER
;
857 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
858 fmtp_p
->par_width
= par_width
;
859 fmtp_p
->par_height
= par_height
;
860 codec_info_found
= TRUE
;
862 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[11].name
,
863 sdp_fmtp_codec_param
[11].strlen
) == 0) {
864 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "cpcf", tmp
, sizeof(tmp
), &tok
);
865 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
867 temp
=PL_strtok_r(tok
, ".", &strtok_state
);
868 if ( temp
!= NULL
) {
870 strtoul_result
= strtoul(temp
, &strtoul_end
, 10);
872 if (errno
|| temp
== strtoul_end
|| strtoul_result
> USHRT_MAX
) {
875 cpcf
= (uint16_t) strtoul_result
;
880 sdp_attr_fmtp_invalid_value(sdp_p
, "cpcf", tok
);
882 return SDP_INVALID_PARAMETER
;
884 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
886 codec_info_found
= TRUE
;
888 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[12].name
,
889 sdp_fmtp_codec_param
[12].strlen
) == 0) {
890 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "bpp", tmp
, sizeof(tmp
),
891 &tok
, &strtoul_result
, 0, -1, USHRT_MAX
);
892 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
894 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
895 fmtp_p
->bpp
= (uint16_t) strtoul_result
;
896 codec_info_found
= TRUE
;
898 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[13].name
,
899 sdp_fmtp_codec_param
[13].strlen
) == 0) {
900 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "hrd", tmp
, sizeof(tmp
),
901 &tok
, &strtoul_result
, 0, -1, USHRT_MAX
);
902 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
904 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
905 fmtp_p
->hrd
= (uint16_t) strtoul_result
;
906 codec_info_found
= TRUE
;
908 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[14].name
,
909 sdp_fmtp_codec_param
[14].strlen
) == 0) {
910 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "profile", tmp
, sizeof(tmp
),
911 &tok
, &strtoul_result
, -1, -1, SDP_MAX_PROFILE_VALUE
);
912 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
914 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
915 fmtp_p
->profile
= (short) strtoul_result
;
916 codec_info_found
= TRUE
;
918 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[15].name
,
919 sdp_fmtp_codec_param
[15].strlen
) == 0) {
920 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "level", tmp
, sizeof(tmp
),
921 &tok
, &strtoul_result
, -1, -1, SDP_MAX_LEVEL_VALUE
);
922 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
924 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
925 fmtp_p
->level
= (short) strtoul_result
;
926 codec_info_found
= TRUE
;
928 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[16].name
,
929 sdp_fmtp_codec_param
[16].strlen
) == 0) {
930 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
931 fmtp_p
->is_interlace
= TRUE
;
932 codec_info_found
= TRUE
;
934 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[17].name
,
935 sdp_fmtp_codec_param
[17].strlen
) == 0) {
936 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "profile_level_id", tmp
, sizeof(tmp
), &tok
);
937 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
939 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
940 sstrncpy(fmtp_p
->profile_level_id
, tok
, sizeof(fmtp_p
->profile_level_id
));
941 codec_info_found
= TRUE
;
943 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[18].name
,
944 sdp_fmtp_codec_param
[18].strlen
) == 0) {
945 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "parameter_sets", tmp
, sizeof(tmp
), &tok
);
946 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
948 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
949 sstrncpy(fmtp_p
->parameter_sets
, tok
, sizeof(fmtp_p
->parameter_sets
));
950 codec_info_found
= TRUE
;
952 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[19].name
,
953 sdp_fmtp_codec_param
[19].strlen
) == 0) {
954 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "packetization_mode", tmp
, sizeof(tmp
),
955 &tok
, &strtoul_result
, -1, -1, 2);
956 // this one is different for some reason. Most others don't increment
957 // the num_invalid_param field. (mjf)
958 if (result1
== SDP_INVALID_PARAMETER
) { sdp_p
->conf_p
->num_invalid_param
++; }
959 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
961 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
962 fmtp_p
->packetization_mode
= (int16_t) strtoul_result
;
963 codec_info_found
= TRUE
;
965 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[20].name
,
966 sdp_fmtp_codec_param
[20].strlen
) == 0) {
967 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "interleaving_depth", tmp
, sizeof(tmp
),
968 &tok
, &strtoul_result
, 0, -1, USHRT_MAX
);
969 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
971 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
972 fmtp_p
->interleaving_depth
= (uint16_t) strtoul_result
;
973 codec_info_found
= TRUE
;
975 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[21].name
,
976 sdp_fmtp_codec_param
[21].strlen
) == 0) {
977 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "deint_buf", tmp
, sizeof(tmp
), &tok
);
978 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
980 if (sdp_checkrange(sdp_p
, tok
, &l_val
) == TRUE
) {
981 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
982 fmtp_p
->deint_buf_req
= (uint32_t) l_val
;
983 fmtp_p
->flag
|= SDP_DEINT_BUF_REQ_FLAG
;
984 codec_info_found
= TRUE
;
986 sdp_attr_fmtp_invalid_value(sdp_p
, "deint_buf_req", tok
);
988 return SDP_INVALID_PARAMETER
;
991 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[22].name
,
992 sdp_fmtp_codec_param
[22].strlen
) == 0) {
993 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "max_don_diff", tmp
, sizeof(tmp
),
994 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
995 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
997 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
998 fmtp_p
->max_don_diff
= (uint32_t) strtoul_result
;
999 codec_info_found
= TRUE
;
1001 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[23].name
,
1002 sdp_fmtp_codec_param
[23].strlen
) == 0) {
1003 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "init_buf_time", tmp
, sizeof(tmp
), &tok
);
1004 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1006 if (sdp_checkrange(sdp_p
, tok
, &l_val
) == TRUE
) {
1007 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1008 fmtp_p
->init_buf_time
= (uint32_t) l_val
;
1009 fmtp_p
->flag
|= SDP_INIT_BUF_TIME_FLAG
;
1010 codec_info_found
= TRUE
;
1012 sdp_attr_fmtp_invalid_value(sdp_p
, "init_buf_time", tok
);
1014 return SDP_INVALID_PARAMETER
;
1017 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[24].name
,
1018 sdp_fmtp_codec_param
[24].strlen
) == 0) {
1019 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "max_mbps", tmp
, sizeof(tmp
),
1020 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
1021 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1023 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1024 fmtp_p
->max_mbps
= (uint32_t) strtoul_result
;
1025 codec_info_found
= TRUE
;
1027 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[25].name
,
1028 sdp_fmtp_codec_param
[25].strlen
) == 0) {
1029 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "max-fs", tmp
, sizeof(tmp
),
1030 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
1031 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1033 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1034 fmtp_p
->max_fs
= (uint32_t) strtoul_result
;
1035 codec_info_found
= TRUE
;
1037 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[26].name
,
1038 sdp_fmtp_codec_param
[26].strlen
) == 0) {
1039 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "max_cbp", tmp
, sizeof(tmp
),
1040 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
1041 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1043 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1044 fmtp_p
->max_cpb
= (uint32_t) strtoul_result
;
1045 codec_info_found
= TRUE
;
1047 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[27].name
,
1048 sdp_fmtp_codec_param
[27].strlen
) == 0) {
1049 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "max_dpb", tmp
, sizeof(tmp
),
1050 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
1051 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1053 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1054 fmtp_p
->max_dpb
= (uint32_t) strtoul_result
;
1055 codec_info_found
= TRUE
;
1057 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[28].name
,
1058 sdp_fmtp_codec_param
[28].strlen
) == 0) {
1059 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "max_br", tmp
, sizeof(tmp
),
1060 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
1061 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1063 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1064 fmtp_p
->max_br
= (uint32_t) strtoul_result
;
1065 codec_info_found
= TRUE
;
1067 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[29].name
,
1068 sdp_fmtp_codec_param
[29].strlen
) == 0) {
1069 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "redundant_pic_cap", tmp
, sizeof(tmp
),
1070 &tok
, &strtoul_result
, 0, -1, 1);
1071 fmtp_p
->redundant_pic_cap
= (result1
== SDP_SUCCESS
);
1072 codec_info_found
= TRUE
;
1074 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[30].name
,
1075 sdp_fmtp_codec_param
[30].strlen
) == 0) {
1076 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "deint_buf_cap", tmp
, sizeof(tmp
), &tok
);
1077 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1079 if (sdp_checkrange(sdp_p
, tok
, &l_val
) == TRUE
) {
1080 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1081 fmtp_p
->deint_buf_cap
= (uint32_t) l_val
;
1082 fmtp_p
->flag
|= SDP_DEINT_BUF_CAP_FLAG
;
1083 codec_info_found
= TRUE
;
1085 sdp_attr_fmtp_invalid_value(sdp_p
, "deint_buf_cap", tok
);
1087 return SDP_INVALID_PARAMETER
;
1090 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[31].name
,
1091 sdp_fmtp_codec_param
[31].strlen
) == 0) {
1092 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "max_rcmd_nalu_size", tmp
, sizeof(tmp
), &tok
);
1093 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1095 if (sdp_checkrange(sdp_p
, tok
, &l_val
) == TRUE
) {
1096 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1097 fmtp_p
->max_rcmd_nalu_size
= (uint32_t) l_val
;
1098 fmtp_p
->flag
|= SDP_MAX_RCMD_NALU_SIZE_FLAG
;
1099 codec_info_found
= TRUE
;
1101 sdp_attr_fmtp_invalid_value(sdp_p
, "max_rcmd_nalu_size", tok
);
1103 return SDP_INVALID_PARAMETER
;
1106 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[32].name
,
1107 sdp_fmtp_codec_param
[32].strlen
) == 0) {
1108 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "parameter_add", tmp
, sizeof(tmp
),
1109 &tok
, &strtoul_result
, 0, -1, 1);
1110 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1112 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1113 fmtp_p
->parameter_add
= (uint16_t) strtoul_result
;
1114 codec_info_found
= TRUE
;
1116 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[33].name
,
1117 sdp_fmtp_codec_param
[33].strlen
) == 0) {
1118 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1119 fmtp_p
->annex_d
= TRUE
;
1120 codec_info_found
= TRUE
;
1122 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[34].name
,
1123 sdp_fmtp_codec_param
[34].strlen
) == 0) {
1124 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1125 fmtp_p
->annex_f
= TRUE
;
1126 codec_info_found
= TRUE
;
1128 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[35].name
,
1129 sdp_fmtp_codec_param
[35].strlen
) == 0) {
1130 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1131 fmtp_p
->annex_i
= TRUE
;
1132 codec_info_found
= TRUE
;
1134 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[36].name
,
1135 sdp_fmtp_codec_param
[36].strlen
) == 0) {
1136 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1137 fmtp_p
->annex_j
= TRUE
;
1138 codec_info_found
= TRUE
;
1140 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[37].name
,
1141 sdp_fmtp_codec_param
[36].strlen
) == 0) {
1142 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1143 fmtp_p
->annex_t
= TRUE
;
1144 codec_info_found
= TRUE
;
1146 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[38].name
,
1147 sdp_fmtp_codec_param
[38].strlen
) == 0) {
1148 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "annex_k", tmp
, sizeof(tmp
),
1149 &tok
, &strtoul_result
, 0, -1, USHRT_MAX
);
1150 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1152 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1153 fmtp_p
->annex_k_val
= (uint16_t) strtoul_result
;
1154 codec_info_found
= TRUE
;
1156 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[39].name
,
1157 sdp_fmtp_codec_param
[39].strlen
) == 0) {
1158 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "annex_n", tmp
, sizeof(tmp
),
1159 &tok
, &strtoul_result
, 0, -1, USHRT_MAX
);
1160 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1162 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1163 fmtp_p
->annex_n_val
= (uint16_t) strtoul_result
;
1164 codec_info_found
= TRUE
;
1166 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[40].name
,
1167 sdp_fmtp_codec_param
[40].strlen
) == 0) {
1168 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "annex_p", tmp
, sizeof(tmp
), &tok
);
1169 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1171 fmtp_p
->annex_p_val_picture_resize
= 0;
1172 fmtp_p
->annex_p_val_warp
= 0;
1173 temp
= PL_strtok_r(tok
, ",", &strtok_state
);
1176 while (temp
!= NULL
) {
1178 strtoul_result
= strtoul(temp
, &strtoul_end
, 10);
1180 if (errno
|| temp
== strtoul_end
|| strtoul_result
> USHRT_MAX
) {
1185 fmtp_p
->annex_p_val_picture_resize
= (uint16_t) strtoul_result
;
1187 fmtp_p
->annex_p_val_warp
= (uint16_t) strtoul_result
;
1189 temp
= PL_strtok_r(NULL
, ",", &strtok_state
);
1194 return SDP_INVALID_PARAMETER
;
1197 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1198 codec_info_found
= TRUE
;
1200 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[42].name
,
1201 sdp_fmtp_codec_param
[42].strlen
) == 0) {
1202 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "level_asymmetry_allowed", tmp
, sizeof(tmp
),
1203 &tok
, &strtoul_result
, -1, -1, SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE
);
1204 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1206 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1207 fmtp_p
->level_asymmetry_allowed
= (int) strtoul_result
;
1208 codec_info_found
= TRUE
;
1210 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[43].name
,
1211 sdp_fmtp_codec_param
[43].strlen
) == 0) {
1212 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "maxaveragebitrate", tmp
, sizeof(tmp
),
1213 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
1214 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1216 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1217 fmtp_p
->maxaveragebitrate
= (uint32_t) strtoul_result
;
1218 codec_info_found
= TRUE
;
1220 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[44].name
,
1221 sdp_fmtp_codec_param
[44].strlen
) == 0) {
1222 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "usedtx", tmp
, sizeof(tmp
),
1223 &tok
, &strtoul_result
, -1, -1, 1);
1224 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1226 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1227 fmtp_p
->usedtx
= (uint16_t) strtoul_result
;
1228 codec_info_found
= TRUE
;
1230 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[45].name
,
1231 sdp_fmtp_codec_param
[45].strlen
) == 0) {
1232 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "stereo", tmp
, sizeof(tmp
),
1233 &tok
, &strtoul_result
, -1, -1, 1);
1234 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1236 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1237 fmtp_p
->stereo
= (uint16_t) strtoul_result
;
1238 codec_info_found
= TRUE
;
1240 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[46].name
,
1241 sdp_fmtp_codec_param
[46].strlen
) == 0) {
1242 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "useinbandfec", tmp
, sizeof(tmp
),
1243 &tok
, &strtoul_result
, -1, -1, 1);
1244 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1246 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1247 fmtp_p
->useinbandfec
= (uint16_t) strtoul_result
;
1248 codec_info_found
= TRUE
;
1250 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[47].name
,
1251 sdp_fmtp_codec_param
[47].strlen
) == 0) {
1252 result1
= sdp_get_fmtp_tok(sdp_p
, &fmtp_ptr
, "maxcodedaudiobandwidth", tmp
, sizeof(tmp
), &tok
);
1253 // this one is different for some reason. Most others don't increment
1254 // the num_invalid_param field. (mjf)
1255 if (result1
== SDP_INVALID_PARAMETER
) { sdp_p
->conf_p
->num_invalid_param
++; }
1256 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1258 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1259 sstrncpy(fmtp_p
->maxcodedaudiobandwidth
, tok
, sizeof(fmtp_p
->maxcodedaudiobandwidth
));
1260 codec_info_found
= TRUE
;
1262 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[48].name
,
1263 sdp_fmtp_codec_param
[48].strlen
) == 0) {
1264 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "cbr", tmp
, sizeof(tmp
),
1265 &tok
, &strtoul_result
, -1, -1, 1);
1266 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1268 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1269 fmtp_p
->cbr
= (uint16_t) strtoul_result
;
1270 codec_info_found
= TRUE
;
1272 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[49].name
,
1273 sdp_fmtp_codec_param
[49].strlen
) == 0) {
1274 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "max-fr", tmp
, sizeof(tmp
),
1275 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
1276 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1278 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1279 fmtp_p
->max_fr
= (uint32_t) strtoul_result
;
1280 codec_info_found
= TRUE
;
1282 } else if (cpr_strncasecmp(tmp
,sdp_fmtp_codec_param
[50].name
,
1283 sdp_fmtp_codec_param
[50].strlen
) == 0) {
1284 result1
= sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "maxplaybackrate", tmp
, sizeof(tmp
),
1285 &tok
, &strtoul_result
, 0, -1, UINT_MAX
);
1286 if (result1
!= SDP_SUCCESS
) { SDP_FREE(temp_ptr
); return result1
; }
1288 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1289 fmtp_p
->maxplaybackrate
= (uint32_t) strtoul_result
;
1290 codec_info_found
= TRUE
;
1292 } else if (cpr_strncasecmp(tmp
, sdp_fmtp_codec_param
[51].name
,
1293 sdp_fmtp_codec_param
[51].strlen
) == 0) {
1295 sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "apt", tmp
, sizeof(tmp
),
1296 &tok
, &strtoul_result
, -1, 0, UINT8_MAX
);
1297 if (result1
!= SDP_SUCCESS
) {
1302 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1303 fmtp_p
->apt
= (uint8_t)strtoul_result
;
1305 codec_info_found
= TRUE
;
1307 } else if (cpr_strncasecmp(tmp
, sdp_fmtp_codec_param
[52].name
,
1308 sdp_fmtp_codec_param
[52].strlen
) == 0) {
1311 sdp_get_fmtp_tok_val(sdp_p
, &fmtp_ptr
, "rtx_time", tmp
, sizeof(tmp
),
1312 &tok
, &strtoul_result
, -1, 0, UINT_MAX
);
1313 if (result1
!= SDP_SUCCESS
) {
1318 fmtp_p
->fmtp_format
= SDP_FMTP_CODEC_INFO
;
1319 fmtp_p
->has_rtx_time
= TRUE
;
1320 fmtp_p
->rtx_time
= (uint32_t)strtoul_result
;
1322 codec_info_found
= TRUE
;
1324 } else if (fmtp_ptr
!= NULL
&& *fmtp_ptr
== '\n') {
1325 temp
=PL_strtok_r(tmp
, ";", &strtok_state
);
1327 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1328 SDP_PRINT("%s Annexes are possibly there for this fmtp %s tmp: %s line\n",
1329 sdp_p
->debug_str
, fmtp_ptr
, tmp
);
1331 while (temp
!= NULL
) {
1332 if (strchr(temp
, 'D') !=NULL
) {
1333 attr_p
->attr
.fmtp
.annex_d
= TRUE
;
1335 if (strchr(temp
, 'F') !=NULL
) {
1336 attr_p
->attr
.fmtp
.annex_f
= TRUE
;
1338 if (strchr(temp
, 'I') !=NULL
) {
1339 attr_p
->attr
.fmtp
.annex_i
= TRUE
;
1341 if (strchr(temp
, 'J') !=NULL
) {
1342 attr_p
->attr
.fmtp
.annex_j
= TRUE
;
1344 if (strchr(temp
, 'T') !=NULL
) {
1345 attr_p
->attr
.fmtp
.annex_t
= TRUE
;
1347 temp
=PL_strtok_r(NULL
, ";", &strtok_state
);
1351 } else if (strchr(tmp
, '/')) {
1352 // XXX Note that because RFC 5109 so conveniently specified
1353 // this fmtp with no param names, we hope that nothing else
1354 // has a slash in the string because otherwise we won't know
1355 // how to differentiate.
1356 temp
=PL_strtok_r(tmp
, "/", &strtok_state
);
1359 while (temp
!= NULL
) {
1361 strtoul_result
= strtoul(temp
, &strtoul_end
, 10);
1364 temp
== strtoul_end
|| strtoul_result
> USHRT_MAX
) {
1368 fmtp_p
->redundant_encodings
[iter
++] =
1369 (uint8_t)strtoul_result
;
1370 temp
=PL_strtok_r(NULL
, "/", &strtok_state
);
1373 } else if (SDP_SUCCESS
== sdp_verify_attr_fmtp_telephone_event(tmp
)) {
1374 // XXX Note that DTMF fmtp will fall into here:
1375 // a=fmtp:101 0-15 (or 0-15,NN,NN etc)
1376 sstrncpy(fmtp_p
->dtmf_tones
, tmp
, sizeof(fmtp_p
->dtmf_tones
));
1377 codec_info_found
= TRUE
;
1379 // unknown parameter - eat chars until ';'
1380 SDPLogDebug(logTag
, "%s Unknown fmtp type (%s) - ignoring", __FUNCTION__
,
1382 fmtp_ptr
= sdp_getnextstrtok(fmtp_ptr
, tmp
, sizeof(tmp
), "; \t",
1384 if (result1
!= SDP_SUCCESS
) {
1385 fmtp_ptr
= sdp_getnextstrtok(fmtp_ptr
, tmp
, sizeof(tmp
), " \t", &result1
);
1386 if (result1
!= SDP_SUCCESS
) {
1387 // hmmm, no ; or spaces or tabs; continue on
1391 if (*fmtp_ptr
== '\n') {
1392 // reached end of line, stop parsing
1400 } /* while - done loop*/
1402 if (codec_info_found
) {
1404 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1405 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",
1407 sdp_get_attr_name(attr_p
->type
),
1408 attr_p
->attr
.fmtp
.payload_num
,
1409 attr_p
->attr
.fmtp
.bitrate
,
1410 attr_p
->attr
.fmtp
.mode
,
1411 attr_p
->attr
.fmtp
.qcif
,
1412 attr_p
->attr
.fmtp
.cif
,
1413 attr_p
->attr
.fmtp
.maxbr
,
1414 attr_p
->attr
.fmtp
.sqcif
,
1415 attr_p
->attr
.fmtp
.cif4
,
1416 attr_p
->attr
.fmtp
.cif16
,
1417 attr_p
->attr
.fmtp
.custom_x
,attr_p
->attr
.fmtp
.custom_y
,
1418 attr_p
->attr
.fmtp
.custom_mpi
,
1419 attr_p
->attr
.fmtp
.par_width
,
1420 attr_p
->attr
.fmtp
.par_height
,
1421 attr_p
->attr
.fmtp
.cpcf
,
1422 attr_p
->attr
.fmtp
.bpp
,
1423 attr_p
->attr
.fmtp
.hrd
1427 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1428 SDP_PRINT("%s Parsed a=%s, payload type %u,PROFILE=%u,LEVEL=%u, INTERLACE - %s",
1430 sdp_get_attr_name(attr_p
->type
),
1431 attr_p
->attr
.fmtp
.payload_num
,
1432 attr_p
->attr
.fmtp
.profile
,
1433 attr_p
->attr
.fmtp
.level
,
1434 attr_p
->attr
.fmtp
.is_interlace
? "YES":"NO");
1437 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1438 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",
1440 attr_p
->attr
.fmtp
.profile_level_id
,
1441 attr_p
->attr
.fmtp
.parameter_sets
,
1442 attr_p
->attr
.fmtp
.packetization_mode
,
1443 attr_p
->attr
.fmtp
.level_asymmetry_allowed
,
1444 attr_p
->attr
.fmtp
.interleaving_depth
,
1445 attr_p
->attr
.fmtp
.deint_buf_req
,
1446 attr_p
->attr
.fmtp
.max_don_diff
,
1447 attr_p
->attr
.fmtp
.init_buf_time
1451 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1452 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",
1454 attr_p
->attr
.fmtp
.max_mbps
,
1455 attr_p
->attr
.fmtp
.max_fs
,
1456 attr_p
->attr
.fmtp
.max_cpb
,
1457 attr_p
->attr
.fmtp
.max_dpb
,
1458 attr_p
->attr
.fmtp
.max_br
,
1459 attr_p
->attr
.fmtp
.redundant_pic_cap
,
1460 attr_p
->attr
.fmtp
.deint_buf_cap
,
1461 attr_p
->attr
.fmtp
.max_rcmd_nalu_size
,
1462 attr_p
->attr
.fmtp
.parameter_add
);
1465 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1466 SDP_PRINT("%s Parsed annexes are : D=%d F=%d I=%d J=%d T=%d, K=%d N=%d P=%d,%d\n",
1468 attr_p
->attr
.fmtp
.annex_d
,
1469 attr_p
->attr
.fmtp
.annex_f
, attr_p
->attr
.fmtp
.annex_i
,
1470 attr_p
->attr
.fmtp
.annex_j
, attr_p
->attr
.fmtp
.annex_t
,
1471 attr_p
->attr
.fmtp
.annex_k_val
,
1472 attr_p
->attr
.fmtp
.annex_n_val
,
1473 attr_p
->attr
.fmtp
.annex_p_val_picture_resize
,
1474 attr_p
->attr
.fmtp
.annex_p_val_warp
);
1478 return (SDP_SUCCESS
);
1485 for (i
=0; !done
; i
++) {
1486 fmtp_p
->fmtp_format
= SDP_FMTP_NTE
;
1487 /* Look for comma separated events */
1488 fmtp_ptr
= sdp_getnextstrtok(fmtp_ptr
, tmp
, sizeof(tmp
), ", \t", &result1
);
1489 if (result1
!= SDP_SUCCESS
) {
1493 /* Now look for '-' separated range */
1495 low_val
= (uint8_t)sdp_getnextnumtok(ptr2
, (const char **)&ptr2
,
1498 high_val
= (uint8_t)sdp_getnextnumtok(ptr2
, (const char **)&ptr2
,
1504 if ((result1
!= SDP_SUCCESS
) || (result2
!= SDP_SUCCESS
)) {
1505 sdp_parse_error(sdp_p
,
1506 "%s Warning: Invalid named events specified for fmtp attribute.",
1508 sdp_p
->conf_p
->num_invalid_param
++;
1510 return (SDP_INVALID_PARAMETER
);
1513 for (i
= low_val
; i
<= high_val
; i
++) {
1514 mapword
= i
/SDP_NE_BITS_PER_WORD
;
1515 bmap
= ((unsigned)SDP_NE_BIT_0
) << (i
%32);
1516 fmtp_p
->bmap
[mapword
] |= bmap
;
1518 if (high_val
> fmtp_p
->maxval
) {
1519 fmtp_p
->maxval
= high_val
;
1523 if (fmtp_p
->maxval
== 0) {
1524 sdp_parse_error(sdp_p
,
1525 "%s Warning: No named events specified for fmtp attribute.",
1527 sdp_p
->conf_p
->num_invalid_param
++;
1529 return (SDP_INVALID_PARAMETER
);
1532 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1533 SDP_PRINT("%s Parsed a=%s, payload type %u, ", sdp_p
->debug_str
,
1534 sdp_get_attr_name(attr_p
->type
),
1535 attr_p
->attr
.fmtp
.payload_num
);
1538 return (SDP_SUCCESS
);
1542 sdp_build_attr_fmtp_params (sdp_t
*sdp_p
, sdp_fmtp_t
*fmtp_p
, flex_string
*fs
)
1549 tinybool range_start
= FALSE
;
1550 tinybool range_end
= FALSE
;
1551 tinybool semicolon
= FALSE
;
1553 switch (fmtp_p
->fmtp_format
) {
1555 sdp_append_name_and_unsigned(fs
, "mode", fmtp_p
->mode
, FALSE
);
1558 case SDP_FMTP_CODEC_INFO
:
1559 FMTP_BUILD_UNSIGNED(fmtp_p
->bitrate
> 0, "bitrate", fmtp_p
->bitrate
)
1561 FMTP_BUILD_STRING(fmtp_p
->annexa_required
,
1562 "annexa", (fmtp_p
->annexa
? "yes" : "no"))
1564 FMTP_BUILD_STRING(fmtp_p
->annexb_required
,
1565 "annexb", (fmtp_p
->annexa
? "yes" : "no"))
1567 FMTP_BUILD_UNSIGNED(fmtp_p
->qcif
> 0, "QCIF", fmtp_p
->qcif
)
1569 FMTP_BUILD_UNSIGNED(fmtp_p
->cif
> 0, "CIF", fmtp_p
->cif
)
1571 FMTP_BUILD_UNSIGNED(fmtp_p
->maxbr
> 0, "MAXBR", fmtp_p
->maxbr
)
1573 FMTP_BUILD_UNSIGNED(fmtp_p
->sqcif
> 0, "SQCIF", fmtp_p
->sqcif
)
1575 FMTP_BUILD_UNSIGNED(fmtp_p
->cif4
> 0, "CIF4", fmtp_p
->cif4
)
1577 FMTP_BUILD_UNSIGNED(fmtp_p
->cif16
> 0, "CIF16", fmtp_p
->cif16
)
1579 if ((fmtp_p
->custom_x
> 0) && (fmtp_p
->custom_y
> 0) &&
1580 (fmtp_p
->custom_mpi
> 0)) {
1581 flex_string_sprintf(fs
, "%sCUSTOM=%u,%u,%u",
1582 semicolon
? ";" : "",
1585 fmtp_p
->custom_mpi
);
1590 if ((fmtp_p
->par_height
> 0) && (fmtp_p
->par_width
> 0)) {
1591 flex_string_sprintf(fs
, "%sPAR=%u:%u",
1592 semicolon
? ";" : "",
1599 FMTP_BUILD_UNSIGNED(fmtp_p
->cpcf
> 0, "CPCF", fmtp_p
->cpcf
)
1601 FMTP_BUILD_UNSIGNED(fmtp_p
->bpp
> 0, "BPP", fmtp_p
->bpp
)
1603 FMTP_BUILD_UNSIGNED(fmtp_p
->hrd
> 0, "HRD", fmtp_p
->hrd
)
1605 FMTP_BUILD_UNSIGNED(fmtp_p
->profile
>= 0, "PROFILE", fmtp_p
->profile
)
1607 FMTP_BUILD_UNSIGNED(fmtp_p
->level
>= 0, "LEVEL", fmtp_p
->level
)
1609 FMTP_BUILD_FLAG(fmtp_p
->is_interlace
, "INTERLACE")
1611 FMTP_BUILD_FLAG(fmtp_p
->annex_d
, "D")
1613 FMTP_BUILD_FLAG(fmtp_p
->annex_f
, "F")
1615 FMTP_BUILD_FLAG(fmtp_p
->annex_i
, "I")
1617 FMTP_BUILD_FLAG(fmtp_p
->annex_j
, "J")
1619 FMTP_BUILD_FLAG(fmtp_p
->annex_t
, "T")
1621 FMTP_BUILD_UNSIGNED(fmtp_p
->annex_k_val
> 0,
1622 "K", fmtp_p
->annex_k_val
)
1624 FMTP_BUILD_UNSIGNED(fmtp_p
->annex_n_val
> 0,
1625 "N", fmtp_p
->annex_n_val
)
1627 if ((fmtp_p
->annex_p_val_picture_resize
> 0) &&
1628 (fmtp_p
->annex_p_val_warp
> 0)) {
1629 flex_string_sprintf(fs
, "%sP=%d:%d",
1630 semicolon
? ";" : "",
1631 fmtp_p
->annex_p_val_picture_resize
,
1632 fmtp_p
->annex_p_val_warp
);
1637 FMTP_BUILD_STRING(strlen(fmtp_p
->profile_level_id
) > 0,
1638 "profile-level-id", fmtp_p
->profile_level_id
)
1640 FMTP_BUILD_STRING(strlen(fmtp_p
->parameter_sets
) > 0,
1641 "sprop-parameter-sets", fmtp_p
->parameter_sets
)
1643 FMTP_BUILD_UNSIGNED(
1644 fmtp_p
->packetization_mode
< SDP_MAX_PACKETIZATION_MODE_VALUE
,
1645 "packetization-mode", fmtp_p
->packetization_mode
)
1647 FMTP_BUILD_UNSIGNED(
1648 fmtp_p
->level_asymmetry_allowed
<=
1649 SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE
,
1650 "level-asymmetry-allowed", fmtp_p
->level_asymmetry_allowed
)
1652 FMTP_BUILD_UNSIGNED(fmtp_p
->interleaving_depth
> 0,
1653 "sprop-interleaving-depth", fmtp_p
->interleaving_depth
)
1655 FMTP_BUILD_UNSIGNED(fmtp_p
->flag
& SDP_DEINT_BUF_REQ_FLAG
,
1656 "sprop-deint-buf-req", fmtp_p
->deint_buf_req
)
1658 FMTP_BUILD_UNSIGNED(fmtp_p
->max_don_diff
> 0,
1659 "sprop-max-don-diff", fmtp_p
->max_don_diff
)
1661 FMTP_BUILD_UNSIGNED(fmtp_p
->flag
& SDP_INIT_BUF_TIME_FLAG
,
1662 "sprop-init-buf-time", fmtp_p
->init_buf_time
)
1664 FMTP_BUILD_UNSIGNED(fmtp_p
->max_mbps
> 0,
1665 "max-mbps", fmtp_p
->max_mbps
)
1667 FMTP_BUILD_UNSIGNED(fmtp_p
->max_fs
> 0, "max-fs", fmtp_p
->max_fs
)
1669 FMTP_BUILD_UNSIGNED(fmtp_p
->max_fr
> 0, "max-fr", fmtp_p
->max_fr
)
1671 FMTP_BUILD_UNSIGNED(fmtp_p
->max_cpb
> 0, "max-cpb", fmtp_p
->max_cpb
)
1673 FMTP_BUILD_UNSIGNED(fmtp_p
->max_dpb
> 0, "max-dpb", fmtp_p
->max_dpb
)
1675 FMTP_BUILD_UNSIGNED(fmtp_p
->max_br
> 0, "max-br", fmtp_p
->max_br
)
1677 FMTP_BUILD_UNSIGNED(fmtp_p
->redundant_pic_cap
> 0,
1678 "redundant-pic-cap", fmtp_p
->redundant_pic_cap
)
1680 FMTP_BUILD_UNSIGNED(fmtp_p
->flag
& SDP_DEINT_BUF_CAP_FLAG
,
1681 "deint-buf-cap", fmtp_p
->deint_buf_cap
)
1683 FMTP_BUILD_UNSIGNED(fmtp_p
->flag
& SDP_MAX_RCMD_NALU_SIZE_FLAG
,
1684 "max-rcmd-naFMTP_BUILD_FLlu-size", fmtp_p
->max_rcmd_nalu_size
)
1686 FMTP_BUILD_UNSIGNED(fmtp_p
->parameter_add
<= 1, "parameter-add",
1687 fmtp_p
->parameter_add
)
1689 FMTP_BUILD_UNSIGNED(fmtp_p
->maxaveragebitrate
> 0,
1690 "maxaveragebitrate", fmtp_p
->maxaveragebitrate
)
1692 FMTP_BUILD_UNSIGNED(fmtp_p
->usedtx
<= 1, "usedtx", fmtp_p
->usedtx
)
1694 FMTP_BUILD_UNSIGNED(fmtp_p
->stereo
<= 1, "stereo", fmtp_p
->stereo
)
1696 FMTP_BUILD_UNSIGNED(fmtp_p
->useinbandfec
<= 1,
1697 "useinbandfec", fmtp_p
->useinbandfec
)
1699 FMTP_BUILD_STRING(strlen(fmtp_p
->maxcodedaudiobandwidth
) > 0,
1700 "maxcodedaudiobandwidth", fmtp_p
->maxcodedaudiobandwidth
)
1702 FMTP_BUILD_UNSIGNED(fmtp_p
->cbr
<= 1, "cbr", fmtp_p
->cbr
)
1711 for(event_id
= 0, mapword
= 0, mask
= SDP_NE_BIT_0
;
1712 event_id
<= fmtp_p
->maxval
;
1713 event_id
++, mapword
= event_id
/SDP_NE_BITS_PER_WORD
) {
1715 if (event_id
% SDP_NE_BITS_PER_WORD
) {
1718 /* crossed a bitmap word boundary */
1719 mask
= SDP_NE_BIT_0
;
1720 if (!range_start
&& !range_end
&& !fmtp_p
->bmap
[mapword
]) {
1721 /* no events in this word, skip to the last event id
1722 * in this bitmap word. */
1723 event_id
+= SDP_NE_BITS_PER_WORD
- 1;
1728 if (fmtp_p
->bmap
[mapword
] & mask
) {
1731 min
= max
= (uint8_t)event_id
;
1733 max
= (uint8_t)event_id
;
1735 range_end
= (max
== fmtp_p
->maxval
);
1737 /* If we were in the middle of a range, then we've hit the
1738 * end. If we weren't, there is no end to hit. */
1739 range_end
= range_start
;
1742 /* If this is the end of the range, print it to the string. */
1744 range_start
= range_end
= FALSE
;
1746 flex_string_sprintf(fs
, "%u", min
);
1749 flex_string_sprintf(fs
, "-%u", max
);
1752 if (max
!= fmtp_p
->maxval
) {
1753 flex_string_append(fs
, ",");
1760 sdp_result_e
sdp_build_attr_fmtp (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
, flex_string
*fs
)
1763 sdp_result_e result
;
1765 flex_string_sprintf(fs
, "a=%s:%u ",
1766 sdp_attr
[attr_p
->type
].name
,
1767 attr_p
->attr
.fmtp
.payload_num
);
1769 fmtp_p
= &(attr_p
->attr
.fmtp
);
1771 result
= sdp_build_attr_fmtp_params(sdp_p
, fmtp_p
, fs
);
1773 if (result
!= SDP_SUCCESS
) {
1777 flex_string_append(fs
, "\r\n");
1782 sdp_result_e
sdp_parse_attr_sctpmap(sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
1785 sdp_result_e result
= SDP_SUCCESS
;
1786 char tmp
[SDP_MAX_STRING_LEN
];
1789 /* Find the payload type number. */
1790 attr_p
->attr
.sctpmap
.port
= (uint16_t)sdp_getnextnumtok(ptr
, &ptr
,
1792 if (result
!= SDP_SUCCESS
) {
1793 sdp_parse_error(sdp_p
,
1794 "%s Warning: no sctpmap port number",
1796 return SDP_INVALID_PARAMETER
;
1799 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
1800 if (result
!= SDP_SUCCESS
) {
1801 sdp_parse_error(sdp_p
,
1802 "%s Warning: No sctpmap protocol specified.",
1804 sdp_p
->conf_p
->num_invalid_param
++;
1805 return SDP_INVALID_PARAMETER
;
1807 sstrncpy(attr_p
->attr
.sctpmap
.protocol
, tmp
,
1808 sizeof (attr_p
->attr
.sctpmap
.protocol
));
1810 streams
= sdp_getnextnumtok(ptr
, &ptr
, " \t", &result
);
1811 if (result
!= SDP_SUCCESS
) {
1812 sdp_parse_error(sdp_p
,
1813 "%s Warning: No sctpmap streams specified.",
1815 sdp_p
->conf_p
->num_invalid_param
++;
1816 return SDP_INVALID_PARAMETER
;
1819 attr_p
->attr
.sctpmap
.streams
= streams
;
1824 sdp_result_e
sdp_build_attr_sctpmap(sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
1827 flex_string_sprintf(fs
, "a=%s:%u %s %u\r\n",
1828 sdp_attr
[attr_p
->type
].name
,
1829 attr_p
->attr
.sctpmap
.port
,
1830 attr_p
->attr
.sctpmap
.protocol
,
1831 attr_p
->attr
.sctpmap
.streams
);
1836 sdp_result_e
sdp_parse_attr_direction (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
1839 /* No parameters to parse. */
1840 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1841 SDP_PRINT("%s Parsed a=%s", sdp_p
->debug_str
,
1842 sdp_get_attr_name(attr_p
->type
));
1845 return (SDP_SUCCESS
);
1848 sdp_result_e
sdp_build_attr_direction (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
, flex_string
*fs
)
1850 flex_string_sprintf(fs
, "a=%s\r\n", sdp_get_attr_name(attr_p
->type
));
1855 sdp_result_e
sdp_parse_attr_qos (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
1859 sdp_result_e result
;
1860 char tmp
[SDP_MAX_STRING_LEN
];
1862 /* Find the strength tag. */
1863 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
1864 if (result
!= SDP_SUCCESS
) {
1865 sdp_parse_error(sdp_p
,
1866 "%s Warning: No qos strength tag specified.",
1868 sdp_p
->conf_p
->num_invalid_param
++;
1869 return (SDP_INVALID_PARAMETER
);
1871 attr_p
->attr
.qos
.strength
= SDP_QOS_STRENGTH_UNKNOWN
;
1872 for (i
=0; i
< SDP_MAX_QOS_STRENGTH
; i
++) {
1873 if (cpr_strncasecmp(tmp
, sdp_qos_strength
[i
].name
,
1874 sdp_qos_strength
[i
].strlen
) == 0) {
1875 attr_p
->attr
.qos
.strength
= (sdp_qos_strength_e
)i
;
1878 if (attr_p
->attr
.qos
.strength
== SDP_QOS_STRENGTH_UNKNOWN
) {
1879 sdp_parse_error(sdp_p
,
1880 "%s Warning: QOS strength tag unrecognized (%s)",
1881 sdp_p
->debug_str
, tmp
);
1882 sdp_p
->conf_p
->num_invalid_param
++;
1883 return (SDP_INVALID_PARAMETER
);
1886 /* Find the qos direction. */
1887 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
1888 if (result
!= SDP_SUCCESS
) {
1889 sdp_parse_error(sdp_p
,
1890 "%s Warning: No qos direction specified.",
1892 sdp_p
->conf_p
->num_invalid_param
++;
1893 return (SDP_INVALID_PARAMETER
);
1895 attr_p
->attr
.qos
.direction
= SDP_QOS_DIR_UNKNOWN
;
1896 for (i
=0; i
< SDP_MAX_QOS_DIR
; i
++) {
1897 if (cpr_strncasecmp(tmp
, sdp_qos_direction
[i
].name
,
1898 sdp_qos_direction
[i
].strlen
) == 0) {
1899 attr_p
->attr
.qos
.direction
= (sdp_qos_dir_e
)i
;
1902 if (attr_p
->attr
.qos
.direction
== SDP_QOS_DIR_UNKNOWN
) {
1903 sdp_parse_error(sdp_p
,
1904 "%s Warning: QOS direction unrecognized (%s)",
1905 sdp_p
->debug_str
, tmp
);
1906 sdp_p
->conf_p
->num_invalid_param
++;
1907 return (SDP_INVALID_PARAMETER
);
1910 /* See if confirm was specified. Defaults to FALSE. */
1911 attr_p
->attr
.qos
.confirm
= FALSE
;
1912 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
1913 if (result
== SDP_SUCCESS
) {
1914 if (cpr_strncasecmp(tmp
, "confirm", sizeof("confirm")) == 0) {
1915 attr_p
->attr
.qos
.confirm
= TRUE
;
1917 if (attr_p
->attr
.qos
.confirm
== FALSE
) {
1918 sdp_parse_error(sdp_p
,
1919 "%s Warning: QOS confirm parameter invalid (%s)",
1920 sdp_p
->debug_str
, tmp
);
1921 sdp_p
->conf_p
->num_invalid_param
++;
1922 return (SDP_INVALID_PARAMETER
);
1926 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
1927 SDP_PRINT("%s Parsed a=%s, strength %s, direction %s, confirm %s",
1928 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
1929 sdp_get_qos_strength_name(attr_p
->attr
.qos
.strength
),
1930 sdp_get_qos_direction_name(attr_p
->attr
.qos
.direction
),
1931 (attr_p
->attr
.qos
.confirm
? "set" : "not set"));
1934 return (SDP_SUCCESS
);
1937 sdp_result_e
sdp_build_attr_qos (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
, flex_string
*fs
)
1939 flex_string_sprintf(fs
, "a=%s:%s %s%s\r\n", sdp_attr
[attr_p
->type
].name
,
1940 sdp_get_qos_strength_name(attr_p
->attr
.qos
.strength
),
1941 sdp_get_qos_direction_name(attr_p
->attr
.qos
.direction
),
1942 attr_p
->attr
.qos
.confirm
? " confirm" : "");
1947 sdp_result_e
sdp_parse_attr_curr (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
1951 sdp_result_e result
;
1952 char tmp
[SDP_MAX_STRING_LEN
];
1954 /* Find the curr type tag. */
1955 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
1956 if (result
!= SDP_SUCCESS
) {
1957 sdp_parse_error(sdp_p
,
1958 "%s Warning: No curr attr type specified.",
1960 sdp_p
->conf_p
->num_invalid_param
++;
1961 return (SDP_INVALID_PARAMETER
);
1963 attr_p
->attr
.curr
.type
= SDP_CURR_UNKNOWN_TYPE
;
1964 for (i
=0; i
< SDP_MAX_CURR_TYPES
; i
++) {
1965 if (cpr_strncasecmp(tmp
, sdp_curr_type
[i
].name
,
1966 sdp_curr_type
[i
].strlen
) == 0) {
1967 attr_p
->attr
.curr
.type
= (sdp_curr_type_e
)i
;
1971 if (attr_p
->attr
.curr
.type
!= SDP_CURR_QOS_TYPE
) {
1972 sdp_parse_error(sdp_p
,
1973 "%s Warning: Unknown curr type.",
1975 sdp_p
->conf_p
->num_invalid_param
++;
1976 return (SDP_INVALID_PARAMETER
);
1979 /* Check qos status type */
1980 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
1981 if (result
!= SDP_SUCCESS
) {
1982 sdp_parse_error(sdp_p
,
1983 "%s Warning: No curr attr type specified.",
1985 sdp_p
->conf_p
->num_invalid_param
++;
1986 return (SDP_INVALID_PARAMETER
);
1988 attr_p
->attr
.curr
.status_type
= SDP_QOS_STATUS_TYPE_UNKNOWN
;
1989 for (i
=0; i
< SDP_MAX_QOS_STATUS_TYPES
; i
++) {
1990 if (cpr_strncasecmp(tmp
, sdp_qos_status_type
[i
].name
,
1991 sdp_qos_status_type
[i
].strlen
) == 0) {
1992 attr_p
->attr
.curr
.status_type
= (sdp_qos_status_types_e
)i
;
1997 /* Find the qos direction. */
1998 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
1999 if (result
!= SDP_SUCCESS
) {
2000 sdp_parse_error(sdp_p
,
2001 "%s Warning: No qos direction specified.",
2003 sdp_p
->conf_p
->num_invalid_param
++;
2004 return (SDP_INVALID_PARAMETER
);
2006 attr_p
->attr
.curr
.direction
= SDP_QOS_DIR_UNKNOWN
;
2007 for (i
=0; i
< SDP_MAX_QOS_DIR
; i
++) {
2008 if (cpr_strncasecmp(tmp
, sdp_qos_direction
[i
].name
,
2009 sdp_qos_direction
[i
].strlen
) == 0) {
2010 attr_p
->attr
.curr
.direction
= (sdp_qos_dir_e
)i
;
2013 if (attr_p
->attr
.curr
.direction
== SDP_QOS_DIR_UNKNOWN
) {
2014 sdp_parse_error(sdp_p
,
2015 "%s Warning: QOS direction unrecognized (%s)",
2016 sdp_p
->debug_str
, tmp
);
2017 sdp_p
->conf_p
->num_invalid_param
++;
2018 return (SDP_INVALID_PARAMETER
);
2021 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2022 SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
2023 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
2024 sdp_get_curr_type_name(attr_p
->attr
.curr
.type
),
2025 sdp_get_qos_status_type_name(attr_p
->attr
.curr
.status_type
),
2026 sdp_get_qos_direction_name(attr_p
->attr
.curr
.direction
));
2029 return (SDP_SUCCESS
);
2032 sdp_result_e
sdp_build_attr_curr (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
, flex_string
*fs
)
2034 flex_string_sprintf(fs
, "a=%s:%s %s %s\r\n",
2035 sdp_attr
[attr_p
->type
].name
,
2036 sdp_get_curr_type_name(attr_p
->attr
.curr
.type
),
2037 sdp_get_qos_status_type_name(attr_p
->attr
.curr
.status_type
),
2038 sdp_get_qos_direction_name(attr_p
->attr
.curr
.direction
));
2043 sdp_result_e
sdp_parse_attr_des (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2047 sdp_result_e result
;
2048 char tmp
[SDP_MAX_STRING_LEN
];
2050 /* Find the curr type tag. */
2051 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2052 if (result
!= SDP_SUCCESS
) {
2053 sdp_parse_error(sdp_p
,
2054 "%s Warning: No des attr type specified.",
2056 sdp_p
->conf_p
->num_invalid_param
++;
2057 return (SDP_INVALID_PARAMETER
);
2059 attr_p
->attr
.des
.type
= SDP_DES_UNKNOWN_TYPE
;
2060 for (i
=0; i
< SDP_MAX_CURR_TYPES
; i
++) {
2061 if (cpr_strncasecmp(tmp
, sdp_des_type
[i
].name
,
2062 sdp_des_type
[i
].strlen
) == 0) {
2063 attr_p
->attr
.des
.type
= (sdp_des_type_e
)i
;
2067 if (attr_p
->attr
.des
.type
!= SDP_DES_QOS_TYPE
) {
2068 sdp_parse_error(sdp_p
,
2069 "%s Warning: Unknown conf type.",
2071 sdp_p
->conf_p
->num_invalid_param
++;
2072 return (SDP_INVALID_PARAMETER
);
2075 /* Find the strength tag. */
2076 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2077 if (result
!= SDP_SUCCESS
) {
2078 sdp_parse_error(sdp_p
,
2079 "%s Warning: No qos strength tag specified.",
2081 sdp_p
->conf_p
->num_invalid_param
++;
2082 return (SDP_INVALID_PARAMETER
);
2084 attr_p
->attr
.des
.strength
= SDP_QOS_STRENGTH_UNKNOWN
;
2085 for (i
=0; i
< SDP_MAX_QOS_STRENGTH
; i
++) {
2086 if (cpr_strncasecmp(tmp
, sdp_qos_strength
[i
].name
,
2087 sdp_qos_strength
[i
].strlen
) == 0) {
2088 attr_p
->attr
.des
.strength
= (sdp_qos_strength_e
)i
;
2091 if (attr_p
->attr
.des
.strength
== SDP_QOS_STRENGTH_UNKNOWN
) {
2092 sdp_parse_error(sdp_p
,
2093 "%s Warning: QOS strength tag unrecognized (%s)",
2094 sdp_p
->debug_str
, tmp
);
2095 sdp_p
->conf_p
->num_invalid_param
++;
2096 return (SDP_INVALID_PARAMETER
);
2099 /* Check qos status type */
2100 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2101 if (result
!= SDP_SUCCESS
) {
2102 sdp_parse_error(sdp_p
,
2103 "%s Warning: No des attr type specified.",
2105 sdp_p
->conf_p
->num_invalid_param
++;
2106 return (SDP_INVALID_PARAMETER
);
2108 attr_p
->attr
.des
.status_type
= SDP_QOS_STATUS_TYPE_UNKNOWN
;
2109 for (i
=0; i
< SDP_MAX_QOS_STATUS_TYPES
; i
++) {
2110 if (cpr_strncasecmp(tmp
, sdp_qos_status_type
[i
].name
,
2111 sdp_qos_status_type
[i
].strlen
) == 0) {
2112 attr_p
->attr
.des
.status_type
= (sdp_qos_status_types_e
)i
;
2117 /* Find the qos direction. */
2118 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2119 if (result
!= SDP_SUCCESS
) {
2120 sdp_parse_error(sdp_p
,
2121 "%s Warning: No qos direction specified.",
2123 sdp_p
->conf_p
->num_invalid_param
++;
2124 return (SDP_INVALID_PARAMETER
);
2126 attr_p
->attr
.des
.direction
= SDP_QOS_DIR_UNKNOWN
;
2127 for (i
=0; i
< SDP_MAX_QOS_DIR
; i
++) {
2128 if (cpr_strncasecmp(tmp
, sdp_qos_direction
[i
].name
,
2129 sdp_qos_direction
[i
].strlen
) == 0) {
2130 attr_p
->attr
.des
.direction
= (sdp_qos_dir_e
)i
;
2133 if (attr_p
->attr
.des
.direction
== SDP_QOS_DIR_UNKNOWN
) {
2134 sdp_parse_error(sdp_p
,
2135 "%s Warning: QOS direction unrecognized (%s)",
2136 sdp_p
->debug_str
, tmp
);
2137 sdp_p
->conf_p
->num_invalid_param
++;
2138 return (SDP_INVALID_PARAMETER
);
2141 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2142 SDP_PRINT("%s Parsed a=%s, type %s strength %s status type %s, direction %s",
2143 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
2144 sdp_get_des_type_name(attr_p
->attr
.des
.type
),
2145 sdp_get_qos_strength_name(attr_p
->attr
.qos
.strength
),
2146 sdp_get_qos_status_type_name(attr_p
->attr
.des
.status_type
),
2147 sdp_get_qos_direction_name(attr_p
->attr
.des
.direction
));
2150 return (SDP_SUCCESS
);
2154 sdp_result_e
sdp_build_attr_des (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
, flex_string
*fs
)
2156 flex_string_sprintf(fs
, "a=%s:%s %s %s %s\r\n",
2157 sdp_attr
[attr_p
->type
].name
,
2158 sdp_get_curr_type_name((sdp_curr_type_e
)attr_p
->attr
.des
.type
),
2159 sdp_get_qos_strength_name(attr_p
->attr
.des
.strength
),
2160 sdp_get_qos_status_type_name(attr_p
->attr
.des
.status_type
),
2161 sdp_get_qos_direction_name(attr_p
->attr
.des
.direction
));
2166 sdp_result_e
sdp_parse_attr_conf (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2170 sdp_result_e result
;
2171 char tmp
[SDP_MAX_STRING_LEN
];
2173 /* Find the curr type tag. */
2174 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2175 if (result
!= SDP_SUCCESS
) {
2176 sdp_parse_error(sdp_p
,
2177 "%s Warning: No conf attr type specified.",
2179 sdp_p
->conf_p
->num_invalid_param
++;
2180 return (SDP_INVALID_PARAMETER
);
2182 attr_p
->attr
.conf
.type
= SDP_CONF_UNKNOWN_TYPE
;
2183 for (i
=0; i
< SDP_MAX_CURR_TYPES
; i
++) {
2184 if (cpr_strncasecmp(tmp
, sdp_conf_type
[i
].name
,
2185 sdp_conf_type
[i
].strlen
) == 0) {
2186 attr_p
->attr
.conf
.type
= (sdp_conf_type_e
)i
;
2190 if (attr_p
->attr
.conf
.type
!= SDP_CONF_QOS_TYPE
) {
2191 sdp_parse_error(sdp_p
,
2192 "%s Warning: Unknown conf type.",
2194 sdp_p
->conf_p
->num_invalid_param
++;
2195 return (SDP_INVALID_PARAMETER
);
2198 /* Check qos status type */
2199 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2200 if (result
!= SDP_SUCCESS
) {
2201 sdp_parse_error(sdp_p
,
2202 "%s Warning: No conf attr type specified.",
2204 sdp_p
->conf_p
->num_invalid_param
++;
2205 return (SDP_INVALID_PARAMETER
);
2207 attr_p
->attr
.conf
.status_type
= SDP_QOS_STATUS_TYPE_UNKNOWN
;
2208 for (i
=0; i
< SDP_MAX_QOS_STATUS_TYPES
; i
++) {
2209 if (cpr_strncasecmp(tmp
, sdp_qos_status_type
[i
].name
,
2210 sdp_qos_status_type
[i
].strlen
) == 0) {
2211 attr_p
->attr
.conf
.status_type
= (sdp_qos_status_types_e
)i
;
2216 /* Find the qos direction. */
2217 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2218 if (result
!= SDP_SUCCESS
) {
2219 sdp_parse_error(sdp_p
,
2220 "%s Warning: No qos direction specified.",
2222 sdp_p
->conf_p
->num_invalid_param
++;
2223 return (SDP_INVALID_PARAMETER
);
2225 attr_p
->attr
.conf
.direction
= SDP_QOS_DIR_UNKNOWN
;
2226 for (i
=0; i
< SDP_MAX_QOS_DIR
; i
++) {
2227 if (cpr_strncasecmp(tmp
, sdp_qos_direction
[i
].name
,
2228 sdp_qos_direction
[i
].strlen
) == 0) {
2229 attr_p
->attr
.conf
.direction
= (sdp_qos_dir_e
)i
;
2232 if (attr_p
->attr
.conf
.direction
== SDP_QOS_DIR_UNKNOWN
) {
2233 sdp_parse_error(sdp_p
,
2234 "%s Warning: QOS direction unrecognized (%s)",
2235 sdp_p
->debug_str
, tmp
);
2236 sdp_p
->conf_p
->num_invalid_param
++;
2237 return (SDP_INVALID_PARAMETER
);
2240 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2241 SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
2242 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
2243 sdp_get_conf_type_name(attr_p
->attr
.conf
.type
),
2244 sdp_get_qos_status_type_name(attr_p
->attr
.conf
.status_type
),
2245 sdp_get_qos_direction_name(attr_p
->attr
.conf
.direction
));
2248 return (SDP_SUCCESS
);
2251 sdp_result_e
sdp_build_attr_conf (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
, flex_string
*fs
)
2253 flex_string_sprintf(fs
, "a=%s:%s %s %s\r\n",
2254 sdp_attr
[attr_p
->type
].name
,
2255 sdp_get_conf_type_name(attr_p
->attr
.conf
.type
),
2256 sdp_get_qos_status_type_name(attr_p
->attr
.conf
.status_type
),
2257 sdp_get_qos_direction_name(attr_p
->attr
.conf
.direction
));
2263 * Parse a rtpmap or a sprtmap. Both formats use the same structure
2264 * the only difference being the keyword "rtpmap" vs "sprtmap". The
2265 * rtpmap field in the sdp_attr_t is used to store both mappings.
2267 sdp_result_e
sdp_parse_attr_transport_map (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2270 sdp_result_e result
;
2272 attr_p
->attr
.transport_map
.payload_num
= 0;
2273 attr_p
->attr
.transport_map
.encname
[0] = '\0';
2274 attr_p
->attr
.transport_map
.clockrate
= 0;
2275 attr_p
->attr
.transport_map
.num_chan
= 1;
2277 /* Find the payload type number. */
2278 attr_p
->attr
.transport_map
.payload_num
=
2279 (uint16_t)sdp_getnextnumtok(ptr
, &ptr
, " \t", &result
);
2280 if (result
!= SDP_SUCCESS
) {
2281 sdp_parse_error(sdp_p
,
2282 "%s Warning: Invalid payload type specified for %s attribute.",
2283 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
2284 sdp_p
->conf_p
->num_invalid_param
++;
2285 return (SDP_INVALID_PARAMETER
);
2288 /* Find the encoding name. */
2289 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.transport_map
.encname
,
2290 sizeof(attr_p
->attr
.transport_map
.encname
), "/ \t", &result
);
2291 if (result
!= SDP_SUCCESS
) {
2292 sdp_parse_error(sdp_p
,
2293 "%s Warning: No encoding name specified in %s attribute.",
2294 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
2295 sdp_p
->conf_p
->num_invalid_param
++;
2296 return (SDP_INVALID_PARAMETER
);
2299 /* Find the clockrate. */
2300 attr_p
->attr
.transport_map
.clockrate
=
2301 sdp_getnextnumtok(ptr
, &ptr
, "/ \t", &result
);
2302 if (result
!= SDP_SUCCESS
) {
2303 sdp_parse_error(sdp_p
,
2304 "%s Warning: No clockrate specified for "
2305 "%s attribute, set to default of 8000.",
2306 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
2307 attr_p
->attr
.transport_map
.clockrate
= 8000;
2310 /* Find the number of channels, if specified. This is optional. */
2312 /* If a '/' exists, expect something valid beyond it. */
2313 attr_p
->attr
.transport_map
.num_chan
=
2314 (uint16_t)sdp_getnextnumtok(ptr
, &ptr
, "/ \t", &result
);
2315 if (result
!= SDP_SUCCESS
) {
2316 sdp_parse_error(sdp_p
,
2317 "%s Warning: Invalid number of channels parameter"
2318 " for rtpmap attribute.", sdp_p
->debug_str
);
2319 sdp_p
->conf_p
->num_invalid_param
++;
2320 return (SDP_INVALID_PARAMETER
);
2324 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2325 SDP_PRINT("%s Parsed a=%s, payload type %u, encoding name %s, "
2326 "clockrate %u", sdp_p
->debug_str
,
2327 sdp_get_attr_name(attr_p
->type
),
2328 attr_p
->attr
.transport_map
.payload_num
,
2329 attr_p
->attr
.transport_map
.encname
,
2330 attr_p
->attr
.transport_map
.clockrate
);
2331 if (attr_p
->attr
.transport_map
.num_chan
!= 1) {
2332 SDP_PRINT("/%u", attr_p
->attr
.transport_map
.num_chan
);
2336 return (SDP_SUCCESS
);
2340 * Build a rtpmap or a sprtmap. Both formats use the same structure
2341 * the only difference being the keyword "rtpmap" vs "sprtmap". The
2342 * rtpmap field in the sdp_attr_t is used for both mappings.
2344 sdp_result_e
sdp_build_attr_transport_map (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2347 if (attr_p
->attr
.transport_map
.num_chan
== 1) {
2348 flex_string_sprintf(fs
, "a=%s:%u %s/%u\r\n",
2349 sdp_attr
[attr_p
->type
].name
,
2350 attr_p
->attr
.transport_map
.payload_num
,
2351 attr_p
->attr
.transport_map
.encname
,
2352 attr_p
->attr
.transport_map
.clockrate
);
2354 flex_string_sprintf(fs
, "a=%s:%u %s/%u/%u\r\n",
2355 sdp_attr
[attr_p
->type
].name
,
2356 attr_p
->attr
.transport_map
.payload_num
,
2357 attr_p
->attr
.transport_map
.encname
,
2358 attr_p
->attr
.transport_map
.clockrate
,
2359 attr_p
->attr
.transport_map
.num_chan
);
2365 sdp_result_e
sdp_parse_attr_subnet (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2370 sdp_result_e result
;
2371 tinybool type_found
= FALSE
;
2372 char tmp
[SDP_MAX_STRING_LEN
];
2374 /* Find the subnet network type. */
2375 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2376 if (result
!= SDP_SUCCESS
) {
2377 sdp_parse_error(sdp_p
,
2378 "%s Warning: No network type specified in subnet attribute.",
2380 sdp_p
->conf_p
->num_invalid_param
++;
2381 return (SDP_INVALID_PARAMETER
);
2383 attr_p
->attr
.subnet
.nettype
= SDP_NT_UNSUPPORTED
;
2384 for (i
=0; i
< SDP_MAX_NETWORK_TYPES
; i
++) {
2385 if (cpr_strncasecmp(tmp
, sdp_nettype
[i
].name
,
2386 sdp_nettype
[i
].strlen
) == 0) {
2389 if (type_found
== TRUE
) {
2390 if (sdp_p
->conf_p
->nettype_supported
[i
] == TRUE
) {
2391 attr_p
->attr
.subnet
.nettype
= (sdp_nettype_e
)i
;
2396 if (attr_p
->attr
.subnet
.nettype
== SDP_NT_UNSUPPORTED
) {
2397 sdp_parse_error(sdp_p
,
2398 "%s Warning: Subnet network type unsupported (%s).",
2399 sdp_p
->debug_str
, tmp
);
2400 sdp_p
->conf_p
->num_invalid_param
++;
2401 return (SDP_INVALID_PARAMETER
);
2404 /* Find the subnet address type. */
2405 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2406 if (result
!= SDP_SUCCESS
) {
2407 sdp_parse_error(sdp_p
,
2408 "%s Warning: No address type specified in subnet attribute.",
2410 sdp_p
->conf_p
->num_invalid_param
++;
2411 return (SDP_INVALID_PARAMETER
);
2413 attr_p
->attr
.subnet
.addrtype
= SDP_AT_UNSUPPORTED
;
2414 for (i
=0; i
< SDP_MAX_ADDR_TYPES
; i
++) {
2415 if (cpr_strncasecmp(tmp
, sdp_addrtype
[i
].name
,
2416 sdp_addrtype
[i
].strlen
) == 0) {
2419 if (type_found
== TRUE
) {
2420 if (sdp_p
->conf_p
->addrtype_supported
[i
] == TRUE
) {
2421 attr_p
->attr
.subnet
.addrtype
= (sdp_addrtype_e
)i
;
2426 if (attr_p
->attr
.subnet
.addrtype
== SDP_AT_UNSUPPORTED
) {
2427 sdp_parse_error(sdp_p
,
2428 "%s Warning: Subnet address type unsupported (%s).",
2429 sdp_p
->debug_str
, tmp
);
2430 sdp_p
->conf_p
->num_invalid_param
++;
2431 return (SDP_INVALID_PARAMETER
);
2434 /* Find the subnet address. */
2435 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.subnet
.addr
,
2436 sizeof(attr_p
->attr
.subnet
.addr
), " \t", &result
);
2437 if (result
!= SDP_SUCCESS
) {
2438 sdp_parse_error(sdp_p
,
2439 "%s Warning: No subnet address specified in "
2440 "subnet attribute.", sdp_p
->debug_str
);
2441 sdp_p
->conf_p
->num_invalid_param
++;
2442 return (SDP_INVALID_PARAMETER
);
2444 slash_ptr
= sdp_findchar(attr_p
->attr
.subnet
.addr
, "/");
2445 if (*slash_ptr
== '/') {
2446 *slash_ptr
++ = '\0';
2447 /* If the '/' exists, expect a valid prefix to follow. */
2448 attr_p
->attr
.subnet
.prefix
= sdp_getnextnumtok(slash_ptr
,
2449 (const char **)&slash_ptr
,
2451 if (result
!= SDP_SUCCESS
) {
2452 sdp_parse_error(sdp_p
,
2453 "%s Warning: Invalid subnet prefix specified in "
2454 "subnet attribute.", sdp_p
->debug_str
);
2455 sdp_p
->conf_p
->num_invalid_param
++;
2456 return (SDP_INVALID_PARAMETER
);
2459 attr_p
->attr
.subnet
.prefix
= SDP_INVALID_VALUE
;
2462 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2463 SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s ",
2464 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
2465 sdp_get_network_name(attr_p
->attr
.subnet
.nettype
),
2466 sdp_get_address_name(attr_p
->attr
.subnet
.addrtype
),
2467 attr_p
->attr
.subnet
.addr
);
2468 if (attr_p
->attr
.subnet
.prefix
!= SDP_INVALID_VALUE
) {
2469 SDP_PRINT("/%u", (ushort
)attr_p
->attr
.subnet
.prefix
);
2473 return (SDP_SUCCESS
);
2476 sdp_result_e
sdp_build_attr_subnet (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2479 if (attr_p
->attr
.subnet
.prefix
== SDP_INVALID_VALUE
) {
2480 flex_string_sprintf(fs
, "a=%s:%s %s %s\r\n",
2481 sdp_attr
[attr_p
->type
].name
,
2482 sdp_get_network_name(attr_p
->attr
.subnet
.nettype
),
2483 sdp_get_address_name(attr_p
->attr
.subnet
.addrtype
),
2484 attr_p
->attr
.subnet
.addr
);
2486 flex_string_sprintf(fs
, "a=%s:%s %s %s/%u\r\n",
2487 sdp_attr
[attr_p
->type
].name
,
2488 sdp_get_network_name(attr_p
->attr
.subnet
.nettype
),
2489 sdp_get_address_name(attr_p
->attr
.subnet
.addrtype
),
2490 attr_p
->attr
.subnet
.addr
,
2491 (ushort
)attr_p
->attr
.subnet
.prefix
);
2497 sdp_result_e
sdp_parse_attr_t38_ratemgmt (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2501 sdp_result_e result
;
2502 char tmp
[SDP_MAX_STRING_LEN
];
2504 /* Find the rate mgmt. */
2505 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2506 if (result
!= SDP_SUCCESS
) {
2507 sdp_parse_error(sdp_p
,
2508 "%s Warning: No t38 rate management specified.",
2510 sdp_p
->conf_p
->num_invalid_param
++;
2511 return (SDP_INVALID_PARAMETER
);
2513 attr_p
->attr
.t38ratemgmt
= SDP_T38_UNKNOWN_RATE
;
2514 for (i
=0; i
< SDP_T38_MAX_RATES
; i
++) {
2515 if (cpr_strncasecmp(tmp
, sdp_t38_rate
[i
].name
,
2516 sdp_t38_rate
[i
].strlen
) == 0) {
2517 attr_p
->attr
.t38ratemgmt
= (sdp_t38_ratemgmt_e
)i
;
2521 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2522 SDP_PRINT("%s Parsed a=%s, rate %s", sdp_p
->debug_str
,
2523 sdp_get_attr_name(attr_p
->type
),
2524 sdp_get_t38_ratemgmt_name(attr_p
->attr
.t38ratemgmt
));
2527 return (SDP_SUCCESS
);
2530 sdp_result_e
sdp_build_attr_t38_ratemgmt (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2533 flex_string_sprintf(fs
, "a=%s:%s\r\n",
2534 sdp_attr
[attr_p
->type
].name
,
2535 sdp_get_t38_ratemgmt_name(attr_p
->attr
.t38ratemgmt
));
2540 sdp_result_e
sdp_parse_attr_t38_udpec (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2544 sdp_result_e result
;
2545 char tmp
[SDP_MAX_STRING_LEN
];
2547 /* Find the udpec. */
2548 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2549 if (result
!= SDP_SUCCESS
) {
2550 sdp_parse_error(sdp_p
,
2551 "%s Warning: No t38 udpEC specified.",
2553 sdp_p
->conf_p
->num_invalid_param
++;
2554 return (SDP_INVALID_PARAMETER
);
2556 attr_p
->attr
.t38udpec
= SDP_T38_UDPEC_UNKNOWN
;
2557 for (i
=0; i
< SDP_T38_MAX_UDPEC
; i
++) {
2558 if (cpr_strncasecmp(tmp
, sdp_t38_udpec
[i
].name
,
2559 sdp_t38_udpec
[i
].strlen
) == 0) {
2560 attr_p
->attr
.t38udpec
= (sdp_t38_udpec_e
)i
;
2564 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2565 SDP_PRINT("%s Parsed a=%s, udpec %s", sdp_p
->debug_str
,
2566 sdp_get_attr_name(attr_p
->type
),
2567 sdp_get_t38_udpec_name(attr_p
->attr
.t38udpec
));
2570 return (SDP_SUCCESS
);
2573 sdp_result_e
sdp_build_attr_t38_udpec (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2576 flex_string_sprintf(fs
, "a=%s:%s\r\n",
2577 sdp_attr
[attr_p
->type
].name
,
2578 sdp_get_t38_udpec_name(attr_p
->attr
.t38udpec
));
2583 sdp_result_e
sdp_parse_attr_pc_codec (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2587 sdp_result_e result
;
2589 for (i
=0; i
< SDP_MAX_PAYLOAD_TYPES
; i
++) {
2590 attr_p
->attr
.pccodec
.payload_type
[i
] = (ushort
)sdp_getnextnumtok(ptr
, &ptr
,
2592 if (result
!= SDP_SUCCESS
) {
2595 attr_p
->attr
.pccodec
.num_payloads
++;
2598 if (attr_p
->attr
.pccodec
.num_payloads
== 0) {
2599 sdp_parse_error(sdp_p
,
2600 "%s Warning: No payloads specified for %s attr.",
2601 sdp_p
->debug_str
, sdp_attr
[attr_p
->type
].name
);
2602 sdp_p
->conf_p
->num_invalid_param
++;
2603 return (SDP_INVALID_PARAMETER
);
2606 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2607 SDP_PRINT("%s Parsed a=%s, num payloads %u, payloads: ",
2608 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
2609 attr_p
->attr
.pccodec
.num_payloads
);
2610 for (i
=0; i
< attr_p
->attr
.pccodec
.num_payloads
; i
++) {
2611 SDP_PRINT("%u ", attr_p
->attr
.pccodec
.payload_type
[i
]);
2615 return (SDP_SUCCESS
);
2618 sdp_result_e
sdp_build_attr_pc_codec (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2623 flex_string_sprintf(fs
, "a=%s: ", sdp_attr
[attr_p
->type
].name
);
2625 for (i
=0; i
< attr_p
->attr
.pccodec
.num_payloads
; i
++) {
2626 flex_string_sprintf(fs
, "%u ", attr_p
->attr
.pccodec
.payload_type
[i
]);
2629 flex_string_append(fs
, "\r\n");
2635 sdp_result_e
sdp_parse_attr_cap (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2639 sdp_result_e result
;
2641 char tmp
[SDP_MAX_STRING_LEN
];
2643 /* Set the capability pointer to NULL for now in case we encounter
2644 * an error in parsing.
2646 attr_p
->attr
.cap_p
= NULL
;
2647 /* Set the capability valid flag to FALSE in case we encounter an
2648 * error. If we do, we don't want to process any X-cpar/cpar attributes
2649 * from this point until we process the next valid X-cap/cdsc attr. */
2650 sdp_p
->cap_valid
= FALSE
;
2652 /* Allocate resource for new capability. Note that the capability
2653 * uses the same structure used for media lines.
2655 cap_p
= sdp_alloc_mca(sdp_p
->parse_line
);
2656 if (cap_p
== NULL
) {
2657 sdp_p
->conf_p
->num_no_resource
++;
2658 return (SDP_NO_RESOURCE
);
2661 /* Find the capability number. We don't need to store this since we
2662 * calculate it for ourselves as we need to. But it must be specified. */
2663 (void)sdp_getnextnumtok(ptr
, &ptr
, "/ \t", &result
);
2664 if (result
!= SDP_SUCCESS
) {
2665 sdp_parse_error(sdp_p
,
2666 "%s Warning: Capability not specified for %s, "
2667 "unable to parse.", sdp_p
->debug_str
,
2668 sdp_get_attr_name(attr_p
->type
));
2670 sdp_p
->conf_p
->num_invalid_param
++;
2671 return (SDP_INVALID_PARAMETER
);
2674 /* Find the media type. */
2675 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2676 if (result
!= SDP_SUCCESS
) {
2677 sdp_parse_error(sdp_p
,
2678 "%s No media type specified for %s attribute, "
2680 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
2682 sdp_p
->conf_p
->num_invalid_param
++;
2683 return (SDP_INVALID_PARAMETER
);
2685 cap_p
->media
= SDP_MEDIA_UNSUPPORTED
;
2686 for (i
=0; i
< SDP_MAX_MEDIA_TYPES
; i
++) {
2687 if (cpr_strncasecmp(tmp
, sdp_media
[i
].name
, sdp_media
[i
].strlen
) == 0) {
2688 cap_p
->media
= (sdp_media_e
)i
;
2692 if (cap_p
->media
== SDP_MEDIA_UNSUPPORTED
) {
2693 sdp_parse_error(sdp_p
,
2694 "%s Warning: Media type unsupported (%s).",
2695 sdp_p
->debug_str
, tmp
);
2697 sdp_p
->conf_p
->num_invalid_param
++;
2698 return (SDP_INVALID_PARAMETER
);
2701 /* Find the transport protocol type. */
2702 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
2703 if (result
!= SDP_SUCCESS
) {
2704 sdp_parse_error(sdp_p
,
2705 "%s No transport protocol type specified, "
2706 "unable to parse.", sdp_p
->debug_str
);
2708 sdp_p
->conf_p
->num_invalid_param
++;
2709 return (SDP_INVALID_PARAMETER
);
2711 cap_p
->transport
= SDP_TRANSPORT_UNSUPPORTED
;
2712 for (i
=0; i
< SDP_MAX_TRANSPORT_TYPES
; i
++) {
2713 if (cpr_strncasecmp(tmp
, sdp_transport
[i
].name
,
2714 sdp_transport
[i
].strlen
) == 0) {
2715 cap_p
->transport
= (sdp_transport_e
)i
;
2719 if (cap_p
->transport
== SDP_TRANSPORT_UNSUPPORTED
) {
2720 sdp_parse_error(sdp_p
,
2721 "%s Warning: Transport protocol type unsupported (%s).",
2722 sdp_p
->debug_str
, tmp
);
2724 sdp_p
->conf_p
->num_invalid_param
++;
2725 return (SDP_INVALID_PARAMETER
);
2728 /* Find payload formats. AAL2 X-cap lines allow multiple
2729 * transport/profile types per line, so these are handled differently.
2731 if ((cap_p
->transport
== SDP_TRANSPORT_AAL2_ITU
) ||
2732 (cap_p
->transport
== SDP_TRANSPORT_AAL2_ATMF
) ||
2733 (cap_p
->transport
== SDP_TRANSPORT_AAL2_CUSTOM
)) {
2734 /* Capability processing is not currently defined for AAL2 types
2735 * with multiple profiles. We don't process. */
2736 sdp_parse_error(sdp_p
,
2737 "%s Warning: AAL2 profiles unsupported with "
2738 "%s attributes.", sdp_p
->debug_str
,
2739 sdp_get_attr_name(attr_p
->type
));
2741 sdp_p
->conf_p
->num_invalid_param
++;
2742 return (SDP_INVALID_PARAMETER
);
2744 /* Transport is a non-AAL2 type. Parse payloads normally. */
2745 sdp_parse_payload_types(sdp_p
, cap_p
, ptr
);
2746 if (cap_p
->num_payloads
== 0) {
2748 sdp_p
->conf_p
->num_invalid_param
++;
2749 return (SDP_INVALID_PARAMETER
);
2753 attr_p
->attr
.cap_p
= cap_p
;
2755 * This capability attr is valid. We can now handle X-cpar or
2758 sdp_p
->cap_valid
= TRUE
;
2759 sdp_p
->last_cap_inst
++;
2761 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2762 SDP_PRINT("%s Parsed %s media type %s, Transport %s, "
2763 "Num payloads %u", sdp_p
->debug_str
,
2764 sdp_get_attr_name(attr_p
->type
),
2765 sdp_get_media_name(cap_p
->media
),
2766 sdp_get_transport_name(cap_p
->transport
),
2767 cap_p
->num_payloads
);
2769 return (SDP_SUCCESS
);
2772 sdp_result_e
sdp_build_attr_cap (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2777 sdp_media_profiles_t
*profile_p
;
2779 /* Get a pointer to the capability structure. */
2780 cap_p
= attr_p
->attr
.cap_p
;
2782 if (cap_p
== NULL
) {
2783 SDPLogError(logTag
, "%s Invalid %s attribute, unable to build.",
2784 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
2785 sdp_p
->conf_p
->num_invalid_param
++;
2786 /* Return success so build won't fail. */
2787 return (SDP_SUCCESS
);
2790 /* Validate params for this capability line */
2791 if ((cap_p
->media
>= SDP_MAX_MEDIA_TYPES
) ||
2792 (cap_p
->transport
>= SDP_MAX_TRANSPORT_TYPES
)) {
2793 SDPLogDebug(logTag
, logTag
, "%s Media or transport type invalid for %s "
2794 "attribute, unable to build.", sdp_p
->debug_str
,
2795 sdp_get_attr_name(attr_p
->type
));
2796 sdp_p
->conf_p
->num_invalid_param
++;
2797 /* Return success so build won't fail. */
2798 return (SDP_SUCCESS
);
2801 flex_string_sprintf(fs
, "a=%s: %u %s ", sdp_attr
[attr_p
->type
].name
,
2802 sdp_p
->cur_cap_num
, sdp_get_media_name(cap_p
->media
));
2804 /* If the X-cap line has AAL2 profiles, build them differently. */
2805 if ((cap_p
->transport
== SDP_TRANSPORT_AAL2_ITU
) ||
2806 (cap_p
->transport
== SDP_TRANSPORT_AAL2_ATMF
) ||
2807 (cap_p
->transport
== SDP_TRANSPORT_AAL2_CUSTOM
)) {
2808 profile_p
= cap_p
->media_profiles_p
;
2809 for (i
=0; i
< profile_p
->num_profiles
; i
++) {
2810 flex_string_sprintf(fs
, "%s",
2811 sdp_get_transport_name(profile_p
->profile
[i
]));
2813 for (j
=0; j
< profile_p
->num_payloads
[i
]; j
++) {
2814 flex_string_sprintf(fs
, " %u",
2815 profile_p
->payload_type
[i
][j
]);
2817 flex_string_append(fs
, " ");
2820 flex_string_append(fs
, "\r\n");
2821 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
2822 SDP_PRINT("%s Built m= media line", sdp_p
->debug_str
);
2827 /* Build the transport name */
2828 flex_string_sprintf(fs
, "%s", sdp_get_transport_name(cap_p
->transport
));
2830 /* Build the format lists */
2831 for (i
=0; i
< cap_p
->num_payloads
; i
++) {
2832 if (cap_p
->payload_indicator
[i
] == SDP_PAYLOAD_ENUM
) {
2833 flex_string_sprintf(fs
, " %s",
2834 sdp_get_payload_name((sdp_payload_e
)cap_p
->payload_type
[i
]));
2836 flex_string_sprintf(fs
, " %u", cap_p
->payload_type
[i
]);
2840 flex_string_append(fs
, "\r\n");
2842 /* Increment the current capability number for the next X-cap/cdsc attr. */
2843 sdp_p
->cur_cap_num
+= cap_p
->num_payloads
;
2844 sdp_p
->last_cap_type
= attr_p
->type
;
2846 /* Build any X-cpar/cpar attributes associated with this X-cap/cdsc line. */
2847 return sdp_build_attr_cpar(sdp_p
, cap_p
->media_attrs_p
, fs
);
2851 sdp_result_e
sdp_parse_attr_cpar (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
2855 sdp_result_e result
;
2857 sdp_attr_t
*cap_attr_p
= NULL
;
2858 sdp_attr_t
*prev_attr_p
;
2859 char tmp
[SDP_MAX_STRING_LEN
] = {0};
2861 /* Make sure we've processed a valid X-cap/cdsc attr prior to this and
2862 * if so, get the cap pointer. */
2863 if (sdp_p
->cap_valid
== TRUE
) {
2864 sdp_attr_e cap_type
;
2866 if (attr_p
->type
== SDP_ATTR_CPAR
) {
2867 cap_type
= SDP_ATTR_CDSC
;
2869 /* Default to X-CAP for everything else */
2870 cap_type
= SDP_ATTR_X_CAP
;
2873 if (sdp_p
->mca_count
== 0) {
2874 cap_attr_p
= sdp_find_attr(sdp_p
, SDP_SESSION_LEVEL
, 0,
2875 cap_type
, sdp_p
->last_cap_inst
);
2877 cap_attr_p
= sdp_find_attr(sdp_p
, sdp_p
->mca_count
, 0,
2878 cap_type
, sdp_p
->last_cap_inst
);
2881 if ((cap_attr_p
== NULL
) || (cap_attr_p
->attr
.cap_p
== NULL
)) {
2882 sdp_parse_error(sdp_p
,
2883 "%s Warning: %s attribute specified with no "
2884 "prior %s attribute", sdp_p
->debug_str
,
2885 sdp_get_attr_name(attr_p
->type
),
2886 (attr_p
->type
== SDP_ATTR_CPAR
)?
2887 (sdp_get_attr_name(SDP_ATTR_CDSC
)) :
2888 (sdp_get_attr_name(SDP_ATTR_X_CAP
)) );
2889 sdp_p
->conf_p
->num_invalid_param
++;
2890 return (SDP_INVALID_PARAMETER
);
2894 * Ensure there is no mixed syntax like CDSC followed by X-CPAR
2895 * or X-CAP followed by CPAR.
2897 if (((cap_attr_p
->type
== SDP_ATTR_CDSC
) &&
2898 (attr_p
->type
== SDP_ATTR_X_CPAR
)) ||
2899 ( (cap_attr_p
->type
== SDP_ATTR_X_CAP
) &&
2900 (attr_p
->type
== SDP_ATTR_CPAR
)) ) {
2901 sdp_parse_error(sdp_p
,
2902 "%s Warning: %s attribute inconsistent with "
2903 "prior %s attribute", sdp_p
->debug_str
,
2904 sdp_get_attr_name(attr_p
->type
),
2905 sdp_get_attr_name(cap_attr_p
->type
));
2906 sdp_p
->conf_p
->num_invalid_param
++;
2907 return (SDP_INVALID_PARAMETER
);
2909 cap_p
= cap_attr_p
->attr
.cap_p
;
2911 /* a= is the only token we handle in an X-cpar/cpar attribute. */
2912 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), "= \t", &result
);
2914 if ((result
!= SDP_SUCCESS
) || (tmp
[0] != 'a') || (tmp
[1] != '\0')) {
2915 sdp_parse_error(sdp_p
,
2916 "%s Warning: Invalid token type in %s "
2917 "attribute, unable to parse", sdp_p
->debug_str
,
2918 sdp_get_attr_name(attr_p
->type
));
2919 sdp_p
->conf_p
->num_invalid_param
++;
2920 return (SDP_INVALID_PARAMETER
);
2922 /*sa_ignore NO_NULL_CHK
2923 *{ptr is valid since the pointer was checked earlier and the
2924 * function would have exited if NULL.}
2930 /* Find the attribute type. */
2931 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), ": \t", &result
);
2932 /*sa_ignore NO_NULL_CHK
2933 *{ptr is valid since the pointer was checked earlier and the
2934 * function would have exited if NULL.}
2936 if (ptr
[0] == ':') {
2937 /* Skip the ':' char for parsing attribute parameters. */
2940 if (result
!= SDP_SUCCESS
) {
2941 sdp_parse_error(sdp_p
,
2942 "%s No attribute type specified for %s attribute, unable to parse.",
2944 sdp_get_attr_name(attr_p
->type
));
2945 sdp_p
->conf_p
->num_invalid_param
++;
2946 return (SDP_INVALID_PARAMETER
);
2949 /* Reset the type of the attribute from X-cpar/cpar to whatever the
2950 * specified type is. */
2951 attr_p
->type
= SDP_ATTR_INVALID
;
2952 attr_p
->next_p
= NULL
;
2953 for (i
=0; i
< SDP_MAX_ATTR_TYPES
; i
++) {
2954 if (cpr_strncasecmp(tmp
, sdp_attr
[i
].name
, sdp_attr
[i
].strlen
) == 0) {
2955 attr_p
->type
= (sdp_attr_e
)i
;
2958 if (attr_p
->type
== SDP_ATTR_INVALID
) {
2959 sdp_parse_error(sdp_p
,
2960 "%s Warning: Unrecognized attribute (%s) for %s attribute, unable to parse.",
2961 sdp_p
->debug_str
, tmp
,
2962 sdp_get_attr_name(attr_p
->type
));
2963 sdp_p
->conf_p
->num_invalid_param
++;
2964 return (SDP_INVALID_PARAMETER
);
2967 /* We don't allow recursion with the capability attributes. */
2968 if ((attr_p
->type
== SDP_ATTR_X_SQN
) ||
2969 (attr_p
->type
== SDP_ATTR_X_CAP
) ||
2970 (attr_p
->type
== SDP_ATTR_X_CPAR
) ||
2971 (attr_p
->type
== SDP_ATTR_SQN
) ||
2972 (attr_p
->type
== SDP_ATTR_CDSC
) ||
2973 (attr_p
->type
== SDP_ATTR_CPAR
)) {
2974 sdp_parse_error(sdp_p
,
2975 "%s Warning: Invalid attribute (%s) for %s"
2976 " attribute, unable to parse.", sdp_p
->debug_str
, tmp
,
2977 sdp_get_attr_name(attr_p
->type
));
2978 sdp_p
->conf_p
->num_invalid_param
++;
2979 return (SDP_INVALID_PARAMETER
);
2982 /* Parse the attribute. */
2983 result
= sdp_attr
[attr_p
->type
].parse_func(sdp_p
, attr_p
, ptr
);
2984 if (result
!= SDP_SUCCESS
) {
2988 /* Hook the attribute into the capability structure. */
2989 if (cap_p
->media_attrs_p
== NULL
) {
2990 cap_p
->media_attrs_p
= attr_p
;
2992 for (prev_attr_p
= cap_p
->media_attrs_p
;
2993 prev_attr_p
->next_p
!= NULL
;
2994 prev_attr_p
= prev_attr_p
->next_p
) {
2997 prev_attr_p
->next_p
= attr_p
;
3000 return (SDP_SUCCESS
);
3003 sdp_result_e
sdp_build_attr_cpar (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3006 sdp_result_e result
;
3007 const char *cpar_name
;
3009 /* Determine whether to use cpar or X-cpar */
3010 if (sdp_p
->last_cap_type
== SDP_ATTR_CDSC
) {
3011 cpar_name
= sdp_get_attr_name(SDP_ATTR_CPAR
);
3014 * Default to X-CPAR if anything else. This is the backward
3017 cpar_name
= sdp_get_attr_name(SDP_ATTR_X_CPAR
);
3020 while (attr_p
!= NULL
) {
3021 if (attr_p
->type
>= SDP_MAX_ATTR_TYPES
) {
3022 SDPLogDebug(logTag
, "%s Invalid attribute type to build (%u)",
3023 sdp_p
->debug_str
, (unsigned)attr_p
->type
);
3025 flex_string_sprintf(fs
, "a=%s: ", cpar_name
);
3027 result
= sdp_attr
[attr_p
->type
].build_func(sdp_p
, attr_p
, fs
);
3029 if (result
== SDP_SUCCESS
) {
3030 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3031 SDP_PRINT("%s Built %s a=%s attribute line",
3032 sdp_p
->debug_str
, cpar_name
,
3033 sdp_get_attr_name(attr_p
->type
));
3037 attr_p
= attr_p
->next_p
;
3040 return (SDP_SUCCESS
);
3043 sdp_result_e
sdp_parse_attr_rtcp (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3046 sdp_result_e result
;
3047 char nettype
[SDP_MAX_STRING_LEN
];
3048 sdp_rtcp_t
*rtcp_p
= &(attr_p
->attr
.rtcp
);
3051 memset(rtcp_p
, 0, sizeof(sdp_rtcp_t
));
3053 rtcp_p
->port
= (uint16_t)sdp_getnextnumtok(ptr
, &ptr
, " \t", &result
);
3054 if (result
!= SDP_SUCCESS
) {
3055 sdp_parse_error(sdp_p
,
3056 "%s Warning: could not parse port for rtcp attribute",
3058 sdp_p
->conf_p
->num_invalid_param
++;
3060 return SDP_INVALID_PARAMETER
;
3063 /* The rest is optional, although it is all-or-nothing */
3064 (void)sdp_getnextstrtok(ptr
, nettype
, sizeof(nettype
), " \t", &result
);
3065 if (result
== SDP_EMPTY_TOKEN
) {
3066 /* Nothing after the port */
3070 enum_raw
= find_token_enum("Nettype", sdp_p
, &ptr
, sdp_nettype
,
3071 SDP_MAX_NETWORK_TYPES
, SDP_NT_UNSUPPORTED
);
3072 if (enum_raw
== -1) {
3073 return SDP_INVALID_PARAMETER
;
3075 rtcp_p
->nettype
= (sdp_nettype_e
)enum_raw
;
3077 enum_raw
= find_token_enum("Addrtype", sdp_p
, &ptr
, sdp_addrtype
,
3078 SDP_MAX_ADDR_TYPES
, SDP_AT_UNSUPPORTED
);
3079 if (enum_raw
== -1) {
3080 return SDP_INVALID_PARAMETER
;
3082 rtcp_p
->addrtype
= (sdp_addrtype_e
)enum_raw
;
3084 ptr
= sdp_getnextstrtok(ptr
, rtcp_p
->addr
, sizeof(rtcp_p
->addr
), " \t",
3086 if (result
!= SDP_SUCCESS
) {
3087 sdp_parse_error(sdp_p
,
3088 "%s Warning: could not parse addr for rtcp attribute",
3090 sdp_p
->conf_p
->num_invalid_param
++;
3092 return SDP_INVALID_PARAMETER
;
3098 sdp_result_e
sdp_build_attr_rtcp (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3101 /* We should not be serializing SDP anyway, but we need this function until
3102 * Bug 1112737 is resolved. */
3106 sdp_result_e
sdp_parse_attr_rtr (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3109 sdp_result_e result
;
3110 char tmp
[SDP_MAX_STRING_LEN
];
3112 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3113 SDP_PRINT("%s Parsing a=%s", sdp_p
->debug_str
,
3114 sdp_get_attr_name(attr_p
->type
));
3116 /*Default confirm to FALSE. */
3117 attr_p
->attr
.rtr
.confirm
= FALSE
;
3119 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3120 if (result
!= SDP_SUCCESS
){ // No confirm tag specified is not an error
3121 return (SDP_SUCCESS
);
3123 /* See if confirm was specified. Defaults to FALSE. */
3124 if (cpr_strncasecmp(tmp
, "confirm", sizeof("confirm")) == 0) {
3125 attr_p
->attr
.rtr
.confirm
= TRUE
;
3127 if (attr_p
->attr
.rtr
.confirm
== FALSE
) {
3128 sdp_parse_error(sdp_p
,
3129 "%s Warning: RTR confirm parameter invalid (%s)",
3130 sdp_p
->debug_str
, tmp
);
3131 sdp_p
->conf_p
->num_invalid_param
++;
3132 return (SDP_INVALID_PARAMETER
);
3134 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3135 SDP_PRINT("%s Parsed a=%s, %s", sdp_p
->debug_str
,
3136 sdp_get_attr_name(attr_p
->type
),
3139 return (SDP_SUCCESS
);
3143 sdp_result_e
sdp_build_attr_rtr (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3146 flex_string_sprintf(fs
, "a=%s%s\r\n",
3147 sdp_attr
[attr_p
->type
].name
,
3148 attr_p
->attr
.rtr
.confirm
? ":confirm" : "");
3153 sdp_result_e
sdp_parse_attr_comediadir (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3157 sdp_result_e result
;
3158 tinybool type_found
= FALSE
;
3159 char tmp
[SDP_MAX_STRING_LEN
];
3161 attr_p
->attr
.comediadir
.role
= SDP_MEDIADIR_ROLE_PASSIVE
;
3162 attr_p
->attr
.comediadir
.conn_info_present
= FALSE
;
3163 attr_p
->attr
.comediadir
.conn_info
.nettype
= SDP_NT_INVALID
;
3164 attr_p
->attr
.comediadir
.src_port
= 0;
3166 /* Find the media direction role. */
3167 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), ": \t", &result
);
3169 if (result
!= SDP_SUCCESS
) {
3170 sdp_parse_error(sdp_p
,
3171 "%s Warning: No role parameter specified for "
3172 "comediadir attribute.", sdp_p
->debug_str
);
3173 sdp_p
->conf_p
->num_invalid_param
++;
3174 return (SDP_INVALID_PARAMETER
);
3176 attr_p
->attr
.comediadir
.role
= SDP_MEDIADIR_ROLE_UNSUPPORTED
;
3177 for (i
=0; i
< SDP_MAX_MEDIADIR_ROLES
; i
++) {
3178 if (cpr_strncasecmp(tmp
, sdp_mediadir_role
[i
].name
,
3179 sdp_mediadir_role
[i
].strlen
) == 0) {
3181 attr_p
->attr
.comediadir
.role
= (sdp_mediadir_role_e
)i
;
3185 if (attr_p
->attr
.comediadir
.role
== SDP_MEDIADIR_ROLE_UNSUPPORTED
) {
3186 sdp_parse_error(sdp_p
,
3187 "%s Warning: Invalid role type specified for "
3188 "comediadir attribute (%s).", sdp_p
->debug_str
, tmp
);
3189 sdp_p
->conf_p
->num_invalid_param
++;
3190 return (SDP_INVALID_PARAMETER
);
3193 /* If the role is passive, we don't expect any more params. */
3194 if (attr_p
->attr
.comediadir
.role
== SDP_MEDIADIR_ROLE_PASSIVE
) {
3195 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3196 SDP_PRINT("%s Parsed a=%s, passive",
3197 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
3199 return (SDP_SUCCESS
);
3202 /* Find the connection information if present */
3203 /* parse to get the nettype */
3204 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3205 if (result
!= SDP_SUCCESS
) {
3206 sdp_parse_error(sdp_p
,
3207 "%s Warning: No network type specified in comediadir "
3208 "attribute.", sdp_p
->debug_str
);
3209 sdp_p
->conf_p
->num_invalid_param
++;
3210 return (SDP_SUCCESS
); /* as the optional parameters are not there */
3212 attr_p
->attr
.comediadir
.conn_info
.nettype
= SDP_NT_UNSUPPORTED
;
3213 for (i
=0; i
< SDP_MAX_NETWORK_TYPES
; i
++) {
3214 if (cpr_strncasecmp(tmp
, sdp_nettype
[i
].name
,
3215 sdp_nettype
[i
].strlen
) == 0) {
3218 if (type_found
== TRUE
) {
3219 if (sdp_p
->conf_p
->nettype_supported
[i
] == TRUE
) {
3220 attr_p
->attr
.comediadir
.conn_info
.nettype
= (sdp_nettype_e
)i
;
3225 if (attr_p
->attr
.comediadir
.conn_info
.nettype
== SDP_NT_UNSUPPORTED
) {
3226 sdp_parse_error(sdp_p
,
3227 "%s Warning: ConnInfo in Comediadir: network type "
3228 "unsupported (%s).", sdp_p
->debug_str
, tmp
);
3229 sdp_p
->conf_p
->num_invalid_param
++;
3232 /* Find the comedia address type. */
3233 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3234 if (result
!= SDP_SUCCESS
) {
3235 sdp_parse_error(sdp_p
,
3236 "%s Warning: No address type specified in comediadir"
3237 " attribute.", sdp_p
->debug_str
);
3238 sdp_p
->conf_p
->num_invalid_param
++;
3240 attr_p
->attr
.comediadir
.conn_info
.addrtype
= SDP_AT_UNSUPPORTED
;
3241 for (i
=0; i
< SDP_MAX_ADDR_TYPES
; i
++) {
3242 if (cpr_strncasecmp(tmp
, sdp_addrtype
[i
].name
,
3243 sdp_addrtype
[i
].strlen
) == 0) {
3246 if (type_found
== TRUE
) {
3247 if (sdp_p
->conf_p
->addrtype_supported
[i
] == TRUE
) {
3248 attr_p
->attr
.comediadir
.conn_info
.addrtype
= (sdp_addrtype_e
)i
;
3253 if (attr_p
->attr
.comediadir
.conn_info
.addrtype
== SDP_AT_UNSUPPORTED
) {
3254 sdp_parse_error(sdp_p
,
3255 "%s Warning: Conninfo address type unsupported "
3256 "(%s).", sdp_p
->debug_str
, tmp
);
3257 sdp_p
->conf_p
->num_invalid_param
++;
3260 /* Find the conninfo address. */
3261 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.comediadir
.conn_info
.conn_addr
,
3262 sizeof(attr_p
->attr
.comediadir
.conn_info
.conn_addr
), " \t", &result
);
3263 if (result
!= SDP_SUCCESS
) {
3264 sdp_parse_error(sdp_p
,
3265 "%s Warning: No conninfo address specified in "
3266 "comediadir attribute.", sdp_p
->debug_str
);
3267 sdp_p
->conf_p
->num_invalid_param
++;
3270 /* Find the src port info , if any */
3271 attr_p
->attr
.comediadir
.src_port
= sdp_getnextnumtok(ptr
, &ptr
, " \t",
3273 if (result
!= SDP_SUCCESS
) {
3274 sdp_parse_error(sdp_p
,
3275 "%s Warning: No src port specified in "
3276 "comediadir attribute.", sdp_p
->debug_str
);
3277 sdp_p
->conf_p
->num_invalid_param
++;
3280 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3281 SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s "
3283 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
3284 sdp_get_network_name(attr_p
->attr
.comediadir
.conn_info
.nettype
),
3285 sdp_get_address_name(attr_p
->attr
.comediadir
.conn_info
.addrtype
),
3286 attr_p
->attr
.comediadir
.conn_info
.conn_addr
,
3287 (unsigned int)attr_p
->attr
.comediadir
.src_port
);
3290 if (sdp_p
->conf_p
->num_invalid_param
> 0) {
3291 return (SDP_INVALID_PARAMETER
);
3293 return (SDP_SUCCESS
);
3297 sdp_build_attr_comediadir (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3300 flex_string_sprintf(fs
, "a=%s:%s\r\n",
3301 sdp_attr
[attr_p
->type
].name
,
3302 sdp_get_mediadir_role_name(attr_p
->attr
.comediadir
.role
));
3307 sdp_result_e
sdp_parse_attr_silencesupp (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3311 sdp_result_e result
;
3312 char tmp
[SDP_MAX_STRING_LEN
];
3314 /* Find silenceSuppEnable */
3315 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3317 if (result
!= SDP_SUCCESS
) {
3318 sdp_parse_error(sdp_p
,
3319 "%s No silenceSupp enable value specified, parse failed.",
3321 sdp_p
->conf_p
->num_invalid_param
++;
3322 return (SDP_INVALID_PARAMETER
);
3325 if (cpr_strncasecmp(tmp
, "on", sizeof("on")) == 0) {
3326 attr_p
->attr
.silencesupp
.enabled
= TRUE
;
3327 } else if (cpr_strncasecmp(tmp
, "off", sizeof("off")) == 0) {
3328 attr_p
->attr
.silencesupp
.enabled
= FALSE
;
3329 } else if (cpr_strncasecmp(tmp
, "-", sizeof("-")) == 0) {
3330 attr_p
->attr
.silencesupp
.enabled
= FALSE
;
3332 sdp_parse_error(sdp_p
,
3333 "%s Warning: silenceSuppEnable parameter invalid (%s)",
3334 sdp_p
->debug_str
, tmp
);
3335 sdp_p
->conf_p
->num_invalid_param
++;
3336 return (SDP_INVALID_PARAMETER
);
3339 /* Find silenceTimer -- uint16_t or "-" */
3341 attr_p
->attr
.silencesupp
.timer
=
3342 (uint16_t)sdp_getnextnumtok_or_null(ptr
, &ptr
, " \t",
3343 &attr_p
->attr
.silencesupp
.timer_null
,
3345 if (result
!= SDP_SUCCESS
) {
3346 sdp_parse_error(sdp_p
,
3347 "%s Warning: Invalid timer value specified for "
3348 "silenceSupp attribute.", sdp_p
->debug_str
);
3349 sdp_p
->conf_p
->num_invalid_param
++;
3350 return (SDP_INVALID_PARAMETER
);
3354 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3355 if (result
!= SDP_SUCCESS
) {
3356 sdp_parse_error(sdp_p
,
3357 "%s Warning: No silenceSupp pref specified.",
3359 sdp_p
->conf_p
->num_invalid_param
++;
3360 return (SDP_INVALID_PARAMETER
);
3362 attr_p
->attr
.silencesupp
.pref
= SDP_SILENCESUPP_PREF_UNKNOWN
;
3363 for (i
=0; i
< SDP_MAX_SILENCESUPP_PREF
; i
++) {
3364 if (cpr_strncasecmp(tmp
, sdp_silencesupp_pref
[i
].name
,
3365 sdp_silencesupp_pref
[i
].strlen
) == 0) {
3366 attr_p
->attr
.silencesupp
.pref
= (sdp_silencesupp_pref_e
)i
;
3369 if (attr_p
->attr
.silencesupp
.pref
== SDP_SILENCESUPP_PREF_UNKNOWN
) {
3370 sdp_parse_error(sdp_p
,
3371 "%s Warning: silenceSupp pref unrecognized (%s)",
3372 sdp_p
->debug_str
, tmp
);
3373 sdp_p
->conf_p
->num_invalid_param
++;
3374 return (SDP_INVALID_PARAMETER
);
3378 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3379 if (result
!= SDP_SUCCESS
) {
3380 sdp_parse_error(sdp_p
,
3381 "%s Warning: No silenceSupp sidUse specified.",
3383 sdp_p
->conf_p
->num_invalid_param
++;
3384 return (SDP_INVALID_PARAMETER
);
3386 attr_p
->attr
.silencesupp
.siduse
= SDP_SILENCESUPP_SIDUSE_UNKNOWN
;
3387 for (i
=0; i
< SDP_MAX_SILENCESUPP_SIDUSE
; i
++) {
3388 if (cpr_strncasecmp(tmp
, sdp_silencesupp_siduse
[i
].name
,
3389 sdp_silencesupp_siduse
[i
].strlen
) == 0) {
3390 attr_p
->attr
.silencesupp
.siduse
= (sdp_silencesupp_siduse_e
)i
;
3393 if (attr_p
->attr
.silencesupp
.siduse
== SDP_SILENCESUPP_SIDUSE_UNKNOWN
) {
3394 sdp_parse_error(sdp_p
,
3395 "%s Warning: silenceSupp sidUse unrecognized (%s)",
3396 sdp_p
->debug_str
, tmp
);
3397 sdp_p
->conf_p
->num_invalid_param
++;
3398 return (SDP_INVALID_PARAMETER
);
3401 /* Find fxnslevel -- uint8_t or "-" */
3402 attr_p
->attr
.silencesupp
.fxnslevel
=
3403 (uint8_t)sdp_getnextnumtok_or_null(ptr
, &ptr
, " \t",
3404 &attr_p
->attr
.silencesupp
.fxnslevel_null
,
3407 if (result
!= SDP_SUCCESS
) {
3408 sdp_parse_error(sdp_p
,
3409 "%s Warning: Invalid fxnslevel value specified for "
3410 "silenceSupp attribute.", sdp_p
->debug_str
);
3411 sdp_p
->conf_p
->num_invalid_param
++;
3412 return (SDP_INVALID_PARAMETER
);
3415 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3416 SDP_PRINT("%s Parsed a=%s, enabled %s",
3417 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
3418 (attr_p
->attr
.silencesupp
.enabled
? "on" : "off"));
3419 if (attr_p
->attr
.silencesupp
.timer_null
) {
3420 SDP_PRINT(" timer=-");
3422 SDP_PRINT(" timer=%u,", attr_p
->attr
.silencesupp
.timer
);
3424 SDP_PRINT(" pref=%s, siduse=%s,",
3425 sdp_get_silencesupp_pref_name(attr_p
->attr
.silencesupp
.pref
),
3426 sdp_get_silencesupp_siduse_name(
3427 attr_p
->attr
.silencesupp
.siduse
));
3428 if (attr_p
->attr
.silencesupp
.fxnslevel_null
) {
3429 SDP_PRINT(" fxnslevel=-");
3431 SDP_PRINT(" fxnslevel=%u,", attr_p
->attr
.silencesupp
.fxnslevel
);
3435 return (SDP_SUCCESS
);
3438 sdp_result_e
sdp_build_attr_silencesupp (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3441 char temp_timer_string
[11];
3442 char temp_fxnslevel_string
[11];
3444 if (attr_p
->attr
.silencesupp
.timer_null
) {
3445 snprintf(temp_timer_string
, sizeof(temp_timer_string
), "-");
3447 snprintf(temp_timer_string
, sizeof(temp_timer_string
), "%u", attr_p
->attr
.silencesupp
.timer
);
3450 if (attr_p
->attr
.silencesupp
.fxnslevel_null
) {
3451 snprintf(temp_fxnslevel_string
, sizeof(temp_fxnslevel_string
), "-");
3453 snprintf(temp_fxnslevel_string
, sizeof(temp_fxnslevel_string
), "%u", attr_p
->attr
.silencesupp
.fxnslevel
);
3456 flex_string_sprintf(fs
, "a=%s:%s %s %s %s %s\r\n",
3457 sdp_attr
[attr_p
->type
].name
,
3458 (attr_p
->attr
.silencesupp
.enabled
? "on" : "off"),
3460 sdp_get_silencesupp_pref_name(attr_p
->attr
.silencesupp
.pref
),
3461 sdp_get_silencesupp_siduse_name(attr_p
->attr
.silencesupp
.siduse
),
3462 temp_fxnslevel_string
);
3468 * sdp_parse_context_crypto_suite
3470 * This routine parses the crypto suite pointed to by str, stores the crypto suite value into the
3471 * srtp context suite component of the LocalConnectionOptions pointed to by lco_node_ptr and stores
3472 * pointer to the next crypto parameter in tmp_ptr
3474 tinybool
sdp_parse_context_crypto_suite(char * str
, sdp_attr_t
*attr_p
, sdp_t
*sdp_p
) {
3476 * Three crypto_suites are defined: (Notice no SPACE between "crypto:" and the <crypto-suite>
3477 * AES_CM_128_HMAC_SHA1_80
3478 * AES_CM_128_HMAC_SHA1_32
3479 * F8_128_HMAC_SHA1_80
3484 /* Check crypto suites */
3485 for(i
=0; i
<SDP_SRTP_MAX_NUM_CRYPTO_SUITES
; i
++) {
3486 if (!cpr_strcasecmp(sdp_srtp_crypto_suite_array
[i
].crypto_suite_str
, str
)) {
3487 attr_p
->attr
.srtp_context
.suite
= sdp_srtp_crypto_suite_array
[i
].crypto_suite_val
;
3488 attr_p
->attr
.srtp_context
.master_key_size_bytes
=
3489 sdp_srtp_crypto_suite_array
[i
].key_size_bytes
;
3490 attr_p
->attr
.srtp_context
.master_salt_size_bytes
=
3491 sdp_srtp_crypto_suite_array
[i
].salt_size_bytes
;
3492 return TRUE
; /* There is a succesful match so exit */
3495 /* couldn't find a matching crypto suite */
3496 sdp_parse_error(sdp_p
,
3497 "%s No Matching crypto suite for SRTP Context(%s)-'X-crypto:v1' expected",
3498 sdp_p
->debug_str
, str
);
3504 sdp_result_e
sdp_build_attr_srtpcontext (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3507 #define MAX_BASE64_ENCODE_SIZE_BYTES 60
3508 int output_len
= MAX_BASE64_ENCODE_SIZE_BYTES
;
3509 int key_size
= attr_p
->attr
.srtp_context
.master_key_size_bytes
;
3510 int salt_size
= attr_p
->attr
.srtp_context
.master_salt_size_bytes
;
3511 unsigned char base64_encoded_data
[MAX_BASE64_ENCODE_SIZE_BYTES
];
3512 unsigned char base64_encoded_input
[MAX_BASE64_ENCODE_SIZE_BYTES
];
3513 base64_result_t status
;
3515 output_len
= MAX_BASE64_ENCODE_SIZE_BYTES
;
3517 /* Append master and salt keys */
3518 memcpy(base64_encoded_input
,
3519 attr_p
->attr
.srtp_context
.master_key
,
3521 memcpy(base64_encoded_input
+ key_size
,
3522 attr_p
->attr
.srtp_context
.master_salt
,
3525 if ((status
= base64_encode(base64_encoded_input
, key_size
+ salt_size
,
3526 base64_encoded_data
, &output_len
)) != BASE64_SUCCESS
) {
3527 if (sdp_p
->debug_flag
[SDP_DEBUG_ERRORS
]) {
3528 SDPLogError(logTag
, "%s Error: Failure to Base64 Encoded data (%s) ",
3529 sdp_p
->debug_str
, BASE64_RESULT_TO_STRING(status
));
3531 return (SDP_INVALID_PARAMETER
);
3534 *(base64_encoded_data
+ output_len
) = '\0';
3536 flex_string_sprintf(fs
, "a=%s:%s inline:%s||\r\n",
3537 sdp_attr
[attr_p
->type
].name
,
3538 sdp_srtp_context_crypto_suite
[attr_p
->attr
.srtp_context
.suite
].name
,
3539 base64_encoded_data
);
3545 * sdp_parse_attr_mptime
3546 * This function parses the a=mptime sdp line. This parameter consists of
3547 * one or more numbers or hyphens ("-"). The first parameter must be a
3548 * number. The number of parameters must match the number of formats specified
3549 * on the m= line. This function is liberal in that it does not match against
3550 * the m= line or require a number for the first parameter.
3552 sdp_result_e
sdp_parse_attr_mptime (
3557 uint16_t i
; /* loop counter for parameters */
3558 sdp_result_e result
; /* value returned by this function */
3559 tinybool null_ind
; /* true if a parameter is "-" */
3562 * Scan the input line up to the maximum number of parameters supported.
3563 * Look for numbers or hyphens and store the resulting values. Hyphens
3564 * are stored as zeros.
3566 for (i
=0; i
<SDP_MAX_PAYLOAD_TYPES
; i
++) {
3567 attr_p
->attr
.mptime
.intervals
[i
] =
3568 (ushort
)sdp_getnextnumtok_or_null(ptr
,&ptr
," \t",&null_ind
,&result
);
3569 if (result
!= SDP_SUCCESS
) {
3572 attr_p
->attr
.mptime
.num_intervals
++;
3576 * At least one parameter must be supplied. If not, return an error
3577 * and optionally log the failure.
3579 if (attr_p
->attr
.mptime
.num_intervals
== 0) {
3580 sdp_parse_error(sdp_p
,
3581 "%s Warning: No intervals specified for %s attr.",
3582 sdp_p
->debug_str
, sdp_attr
[attr_p
->type
].name
);
3583 sdp_p
->conf_p
->num_invalid_param
++;
3584 return (SDP_INVALID_PARAMETER
);
3588 * Here is some debugging code that helps us track what data
3589 * is received and parsed.
3591 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3592 SDP_PRINT("%s Parsed a=%s, num intervals %u, intervals: ",
3593 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
),
3594 attr_p
->attr
.mptime
.num_intervals
);
3595 for (i
=0; i
< attr_p
->attr
.mptime
.num_intervals
; i
++) {
3596 SDP_PRINT("%u ", attr_p
->attr
.mptime
.intervals
[i
]);
3604 * sdp_build_attr_mptime
3605 * This function builds the a=mptime sdp line. It reads the selected attribute
3606 * from the sdp structure. Parameters with a value of zero are replaced by
3609 sdp_result_e
sdp_build_attr_mptime (
3616 flex_string_sprintf(fs
, "a=%s:", sdp_attr
[attr_p
->type
].name
);
3619 * Run the list of mptime parameter values and write each one
3620 * to the sdp line. Replace zeros with hyphens.
3622 for (i
=0; i
< attr_p
->attr
.mptime
.num_intervals
; i
++) {
3624 flex_string_append(fs
, " ");
3627 if (attr_p
->attr
.mptime
.intervals
[i
] == 0) {
3628 flex_string_append(fs
, "-");
3630 flex_string_sprintf(fs
, "%u", attr_p
->attr
.mptime
.intervals
[i
]);
3634 flex_string_append(fs
, "\r\n");
3641 sdp_result_e
sdp_parse_attr_x_sidin (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3644 sdp_result_e result
;
3645 attr_p
->attr
.stream_data
.x_sidin
[0] = '\0';
3647 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3648 SDP_PRINT("%s Parsing a=%s", sdp_p
->debug_str
,
3649 sdp_get_attr_name(attr_p
->type
));
3652 /* Find the X-sidin value */
3653 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.stream_data
.x_sidin
,
3654 sizeof(attr_p
->attr
.stream_data
.x_sidin
), " \t", &result
);
3655 if (result
!= SDP_SUCCESS
) {
3656 sdp_parse_error(sdp_p
,
3657 "%s Warning: No Stream Id incoming specified for X-sidin attribute.",
3659 sdp_p
->conf_p
->num_invalid_param
++;
3660 return (SDP_INVALID_PARAMETER
);
3663 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3664 SDP_PRINT("%s Parsed a=%s, %s", sdp_p
->debug_str
,
3665 sdp_get_attr_name(attr_p
->type
),
3666 attr_p
->attr
.stream_data
.x_sidin
);
3668 return (SDP_SUCCESS
);
3671 sdp_result_e
sdp_build_attr_x_sidin (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3674 flex_string_sprintf(fs
, "a=%s:%s\r\n",
3675 sdp_attr
[attr_p
->type
].name
,
3676 attr_p
->attr
.stream_data
.x_sidin
);
3681 sdp_result_e
sdp_parse_attr_x_sidout (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3684 sdp_result_e result
;
3685 attr_p
->attr
.stream_data
.x_sidout
[0] = '\0';
3687 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3688 SDP_PRINT("%s Parsing a=%s", sdp_p
->debug_str
,
3689 sdp_get_attr_name(attr_p
->type
));
3692 /* Find the X-sidout value */
3693 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.stream_data
.x_sidout
,
3694 sizeof(attr_p
->attr
.stream_data
.x_sidout
), " \t", &result
);
3695 if (result
!= SDP_SUCCESS
) {
3696 sdp_parse_error(sdp_p
,
3697 "%s Warning: No Stream Id outgoing specified for X-sidout attribute.",
3699 sdp_p
->conf_p
->num_invalid_param
++;
3700 return (SDP_INVALID_PARAMETER
);
3703 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3704 SDP_PRINT("%s Parsed a=%s, %s", sdp_p
->debug_str
,
3705 sdp_get_attr_name(attr_p
->type
),
3706 attr_p
->attr
.stream_data
.x_sidout
);
3708 return (SDP_SUCCESS
);
3711 sdp_result_e
sdp_build_attr_x_sidout (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3714 flex_string_sprintf(fs
, "a=%s:%s\r\n",
3715 sdp_attr
[attr_p
->type
].name
,
3716 attr_p
->attr
.stream_data
.x_sidout
);
3722 sdp_result_e
sdp_parse_attr_x_confid (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3725 sdp_result_e result
;
3726 attr_p
->attr
.stream_data
.x_confid
[0] = '\0';
3728 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3729 SDP_PRINT("%s Parsing a=%s", sdp_p
->debug_str
,
3730 sdp_get_attr_name(attr_p
->type
));
3733 /* Find the X-confid value */
3734 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.stream_data
.x_confid
,
3735 sizeof(attr_p
->attr
.stream_data
.x_confid
), " \t", &result
);
3736 if (result
!= SDP_SUCCESS
) {
3737 sdp_parse_error(sdp_p
,
3738 "%s Warning: No Conf Id incoming specified for "
3739 "X-confid attribute.", sdp_p
->debug_str
);
3740 sdp_p
->conf_p
->num_invalid_param
++;
3741 return (SDP_INVALID_PARAMETER
);
3744 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3745 SDP_PRINT("%s Parsed a=%s, %s", sdp_p
->debug_str
,
3746 sdp_get_attr_name(attr_p
->type
),
3747 attr_p
->attr
.stream_data
.x_confid
);
3749 return (SDP_SUCCESS
);
3752 sdp_result_e
sdp_build_attr_x_confid (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3755 if (strlen(attr_p
->attr
.stream_data
.x_confid
) <= 0) {
3756 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3757 SDP_PRINT("%s X-confid value is not set. Cannot build a=X-confid line\n",
3761 return SDP_INVALID_PARAMETER
;
3764 flex_string_sprintf(fs
, "a=%s:%s\r\n",
3765 sdp_attr
[attr_p
->type
].name
,
3766 attr_p
->attr
.stream_data
.x_confid
);
3771 sdp_result_e
sdp_parse_attr_group (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3774 sdp_result_e result
;
3778 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3779 SDP_PRINT("%s Parsing a=%s", sdp_p
->debug_str
,
3780 sdp_get_attr_name(attr_p
->type
));
3783 /* Find the a=group:<attrib> <id1> < id2> ... values */
3784 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3785 if (result
!= SDP_SUCCESS
) {
3786 sdp_parse_error(sdp_p
,
3787 "%s Warning: No group attribute value specified for "
3788 "a=group line", sdp_p
->debug_str
);
3789 sdp_p
->conf_p
->num_invalid_param
++;
3790 return (SDP_INVALID_PARAMETER
);
3793 attr_p
->attr
.stream_data
.group_attr
= SDP_GROUP_ATTR_UNSUPPORTED
;
3794 for (i
=0; i
< SDP_MAX_GROUP_ATTR_VAL
; i
++) {
3795 if (cpr_strncasecmp(tmp
, sdp_group_attr_val
[i
].name
,
3796 sdp_group_attr_val
[i
].strlen
) == 0) {
3797 attr_p
->attr
.stream_data
.group_attr
= (sdp_group_attr_e
)i
;
3802 if (attr_p
->attr
.stream_data
.group_attr
== SDP_GROUP_ATTR_UNSUPPORTED
) {
3803 sdp_parse_error(sdp_p
,
3804 "%s Warning: Group attribute type unsupported (%s).",
3805 sdp_p
->debug_str
, tmp
);
3810 * Scan the input line up after group:<attr> to the maximum number
3813 attr_p
->attr
.stream_data
.num_group_id
=0;
3815 for (i
=0; i
<SDP_MAX_MEDIA_STREAMS
; i
++) {
3816 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3818 if (result
!= SDP_SUCCESS
) {
3821 attr_p
->attr
.stream_data
.group_ids
[i
] = cpr_strdup(tmp
);
3822 if (!attr_p
->attr
.stream_data
.group_ids
[i
]) {
3826 attr_p
->attr
.stream_data
.num_group_id
++;
3829 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
3830 SDP_PRINT("%s Parsed a=%s:%s\n", sdp_p
->debug_str
,
3831 sdp_get_attr_name(attr_p
->type
),
3832 sdp_get_group_attr_name (attr_p
->attr
.stream_data
.group_attr
));
3833 for (i
=0; i
< attr_p
->attr
.stream_data
.num_group_id
; i
++) {
3834 SDP_PRINT("%s Parsed group line id : %s\n", sdp_p
->debug_str
,
3835 attr_p
->attr
.stream_data
.group_ids
[i
]);
3838 return (SDP_SUCCESS
);
3841 sdp_result_e
sdp_build_attr_group (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3846 flex_string_sprintf(fs
, "a=%s:%s",
3847 sdp_attr
[attr_p
->type
].name
,
3848 sdp_get_group_attr_name(attr_p
->attr
.stream_data
.group_attr
));
3850 for (i
=0; i
< attr_p
->attr
.stream_data
.num_group_id
; i
++) {
3851 if (attr_p
->attr
.stream_data
.group_ids
[i
]) {
3852 flex_string_sprintf(fs
, " %s",
3853 attr_p
->attr
.stream_data
.group_ids
[i
]);
3857 flex_string_append(fs
, "\r\n");
3862 /* Parse the source-filter attribute
3863 * "a=source-filter:<filter-mode><filter-spec>"
3864 * <filter-spec> = <nettype><addrtype><dest-addr><src_addr><src_addr>...
3866 sdp_result_e
sdp_parse_attr_source_filter (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3870 sdp_result_e result
;
3871 char tmp
[SDP_MAX_STRING_LEN
];
3873 attr_p
->attr
.source_filter
.mode
= SDP_FILTER_MODE_NOT_PRESENT
;
3874 attr_p
->attr
.source_filter
.nettype
= SDP_NT_UNSUPPORTED
;
3875 attr_p
->attr
.source_filter
.addrtype
= SDP_AT_UNSUPPORTED
;
3876 attr_p
->attr
.source_filter
.dest_addr
[0] = '\0';
3877 attr_p
->attr
.source_filter
.num_src_addr
= 0;
3879 /* Find the filter mode */
3880 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3881 if (result
!= SDP_SUCCESS
) {
3882 sdp_parse_error(sdp_p
,
3883 "%s Warning: No src filter attribute value specified for "
3884 "a=source-filter line", sdp_p
->debug_str
);
3885 sdp_p
->conf_p
->num_invalid_param
++;
3886 return (SDP_INVALID_PARAMETER
);
3888 for (i
= 0; i
< SDP_MAX_FILTER_MODE
; i
++) {
3889 if (cpr_strncasecmp(tmp
, sdp_src_filter_mode_val
[i
].name
,
3890 sdp_src_filter_mode_val
[i
].strlen
) == 0) {
3891 attr_p
->attr
.source_filter
.mode
= (sdp_src_filter_mode_e
)i
;
3895 if (attr_p
->attr
.source_filter
.mode
== SDP_FILTER_MODE_NOT_PRESENT
) {
3896 /* No point continuing */
3897 sdp_parse_error(sdp_p
,
3898 "%s Warning: Invalid src filter mode for a=source-filter "
3899 "line", sdp_p
->debug_str
);
3900 sdp_p
->conf_p
->num_invalid_param
++;
3901 return (SDP_INVALID_PARAMETER
);
3904 /* Find the network type */
3905 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3906 if (result
!= SDP_SUCCESS
) {
3907 sdp_p
->conf_p
->num_invalid_param
++;
3908 return (SDP_INVALID_PARAMETER
);
3910 for (i
= 0; i
< SDP_MAX_NETWORK_TYPES
; i
++) {
3911 if (cpr_strncasecmp(tmp
, sdp_nettype
[i
].name
,
3912 sdp_nettype
[i
].strlen
) == 0) {
3913 if (sdp_p
->conf_p
->nettype_supported
[i
] == TRUE
) {
3914 attr_p
->attr
.source_filter
.nettype
= (sdp_nettype_e
)i
;
3918 if (attr_p
->attr
.source_filter
.nettype
== SDP_NT_UNSUPPORTED
) {
3919 sdp_parse_error(sdp_p
,
3920 "%s Warning: Network type unsupported "
3921 "(%s) for a=source-filter", sdp_p
->debug_str
, tmp
);
3922 sdp_p
->conf_p
->num_invalid_param
++;
3923 return (SDP_INVALID_PARAMETER
);
3926 /* Find the address type */
3927 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
3928 if (result
!= SDP_SUCCESS
) {
3929 sdp_p
->conf_p
->num_invalid_param
++;
3930 return (SDP_INVALID_PARAMETER
);
3932 for (i
= 0; i
< SDP_MAX_ADDR_TYPES
; i
++) {
3933 if (cpr_strncasecmp(tmp
, sdp_addrtype
[i
].name
,
3934 sdp_addrtype
[i
].strlen
) == 0) {
3935 if (sdp_p
->conf_p
->addrtype_supported
[i
] == TRUE
) {
3936 attr_p
->attr
.source_filter
.addrtype
= (sdp_addrtype_e
)i
;
3940 if (attr_p
->attr
.source_filter
.addrtype
== SDP_AT_UNSUPPORTED
) {
3941 if (strncmp(tmp
, "*", 1) == 0) {
3942 attr_p
->attr
.source_filter
.addrtype
= SDP_AT_FQDN
;
3944 sdp_parse_error(sdp_p
,
3945 "%s Warning: Address type unsupported "
3946 "(%s) for a=source-filter", sdp_p
->debug_str
, tmp
);
3947 sdp_p
->conf_p
->num_invalid_param
++;
3948 return (SDP_INVALID_PARAMETER
);
3952 /* Find the destination addr */
3953 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.source_filter
.dest_addr
,
3954 sizeof(attr_p
->attr
.source_filter
.dest_addr
), " \t", &result
);
3955 if (result
!= SDP_SUCCESS
) {
3956 sdp_parse_error(sdp_p
,
3957 "%s No filter destination address specified for "
3958 "a=source-filter", sdp_p
->debug_str
);
3959 sdp_p
->conf_p
->num_invalid_param
++;
3960 return (SDP_INVALID_PARAMETER
);
3963 /* Find the list of source address to apply the filter */
3964 for (i
= 0; i
< SDP_MAX_SRC_ADDR_LIST
; i
++) {
3965 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.source_filter
.src_list
[i
],
3966 sizeof(attr_p
->attr
.source_filter
.src_list
[i
]), " \t", &result
);
3967 if (result
!= SDP_SUCCESS
) {
3970 attr_p
->attr
.source_filter
.num_src_addr
++;
3972 if (attr_p
->attr
.source_filter
.num_src_addr
== 0) {
3973 sdp_parse_error(sdp_p
,
3974 "%s Warning: No source list provided "
3975 "for a=source-filter", sdp_p
->debug_str
);
3976 sdp_p
->conf_p
->num_invalid_param
++;
3977 return (SDP_INVALID_PARAMETER
);
3980 return (SDP_SUCCESS
);
3983 sdp_result_e
sdp_build_source_filter (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
3988 flex_string_sprintf(fs
, "a=%s:%s %s %s %s",
3989 sdp_get_attr_name(attr_p
->type
),
3990 sdp_get_src_filter_mode_name(attr_p
->attr
.source_filter
.mode
),
3991 sdp_get_network_name(attr_p
->attr
.source_filter
.nettype
),
3992 sdp_get_address_name(attr_p
->attr
.source_filter
.addrtype
),
3993 attr_p
->attr
.source_filter
.dest_addr
);
3995 for (i
= 0; i
< attr_p
->attr
.source_filter
.num_src_addr
; i
++) {
3996 flex_string_append(fs
, " ");
3997 flex_string_append(fs
, attr_p
->attr
.source_filter
.src_list
[i
]);
4000 flex_string_append(fs
, "\r\n");
4005 /* Parse the rtcp-unicast attribute
4006 * "a=rtcp-unicast:<reflection|rsi>"
4008 sdp_result_e
sdp_parse_attr_rtcp_unicast (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4011 sdp_result_e result
;
4013 char tmp
[SDP_MAX_STRING_LEN
];
4015 attr_p
->attr
.u32_val
= SDP_RTCP_UNICAST_MODE_NOT_PRESENT
;
4017 memset(tmp
, 0, sizeof(tmp
));
4019 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
4020 if (result
!= SDP_SUCCESS
) {
4021 sdp_parse_error(sdp_p
,
4022 "%s Warning: No rtcp unicast mode specified for "
4023 "a=rtcp-unicast line", sdp_p
->debug_str
);
4024 sdp_p
->conf_p
->num_invalid_param
++;
4025 return (SDP_INVALID_PARAMETER
);
4027 for (i
= 0; i
< SDP_RTCP_MAX_UNICAST_MODE
; i
++) {
4028 if (cpr_strncasecmp(tmp
, sdp_rtcp_unicast_mode_val
[i
].name
,
4029 sdp_rtcp_unicast_mode_val
[i
].strlen
) == 0) {
4030 attr_p
->attr
.u32_val
= i
;
4034 if (attr_p
->attr
.u32_val
== SDP_RTCP_UNICAST_MODE_NOT_PRESENT
) {
4035 sdp_parse_error(sdp_p
,
4036 "%s Warning: Invalid rtcp unicast mode for "
4037 "a=rtcp-unicast line", sdp_p
->debug_str
);
4038 sdp_p
->conf_p
->num_invalid_param
++;
4039 return (SDP_INVALID_PARAMETER
);
4041 return (SDP_SUCCESS
);
4044 sdp_result_e
sdp_build_attr_rtcp_unicast (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4047 if (attr_p
->attr
.u32_val
>= SDP_RTCP_MAX_UNICAST_MODE
) {
4048 return SDP_INVALID_PARAMETER
;
4051 flex_string_sprintf(fs
, "a=%s:%s\r\n",
4052 sdp_get_attr_name(attr_p
->type
),
4053 sdp_get_rtcp_unicast_mode_name((sdp_rtcp_unicast_mode_e
)attr_p
->attr
.u32_val
));
4060 * store_sdescriptions_mki_or_lifetime
4062 * Verifies the syntax of the MKI or lifetime parameter and stores
4063 * it in the sdescriptions attribute struct.
4066 * buf - pointer to MKI or lifetime string assumes string is null
4068 * attr_p - pointer to attribute struct
4071 * Return TRUE all is good otherwise FALSE for error.
4075 store_sdescriptions_mki_or_lifetime (char *buf
, sdp_attr_t
*attr_p
)
4080 char mkiValue
[SDP_SRTP_MAX_MKI_SIZE_BYTES
];
4082 /* MKI has a colon */
4083 if (strstr(buf
, ":")) {
4084 result
= verify_sdescriptions_mki(buf
, mkiValue
, &mkiLen
);
4086 attr_p
->attr
.srtp_context
.mki_size_bytes
= mkiLen
;
4087 sstrncpy((char*)attr_p
->attr
.srtp_context
.mki
, mkiValue
,
4088 SDP_SRTP_MAX_MKI_SIZE_BYTES
);
4092 result
= verify_sdescriptions_lifetime(buf
);
4094 sstrncpy((char*)attr_p
->attr
.srtp_context
.master_key_lifetime
, buf
,
4095 SDP_SRTP_MAX_LIFETIME_BYTES
);
4104 * sdp_parse_sdescriptions_key_param
4106 * This routine parses the srtp key-params pointed to by str.
4108 * key-params = <key-method> ":" <key-info>
4109 * key-method = "inline" / key-method-ext [note V9 only supports 'inline']
4110 * key-info = srtp-key-info
4111 * srtp-key-info = key-salt ["|" lifetime] ["|" mki]
4112 * key-salt = 1*(base64) ; binary key and salt values
4113 * ; concatenated together, and then
4114 * ; base64 encoded [section 6.8 of
4117 * lifetime = ["2^"] 1*(DIGIT)
4118 * mki = mki-value ":" mki-length
4119 * mki-value = 1*DIGIT
4120 * mki-length = 1*3DIGIT ; range 1..128.
4122 * Inputs: str - pointer to beginning of key-params and assumes
4123 * null terminated string.
4128 sdp_parse_sdescriptions_key_param (const char *str
, sdp_attr_t
*attr_p
,
4131 char buf
[SDP_MAX_STRING_LEN
],
4132 base64decodeData
[SDP_MAX_STRING_LEN
];
4134 sdp_result_e result
= SDP_SUCCESS
;
4135 tinybool keyFound
= FALSE
;
4139 base64_result_t status
;
4142 if (cpr_strncasecmp(ptr
, "inline:", 7) != 0) {
4143 sdp_parse_error(sdp_p
,
4144 "%s Could not find keyword inline", sdp_p
->debug_str
);
4145 sdp_p
->conf_p
->num_invalid_param
++;
4149 /* advance pass the inline key word */
4151 ptr
= sdp_getnextstrtok(ptr
, buf
, sizeof(buf
), "|", &result
);
4152 while (result
== SDP_SUCCESS
) {
4153 /* the fist time this loop executes, the key is gotten */
4154 if (keyFound
== FALSE
) {
4156 len
= SDP_MAX_STRING_LEN
;
4157 /* The key is base64 encoded composed of the master key concatenated with the
4160 status
= base64_decode((unsigned char *)buf
, strlen(buf
),
4161 (unsigned char *)base64decodeData
, &len
);
4163 if (status
!= BASE64_SUCCESS
) {
4164 sdp_parse_error(sdp_p
,
4165 "%s key-salt error decoding buffer: %s",
4166 sdp_p
->debug_str
, BASE64_RESULT_TO_STRING(status
));
4170 keySize
= attr_p
->attr
.srtp_context
.master_key_size_bytes
;
4171 saltSize
= attr_p
->attr
.srtp_context
.master_salt_size_bytes
;
4173 if (len
!= keySize
+ saltSize
) {
4174 sdp_parse_error(sdp_p
,
4175 "%s key-salt size doesn't match: (%d, %d, %d)",
4176 sdp_p
->debug_str
, len
, keySize
, saltSize
);
4180 memcpy(attr_p
->attr
.srtp_context
.master_key
,
4184 memcpy(attr_p
->attr
.srtp_context
.master_salt
,
4185 base64decodeData
+ keySize
,
4188 /* Used only for MGCP */
4189 SDP_SRTP_CONTEXT_SET_MASTER_KEY
4190 (attr_p
->attr
.srtp_context
.selection_flags
);
4191 SDP_SRTP_CONTEXT_SET_MASTER_SALT
4192 (attr_p
->attr
.srtp_context
.selection_flags
);
4194 } else if (store_sdescriptions_mki_or_lifetime(buf
, attr_p
) == FALSE
) {
4198 /* if we haven't reached the end of line, get the next token */
4199 ptr
= sdp_getnextstrtok(ptr
, buf
, sizeof(buf
), "|", &result
);
4202 /* if we didn't find the key, error out */
4203 if (keyFound
== FALSE
) {
4204 sdp_parse_error(sdp_p
,
4205 "%s Could not find sdescriptions key", sdp_p
->debug_str
);
4206 sdp_p
->conf_p
->num_invalid_param
++;
4215 * sdp_build_attr_sdescriptions
4217 * Builds a=crypto line for attribute type SDP_ATTR_SDESCRIPTIONS.
4219 * a=crypto:tag 1*WSP crypto-suite 1*WSP key-params
4221 * Where key-params = inline: <key|salt> ["|"lifetime] ["|" MKI:length]
4222 * The key and salt is base64 encoded and lifetime and MKI/length are optional.
4226 sdp_build_attr_sdescriptions (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4230 unsigned char base64_encoded_data
[MAX_BASE64_STRING_LEN
];
4231 unsigned char base64_encoded_input
[MAX_BASE64_STRING_LEN
];
4235 base64_result_t status
;
4237 keySize
= attr_p
->attr
.srtp_context
.master_key_size_bytes
;
4238 saltSize
= attr_p
->attr
.srtp_context
.master_salt_size_bytes
;
4240 /* concatenate the master key + salt then base64 encode it */
4241 memcpy(base64_encoded_input
,
4242 attr_p
->attr
.srtp_context
.master_key
,
4245 memcpy(base64_encoded_input
+ keySize
,
4246 attr_p
->attr
.srtp_context
.master_salt
,
4249 outputLen
= MAX_BASE64_STRING_LEN
;
4250 status
= base64_encode(base64_encoded_input
, keySize
+ saltSize
,
4251 base64_encoded_data
, &outputLen
);
4253 if (status
!= BASE64_SUCCESS
) {
4254 if (sdp_p
->debug_flag
[SDP_DEBUG_ERRORS
]) {
4255 SDPLogError(logTag
, "%s Error: Failure to Base64 Encoded data (%s) ",
4256 sdp_p
->debug_str
, BASE64_RESULT_TO_STRING(status
));
4258 return (SDP_INVALID_PARAMETER
);
4262 base64_encoded_data
[outputLen
] = 0;
4264 /* lifetime and MKI parameters are optional. Only inlcude them if
4269 if (attr_p
->attr
.srtp_context
.master_key_lifetime
[0] != 0 &&
4270 attr_p
->attr
.srtp_context
.mki
[0] != 0) {
4271 flex_string_sprintf(fs
, "a=%s:%d %s inline:%s|%s|%s:%d\r\n",
4272 sdp_attr
[attr_p
->type
].name
,
4273 attr_p
->attr
.srtp_context
.tag
,
4274 sdp_srtp_context_crypto_suite
[attr_p
->attr
.srtp_context
.suite
].name
,
4275 base64_encoded_data
,
4276 attr_p
->attr
.srtp_context
.master_key_lifetime
,
4277 attr_p
->attr
.srtp_context
.mki
,
4278 attr_p
->attr
.srtp_context
.mki_size_bytes
);
4283 /* if we get here, either lifetime is populated and mki and is not or mki is populated
4284 * and lifetime is not or neither is populated
4287 if (attr_p
->attr
.srtp_context
.master_key_lifetime
[0] != 0) {
4288 flex_string_sprintf(fs
, "a=%s:%d %s inline:%s|%s\r\n",
4289 sdp_attr
[attr_p
->type
].name
,
4290 attr_p
->attr
.srtp_context
.tag
,
4291 sdp_srtp_context_crypto_suite
[attr_p
->attr
.srtp_context
.suite
].name
,
4292 base64_encoded_data
,
4293 attr_p
->attr
.srtp_context
.master_key_lifetime
);
4295 } else if (attr_p
->attr
.srtp_context
.mki
[0] != 0) {
4296 flex_string_sprintf(fs
, "a=%s:%d %s inline:%s|%s:%d\r\n",
4297 sdp_attr
[attr_p
->type
].name
,
4298 attr_p
->attr
.srtp_context
.tag
,
4299 sdp_srtp_context_crypto_suite
[attr_p
->attr
.srtp_context
.suite
].name
,
4300 base64_encoded_data
,
4301 attr_p
->attr
.srtp_context
.mki
,
4302 attr_p
->attr
.srtp_context
.mki_size_bytes
);
4305 flex_string_sprintf(fs
, "a=%s:%d %s inline:%s\r\n",
4306 sdp_attr
[attr_p
->type
].name
,
4307 attr_p
->attr
.srtp_context
.tag
,
4308 sdp_srtp_context_crypto_suite
[attr_p
->attr
.srtp_context
.suite
].name
,
4309 base64_encoded_data
);
4319 * sdp_parse_attr_srtp
4321 * Parses Session Description for Protocol Security Descriptions
4322 * version 2 or version 9. Grammar is of the form:
4324 * a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
4326 * Note session-params is not supported and will not be parsed.
4327 * Version 2 does not contain a tag.
4330 * sdp_p - pointer to sdp handle
4331 * attr_p - pointer to attribute structure
4332 * ptr - pointer to string to be parsed
4333 * vtype - version type
4337 sdp_parse_attr_srtp (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4338 const char *ptr
, sdp_attr_e vtype
)
4341 char tmp
[SDP_MAX_STRING_LEN
];
4342 sdp_result_e result
= SDP_FAILURE
;
4345 /* initialize only the optional parameters */
4346 attr_p
->attr
.srtp_context
.master_key_lifetime
[0] = 0;
4347 attr_p
->attr
.srtp_context
.mki
[0] = 0;
4349 /* used only for MGCP */
4350 SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE
4351 (attr_p
->attr
.srtp_context
.selection_flags
);
4353 /* get the tag only if we are version 9 */
4354 if (vtype
== SDP_ATTR_SDESCRIPTIONS
) {
4355 attr_p
->attr
.srtp_context
.tag
=
4356 sdp_getnextnumtok(ptr
, &ptr
, " \t", &result
);
4358 if (result
!= SDP_SUCCESS
) {
4359 sdp_parse_error(sdp_p
,
4360 "%s Could not find sdescriptions tag",
4362 sdp_p
->conf_p
->num_invalid_param
++;
4363 return (SDP_INVALID_PARAMETER
);
4368 /* get the crypto suite */
4369 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
4370 if (result
!= SDP_SUCCESS
) {
4371 sdp_parse_error(sdp_p
,
4372 "%s Could not find sdescriptions crypto suite", sdp_p
->debug_str
);
4373 sdp_p
->conf_p
->num_invalid_param
++;
4374 return (SDP_INVALID_PARAMETER
);
4377 if (!sdp_parse_context_crypto_suite(tmp
, attr_p
, sdp_p
)) {
4378 sdp_parse_error(sdp_p
,
4379 "%s Unsupported crypto suite", sdp_p
->debug_str
);
4380 return (SDP_INVALID_PARAMETER
);
4383 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
4384 if (result
!= SDP_SUCCESS
) {
4385 sdp_parse_error(sdp_p
,
4386 "%s Could not find sdescriptions key params", sdp_p
->debug_str
);
4387 sdp_p
->conf_p
->num_invalid_param
++;
4388 return (SDP_INVALID_PARAMETER
);
4391 if (!sdp_parse_sdescriptions_key_param(tmp
, attr_p
, sdp_p
)) {
4392 sdp_parse_error(sdp_p
,
4393 "%s Failed to parse key-params", sdp_p
->debug_str
);
4394 return (SDP_INVALID_PARAMETER
);
4397 /* if there are session parameters, scan the session parameters
4398 * into tmp until we reach end of line. Currently the sdp parser
4399 * does not parse session parameters but if they are present,
4400 * we store them for the application.
4402 /*sa_ignore NO_NULL_CHK
4403 *{ptr is valid since the pointer was checked earlier and the
4404 * function would have exited if NULL.}
4406 while (*ptr
&& *ptr
!= '\n' && *ptr
!= '\r' && k
< SDP_MAX_STRING_LEN
) {
4410 if ((k
) && (k
< SDP_MAX_STRING_LEN
)) {
4412 attr_p
->attr
.srtp_context
.session_parameters
= cpr_strdup(tmp
);
4419 /* Parses crypto attribute based on the sdescriptions version
4425 sdp_parse_attr_sdescriptions (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4429 return sdp_parse_attr_srtp(sdp_p
, attr_p
, ptr
,
4430 SDP_ATTR_SDESCRIPTIONS
);
4434 /* Parses X-crypto attribute based on the sdescriptions version
4439 sdp_result_e
sdp_parse_attr_srtpcontext (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4443 return sdp_parse_attr_srtp(sdp_p
, attr_p
, ptr
,
4444 SDP_ATTR_SRTP_CONTEXT
);
4448 sdp_result_e
sdp_build_attr_ice_attr (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4450 flex_string_sprintf(fs
, "a=%s:%s\r\n",
4451 sdp_get_attr_name(attr_p
->type
),
4452 attr_p
->attr
.ice_attr
);
4458 sdp_result_e
sdp_parse_attr_ice_attr (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
, const char *ptr
) {
4459 sdp_result_e result
;
4460 char tmp
[SDP_MAX_STRING_LEN
];
4462 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), "\r\n", &result
);
4463 if (result
!= SDP_SUCCESS
){
4464 sdp_parse_error(sdp_p
,
4465 "%s Warning: problem parsing ice attribute ", sdp_p
->debug_str
);
4466 sdp_p
->conf_p
->num_invalid_param
++;
4467 return (SDP_INVALID_PARAMETER
);
4470 snprintf(attr_p
->attr
.ice_attr
, sizeof(attr_p
->attr
.ice_attr
), "%s", tmp
);
4472 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
4473 SDP_PRINT("%s Parsed a=%s, %s", sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
), tmp
);
4475 return (SDP_SUCCESS
);
4479 sdp_result_e
sdp_build_attr_simple_flag (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4481 flex_string_sprintf(fs
, "a=%s\r\n", sdp_get_attr_name(attr_p
->type
));
4487 sdp_result_e
sdp_parse_attr_simple_flag (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4489 /* No parameters to parse. */
4491 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
4492 SDP_PRINT("%s Parsed a=%s", sdp_p
->debug_str
,
4493 sdp_get_attr_name(attr_p
->type
));
4496 return (SDP_SUCCESS
);
4499 static sdp_result_e
sdp_parse_attr_line(sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4500 const char *ptr
, char *buf
, size_t buf_len
) {
4501 sdp_result_e result
;
4503 (void)sdp_getnextstrtok(ptr
, buf
, buf_len
, "\r\n", &result
);
4505 if (result
!= SDP_SUCCESS
) {
4506 sdp_parse_error(sdp_p
,
4507 "%s Warning: No string token found for %s attribute",
4508 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
4509 sdp_p
->conf_p
->num_invalid_param
++;
4510 return (SDP_INVALID_PARAMETER
);
4512 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
4513 SDP_PRINT("%s Parsed a=%s, %s", sdp_p
->debug_str
,
4514 sdp_get_attr_name(attr_p
->type
),
4517 return (SDP_SUCCESS
);
4521 sdp_result_e
sdp_parse_attr_complete_line (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4524 return sdp_parse_attr_line(sdp_p
, attr_p
, ptr
,
4525 attr_p
->attr
.string_val
,
4526 sizeof(attr_p
->attr
.string_val
));
4529 sdp_result_e
sdp_parse_attr_long_line (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4532 sdp_result_e result
;
4533 char buffer
[SDP_MAX_LONG_STRING_LEN
];
4535 result
= sdp_parse_attr_line(sdp_p
, attr_p
, ptr
,
4536 buffer
, sizeof(buffer
));
4537 if (result
== SDP_SUCCESS
) {
4538 attr_p
->attr
.stringp
= cpr_strdup(buffer
);
4543 sdp_result_e
sdp_build_attr_long_line (sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
4546 flex_string_sprintf(fs
, "a=%s:%s\r\n", sdp_attr
[attr_p
->type
].name
,
4547 attr_p
->attr
.stringp
);
4551 sdp_result_e
sdp_build_attr_rtcp_fb(sdp_t
*sdp_p
,
4555 flex_string_sprintf(fs
, "a=%s:", sdp_attr
[attr_p
->type
].name
);
4558 if (attr_p
->attr
.rtcp_fb
.payload_num
== SDP_ALL_PAYLOADS
) {
4559 flex_string_sprintf(fs
, "* ");
4561 flex_string_sprintf(fs
, "%d ",attr_p
->attr
.rtcp_fb
.payload_num
);
4565 if (attr_p
->attr
.rtcp_fb
.feedback_type
< SDP_RTCP_FB_UNKNOWN
) {
4566 flex_string_sprintf(fs
, "%s",
4567 sdp_rtcp_fb_type_val
[attr_p
->attr
.rtcp_fb
.feedback_type
].name
);
4570 /* Feedback Type Parameters */
4571 switch (attr_p
->attr
.rtcp_fb
.feedback_type
) {
4572 case SDP_RTCP_FB_ACK
:
4573 if (attr_p
->attr
.rtcp_fb
.param
.ack
< SDP_MAX_RTCP_FB_ACK
) {
4574 flex_string_sprintf(fs
, " %s",
4575 sdp_rtcp_fb_ack_type_val
[attr_p
->attr
.rtcp_fb
.param
.ack
]
4579 case SDP_RTCP_FB_CCM
: /* RFC 5104 */
4580 if (attr_p
->attr
.rtcp_fb
.param
.ccm
< SDP_MAX_RTCP_FB_CCM
) {
4581 flex_string_sprintf(fs
, " %s",
4582 sdp_rtcp_fb_ccm_type_val
[attr_p
->attr
.rtcp_fb
.param
.ccm
]
4586 case SDP_RTCP_FB_NACK
:
4587 if (attr_p
->attr
.rtcp_fb
.param
.nack
> SDP_RTCP_FB_NACK_BASIC
4588 && attr_p
->attr
.rtcp_fb
.param
.nack
< SDP_MAX_RTCP_FB_NACK
) {
4589 flex_string_sprintf(fs
, " %s",
4590 sdp_rtcp_fb_nack_type_val
[attr_p
->attr
.rtcp_fb
.param
.nack
]
4594 case SDP_RTCP_FB_TRR_INT
:
4595 flex_string_sprintf(fs
, " %u", attr_p
->attr
.rtcp_fb
.param
.trr_int
);
4597 case SDP_RTCP_FB_REMB
:
4598 /* No additional params after REMB */
4600 case SDP_RTCP_FB_TRANSPORT_CC
:
4601 /* No additional params after Transport-CC */
4604 case SDP_RTCP_FB_UNKNOWN
:
4605 /* Contents are in the "extra" field */
4609 SDPLogError(logTag
, "%s Error: Invalid rtcp-fb enum (%d)",
4610 sdp_p
->debug_str
, attr_p
->attr
.rtcp_fb
.feedback_type
);
4614 /* Tack on any information that cannot otherwise be represented by
4615 * the sdp_fmtp_fb_t structure. */
4616 if (attr_p
->attr
.rtcp_fb
.extra
[0]) {
4617 flex_string_sprintf(fs
, " %s", attr_p
->attr
.rtcp_fb
.extra
);
4621 flex_string_sprintf(fs
, "\r\n");
4626 sdp_result_e
sdp_parse_attr_rtcp_fb (sdp_t
*sdp_p
,
4630 sdp_result_e result
= SDP_SUCCESS
;
4631 sdp_fmtp_fb_t
*rtcp_fb_p
= &(attr_p
->attr
.rtcp_fb
);
4634 /* Set up attribute fields */
4635 rtcp_fb_p
->payload_num
= 0;
4636 rtcp_fb_p
->feedback_type
= SDP_RTCP_FB_UNKNOWN
;
4637 rtcp_fb_p
->extra
[0] = '\0';
4639 /* Skip WS (just in case) */
4640 while (*ptr
== ' ' || *ptr
== '\t') {
4644 /* Look for the special "*" payload type */
4646 rtcp_fb_p
->payload_num
= SDP_ALL_PAYLOADS
;
4649 /* If the pt is not '*', parse it out as an integer */
4650 rtcp_fb_p
->payload_num
= (uint16_t)sdp_getnextnumtok(ptr
, &ptr
,
4652 if (result
!= SDP_SUCCESS
) {
4653 sdp_parse_error(sdp_p
,
4654 "%s Warning: could not parse payload type for rtcp-fb attribute",
4656 sdp_p
->conf_p
->num_invalid_param
++;
4658 return SDP_INVALID_PARAMETER
;
4662 /* Read feedback type */
4663 i
= find_token_enum("rtcp-fb attribute", sdp_p
, &ptr
, sdp_rtcp_fb_type_val
,
4664 SDP_MAX_RTCP_FB
, SDP_RTCP_FB_UNKNOWN
);
4666 sdp_parse_error(sdp_p
,
4667 "%s Warning: could not parse feedback type for rtcp-fb attribute",
4669 sdp_p
->conf_p
->num_invalid_param
++;
4670 return SDP_INVALID_PARAMETER
;
4672 rtcp_fb_p
->feedback_type
= (sdp_rtcp_fb_type_e
) i
;
4674 switch(rtcp_fb_p
->feedback_type
) {
4675 case SDP_RTCP_FB_ACK
:
4676 i
= find_token_enum("rtcp-fb ack type", sdp_p
, &ptr
,
4677 sdp_rtcp_fb_ack_type_val
,
4678 SDP_MAX_RTCP_FB_ACK
, SDP_RTCP_FB_ACK_UNKNOWN
);
4680 sdp_parse_error(sdp_p
,
4681 "%s Warning: could not parse ack type for rtcp-fb attribute",
4683 sdp_p
->conf_p
->num_invalid_param
++;
4684 return SDP_INVALID_PARAMETER
;
4686 rtcp_fb_p
->param
.ack
= (sdp_rtcp_fb_ack_type_e
) i
;
4689 case SDP_RTCP_FB_CCM
:
4690 i
= find_token_enum("rtcp-fb ccm type", sdp_p
, &ptr
,
4691 sdp_rtcp_fb_ccm_type_val
,
4692 SDP_MAX_RTCP_FB_CCM
, SDP_RTCP_FB_CCM_UNKNOWN
);
4694 sdp_parse_error(sdp_p
,
4695 "%s Warning: could not parse ccm type for rtcp-fb attribute",
4697 sdp_p
->conf_p
->num_invalid_param
++;
4698 return SDP_INVALID_PARAMETER
;
4700 rtcp_fb_p
->param
.ccm
= (sdp_rtcp_fb_ccm_type_e
) i
;
4702 /* TODO -- We don't currently parse tmmbr parameters or vbcm
4703 submessage types. If we decide to support these modes of
4704 operation, we probably want to add parsing code for them.
4705 For the time being, they'll just end up parsed into "extra"
4710 case SDP_RTCP_FB_NACK
:
4711 /* Skip any remaining WS -- see
4712 http://code.google.com/p/webrtc/issues/detail?id=1922 */
4713 while (*ptr
== ' ' || *ptr
== '\t') {
4716 /* Check for empty string */
4717 if (*ptr
== '\r' || *ptr
== '\n') {
4718 rtcp_fb_p
->param
.nack
= SDP_RTCP_FB_NACK_BASIC
;
4721 i
= find_token_enum("rtcp-fb nack type", sdp_p
, &ptr
,
4722 sdp_rtcp_fb_nack_type_val
,
4723 SDP_MAX_RTCP_FB_NACK
, SDP_RTCP_FB_NACK_UNKNOWN
);
4725 sdp_parse_error(sdp_p
,
4726 "%s Warning: could not parse nack type for rtcp-fb attribute",
4728 sdp_p
->conf_p
->num_invalid_param
++;
4729 return SDP_INVALID_PARAMETER
;
4731 rtcp_fb_p
->param
.nack
= (sdp_rtcp_fb_nack_type_e
) i
;
4734 case SDP_RTCP_FB_TRR_INT
:
4735 rtcp_fb_p
->param
.trr_int
= sdp_getnextnumtok(ptr
, &ptr
,
4737 if (result
!= SDP_SUCCESS
) {
4738 sdp_parse_error(sdp_p
,
4739 "%s Warning: could not parse trr-int value for rtcp-fb "
4740 "attribute", sdp_p
->debug_str
);
4741 sdp_p
->conf_p
->num_invalid_param
++;
4742 return SDP_INVALID_PARAMETER
;
4746 case SDP_RTCP_FB_REMB
:
4747 /* No additional tokens to parse after goog-remb */
4750 case SDP_RTCP_FB_TRANSPORT_CC
:
4751 /* No additional tokens to parse after transport-cc */
4754 case SDP_RTCP_FB_UNKNOWN
:
4755 /* Handled by "extra", below */
4759 /* This is an internal error, not a parsing error */
4760 SDPLogError(logTag
, "%s Error: Invalid rtcp-fb enum (%d)",
4761 sdp_p
->debug_str
, attr_p
->attr
.rtcp_fb
.feedback_type
);
4765 /* Skip any remaining WS */
4766 while (*ptr
== ' ' || *ptr
== '\t') {
4770 /* Just store the rest of the line in "extra" -- this will return
4771 a failure result if there is no more text, but that's fine. */
4772 ptr
= sdp_getnextstrtok(ptr
, rtcp_fb_p
->extra
,
4773 sizeof(rtcp_fb_p
->extra
), "\r\n", &result
);
4778 sdp_result_e
sdp_build_attr_setup(sdp_t
*sdp_p
,
4782 switch (attr_p
->attr
.setup
) {
4783 case SDP_SETUP_ACTIVE
:
4784 case SDP_SETUP_PASSIVE
:
4785 case SDP_SETUP_ACTPASS
:
4786 case SDP_SETUP_HOLDCONN
:
4787 flex_string_sprintf(fs
, "a=%s:%s\r\n",
4788 sdp_attr
[attr_p
->type
].name
,
4789 sdp_setup_type_val
[attr_p
->attr
.setup
].name
);
4792 SDPLogError(logTag
, "%s Error: Invalid setup enum (%d)",
4793 sdp_p
->debug_str
, attr_p
->attr
.setup
);
4800 sdp_result_e
sdp_parse_attr_setup(sdp_t
*sdp_p
,
4804 int i
= find_token_enum("setup attribute", sdp_p
, &ptr
,
4806 SDP_MAX_SETUP
, SDP_SETUP_UNKNOWN
);
4809 sdp_parse_error(sdp_p
,
4810 "%s Warning: could not parse setup attribute",
4812 sdp_p
->conf_p
->num_invalid_param
++;
4813 return SDP_INVALID_PARAMETER
;
4816 attr_p
->attr
.setup
= (sdp_setup_type_e
) i
;
4818 switch (attr_p
->attr
.setup
) {
4819 case SDP_SETUP_ACTIVE
:
4820 case SDP_SETUP_PASSIVE
:
4821 case SDP_SETUP_ACTPASS
:
4822 case SDP_SETUP_HOLDCONN
:
4823 /* All these values are OK */
4825 case SDP_SETUP_UNKNOWN
:
4826 sdp_parse_error(sdp_p
,
4827 "%s Warning: Unknown setup attribute",
4829 return SDP_INVALID_PARAMETER
;
4831 /* This is an internal error, not a parsing error */
4832 SDPLogError(logTag
, "%s Error: Invalid setup enum (%d)",
4833 sdp_p
->debug_str
, attr_p
->attr
.setup
);
4840 sdp_result_e
sdp_build_attr_connection(sdp_t
*sdp_p
,
4844 switch (attr_p
->attr
.connection
) {
4845 case SDP_CONNECTION_NEW
:
4846 case SDP_CONNECTION_EXISTING
:
4847 flex_string_sprintf(fs
, "a=%s:%s\r\n",
4848 sdp_attr
[attr_p
->type
].name
,
4849 sdp_connection_type_val
[attr_p
->attr
.connection
].name
);
4852 SDPLogError(logTag
, "%s Error: Invalid connection enum (%d)",
4853 sdp_p
->debug_str
, attr_p
->attr
.connection
);
4860 sdp_result_e
sdp_parse_attr_connection(sdp_t
*sdp_p
,
4864 int i
= find_token_enum("connection attribute", sdp_p
, &ptr
,
4865 sdp_connection_type_val
,
4866 SDP_MAX_CONNECTION
, SDP_CONNECTION_UNKNOWN
);
4869 sdp_parse_error(sdp_p
,
4870 "%s Warning: could not parse connection attribute",
4872 sdp_p
->conf_p
->num_invalid_param
++;
4873 return SDP_INVALID_PARAMETER
;
4876 attr_p
->attr
.connection
= (sdp_connection_type_e
) i
;
4878 switch (attr_p
->attr
.connection
) {
4879 case SDP_CONNECTION_NEW
:
4880 case SDP_CONNECTION_EXISTING
:
4881 /* All these values are OK */
4883 case SDP_CONNECTION_UNKNOWN
:
4884 sdp_parse_error(sdp_p
,
4885 "%s Warning: Unknown connection attribute",
4887 return SDP_INVALID_PARAMETER
;
4889 /* This is an internal error, not a parsing error */
4890 SDPLogError(logTag
, "%s Error: Invalid connection enum (%d)",
4891 sdp_p
->debug_str
, attr_p
->attr
.connection
);
4897 sdp_result_e
sdp_build_attr_extmap(sdp_t
*sdp_p
,
4901 flex_string_sprintf(fs
, "a=extmap:%d %s\r\n",
4902 attr_p
->attr
.extmap
.id
,
4903 attr_p
->attr
.extmap
.uri
);
4908 sdp_result_e
sdp_parse_attr_extmap(sdp_t
*sdp_p
,
4912 sdp_result_e result
;
4914 attr_p
->attr
.extmap
.id
= 0;
4915 attr_p
->attr
.extmap
.media_direction
= SDP_DIRECTION_SENDRECV
;
4916 attr_p
->attr
.extmap
.media_direction_specified
= FALSE
;
4917 attr_p
->attr
.extmap
.uri
[0] = '\0';
4918 attr_p
->attr
.extmap
.extension_attributes
[0] = '\0';
4920 /* Find the payload type number. */
4921 attr_p
->attr
.extmap
.id
=
4922 (uint16_t)sdp_getnextnumtok(ptr
, &ptr
, "/ \t", &result
);
4923 if (result
!= SDP_SUCCESS
) {
4924 sdp_parse_error(sdp_p
,
4925 "%s Warning: Invalid extmap id specified for %s attribute.",
4926 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
4927 sdp_p
->conf_p
->num_invalid_param
++;
4928 return (SDP_INVALID_PARAMETER
);
4932 char direction
[SDP_MAX_STRING_LEN
+1];
4933 ++ptr
; /* Skip over '/' */
4934 ptr
= sdp_getnextstrtok(ptr
, direction
,
4935 sizeof(direction
), " \t", &result
);
4936 if (result
!= SDP_SUCCESS
) {
4937 sdp_parse_error(sdp_p
,
4938 "%s Warning: Invalid direction specified in %s attribute.",
4939 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
4940 sdp_p
->conf_p
->num_invalid_param
++;
4941 return (SDP_INVALID_PARAMETER
);
4944 if (!cpr_strcasecmp(direction
, "sendrecv")) {
4945 attr_p
->attr
.extmap
.media_direction
= SDP_DIRECTION_SENDRECV
;
4946 } else if (!cpr_strcasecmp(direction
, "sendonly")) {
4947 attr_p
->attr
.extmap
.media_direction
= SDP_DIRECTION_SENDONLY
;
4948 } else if (!cpr_strcasecmp(direction
, "recvonly")) {
4949 attr_p
->attr
.extmap
.media_direction
= SDP_DIRECTION_RECVONLY
;
4950 } else if (!cpr_strcasecmp(direction
, "inactive")) {
4951 attr_p
->attr
.extmap
.media_direction
= SDP_DIRECTION_INACTIVE
;
4953 sdp_parse_error(sdp_p
,
4954 "%s Warning: Invalid direction specified in %s attribute.",
4955 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
4956 sdp_p
->conf_p
->num_invalid_param
++;
4957 return (SDP_INVALID_PARAMETER
);
4959 attr_p
->attr
.extmap
.media_direction_specified
= TRUE
;
4962 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.extmap
.uri
,
4963 sizeof(attr_p
->attr
.extmap
.uri
), " \t", &result
);
4964 if (result
!= SDP_SUCCESS
) {
4965 sdp_parse_error(sdp_p
,
4966 "%s Warning: No uri specified in %s attribute.",
4967 sdp_p
->debug_str
, sdp_get_attr_name(attr_p
->type
));
4968 sdp_p
->conf_p
->num_invalid_param
++;
4969 return (SDP_INVALID_PARAMETER
);
4972 while (*ptr
== ' ' || *ptr
== '\t') {
4976 /* Grab everything that follows, even if it contains whitespace */
4977 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.extmap
.extension_attributes
,
4978 sizeof(attr_p
->attr
.extmap
.extension_attributes
), "\r\n", &result
);
4980 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
4981 SDP_PRINT("%s Parsed a=%s, id %u, direction %s, "
4982 "uri %s, extension %s", sdp_p
->debug_str
,
4983 sdp_get_attr_name(attr_p
->type
),
4984 attr_p
->attr
.extmap
.id
,
4985 SDP_DIRECTION_PRINT(attr_p
->attr
.extmap
.media_direction
),
4986 attr_p
->attr
.extmap
.uri
,
4987 attr_p
->attr
.extmap
.extension_attributes
);
4990 return (SDP_SUCCESS
);
4993 sdp_result_e
sdp_parse_attr_msid(sdp_t
*sdp_p
,
4997 sdp_result_e result
;
4999 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.msid
.identifier
,
5000 sizeof(attr_p
->attr
.msid
.identifier
), " \t", &result
);
5001 if (result
!= SDP_SUCCESS
) {
5002 sdp_parse_error(sdp_p
, "%s Warning: Bad msid identity value",
5004 sdp_p
->conf_p
->num_invalid_param
++;
5005 return SDP_INVALID_PARAMETER
;
5008 ptr
= sdp_getnextstrtok(ptr
, attr_p
->attr
.msid
.appdata
,
5009 sizeof(attr_p
->attr
.msid
.appdata
), " \t", &result
);
5010 if ((result
!= SDP_SUCCESS
) && (result
!= SDP_EMPTY_TOKEN
)) {
5011 sdp_parse_error(sdp_p
, "%s Warning: Bad msid appdata value",
5013 sdp_p
->conf_p
->num_invalid_param
++;
5014 return SDP_INVALID_PARAMETER
;
5016 if (result
== SDP_EMPTY_TOKEN
) {
5017 attr_p
->attr
.msid
.appdata
[0] = '\0';
5020 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
5021 SDP_PRINT("%s Parsed a=msid, %s %s", sdp_p
->debug_str
,
5022 attr_p
->attr
.msid
.identifier
, attr_p
->attr
.msid
.appdata
);
5029 sdp_result_e
sdp_build_attr_msid(sdp_t
*sdp_p
,
5033 flex_string_sprintf(fs
, "a=msid:%s%s%s\r\n",
5034 attr_p
->attr
.msid
.identifier
,
5035 attr_p
->attr
.msid
.appdata
[0] ? " " : "",
5036 attr_p
->attr
.msid
.appdata
);
5040 sdp_result_e
sdp_parse_attr_msid_semantic(sdp_t
*sdp_p
,
5044 sdp_result_e result
;
5047 ptr
= sdp_getnextstrtok(ptr
,
5048 attr_p
->attr
.msid_semantic
.semantic
,
5049 sizeof(attr_p
->attr
.msid_semantic
.semantic
),
5053 if (result
!= SDP_SUCCESS
) {
5054 sdp_parse_error(sdp_p
, "%s Warning: Bad msid-semantic attribute; "
5057 sdp_p
->conf_p
->num_invalid_param
++;
5058 return SDP_INVALID_PARAMETER
;
5061 for (i
= 0; i
< SDP_MAX_MEDIA_STREAMS
; ++i
) {
5062 /* msid-id can be up to 64 characters long, plus null terminator */
5064 ptr
= sdp_getnextstrtok(ptr
, temp
, sizeof(temp
), " \t", &result
);
5066 if (result
!= SDP_SUCCESS
) {
5070 attr_p
->attr
.msid_semantic
.msids
[i
] = cpr_strdup(temp
);
5073 if ((result
!= SDP_SUCCESS
) && (result
!= SDP_EMPTY_TOKEN
)) {
5074 sdp_parse_error(sdp_p
, "%s Warning: Bad msid-semantic attribute",
5076 sdp_p
->conf_p
->num_invalid_param
++;
5077 return SDP_INVALID_PARAMETER
;
5080 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
5081 SDP_PRINT("%s Parsed a=msid-semantic, %s", sdp_p
->debug_str
,
5082 attr_p
->attr
.msid_semantic
.semantic
);
5083 for (i
= 0; i
< SDP_MAX_MEDIA_STREAMS
; ++i
) {
5084 if (!attr_p
->attr
.msid_semantic
.msids
[i
]) {
5088 SDP_PRINT("%s ... msid %s", sdp_p
->debug_str
,
5089 attr_p
->attr
.msid_semantic
.msids
[i
]);
5097 sdp_result_e
sdp_build_attr_msid_semantic(sdp_t
*sdp_p
,
5102 flex_string_sprintf(fs
, "a=msid-semantic:%s",
5103 attr_p
->attr
.msid_semantic
.semantic
);
5104 for (i
= 0; i
< SDP_MAX_MEDIA_STREAMS
; ++i
) {
5105 if (!attr_p
->attr
.msid_semantic
.msids
[i
]) {
5109 flex_string_sprintf(fs
, " %s",
5110 attr_p
->attr
.msid_semantic
.msids
[i
]);
5112 flex_string_sprintf(fs
, "\r\n");
5116 sdp_result_e
sdp_parse_attr_ssrc(sdp_t
*sdp_p
,
5120 sdp_result_e result
;
5122 attr_p
->attr
.ssrc
.ssrc
=
5123 (uint32_t)sdp_getnextnumtok(ptr
, &ptr
, " \t", &result
);
5125 if (result
!= SDP_SUCCESS
) {
5126 sdp_parse_error(sdp_p
, "%s Warning: Bad ssrc attribute, cannot parse ssrc",
5128 sdp_p
->conf_p
->num_invalid_param
++;
5129 return SDP_INVALID_PARAMETER
;
5132 /* Skip any remaining WS */
5133 while (*ptr
== ' ' || *ptr
== '\t') {
5137 /* Just store the rest of the line in "attribute" -- this will return
5138 a failure result if there is no more text, but that's fine. */
5139 ptr
= sdp_getnextstrtok(ptr
,
5140 attr_p
->attr
.ssrc
.attribute
,
5141 sizeof(attr_p
->attr
.ssrc
.attribute
),
5149 sdp_result_e
sdp_build_attr_ssrc(sdp_t
*sdp_p
,
5153 flex_string_sprintf(fs
, "a=ssrc:%s%s%s\r\n",
5154 attr_p
->attr
.ssrc
.ssrc
,
5155 attr_p
->attr
.ssrc
.attribute
[0] ? " " : "",
5156 attr_p
->attr
.ssrc
.attribute
);
5161 sdp_result_e
sdp_parse_attr_ssrc_group(sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
5164 sdp_result_e result
;
5165 char tmp
[SDP_MAX_STRING_LEN
+ 1];
5168 /* Find the a=ssrc-group:<semantic> <ssrc1> <ssrc2> ... values */
5169 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
5170 if (result
!= SDP_SUCCESS
) {
5171 sdp_parse_error(sdp_p
,
5172 "%s Warning: No semantic attribute value specified for "
5173 "a=ssrc-group line",
5175 sdp_p
->conf_p
->num_invalid_param
++;
5176 return (SDP_INVALID_PARAMETER
);
5179 attr_p
->attr
.ssrc_group
.semantic
= SDP_SSRC_GROUP_ATTR_UNSUPPORTED
;
5180 for (i
= 0; i
< SDP_MAX_SSRC_GROUP_ATTR_VAL
; i
++) {
5181 if (cpr_strncasecmp(tmp
, sdp_ssrc_group_attr_val
[i
].name
,
5182 sdp_ssrc_group_attr_val
[i
].strlen
) == 0) {
5183 attr_p
->attr
.ssrc_group
.semantic
= (sdp_ssrc_group_attr_e
)i
;
5188 if (attr_p
->attr
.ssrc_group
.semantic
== SDP_SSRC_GROUP_ATTR_UNSUPPORTED
) {
5189 sdp_parse_error(sdp_p
,
5190 "%s Warning: Ssrc group attribute type unsupported (%s).",
5191 sdp_p
->debug_str
, tmp
);
5194 for (i
= 0; i
< SDP_MAX_SSRC_GROUP_SSRCS
; ++i
) {
5195 attr_p
->attr
.ssrc_group
.ssrcs
[i
] =
5196 (uint32_t)sdp_getnextnumtok(ptr
, &ptr
, " \t", &result
);
5198 if (result
!= SDP_SUCCESS
) {
5202 attr_p
->attr
.ssrc_group
.num_ssrcs
++;
5205 ptr
= sdp_getnextstrtok(ptr
, tmp
, sizeof(tmp
), " \t", &result
);
5206 if (result
== SDP_SUCCESS
) {
5207 sdp_parse_error(sdp_p
,
5208 "%s Warning: Trailing tokens while parsing ssrc-group (%s).",
5209 sdp_p
->debug_str
, tmp
);
5210 sdp_p
->conf_p
->num_invalid_param
++;
5211 return (SDP_INVALID_PARAMETER
);
5214 if (attr_p
->attr
.ssrc_group
.num_ssrcs
== 0) {
5215 sdp_parse_error(sdp_p
,
5216 "%s Warning: Ssrc group must contain at least one ssrc (%s).",
5217 sdp_p
->debug_str
, tmp
);
5218 sdp_p
->conf_p
->num_invalid_param
++;
5219 return (SDP_INVALID_PARAMETER
);
5222 if (sdp_p
->debug_flag
[SDP_DEBUG_TRACE
]) {
5223 SDP_PRINT("%s Parsed a=ssrc-group, semantic %s", sdp_p
->debug_str
,
5224 sdp_get_ssrc_group_attr_name(attr_p
->attr
.ssrc_group
.semantic
));
5225 for (i
= 0; i
< attr_p
->attr
.ssrc_group
.num_ssrcs
; ++i
) {
5226 SDP_PRINT("%s ... ssrc %u", sdp_p
->debug_str
,
5227 attr_p
->attr
.ssrc_group
.ssrcs
[i
]);
5231 return (SDP_SUCCESS
);
5234 sdp_result_e
sdp_build_attr_ssrc_group(sdp_t
*sdp_p
, sdp_attr_t
*attr_p
,
5238 flex_string_sprintf(
5239 fs
, "a=ssrc-group:%s",
5240 sdp_get_ssrc_group_attr_name(attr_p
->attr
.ssrc_group
.semantic
));
5242 if (attr_p
->attr
.ssrc_group
.num_ssrcs
) {
5243 return (SDP_FAILURE
);
5246 for (i
= 0; i
< attr_p
->attr
.ssrc_group
.num_ssrcs
; ++i
) {
5247 flex_string_sprintf(fs
, " %u", attr_p
->attr
.ssrc_group
.ssrcs
[i
]);
5249 flex_string_sprintf(fs
, "\r\n");
5250 return (SDP_SUCCESS
);