Bug 1750884 - Add style_traits::ToCss for AtomIdent r=emilio
[gecko.git] / third_party / sipcc / sdp_attr.c
blob4f75a98fa33b4d019798a38dde04fd53e1702392
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/. */
5 #include <errno.h>
6 #include <limits.h>
7 #include <stdio.h>
9 #include "plstr.h"
10 #include "sdp_os_defs.h"
11 #include "sipcc_sdp.h"
12 #include "sdp_private.h"
13 #include "sdp_base64.h"
15 #include "sdp_log.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) \
24 if ((condition)) { \
25 sdp_append_name_and_string(fs, (name), (value), semicolon); \
26 semicolon = TRUE; \
30 * Macro for sdp_build_attr_fmtp
31 * Adds name-value pair where value is unsigned
33 #define FMTP_BUILD_UNSIGNED(condition, name, value) \
34 if ((condition)) { \
35 sdp_append_name_and_unsigned(fs, (name), (value), semicolon); \
36 semicolon = TRUE; \
40 * Macro for sdp_build_attr_fmtp
41 * Adds flag string on condition
43 #define FMTP_BUILD_FLAG(condition, name) \
44 if ((condition)) { \
45 if (semicolon) { \
46 flex_string_append(fs, ";"); \
47 } \
48 flex_string_append(fs, name); \
49 semicolon = TRUE; \
52 static int find_token_enum(const char *attr_name,
53 sdp_t *sdp_p,
54 const char **ptr,
55 const sdp_namearray_t *types,
56 int type_count,
57 int unknown_value)
59 sdp_result_e result = SDP_SUCCESS;
60 char tmp[SDP_MAX_STRING_LEN+1];
61 int i;
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++;
68 return -1;
71 for (i=0; i < type_count; i++) {
72 if (!cpr_strncasecmp(tmp, types[i].name, types[i].strlen)) {
73 return i;
76 return unknown_value;
80 * Helper function for adding nv-pair where value is string.
82 static void sdp_append_name_and_string(flex_string *fs,
83 const char *name,
84 const char *value,
85 tinybool semicolon)
87 flex_string_sprintf(fs, "%s%s=%s",
88 semicolon ? ";" : "",
89 name,
90 value);
94 * Helper function for adding nv-pair where value is unsigned.
96 static void sdp_append_name_and_unsigned(flex_string *fs,
97 const char *name,
98 unsigned int value,
99 tinybool semicolon)
101 flex_string_sprintf(fs, "%s%s=%u",
102 semicolon ? ";" : "",
103 name,
104 value);
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)
119 int i;
120 uint8_t xcpar_flag = FALSE;
121 sdp_result_e result;
122 sdp_mca_t *mca_p=NULL;
123 sdp_attr_t *attr_p;
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);
131 if (mca_p == NULL) {
132 return (SDP_FAILURE);
136 /* Find the attribute type. */
137 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
138 if (ptr == NULL) {
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);
144 if (ptr[0] == ':') {
145 /* Skip the ':' char for parsing attribute parameters. */
146 ptr++;
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;
166 break;
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)) {
181 xcpar_flag = TRUE;
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) {
198 return (result);
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) {
206 ; /* Empty for */
208 if (prev_attr_p == NULL) {
209 sdp_p->sess_attrs_p = attr_p;
210 } else {
211 prev_attr_p->next_p = attr_p;
213 } else {
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) {
217 ; /* Empty for */
219 if (prev_attr_p == NULL) {
220 mca_p->media_attrs_p = attr_p;
221 } else {
222 prev_attr_p->next_p = attr_p;
226 return (result);
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)
232 sdp_attr_t *attr_p;
233 sdp_mca_t *mca_p=NULL;
234 sdp_result_e result;
236 if (level == SDP_SESSION_LEVEL) {
237 attr_p = sdp_p->sess_attrs_p;
238 } else {
239 mca_p = sdp_find_media_level(sdp_p, level);
240 if (mca_p == NULL) {
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);
256 } else {
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);
261 return 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;
272 return SDP_SUCCESS;
275 sdp_result_e sdp_parse_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
276 const char *ptr)
278 sdp_result_e result;
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);
289 } else {
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,
300 flex_string *fs)
302 flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
303 attr_p->attr.string_val);
305 return SDP_SUCCESS;
308 sdp_result_e sdp_parse_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
309 const char *ptr)
311 sdp_result_e result;
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);
321 } else {
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,
331 flex_string *fs)
333 flex_string_sprintf(fs, "a=%s:%u\r\n", sdp_attr[attr_p->type].name,
334 attr_p->attr.u32_val);
336 return SDP_SUCCESS;
339 sdp_result_e sdp_parse_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
340 const char *ptr)
342 sdp_result_e result;
344 if (sdp_getnextnumtok(ptr, &ptr, " \t", &result) == 0) {
345 attr_p->attr.boolean_val = FALSE;
346 } else {
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);
356 } else {
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));
361 } else {
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,
371 flex_string *fs)
373 flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
374 attr_p->attr.boolean_val ? "1" : "0");
376 return SDP_SUCCESS;
380 * sdp_parse_attr_maxprate
382 * This function parses maxprate attribute lines. The ABNF for this a=
383 * line is:
384 * max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF
385 * packet-rate = 1*DIGIT ["." 1*DIGIT]
387 * Returns:
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
390 * the ABNF.
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,
395 const char *ptr)
397 sdp_result_e result;
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);
408 } else {
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
429 * missing.
432 static void sdp_attr_fmtp_no_value(sdp_t *sdp, const char *param_name)
434 sdp_parse_error(sdp,
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
443 * incorrect.
446 static void sdp_attr_fmtp_invalid_value(sdp_t *sdp, const char *param_name,
447 const char* param_value)
449 sdp_parse_error(sdp,
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
467 if (len < 1
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
477 // the input string.
478 char dtmf_tones[SDP_MAX_STRING_LEN+1];
479 PL_strncpyz(dtmf_tones, fmtpVal, sizeof(dtmf_tones));
481 char *strtok_state;
482 char *temp = PL_strtok_r(dtmf_tones, ",", &strtok_state);
484 while (temp != NULL) {
485 len = strlen(temp);
486 if (len > 5) {
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;
499 uint8_t low_val;
500 uint8_t high_val;
501 low_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
502 "-", &result1);
503 high_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
504 "-", &result2);
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;
511 if (low_val > 99
512 || high_val > 99
513 || high_val <= low_val) {
514 return SDP_INVALID_PARAMETER;
518 temp=PL_strtok_r(NULL, ",", &strtok_state);
521 return SDP_SUCCESS;
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,
541 char* buf,
542 size_t buf_size,
543 char** tok)
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;
555 *tok = buf;
556 (*tok)++;
558 return SDP_SUCCESS;
561 sdp_result_e sdp_get_fmtp_tok_val(sdp_t *sdp_p,
562 const char** fmtp_ptr,
563 const char* fmtp_name,
564 char* buf,
565 size_t buf_size,
566 char** tok,
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;
573 unsigned long value;
574 char* strtoul_end;
576 result1 = sdp_get_fmtp_tok(sdp_p, fmtp_ptr, fmtp_name, buf, buf_size, tok);
577 if (result1 != SDP_SUCCESS) return result1;
579 errno = 0;
580 value = strtoul(*tok, &strtoul_end, 10);
582 if (errno
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;
592 return SDP_SUCCESS;
595 sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
596 const char *ptr)
598 uint16_t i;
599 uint32_t mapword;
600 uint32_t bmap;
601 uint8_t low_val;
602 uint8_t high_val;
603 const char *ptr2;
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;
609 sdp_fmtp_t *fmtp_p;
610 char tmp[SDP_MAX_STRING_LEN];
611 char *src_ptr;
612 char *temp_ptr = NULL;
613 char *tok=NULL;
614 char *temp=NULL;
615 uint16_t custom_x=0;
616 uint16_t custom_y=0;
617 uint16_t custom_mpi=0;
618 uint16_t par_height=0;
619 uint16_t par_width=0;
620 uint16_t cpcf=0;
621 uint16_t iter=0;
623 ulong l_val = 0;
624 char* strtok_state;
625 unsigned long strtoul_result;
626 char* strtoul_end;
628 /* Find the payload type number. */
629 attr_p->attr.fmtp.payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
630 " \t", &result1);
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;
638 fmtp_p->flag = 0;
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;
655 src_ptr = temp_ptr;
656 while (!done) {
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;
674 } else {
675 sdp_attr_fmtp_invalid_value(sdp_p, "annexb", tok);
676 SDP_FREE(temp_ptr);
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;
696 } else {
697 sdp_attr_fmtp_invalid_value(sdp_p, "annexa", tok);
698 SDP_FREE(temp_ptr);
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);
789 iter++;
790 if (temp) {
791 iter=1;
792 while (temp != NULL) {
793 errno = 0;
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;
798 break;
801 if (iter == 1)
802 custom_x = (uint16_t) strtoul_result;
803 if (iter == 2)
804 custom_y = (uint16_t) strtoul_result;
805 if (iter == 3)
806 custom_mpi = (uint16_t) strtoul_result;
808 temp=PL_strtok_r(NULL, ",", &strtok_state);
809 iter++;
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);
816 SDP_FREE(temp_ptr);
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);
831 if (temp) {
832 iter=1;
833 /* get par width and par height for the aspect ratio */
834 while (temp != NULL) {
835 errno = 0;
836 strtoul_result = strtoul(temp, &strtoul_end, 10);
838 if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
839 par_width = par_height = 0;
840 break;
843 if (iter == 1)
844 par_width = (uint16_t) strtoul_result;
845 else
846 par_height = (uint16_t) strtoul_result;
848 temp=PL_strtok_r(NULL, ",", &strtok_state);
849 iter++;
852 if (!par_width || !par_height) {
853 sdp_attr_fmtp_invalid_value(sdp_p, "par_width or par_height", temp);
854 SDP_FREE(temp_ptr);
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 ) {
869 errno = 0;
870 strtoul_result = strtoul(temp, &strtoul_end, 10);
872 if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
873 cpcf = 0;
874 } else {
875 cpcf = (uint16_t) strtoul_result;
879 if (!cpcf) {
880 sdp_attr_fmtp_invalid_value(sdp_p, "cpcf", tok);
881 SDP_FREE(temp_ptr);
882 return SDP_INVALID_PARAMETER;
884 fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
885 fmtp_p->cpcf = cpcf;
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;
985 } else {
986 sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_req", tok);
987 SDP_FREE(temp_ptr);
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;
1011 } else {
1012 sdp_attr_fmtp_invalid_value(sdp_p, "init_buf_time", tok);
1013 SDP_FREE(temp_ptr);
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;
1084 } else {
1085 sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_cap", tok);
1086 SDP_FREE(temp_ptr);
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;
1100 } else {
1101 sdp_attr_fmtp_invalid_value(sdp_p, "max_rcmd_nalu_size", tok);
1102 SDP_FREE(temp_ptr);
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);
1174 if (temp) {
1175 iter=1;
1176 while (temp != NULL) {
1177 errno = 0;
1178 strtoul_result = strtoul(temp, &strtoul_end, 10);
1180 if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
1181 break;
1184 if (iter == 1)
1185 fmtp_p->annex_p_val_picture_resize = (uint16_t) strtoul_result;
1186 else if (iter == 2)
1187 fmtp_p->annex_p_val_warp = (uint16_t) strtoul_result;
1189 temp = PL_strtok_r(NULL, ",", &strtok_state);
1190 iter++;
1192 } else {
1193 SDP_FREE(temp_ptr);
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) {
1294 result1 =
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) {
1298 SDP_FREE(temp_ptr);
1299 return result1;
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) {
1310 result1 =
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) {
1314 SDP_FREE(temp_ptr);
1315 return result1;
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);
1326 if (temp) {
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);
1349 } /* if (temp) */
1350 done = TRUE;
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);
1357 if (temp) {
1358 iter = 0;
1359 while (temp != NULL) {
1360 errno = 0;
1361 strtoul_result = strtoul(temp, &strtoul_end, 10);
1363 if (errno ||
1364 temp == strtoul_end || strtoul_result > USHRT_MAX) {
1365 temp = NULL;
1366 continue;
1368 fmtp_p->redundant_encodings[iter++] =
1369 (uint8_t)strtoul_result;
1370 temp=PL_strtok_r(NULL, "/", &strtok_state);
1372 } /* if (temp) */
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;
1378 } else {
1379 // unknown parameter - eat chars until ';'
1380 SDPLogDebug(logTag, "%s Unknown fmtp type (%s) - ignoring", __FUNCTION__,
1381 tmp);
1382 fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t",
1383 &result1);
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
1393 done = TRUE;
1394 } else {
1395 fmtp_ptr++;
1397 } else {
1398 done = TRUE;
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",
1406 sdp_p->debug_str,
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",
1429 sdp_p->debug_str,
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",
1439 sdp_p->debug_str,
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",
1453 sdp_p->debug_str,
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",
1467 sdp_p->debug_str,
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);
1477 SDP_FREE(temp_ptr);
1478 return (SDP_SUCCESS);
1479 } else {
1480 done = FALSE;
1481 fmtp_ptr = src_ptr;
1482 tmp[0] = '\0';
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) {
1490 done = TRUE;
1491 continue;
1493 /* Now look for '-' separated range */
1494 ptr2 = tmp;
1495 low_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
1496 "- \t", &result1);
1497 if (*ptr2 == '-') {
1498 high_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
1499 "- \t", &result2);
1500 } else {
1501 high_val = low_val;
1504 if ((result1 != SDP_SUCCESS) || (result2 != SDP_SUCCESS)) {
1505 sdp_parse_error(sdp_p,
1506 "%s Warning: Invalid named events specified for fmtp attribute.",
1507 sdp_p->debug_str);
1508 sdp_p->conf_p->num_invalid_param++;
1509 SDP_FREE(temp_ptr);
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.",
1526 sdp_p->debug_str);
1527 sdp_p->conf_p->num_invalid_param++;
1528 SDP_FREE(temp_ptr);
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);
1537 SDP_FREE(temp_ptr);
1538 return (SDP_SUCCESS);
1541 sdp_result_e
1542 sdp_build_attr_fmtp_params (sdp_t *sdp_p, sdp_fmtp_t *fmtp_p, flex_string *fs)
1544 uint16_t event_id;
1545 uint32_t mask;
1546 uint32_t mapword;
1547 uint8_t min = 0;
1548 uint8_t max = 0;
1549 tinybool range_start = FALSE;
1550 tinybool range_end = FALSE;
1551 tinybool semicolon = FALSE;
1553 switch (fmtp_p->fmtp_format) {
1554 case SDP_FMTP_MODE:
1555 sdp_append_name_and_unsigned(fs, "mode", fmtp_p->mode, FALSE);
1556 break;
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 ? ";" : "",
1583 fmtp_p->custom_x,
1584 fmtp_p->custom_y,
1585 fmtp_p->custom_mpi);
1587 semicolon = TRUE;
1590 if ((fmtp_p->par_height > 0) && (fmtp_p->par_width > 0)) {
1591 flex_string_sprintf(fs, "%sPAR=%u:%u",
1592 semicolon ? ";" : "",
1593 fmtp_p->par_width,
1594 fmtp_p->par_width);
1596 semicolon = TRUE;
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);
1634 semicolon = TRUE;
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)
1704 break;
1706 case SDP_FMTP_NTE:
1707 default:
1708 break;
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) {
1716 mask <<= 1;
1717 } else {
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;
1724 continue;
1728 if (fmtp_p->bmap[mapword] & mask) {
1729 if (!range_start) {
1730 range_start = TRUE;
1731 min = max = (uint8_t)event_id;
1732 } else {
1733 max = (uint8_t)event_id;
1735 range_end = (max == fmtp_p->maxval);
1736 } else {
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. */
1743 if (range_end) {
1744 range_start = range_end = FALSE;
1746 flex_string_sprintf(fs, "%u", min);
1748 if (min != max) {
1749 flex_string_sprintf(fs, "-%u", max);
1752 if (max != fmtp_p->maxval) {
1753 flex_string_append(fs, ",");
1757 return SDP_SUCCESS;
1760 sdp_result_e sdp_build_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
1762 sdp_fmtp_t *fmtp_p;
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) {
1774 return result;
1777 flex_string_append(fs, "\r\n");
1779 return SDP_SUCCESS;
1782 sdp_result_e sdp_parse_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
1783 const char *ptr)
1785 sdp_result_e result = SDP_SUCCESS;
1786 char tmp[SDP_MAX_STRING_LEN];
1787 uint32_t streams;
1789 /* Find the payload type number. */
1790 attr_p->attr.sctpmap.port = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
1791 " \t", &result);
1792 if (result != SDP_SUCCESS) {
1793 sdp_parse_error(sdp_p,
1794 "%s Warning: no sctpmap port number",
1795 sdp_p->debug_str);
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.",
1803 sdp_p->debug_str);
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.",
1814 sdp_p->debug_str);
1815 sdp_p->conf_p->num_invalid_param++;
1816 return SDP_INVALID_PARAMETER;
1819 attr_p->attr.sctpmap.streams = streams;
1821 return SDP_SUCCESS;
1824 sdp_result_e sdp_build_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
1825 flex_string *fs)
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);
1833 return SDP_SUCCESS;
1836 sdp_result_e sdp_parse_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p,
1837 const char *ptr)
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));
1852 return SDP_SUCCESS;
1855 sdp_result_e sdp_parse_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p,
1856 const char *ptr)
1858 int i;
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.",
1867 sdp_p->debug_str);
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.",
1891 sdp_p->debug_str);
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" : "");
1944 return SDP_SUCCESS;
1947 sdp_result_e sdp_parse_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p,
1948 const char *ptr)
1950 int i;
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.",
1959 sdp_p->debug_str);
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.",
1974 sdp_p->debug_str);
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.",
1984 sdp_p->debug_str);
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.",
2002 sdp_p->debug_str);
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));
2040 return SDP_SUCCESS;
2043 sdp_result_e sdp_parse_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p,
2044 const char *ptr)
2046 int i;
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.",
2055 sdp_p->debug_str);
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.",
2070 sdp_p->debug_str);
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.",
2080 sdp_p->debug_str);
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.",
2104 sdp_p->debug_str);
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.",
2122 sdp_p->debug_str);
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));
2163 return SDP_SUCCESS;
2166 sdp_result_e sdp_parse_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p,
2167 const char *ptr)
2169 int i;
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.",
2178 sdp_p->debug_str);
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.",
2193 sdp_p->debug_str);
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.",
2203 sdp_p->debug_str);
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.",
2221 sdp_p->debug_str);
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));
2259 return SDP_SUCCESS;
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,
2268 const char *ptr)
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. */
2311 if (*ptr == '/') {
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,
2345 flex_string *fs)
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);
2353 } else {
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);
2362 return SDP_SUCCESS;
2365 sdp_result_e sdp_parse_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
2366 const char *ptr)
2368 int i;
2369 char *slash_ptr;
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.",
2379 sdp_p->debug_str);
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) {
2387 type_found = TRUE;
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;
2393 type_found = FALSE;
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.",
2409 sdp_p->debug_str);
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) {
2417 type_found = TRUE;
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;
2423 type_found = FALSE;
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,
2450 " \t", &result);
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);
2458 } else {
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,
2477 flex_string *fs)
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);
2485 } else {
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);
2494 return SDP_SUCCESS;
2497 sdp_result_e sdp_parse_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
2498 const char *ptr)
2500 int i;
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.",
2509 sdp_p->debug_str);
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,
2531 flex_string *fs)
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));
2537 return SDP_SUCCESS;
2540 sdp_result_e sdp_parse_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
2541 const char *ptr)
2543 int i;
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.",
2552 sdp_p->debug_str);
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,
2574 flex_string *fs)
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));
2580 return SDP_SUCCESS;
2583 sdp_result_e sdp_parse_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
2584 const char *ptr)
2586 uint16_t i;
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,
2591 " \t", &result);
2592 if (result != SDP_SUCCESS) {
2593 break;
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,
2619 flex_string *fs)
2621 int i;
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");
2631 return SDP_SUCCESS;
2635 sdp_result_e sdp_parse_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
2636 const char *ptr)
2638 uint16_t i;
2639 sdp_result_e result;
2640 sdp_mca_t *cap_p;
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));
2669 SDP_FREE(cap_p);
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, "
2679 "unable to parse.",
2680 sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
2681 SDP_FREE(cap_p);
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;
2689 break;
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);
2696 SDP_FREE(cap_p);
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);
2707 SDP_FREE(cap_p);
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;
2716 break;
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);
2723 SDP_FREE(cap_p);
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));
2740 SDP_FREE(cap_p);
2741 sdp_p->conf_p->num_invalid_param++;
2742 return (SDP_INVALID_PARAMETER);
2743 } else {
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) {
2747 SDP_FREE(cap_p);
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
2756 * cpar attrs.
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,
2773 flex_string *fs)
2775 uint16_t i, j;
2776 sdp_mca_t *cap_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);
2824 return SDP_SUCCESS;
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]));
2835 } else {
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,
2852 const char *ptr)
2854 uint16_t i;
2855 sdp_result_e result;
2856 sdp_mca_t *cap_p;
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;
2868 } else {
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);
2876 } else {
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.}
2926 if (*ptr == '=') {
2927 ptr++;
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. */
2938 ptr++;
2940 if (result != SDP_SUCCESS) {
2941 sdp_parse_error(sdp_p,
2942 "%s No attribute type specified for %s attribute, unable to parse.",
2943 sdp_p->debug_str,
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) {
2985 return (result);
2988 /* Hook the attribute into the capability structure. */
2989 if (cap_p->media_attrs_p == NULL) {
2990 cap_p->media_attrs_p = attr_p;
2991 } else {
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) {
2995 ; /* Empty for */
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,
3004 flex_string *fs)
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);
3012 } else {
3014 * Default to X-CPAR if anything else. This is the backward
3015 * compatible value.
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);
3024 } else {
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,
3044 const char *ptr)
3046 sdp_result_e result;
3047 char nettype[SDP_MAX_STRING_LEN];
3048 sdp_rtcp_t *rtcp_p = &(attr_p->attr.rtcp);
3049 int enum_raw;
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",
3057 sdp_p->debug_str);
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 */
3067 return SDP_SUCCESS;
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",
3085 &result);
3086 if (result != SDP_SUCCESS) {
3087 sdp_parse_error(sdp_p,
3088 "%s Warning: could not parse addr for rtcp attribute",
3089 sdp_p->debug_str);
3090 sdp_p->conf_p->num_invalid_param++;
3092 return SDP_INVALID_PARAMETER;
3095 return SDP_SUCCESS;
3098 sdp_result_e sdp_build_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p,
3099 flex_string *fs)
3101 /* We should not be serializing SDP anyway, but we need this function until
3102 * Bug 1112737 is resolved. */
3103 return SDP_FAILURE;
3106 sdp_result_e sdp_parse_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
3107 const char *ptr)
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);
3122 } else {
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),
3137 tmp);
3139 return (SDP_SUCCESS);
3143 sdp_result_e sdp_build_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
3144 flex_string *fs)
3146 flex_string_sprintf(fs, "a=%s%s\r\n",
3147 sdp_attr[attr_p->type].name,
3148 attr_p->attr.rtr.confirm ? ":confirm" : "");
3150 return SDP_SUCCESS;
3153 sdp_result_e sdp_parse_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
3154 const char *ptr)
3156 int i;
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) {
3180 type_found = TRUE;
3181 attr_p->attr.comediadir.role = (sdp_mediadir_role_e)i;
3182 break;
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) {
3216 type_found = TRUE;
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;
3222 type_found = FALSE;
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) {
3244 type_found = TRUE;
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;
3250 type_found = FALSE;
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",
3272 &result);
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 "
3282 "srcport %u ",
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);
3296 sdp_result_e
3297 sdp_build_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
3298 flex_string *fs)
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));
3304 return SDP_SUCCESS;
3307 sdp_result_e sdp_parse_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
3308 const char *ptr)
3310 int i;
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.",
3320 sdp_p->debug_str);
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;
3331 } else {
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,
3344 &result);
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);
3353 /* Find suppPref */
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.",
3358 sdp_p->debug_str);
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);
3377 /* Find sidUse */
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.",
3382 sdp_p->debug_str);
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,
3405 &result);
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=-");
3421 } else {
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=-");
3430 } else {
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,
3439 flex_string *fs)
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), "-");
3446 } else {
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), "-");
3452 } else {
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"),
3459 temp_timer_string,
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);
3464 return SDP_SUCCESS;
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
3482 int i;
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);
3500 return FALSE;
3504 sdp_result_e sdp_build_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
3505 flex_string *fs)
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,
3520 key_size );
3521 memcpy(base64_encoded_input + key_size,
3522 attr_p->attr.srtp_context.master_salt,
3523 salt_size );
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);
3541 return SDP_SUCCESS;
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 (
3553 sdp_t *sdp_p,
3554 sdp_attr_t *attr_p,
3555 const char *ptr)
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) {
3570 break;
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]);
3600 return SDP_SUCCESS;
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
3607 * hyphens.
3609 sdp_result_e sdp_build_attr_mptime (
3610 sdp_t *sdp_p,
3611 sdp_attr_t *attr_p,
3612 flex_string *fs)
3614 int i;
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++) {
3623 if (i > 0) {
3624 flex_string_append(fs, " ");
3627 if (attr_p->attr.mptime.intervals[i] == 0) {
3628 flex_string_append(fs, "-");
3629 } else {
3630 flex_string_sprintf(fs, "%u", attr_p->attr.mptime.intervals[i]);
3634 flex_string_append(fs, "\r\n");
3636 return SDP_SUCCESS;
3641 sdp_result_e sdp_parse_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
3642 const char *ptr)
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.",
3658 sdp_p->debug_str);
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,
3672 flex_string *fs)
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);
3678 return SDP_SUCCESS;
3681 sdp_result_e sdp_parse_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
3682 const char *ptr)
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.",
3698 sdp_p->debug_str);
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,
3712 flex_string *fs)
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);
3718 return SDP_SUCCESS;
3722 sdp_result_e sdp_parse_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
3723 const char *ptr)
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,
3753 flex_string *fs)
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",
3758 sdp_p->debug_str);
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);
3768 return SDP_SUCCESS;
3771 sdp_result_e sdp_parse_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
3772 const char *ptr)
3774 sdp_result_e result;
3775 char tmp[64];
3776 int i=0;
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;
3798 break;
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
3811 * of id available.
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) {
3819 break;
3821 attr_p->attr.stream_data.group_ids[i] = cpr_strdup(tmp);
3822 if (!attr_p->attr.stream_data.group_ids[i]) {
3823 break;
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,
3842 flex_string *fs)
3844 int i;
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");
3859 return SDP_SUCCESS;
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,
3867 const char *ptr)
3869 int i;
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;
3892 break;
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;
3943 } else {
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) {
3968 break;
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,
3984 flex_string *fs)
3986 int i;
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");
4002 return SDP_SUCCESS;
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,
4009 const char *ptr)
4011 sdp_result_e result;
4012 uint32_t i;
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;
4031 break;
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,
4045 flex_string *fs)
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));
4055 return SDP_SUCCESS;
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.
4065 * Inputs:
4066 * buf - pointer to MKI or lifetime string assumes string is null
4067 * terminated.
4068 * attr_p - pointer to attribute struct
4070 * Outputs:
4071 * Return TRUE all is good otherwise FALSE for error.
4074 tinybool
4075 store_sdescriptions_mki_or_lifetime (char *buf, sdp_attr_t *attr_p)
4078 tinybool result;
4079 uint16_t mkiLen;
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);
4085 if (result) {
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);
4091 } else {
4092 result = verify_sdescriptions_lifetime(buf);
4093 if (result) {
4094 sstrncpy((char*)attr_p->attr.srtp_context.master_key_lifetime, buf,
4095 SDP_SRTP_MAX_LIFETIME_BYTES);
4099 return result;
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
4115 * ; RFC2046]
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.
4127 tinybool
4128 sdp_parse_sdescriptions_key_param (const char *str, sdp_attr_t *attr_p,
4129 sdp_t *sdp_p)
4131 char buf[SDP_MAX_STRING_LEN],
4132 base64decodeData[SDP_MAX_STRING_LEN];
4133 const char *ptr;
4134 sdp_result_e result = SDP_SUCCESS;
4135 tinybool keyFound = FALSE;
4136 int len,
4137 keySize,
4138 saltSize;
4139 base64_result_t status;
4141 ptr = str;
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++;
4146 return FALSE;
4149 /* advance pass the inline key word */
4150 ptr = ptr + 7;
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) {
4155 keyFound = TRUE;
4156 len = SDP_MAX_STRING_LEN;
4157 /* The key is base64 encoded composed of the master key concatenated with the
4158 * master salt.
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));
4167 return FALSE;
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);
4177 return(FALSE);
4180 memcpy(attr_p->attr.srtp_context.master_key,
4181 base64decodeData,
4182 keySize);
4184 memcpy(attr_p->attr.srtp_context.master_salt,
4185 base64decodeData + keySize,
4186 saltSize);
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) {
4195 return 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++;
4207 return FALSE;
4210 return TRUE;
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.
4225 sdp_result_e
4226 sdp_build_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
4227 flex_string *fs)
4230 unsigned char base64_encoded_data[MAX_BASE64_STRING_LEN];
4231 unsigned char base64_encoded_input[MAX_BASE64_STRING_LEN];
4232 int keySize,
4233 saltSize,
4234 outputLen;
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,
4243 keySize);
4245 memcpy(base64_encoded_input + keySize,
4246 attr_p->attr.srtp_context.master_salt,
4247 saltSize);
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
4265 * they were set.
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);
4280 return SDP_SUCCESS;
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);
4304 } else {
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);
4313 return SDP_SUCCESS;
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.
4329 * Inputs:
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
4336 sdp_result_e
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;
4343 int k = 0;
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",
4361 sdp_p->debug_str);
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) {
4407 tmp[k++] = *ptr++;
4410 if ((k) && (k < SDP_MAX_STRING_LEN)) {
4411 tmp[k] = 0;
4412 attr_p->attr.srtp_context.session_parameters = cpr_strdup(tmp);
4415 return SDP_SUCCESS;
4419 /* Parses crypto attribute based on the sdescriptions version
4420 * 9 grammar.
4424 sdp_result_e
4425 sdp_parse_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
4426 const char *ptr)
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
4435 * 2 grammar.
4439 sdp_result_e sdp_parse_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
4440 const char *ptr)
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,
4449 flex_string *fs) {
4450 flex_string_sprintf(fs, "a=%s:%s\r\n",
4451 sdp_get_attr_name(attr_p->type),
4452 attr_p->attr.ice_attr);
4454 return SDP_SUCCESS;
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,
4480 flex_string *fs) {
4481 flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
4483 return SDP_SUCCESS;
4487 sdp_result_e sdp_parse_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
4488 const char *ptr) {
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);
4511 } else {
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),
4515 buf);
4517 return (SDP_SUCCESS);
4521 sdp_result_e sdp_parse_attr_complete_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
4522 const char *ptr)
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,
4530 const char *ptr)
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);
4540 return result;
4543 sdp_result_e sdp_build_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
4544 flex_string *fs)
4546 flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
4547 attr_p->attr.stringp);
4548 return SDP_SUCCESS;
4551 sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p,
4552 sdp_attr_t *attr_p,
4553 flex_string *fs)
4555 flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name);
4557 /* Payload Type */
4558 if (attr_p->attr.rtcp_fb.payload_num == SDP_ALL_PAYLOADS) {
4559 flex_string_sprintf(fs, "* ");
4560 } else {
4561 flex_string_sprintf(fs, "%d ",attr_p->attr.rtcp_fb.payload_num);
4564 /* Feedback Type */
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]
4576 .name);
4578 break;
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]
4583 .name);
4585 break;
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]
4591 .name);
4593 break;
4594 case SDP_RTCP_FB_TRR_INT:
4595 flex_string_sprintf(fs, " %u", attr_p->attr.rtcp_fb.param.trr_int);
4596 break;
4597 case SDP_RTCP_FB_REMB:
4598 /* No additional params after REMB */
4599 break;
4600 case SDP_RTCP_FB_TRANSPORT_CC:
4601 /* No additional params after Transport-CC */
4602 break;
4604 case SDP_RTCP_FB_UNKNOWN:
4605 /* Contents are in the "extra" field */
4606 break;
4608 default:
4609 SDPLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)",
4610 sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type);
4611 return SDP_FAILURE;
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);
4620 /* Line ending */
4621 flex_string_sprintf(fs, "\r\n");
4623 return SDP_SUCCESS;
4626 sdp_result_e sdp_parse_attr_rtcp_fb (sdp_t *sdp_p,
4627 sdp_attr_t *attr_p,
4628 const char *ptr)
4630 sdp_result_e result = SDP_SUCCESS;
4631 sdp_fmtp_fb_t *rtcp_fb_p = &(attr_p->attr.rtcp_fb);
4632 int i;
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') {
4641 ptr++;
4644 /* Look for the special "*" payload type */
4645 if (*ptr == '*') {
4646 rtcp_fb_p->payload_num = SDP_ALL_PAYLOADS;
4647 ptr++;
4648 } else {
4649 /* If the pt is not '*', parse it out as an integer */
4650 rtcp_fb_p->payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
4651 " \t", &result);
4652 if (result != SDP_SUCCESS) {
4653 sdp_parse_error(sdp_p,
4654 "%s Warning: could not parse payload type for rtcp-fb attribute",
4655 sdp_p->debug_str);
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);
4665 if (i < 0) {
4666 sdp_parse_error(sdp_p,
4667 "%s Warning: could not parse feedback type for rtcp-fb attribute",
4668 sdp_p->debug_str);
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);
4679 if (i < 0) {
4680 sdp_parse_error(sdp_p,
4681 "%s Warning: could not parse ack type for rtcp-fb attribute",
4682 sdp_p->debug_str);
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;
4687 break;
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);
4693 if (i < 0) {
4694 sdp_parse_error(sdp_p,
4695 "%s Warning: could not parse ccm type for rtcp-fb attribute",
4696 sdp_p->debug_str);
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"
4706 Bug 1097169.
4708 break;
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') {
4714 ptr++;
4716 /* Check for empty string */
4717 if (*ptr == '\r' || *ptr == '\n') {
4718 rtcp_fb_p->param.nack = SDP_RTCP_FB_NACK_BASIC;
4719 break;
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);
4724 if (i < 0) {
4725 sdp_parse_error(sdp_p,
4726 "%s Warning: could not parse nack type for rtcp-fb attribute",
4727 sdp_p->debug_str);
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;
4732 break;
4734 case SDP_RTCP_FB_TRR_INT:
4735 rtcp_fb_p->param.trr_int = sdp_getnextnumtok(ptr, &ptr,
4736 " \t", &result);
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;
4744 break;
4746 case SDP_RTCP_FB_REMB:
4747 /* No additional tokens to parse after goog-remb */
4748 break;
4750 case SDP_RTCP_FB_TRANSPORT_CC:
4751 /* No additional tokens to parse after transport-cc */
4752 break;
4754 case SDP_RTCP_FB_UNKNOWN:
4755 /* Handled by "extra", below */
4756 break;
4758 default:
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);
4762 return SDP_FAILURE;
4765 /* Skip any remaining WS */
4766 while (*ptr == ' ' || *ptr == '\t') {
4767 ptr++;
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);
4775 return SDP_SUCCESS;
4778 sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p,
4779 sdp_attr_t *attr_p,
4780 flex_string *fs)
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);
4790 break;
4791 default:
4792 SDPLogError(logTag, "%s Error: Invalid setup enum (%d)",
4793 sdp_p->debug_str, attr_p->attr.setup);
4794 return SDP_FAILURE;
4797 return SDP_SUCCESS;
4800 sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p,
4801 sdp_attr_t *attr_p,
4802 const char *ptr)
4804 int i = find_token_enum("setup attribute", sdp_p, &ptr,
4805 sdp_setup_type_val,
4806 SDP_MAX_SETUP, SDP_SETUP_UNKNOWN);
4808 if (i < 0) {
4809 sdp_parse_error(sdp_p,
4810 "%s Warning: could not parse setup attribute",
4811 sdp_p->debug_str);
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 */
4824 break;
4825 case SDP_SETUP_UNKNOWN:
4826 sdp_parse_error(sdp_p,
4827 "%s Warning: Unknown setup attribute",
4828 sdp_p->debug_str);
4829 return SDP_INVALID_PARAMETER;
4830 default:
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);
4834 return SDP_FAILURE;
4837 return SDP_SUCCESS;
4840 sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
4841 sdp_attr_t *attr_p,
4842 flex_string *fs)
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);
4850 break;
4851 default:
4852 SDPLogError(logTag, "%s Error: Invalid connection enum (%d)",
4853 sdp_p->debug_str, attr_p->attr.connection);
4854 return SDP_FAILURE;
4857 return SDP_SUCCESS;
4860 sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
4861 sdp_attr_t *attr_p,
4862 const char *ptr)
4864 int i = find_token_enum("connection attribute", sdp_p, &ptr,
4865 sdp_connection_type_val,
4866 SDP_MAX_CONNECTION, SDP_CONNECTION_UNKNOWN);
4868 if (i < 0) {
4869 sdp_parse_error(sdp_p,
4870 "%s Warning: could not parse connection attribute",
4871 sdp_p->debug_str);
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 */
4882 break;
4883 case SDP_CONNECTION_UNKNOWN:
4884 sdp_parse_error(sdp_p,
4885 "%s Warning: Unknown connection attribute",
4886 sdp_p->debug_str);
4887 return SDP_INVALID_PARAMETER;
4888 default:
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);
4892 return SDP_FAILURE;
4894 return SDP_SUCCESS;
4897 sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
4898 sdp_attr_t *attr_p,
4899 flex_string *fs)
4901 flex_string_sprintf(fs, "a=extmap:%d %s\r\n",
4902 attr_p->attr.extmap.id,
4903 attr_p->attr.extmap.uri);
4905 return SDP_SUCCESS;
4908 sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
4909 sdp_attr_t *attr_p,
4910 const char *ptr)
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);
4931 if (*ptr == '/') {
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;
4952 } else {
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') {
4973 ++ptr;
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,
4994 sdp_attr_t *attr_p,
4995 const char *ptr)
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",
5003 sdp_p->debug_str);
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",
5012 sdp_p->debug_str);
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);
5025 return SDP_SUCCESS;
5029 sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p,
5030 sdp_attr_t *attr_p,
5031 flex_string *fs)
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);
5037 return SDP_SUCCESS;
5040 sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p,
5041 sdp_attr_t *attr_p,
5042 const char *ptr)
5044 sdp_result_e result;
5045 int i;
5047 ptr = sdp_getnextstrtok(ptr,
5048 attr_p->attr.msid_semantic.semantic,
5049 sizeof(attr_p->attr.msid_semantic.semantic),
5050 " \t",
5051 &result);
5053 if (result != SDP_SUCCESS) {
5054 sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute; "
5055 "missing semantic",
5056 sdp_p->debug_str);
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 */
5063 char temp[65];
5064 ptr = sdp_getnextstrtok(ptr, temp, sizeof(temp), " \t", &result);
5066 if (result != SDP_SUCCESS) {
5067 break;
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",
5075 sdp_p->debug_str);
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]) {
5085 break;
5088 SDP_PRINT("%s ... msid %s", sdp_p->debug_str,
5089 attr_p->attr.msid_semantic.msids[i]);
5093 return SDP_SUCCESS;
5097 sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p,
5098 sdp_attr_t *attr_p,
5099 flex_string *fs)
5101 int i;
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]) {
5106 break;
5109 flex_string_sprintf(fs, " %s",
5110 attr_p->attr.msid_semantic.msids[i]);
5112 flex_string_sprintf(fs, "\r\n");
5113 return SDP_SUCCESS;
5116 sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p,
5117 sdp_attr_t *attr_p,
5118 const char *ptr)
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",
5127 sdp_p->debug_str);
5128 sdp_p->conf_p->num_invalid_param++;
5129 return SDP_INVALID_PARAMETER;
5132 /* Skip any remaining WS */
5133 while (*ptr == ' ' || *ptr == '\t') {
5134 ptr++;
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),
5142 "\r\n",
5143 &result);
5145 return SDP_SUCCESS;
5149 sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p,
5150 sdp_attr_t *attr_p,
5151 flex_string *fs)
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);
5157 return SDP_SUCCESS;
5161 sdp_result_e sdp_parse_attr_ssrc_group(sdp_t *sdp_p, sdp_attr_t *attr_p,
5162 const char *ptr)
5164 sdp_result_e result;
5165 char tmp[SDP_MAX_STRING_LEN + 1];
5166 int i;
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",
5174 sdp_p->debug_str);
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;
5184 break;
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) {
5199 break;
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,
5235 flex_string *fs)
5237 int i;
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);