comparison stream/freesdp/parser.c @ 19271:64d82a45a05d

introduce new 'stream' directory for all stream layer related components and split them from libmpdemux
author ben
date Mon, 31 Jul 2006 17:39:17 +0000
parents libmpdemux/freesdp/parser.c@af9b014311a5
children 8ed444639678
comparison
equal deleted inserted replaced
19270:7d39b911f0bd 19271:64d82a45a05d
1 /*
2 This file is part of FreeSDP
3 Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org>
4
5 FreeSDP is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Benjamin Zores, (C) 2006
20 added support in parser for the a=control: lines.
21 added support in parser for the a=range: lines.
22 */
23
24 /**
25 * @file parser.c
26 *
27 * @short Parsing module implementation.
28 *
29 * This file implements the parsing routine <code>fsdp_parse</code>
30 * and the <code>fsdp_get_xxxx</code> routines that allow to get the
31 * session properties from a session description object build through
32 * the application of <code>fsdp_parse</code> to a textual SDP session
33 * description.
34 **/
35
36 #include "parserpriv.h"
37
38 /**
39 * Moves the <code>c<code> pointer up to the beginning of the next
40 * line.
41 *
42 * @param c char pointer to pointer
43 * @retval FSDPE_ILLEGAL_CHARACTER, when an illegal '\r' character
44 * (not followed by a '\n') is found, returns
45 */
46 #define NEXT_LINE(c) \
47 ({ \
48 while ((*(c) != '\0') && (*(c) != '\r') && (*(c) != '\n')) { \
49 (c)++; \
50 } \
51 if (*(c) == '\n') { \
52 (c)++; \
53 } else if (*(c) == '\r') { \
54 (c)++; \
55 if (*(c) == '\n') { \
56 (c)++; \
57 } else { \
58 return FSDPE_ILLEGAL_CHARACTER; \
59 } \
60 } \
61 })
62
63 fsdp_error_t
64 fsdp_parse (const char *text_description, fsdp_description_t * dsc)
65 {
66 fsdp_error_t result;
67 const char *p = text_description, *p2;
68 unsigned int index, j;
69 /* temps for sscanf */
70 const unsigned int TEMPCHARS = 6;
71 char fsdp_buf[TEMPCHARS][MAXSHORTFIELDLEN];
72 char longfsdp_buf[MAXLONGFIELDLEN];
73 const unsigned int TEMPINTS = 2;
74 unsigned long int wuint[TEMPINTS];
75
76 if ((NULL == text_description) || (NULL == dsc))
77 return FSDPE_INVALID_PARAMETER;
78
79 /***************************************************************************/
80 /* A) parse session-level description */
81 /***************************************************************************/
82
83 /* `v=' line (protocol version) */
84 /* according to the RFC, only `v=0' is valid */
85 if (sscanf (p, "v=%1lu", &wuint[0]))
86 {
87 if (wuint[0] != 0)
88 return FSDPE_INVALID_VERSION;
89 }
90 else
91 {
92 return FSDPE_MISSING_VERSION;
93 }
94 NEXT_LINE (p);
95
96 /* `o=' line (owner/creator and session identifier) */
97 /* o=<username> <session id> <version> <network type> <address type>
98 <address> */
99 if (!strncmp (p, "o=", 2))
100 {
101 p += 2;
102 /* note that the following max lengths may vary in the future and
103 are quite arbitary */
104 if (sscanf
105 (p,
106 "%" MSFLENS "[\x21-\xFF] %" MSFLENS "[0-9] %" MSFLENS
107 "[0-9] %2s %3s %" MSFLENS "s", fsdp_buf[0], fsdp_buf[1],
108 fsdp_buf[2], fsdp_buf[3], fsdp_buf[4], fsdp_buf[5]) != 6)
109 return FSDPE_INVALID_OWNER;
110 dsc->o_username = strdup (fsdp_buf[0]);
111 dsc->o_session_id = strdup (fsdp_buf[1]);
112 dsc->o_announcement_version = strdup (fsdp_buf[2]);
113 if (!strncmp (fsdp_buf[3], "IN", 2))
114 {
115 dsc->o_network_type = FSDP_NETWORK_TYPE_INET;
116 if (!strncmp (fsdp_buf[4], "IP4", 3))
117 dsc->o_address_type = FSDP_ADDRESS_TYPE_IPV4;
118 else if (!strncmp (fsdp_buf[4], "IP6", 3))
119 dsc->o_address_type = FSDP_ADDRESS_TYPE_IPV6;
120 else
121 return FSDPE_INVALID_OWNER;
122 }
123 else
124 {
125 return FSDPE_INVALID_OWNER;
126 }
127 /* TODO? check valid unicast address/FQDN */
128 dsc->o_address = strdup (fsdp_buf[5]);
129 }
130 else
131 {
132 return FSDPE_MISSING_OWNER;
133 }
134 NEXT_LINE (p);
135
136 /* `s=' line (session name) -note that the name string cannot be empty */
137 /* s=<session name> */
138 if (!strncmp (p, "s=", 2))
139 {
140 if (sscanf (p, "s=%" MLFLENS "[^\r\n]", longfsdp_buf) < 1)
141 return FSDPE_EMPTY_NAME;
142 dsc->s_name = strdup (longfsdp_buf);
143 }
144 else
145 {
146 return FSDPE_MISSING_NAME;
147 }
148 NEXT_LINE (p);
149
150 /* `i=' line (session information) [optional] */
151 /* i=<session description> */
152 if (!strncmp (p, "i=", 2)
153 && sscanf (p, "i=%" MLFLENS "[^\r\n]", longfsdp_buf))
154 {
155 dsc->i_information = strdup (longfsdp_buf);
156 NEXT_LINE (p);
157 }
158 else
159 {
160 /* (optional) information absent */
161 }
162
163 /* `u=' line (URI of description) [optional] */
164 /* u=<URI> */
165 if (!strncmp (p, "u=", 2)
166 && sscanf (p, "u=%" MLFLENS "[^\r\n]", longfsdp_buf))
167 {
168 /* TODO? check valid uri */
169 dsc->u_uri = strdup (longfsdp_buf);
170 NEXT_LINE (p);
171 }
172 else
173 {
174 /* (optional) uri absent */
175 }
176
177 /* `e=' lines (email address) [zero or more] */
178 /* e=<email address> */
179 p2 = p;
180 j = 0;
181 while (!strncmp (p2, "e=", 2))
182 {
183 /* First, count how many emails are there */
184 j++;
185 NEXT_LINE (p2);
186 }
187 dsc->emails_count = j;
188 if (dsc->emails_count > 0)
189 {
190 /* Then, build the array of emails */
191 dsc->emails = calloc (j, sizeof (const char *));
192 for (j = 0; j < dsc->emails_count; j++)
193 {
194 sscanf (p, "e=%" MLFLENS "[^\r\n]", longfsdp_buf);
195 /* TODO? check valid email-address. */
196 dsc->emails[j] = strdup (longfsdp_buf);
197 NEXT_LINE (p);
198 }
199 }
200
201 /* `p=' lines (phone number) [zero or more] */
202 /* p=<phone number> */
203 j = 0;
204 /* assert ( p2 == p ); */
205 while (!strncmp (p2, "p=", 2))
206 {
207 j++;
208 NEXT_LINE (p2);
209 }
210 dsc->phones_count = j;
211 if (dsc->phones_count > 0)
212 {
213 dsc->phones = calloc (j, sizeof (const char *));
214 for (j = 0; j < dsc->phones_count; j++)
215 {
216 sscanf (p, "p=%" MLFLENS "[^\r\n]", longfsdp_buf);
217 /* TODO? check valid phone-number. */
218 dsc->phones[j] = strdup (longfsdp_buf);
219 NEXT_LINE (p);
220 }
221 }
222
223 /* `c=' line (connection information - not required if included in all media) [optional] */
224 /* c=<network type> <address type> <connection address> */
225 result = fsdp_parse_c (&p, &(dsc->c_network_type), &(dsc->c_address_type),
226 &(dsc->c_address));
227 if (FSDPE_OK != result)
228 return result;
229
230 /* `b=' lines (bandwidth information) [optional] */
231 /* b=<modifier>:<bandwidth-value> */
232 result =
233 fsdp_parse_b (&p, &(dsc->bw_modifiers), &(dsc->bw_modifiers_count));
234 if (FSDPE_OK != result)
235 return result;
236
237 /* A.1) Time descriptions: */
238
239 /* `t=' lines (time the session is active) [1 or more] */
240 /* t=<start time> <stop time> */
241 j = 0;
242 p2 = p;
243 while (!strncmp (p2, "t=", 2))
244 {
245 j++;
246 NEXT_LINE (p2);
247 while (!strncmp (p2, "r=", 2))
248 NEXT_LINE (p2);
249 }
250 dsc->time_periods_count = j;
251 if (dsc->time_periods_count == 0)
252 return FSDPE_MISSING_TIME;
253 dsc->time_periods = calloc (dsc->time_periods_count,
254 sizeof (fsdp_time_period_t *));
255 index = 0;
256 for (j = 0; j < dsc->time_periods_count; j++)
257 {
258 unsigned int h = 0;
259 if (sscanf (p, "t=%10lu %10lu", &wuint[0], &wuint[1]) != 2)
260 {
261 /* not all periods have been successfully parsed */
262 dsc->time_periods_count = j;
263 return FSDPE_INVALID_TIME;
264 }
265 dsc->time_periods[j] = calloc (1, sizeof (fsdp_time_period_t));
266
267 /* convert from NTP to time_t time */
268 if (wuint[0] != 0)
269 wuint[0] -= NTP_EPOCH_OFFSET;
270 if (wuint[1] != 0)
271 wuint[1] -= NTP_EPOCH_OFFSET;
272 dsc->time_periods[j]->start = wuint[0];
273 dsc->time_periods[j]->stop = wuint[1];
274 NEXT_LINE (p);
275
276 /* `r' lines [zero or more repeat times for each t=] */
277 /*r=<repeat interval> <active duration> <list of offsets from
278 start-time> */
279 p2 = p;
280 while (!strncmp (p2, "r=", 2))
281 {
282 h++;
283 NEXT_LINE (p2);
284 }
285 dsc->time_periods[j]->repeats_count = h;
286 if (h > 0)
287 {
288 unsigned int index2 = 0;
289 dsc->time_periods[j]->repeats =
290 calloc (h, sizeof (fsdp_repeat_t *));
291 for (h = 0; h < dsc->time_periods[j]->repeats_count; h++)
292 {
293 /*
294 get_repeat_values(p,&(dsc->time_periods[index].repeats[index2]));
295 fsdp_error_t get_repeat_values (const char *r, fsdp_repeat_t
296 *repeat);
297 */
298 if (sscanf (p, "r=%10s %10s %" MLFLENS "[^\r\n]",
299 fsdp_buf[0], fsdp_buf[1], longfsdp_buf) == 3)
300 {
301 fsdp_repeat_t *repeat;
302 dsc->time_periods[j]->repeats[h] =
303 calloc (1, sizeof (fsdp_repeat_t));
304 repeat = dsc->time_periods[j]->repeats[h];
305 /* get interval, duration and list of offsets */
306 result =
307 fsdp_repeat_time_to_uint (fsdp_buf[0],
308 &(repeat->interval));
309 if (result == FSDPE_OK)
310 {
311 result =
312 fsdp_repeat_time_to_uint (fsdp_buf[1],
313 &(repeat->duration));
314 if (result == FSDPE_OK)
315 {
316 unsigned int k = 1;
317 const char *i = longfsdp_buf;
318 while (NULL != (i = strchr (i, ' ')))
319 {
320 k++;
321 if (NULL != i)
322 i++;
323 }
324 repeat->offsets_count = k;
325 repeat->offsets = calloc (k, sizeof (time_t));
326 i = longfsdp_buf;
327 for (k = 0;
328 (k < repeat->offsets_count)
329 && (result == FSDPE_OK); k++)
330 {
331 result =
332 fsdp_repeat_time_to_uint (i,
333 &(repeat->
334 offsets[k]));
335 i = strchr (i, ' ');
336 if (NULL != i)
337 i++;
338 }
339 if (k < repeat->offsets_count)
340 {
341 /* there where invalid repeat offsets */
342 dsc->time_periods[j]->repeats_count = k;
343 return FSDPE_INVALID_REPEAT;
344 }
345 }
346 }
347 if (result != FSDPE_OK)
348 {
349 /* not all repeats have been succesfully parsed */
350 dsc->time_periods[j]->repeats_count = h;
351 return FSDPE_INVALID_REPEAT;
352 }
353 NEXT_LINE (p);
354 }
355 else
356 {
357 /* not all repeats have been succesfully parsed */
358 dsc->time_periods[j]->repeats_count = h;
359 return FSDPE_INVALID_REPEAT;
360 }
361 index2++;
362 }
363 }
364 }
365
366 /* `z=' line (time zone adjustments) [zero or more] */
367 /* z=<adjustment time> <offset> <adjustment time> <offset> .... */
368 if (!strncmp (p, "z=", 2))
369 {
370 if (sscanf (p, "z=%" MLFLENS "[^\r\n]", longfsdp_buf))
371 {
372 /* TODO: guess how many pairs are there and process them */
373 dsc->timezone_adj = strdup (longfsdp_buf);
374 NEXT_LINE (p);
375 }
376 else
377 {
378 return FSDPE_INVALID_TIMEZONE;
379 }
380 }
381
382 /* `k=' line (encryption key) [optional] */
383 /* k=<method>
384 k=<method>:<encryption key> */
385 result = fsdp_parse_k (&p, &(dsc->k_encryption_method),
386 &(dsc->k_encryption_content));
387 if (result != FSDPE_OK)
388 return result;
389
390 /* A.2) Attributes */
391 /* `a=' lines (session attribute) [0 or more] */
392 /* a=<attribute>
393 a=<attribute>:<value> */
394 while (!strncmp (p, "a=", 2))
395 {
396 /* The "9" lenght specifier of the first string is subject to
397 changes */
398 if (sscanf
399 (p, "a=%9[^:\r\n]:%" MSFLENS "[^\r\n]", fsdp_buf[0],
400 fsdp_buf[1]) == 2)
401 {
402 /* session-level value attributes */
403 if (!strncmp (fsdp_buf[0], "cat", 3))
404 dsc->a_category = strdup (fsdp_buf[1]);
405 else if (!strncmp (fsdp_buf[0], "keywds", 6))
406 dsc->a_keywords = strdup (fsdp_buf[1]);
407 else if (!strncmp (fsdp_buf[0], "tool", 4))
408 dsc->a_keywords = strdup (fsdp_buf[1]);
409 else if (!strncmp (fsdp_buf[0], "rtpmap", 6))
410 fsdp_parse_rtpmap (&(dsc->a_rtpmaps),
411 &(dsc->a_rtpmaps_count), fsdp_buf[1]);
412 else if (!strncmp (fsdp_buf[0], "type", 4))
413 {
414 if (!strncmp (fsdp_buf[1], "broadcast", 9))
415 dsc->a_type = FSDP_SESSION_TYPE_BROADCAST;
416 else if (!strncmp (fsdp_buf[1], "meeting", 7))
417 dsc->a_type = FSDP_SESSION_TYPE_MEETING;
418 else if (!strncmp (fsdp_buf[1], "moderated", 9))
419 dsc->a_type = FSDP_SESSION_TYPE_MODERATED;
420 else if (!strncmp (fsdp_buf[1], "test", 4))
421 dsc->a_type = FSDP_SESSION_TYPE_TEST;
422 else if (!strncmp (fsdp_buf[1], "H332", 4))
423 dsc->a_type = FSDP_SESSION_TYPE_H332;
424 else
425 return FSDPE_INVALID_SESSION_TYPE;
426 }
427 else if (!strncmp (fsdp_buf[0], "charset", 7))
428 dsc->a_charset = strdup (fsdp_buf[1]);
429 else if (!strncmp (fsdp_buf[0], "sdplang", 7))
430 {
431 if (NULL == dsc->a_sdplangs)
432 {
433 dsc->a_sdplangs_count = 0;
434 dsc->a_sdplangs =
435 calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
436 }
437 if (dsc->a_sdplangs_count < SDPLANGS_MAX_COUNT)
438 {
439 dsc->a_sdplangs[dsc->a_sdplangs_count] =
440 strdup (fsdp_buf[1]);
441 dsc->a_sdplangs_count++;
442 }
443 }
444 else if (!strncmp (fsdp_buf[0], "lang", 4))
445 {
446 if (NULL == dsc->a_langs)
447 {
448 dsc->a_langs_count = 0;
449 dsc->a_langs = calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
450 }
451 if (dsc->a_langs_count < SDPLANGS_MAX_COUNT)
452 {
453 dsc->a_langs[dsc->a_langs_count] = strdup (fsdp_buf[1]);
454 dsc->a_langs_count++;
455 }
456 }
457 else if (!strncmp (fsdp_buf[0], "control", 7))
458 {
459 if (NULL == dsc->a_controls)
460 {
461 dsc->a_controls_count = 0;
462 dsc->a_controls =
463 calloc (SDPCONTROLS_MAX_COUNT, sizeof (char *));
464 }
465 if (dsc->a_controls_count < SDPCONTROLS_MAX_COUNT)
466 {
467 dsc->a_controls[dsc->a_controls_count] =
468 strdup (fsdp_buf[1]);
469 dsc->a_controls_count++;
470 }
471 }
472 else if (!strncmp (fsdp_buf[0], "range", 5))
473 {
474 if (dsc->a_range)
475 free (dsc->a_range);
476 dsc->a_range = strdup (fsdp_buf[1]);
477 }
478 else
479 {
480 /* ignore unknown attributes, but provide access to them */
481 *longfsdp_buf = '\0';
482 strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN);
483 strncat (longfsdp_buf, ":", MAXLONGFIELDLEN);
484 strncat (longfsdp_buf, fsdp_buf[1], MAXLONGFIELDLEN);
485 if (NULL == dsc->unidentified_attributes)
486 {
487 dsc->unidentified_attributes_count = 0;
488 dsc->unidentified_attributes =
489 calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT,
490 sizeof (char *));
491 }
492 if (dsc->unidentified_attributes_count <
493 UNIDENTIFIED_ATTRIBUTES_MAX_COUNT)
494 {
495 dsc->unidentified_attributes
496 [dsc->unidentified_attributes_count] =
497 strdup (longfsdp_buf);
498 dsc->unidentified_attributes_count++;
499 }
500 }
501 NEXT_LINE (p);
502 }
503 else if (sscanf (p, "a=%20s", fsdp_buf[0]) == 1)
504 {
505 /* session-level property attributes */
506 if (!strncmp (fsdp_buf[0], "recvonly", 8))
507 dsc->a_sendrecv_mode = FSDP_SENDRECV_RECVONLY;
508 else if (!strncmp (fsdp_buf[0], "sendonly", 8))
509 dsc->a_sendrecv_mode = FSDP_SENDRECV_SENDONLY;
510 else if (!strncmp (fsdp_buf[0], "inactive", 8))
511 dsc->a_sendrecv_mode = FSDP_SENDRECV_INACTIVE;
512 else if (!strncmp (fsdp_buf[0], "sendrecv", 8))
513 dsc->a_sendrecv_mode = FSDP_SENDRECV_SENDRECV;
514 else
515 {
516 /* ignore unknown attributes, but provide access to them */
517 *longfsdp_buf = '\0';
518 strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN);
519 if (NULL == dsc->unidentified_attributes)
520 {
521 dsc->unidentified_attributes_count = 0;
522 dsc->unidentified_attributes =
523 calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT,
524 sizeof (char *));
525 }
526 if (dsc->unidentified_attributes_count <
527 UNIDENTIFIED_ATTRIBUTES_MAX_COUNT)
528 {
529 dsc->unidentified_attributes
530 [dsc->unidentified_attributes_count] =
531 strdup (longfsdp_buf);
532 dsc->unidentified_attributes_count++;
533 }
534 }
535 NEXT_LINE (p);
536 }
537 else
538 return FSDPE_INVALID_ATTRIBUTE;
539 }
540
541 /***************************************************************************/
542 /* B) parse media-level descriptions */
543 /***************************************************************************/
544 p2 = p;
545 j = 0;
546 while ((*p2 != '\0') && !strncmp (p2, "m=", 2))
547 {
548 char c;
549 j++;
550 NEXT_LINE (p2);
551 while (sscanf (p2, "%c=", &c) == 1)
552 {
553 if (c == 'i' || c == 'c' || c == 'b' || c == 'k' || c == 'a')
554 {
555 NEXT_LINE (p2);
556 }
557 else if (c == 'm')
558 {
559 break;
560 }
561 else
562 {
563 return FSDPE_INVALID_LINE;
564 }
565 }
566 }
567 dsc->media_announcements_count = j;
568 if (dsc->media_announcements_count == 0)
569 {
570 ;
571 /*return FSDPE_MISSING_MEDIA; */
572 }
573 else
574 { /* dsc->media_announcements_count > 0 */
575 dsc->media_announcements =
576 calloc (j, sizeof (fsdp_media_announcement_t *));
577 for (j = 0; j < dsc->media_announcements_count; j++)
578 {
579 fsdp_media_announcement_t *media = NULL;
580 /* `m=' line (media name, transport address and format list) */
581 /* m=<media> <port> <transport> <fmt list> */
582 /* The max. string lengths are subject to change */
583 if (sscanf (p, "m=%11s %8s %7s %" MLFLENS "[^\r\n]",
584 fsdp_buf[0], fsdp_buf[1], fsdp_buf[2],
585 longfsdp_buf) != 4)
586 {
587 return FSDPE_INVALID_MEDIA;
588 }
589 else
590 {
591 dsc->media_announcements[j] =
592 calloc (1, sizeof (fsdp_media_announcement_t));
593 media = dsc->media_announcements[j];
594 if (!strncmp (fsdp_buf[0], "audio", 5))
595 media->media_type = FSDP_MEDIA_AUDIO;
596 else if (!strncmp (fsdp_buf[0], "video", 5))
597 media->media_type = FSDP_MEDIA_VIDEO;
598 else if (!strncmp (fsdp_buf[0], "application", 11))
599 media->media_type = FSDP_MEDIA_APPLICATION;
600 else if (!strncmp (fsdp_buf[0], "data", 4))
601 media->media_type = FSDP_MEDIA_DATA;
602 else if (!strncmp (fsdp_buf[0], "control", 7))
603 media->media_type = FSDP_MEDIA_CONTROL;
604 else
605 return FSDPE_UNKNOWN_MEDIA_TYPE;
606 { /* try to get port specification as port/number */
607 char *slash;
608 if ((slash = strchr (fsdp_buf[1], '/')))
609 {
610 *slash = '\0';
611 slash++;
612 media->port = strtol (fsdp_buf[1], NULL, 10);
613 media->port_count = strtol (slash, NULL, 10);
614 }
615 else
616 {
617 media->port = strtol (fsdp_buf[1], NULL, 10);
618 media->port_count = 0;
619 }
620 }
621 if (!strncmp (fsdp_buf[2], "RTP/AVP", 7))
622 media->transport = FSDP_TP_RTP_AVP;
623 else if (!strncmp (fsdp_buf[2], "udp", 3))
624 media->transport = FSDP_TP_UDP;
625 else if (!strncmp (fsdp_buf[2], "TCP", 3))
626 media->transport = FSDP_TP_TCP;
627 else if (!strncmp (fsdp_buf[2], "UDPTL", 5))
628 media->transport = FSDP_TP_UDPTL;
629 else if (!strncmp (fsdp_buf[2], "vat", 3))
630 media->transport = FSDP_TP_VAT;
631 else if (!strncmp (fsdp_buf[2], "rtp", 3))
632 media->transport = FSDP_TP_OLD_RTP;
633 else
634 return FSDPE_UNKNOWN_MEDIA_TRANSPORT;
635 {
636 unsigned int k = 0;
637 char *s = longfsdp_buf;
638 while (NULL != (s = strchr (s, ' ')))
639 {
640 k++;
641 if (NULL != s)
642 s++;
643 }
644 k++; /* when there is no space left, count the last format */
645 media->formats_count = k;
646 media->formats = calloc (k, sizeof (char *));
647 s = longfsdp_buf;
648 for (k = 0; k < media->formats_count; k++)
649 {
650 char *space = strchr (s, ' ');
651 if (NULL != space)
652 *space = '\0';
653 media->formats[k] = strdup (s);
654 s = space + 1;
655 }
656 }
657 NEXT_LINE (p);
658 }
659
660 /* `i=' line (media title) [optional] */
661 /* i=<media title> */
662 if (!strncmp (p, "i=", 2)
663 && sscanf (p, "i=%" MLFLENS "[^\r\n]", longfsdp_buf))
664 {
665 media->i_title = strdup (longfsdp_buf);
666 NEXT_LINE (p);
667 }
668 else
669 {
670 /* (optional) information absent */
671 }
672
673 /* `c=' line (connection information - overrides session-level
674 line) [optional if provided at session-level] */
675 /* c=<network type> <address type> <connection address> */
676 result = fsdp_parse_c (&p, &(media->c_network_type),
677 &(media->c_address_type),
678 &(media->c_address));
679 if (result != FSDPE_OK)
680 return result;
681
682 /* `b=' lines (bandwidth information) [optional] */
683 /* b=<modifier>:<bandwidth-value> */
684 result = fsdp_parse_b (&p, &(media->bw_modifiers),
685 &(media->bw_modifiers_count));
686 if (FSDPE_OK != result)
687 return result;
688
689 /* `k=' line (encryption key) [optional] */
690 /* k=<method>
691 k=<method>:<encryption key> */
692 result = fsdp_parse_k (&p, &(media->k_encryption_method),
693 &(media->k_encryption_content));
694 if (result != FSDPE_OK)
695 return result;
696
697 /* B.1) Attributes */
698
699 /* `a=' lines (zero or more media attribute lines) [optional] */
700 /* a=<attribute>
701 a=<attribute>:<value> */
702 while (!strncmp (p, "a=", 2))
703 {
704 if (sscanf
705 (p, "a=%9[^:\r\n]:%" MLFLENS "[^\r\n]", fsdp_buf[0],
706 longfsdp_buf) == 2)
707 {
708 /* media-level value attributes */
709 if (!strncmp (fsdp_buf[0], "ptime", 5))
710 media->a_ptime = strtoul (longfsdp_buf, NULL, 10);
711 else if (!strncmp (fsdp_buf[0], "maxptime", 8))
712 media->a_maxptime = strtoul (longfsdp_buf, NULL, 10);
713 else if (!strncmp (fsdp_buf[0], "rtpmap", 6))
714 fsdp_parse_rtpmap (&(media->a_rtpmaps),
715 &(media->a_rtpmaps_count),
716 longfsdp_buf);
717 else if (!strncmp (fsdp_buf[0], "orient", 6))
718 {
719 if (!strncmp (longfsdp_buf, "portrait", 8))
720 media->a_orient = FSDP_ORIENT_PORTRAIT;
721 else if (!strncmp (longfsdp_buf, "landscape", 9))
722 media->a_orient = FSDP_ORIENT_LANDSCAPE;
723 else if (!strncmp (longfsdp_buf, "seascape", 9))
724 media->a_orient = FSDP_ORIENT_SEASCAPE;
725 }
726 else if (!strncmp (fsdp_buf[0], "sdplang", 7))
727 {
728 if (NULL == dsc->a_sdplangs)
729 {
730 media->a_sdplangs_count = 0;
731 media->a_sdplangs =
732 calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
733 }
734 if (media->a_sdplangs_count < SDPLANGS_MAX_COUNT)
735 {
736 media->a_sdplangs[dsc->a_sdplangs_count] =
737 strdup (longfsdp_buf);
738 media->a_sdplangs_count++;
739 }
740 }
741 else if (!strncmp (fsdp_buf[0], "lang", 4))
742 {
743 if (NULL == dsc->a_langs)
744 {
745 media->a_langs_count = 0;
746 media->a_langs =
747 calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
748 }
749 if (media->a_langs_count < SDPLANGS_MAX_COUNT)
750 {
751 media->a_langs[dsc->a_langs_count] =
752 strdup (longfsdp_buf);
753 media->a_langs_count++;
754 }
755 }
756 else if (!strncmp (fsdp_buf[0], "control", 7))
757 {
758 if (NULL == media->a_controls)
759 {
760 media->a_controls_count = 0;
761 media->a_controls =
762 calloc (SDPCONTROLS_MAX_COUNT, sizeof (char *));
763 }
764 if (media->a_controls_count < SDPCONTROLS_MAX_COUNT)
765 {
766 media->a_controls[media->a_controls_count] =
767 strdup (longfsdp_buf);
768 media->a_controls_count++;
769 }
770 }
771 else if (!strncmp (fsdp_buf[0], "range", 5))
772 {
773 if (media->a_range)
774 free (media->a_range);
775 media->a_range = strdup (fsdp_buf[1]);
776 }
777 else if (!strncmp (fsdp_buf[0], "framerate", 9))
778 media->a_framerate = strtod (longfsdp_buf, NULL);
779 else if (!strncmp (fsdp_buf[0], "fmtp", 4))
780 {
781 if (NULL == media->a_fmtps)
782 {
783 media->a_fmtps_count = 0;
784 media->a_fmtps =
785 calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
786 }
787 if (media->a_fmtps_count < SDPLANGS_MAX_COUNT)
788 {
789 media->a_fmtps[media->a_fmtps_count] =
790 strdup (longfsdp_buf);
791 media->a_fmtps_count++;
792 }
793 }
794 else if (!strncmp (fsdp_buf[0], "rtcp", 4))
795 {
796 int opts = 0;
797 /* rtcp attribute: a=rtcp:<port> <nettype> <addrtype> <address> */
798 opts =
799 sscanf (longfsdp_buf, "%lu %2s %3s %" MSFLENS "s",
800 &wuint[0], fsdp_buf[0], fsdp_buf[1],
801 fsdp_buf[2]);
802 if (opts >= 1)
803 {
804 media->a_rtcp_port = wuint[0];
805 if (opts >= 2)
806 {
807 if (!strncmp (fsdp_buf[0], "IN", 2))
808 {
809 media->a_rtcp_network_type =
810 FSDP_NETWORK_TYPE_INET;
811 } /* else
812 ; TODO: define error code? */
813 if (opts >= 3)
814 {
815 if (!strncmp (fsdp_buf[1], "IP4", 3))
816 media->a_rtcp_address_type =
817 FSDP_ADDRESS_TYPE_IPV4;
818 else if (!strncmp (fsdp_buf[1], "IP6", 3))
819 media->a_rtcp_address_type =
820 FSDP_ADDRESS_TYPE_IPV6;
821 else
822 return FSDPE_INVALID_CONNECTION_NETTYPE;
823 /*add specific code? */
824 if (opts >= 4)
825 media->a_rtcp_address =
826 strdup (fsdp_buf[2]);
827 }
828 }
829 }
830 }
831 else
832 {
833 /* ignore unknown attributes, but provide access to them */
834 *fsdp_buf[1] = '\0';
835 strncat (fsdp_buf[1], fsdp_buf[0], MAXLONGFIELDLEN);
836 strncat (fsdp_buf[1], ":", MAXLONGFIELDLEN);
837 strncat (fsdp_buf[1], longfsdp_buf, MAXLONGFIELDLEN);
838 if (NULL == media->unidentified_attributes)
839 {
840 media->unidentified_attributes_count = 0;
841 media->unidentified_attributes =
842 calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT,
843 sizeof (char *));
844 }
845 if (media->unidentified_attributes_count <
846 UNIDENTIFIED_ATTRIBUTES_MAX_COUNT)
847 {
848 media->unidentified_attributes
849 [media->unidentified_attributes_count] =
850 strdup (fsdp_buf[1]);
851 media->unidentified_attributes_count++;
852 }
853 }
854 NEXT_LINE (p);
855 }
856 else if (sscanf (p, "a=%8s", fsdp_buf[0]) == 1)
857 {
858 /* media-level property attributes */
859 if (!strncmp (fsdp_buf[0], "recvonly", 8))
860 media->a_sendrecv_mode = FSDP_SENDRECV_RECVONLY;
861 else if (!strncmp (fsdp_buf[0], "sendonly", 8))
862 media->a_sendrecv_mode = FSDP_SENDRECV_SENDONLY;
863 else if (!strncmp (fsdp_buf[0], "inactive", 8))
864 media->a_sendrecv_mode = FSDP_SENDRECV_INACTIVE;
865 else if (!strncmp (fsdp_buf[0], "sendrecv", 8))
866 media->a_sendrecv_mode = FSDP_SENDRECV_SENDRECV;
867 else
868 {
869 /* ignore unknown attributes, but provide access to them */
870 *longfsdp_buf = '\0';
871 strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN);
872 if (NULL == media->unidentified_attributes)
873 {
874 media->unidentified_attributes_count = 0;
875 media->unidentified_attributes =
876 calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT,
877 sizeof (char *));
878 }
879 if (media->unidentified_attributes_count <
880 UNIDENTIFIED_ATTRIBUTES_MAX_COUNT)
881 {
882 media->unidentified_attributes
883 [media->unidentified_attributes_count] =
884 strdup (longfsdp_buf);
885 media->unidentified_attributes_count++;
886 }
887 }
888 NEXT_LINE (p);
889 }
890 else
891 return FSDPE_INVALID_ATTRIBUTE;
892 }
893 } /* end of for */
894 }
895
896 /* Check c= has been given at session level or at media level for
897 all media */
898 if (NULL == dsc->c_address.address)
899 {
900 unsigned int c;
901 for (c = 0; c < dsc->media_announcements_count; c++)
902 if (NULL == dsc->media_announcements[c]->c_address.address)
903 return FSDPE_MISSING_CONNECTION_INFO;
904 }
905
906 /* finish */
907 if (*p == '\0')
908 return FSDPE_OK;
909 else
910 return FSDPE_OVERFILLED;
911 }
912
913 static fsdp_error_t
914 fsdp_parse_c (const char **p, fsdp_network_type_t * ntype,
915 fsdp_address_type_t * atype,
916 fsdp_connection_address_t * address)
917 {
918 const unsigned int TEMPCHARS = 3;
919 char fsdp_buf[TEMPCHARS][MAXSHORTFIELDLEN];
920
921 if (!strncmp (*p, "c=", 2))
922 {
923 if (sscanf (*p, "c=%2s %3s %" MSFLENS "s",
924 fsdp_buf[0], fsdp_buf[1], fsdp_buf[2]))
925 {
926 if (!strncmp (fsdp_buf[0], "IN", 2))
927 {
928 *ntype = FSDP_NETWORK_TYPE_INET;
929 if (!strncmp (fsdp_buf[1], "IP4", 3))
930 *atype = FSDP_ADDRESS_TYPE_IPV4;
931 else if (!strncmp (fsdp_buf[1], "IP6", 3))
932 *atype = FSDP_ADDRESS_TYPE_IPV6;
933 else
934 return FSDPE_INVALID_CONNECTION_NETTYPE;
935 }
936 else
937 {
938 return FSDPE_INVALID_CONNECTION_ADDRTYPE;
939 }
940 {
941 char *slash = strchr (fsdp_buf[2], '/');
942 if (NULL == slash)
943 {
944 address->address = strdup (fsdp_buf[2]);
945 address->address_ttl = 0;
946 address->address_count = 0;
947 }
948 else
949 {
950 /* address is IP4 multicast */
951 char *slash2;
952 *slash = '\0';
953 slash++;
954 address->address = strdup (fsdp_buf[2]);
955 slash2 = strchr (slash + 1, '/');
956 if (NULL == slash2)
957 {
958 address->address_ttl = strtol (slash, NULL, 10);
959 address->address_count = 0;
960 }
961 else
962 {
963 *slash2 = '\0';
964 slash2++;
965 address->address_ttl = strtol (slash, NULL, 10);
966 address->address_count = strtol (slash2, NULL, 10);
967 }
968 }
969 }
970 NEXT_LINE (*p);
971 }
972 else
973 {
974 return FSDPE_INVALID_CONNECTION;
975 }
976 }
977 return FSDPE_OK;
978 }
979
980 static fsdp_error_t
981 fsdp_parse_b (const char **p, fsdp_bw_modifier_t ** bw_modifiers,
982 unsigned int *bw_modifiers_count)
983 {
984 char fsdp_buf[MAXSHORTFIELDLEN];
985 unsigned long int wuint;
986 unsigned int i = 0;
987 char *lp = (char *) *p;
988
989 /* count b= lines */
990 while (!strncmp (lp, "b=", 2))
991 {
992 NEXT_LINE (lp);
993 i++;
994 }
995 *bw_modifiers = calloc (i, sizeof (fsdp_bw_modifier_t));
996 *bw_modifiers_count = i;
997
998 while (i > 0)
999 {
1000 unsigned int index = *bw_modifiers_count - i;
1001 if (2 == sscanf (*p, "b=%20[^:\r\n]:%lu", fsdp_buf, &wuint))
1002 {
1003 if (!strncmp (fsdp_buf, "CT", 2))
1004 (*bw_modifiers)[index].b_mod_type =
1005 FSDP_BW_MOD_TYPE_CONFERENCE_TOTAL;
1006 else if (!strncmp (fsdp_buf, "AS", 2))
1007 (*bw_modifiers)[index].b_mod_type =
1008 FSDP_BW_MOD_TYPE_APPLICATION_SPECIFIC;
1009 else if (!strncmp (fsdp_buf, "RS", 2))
1010 (*bw_modifiers)[index].b_mod_type = FSDP_BW_MOD_TYPE_RTCP_SENDERS;
1011 else if (!strncmp (fsdp_buf, "RR", 2))
1012 (*bw_modifiers)[index].b_mod_type =
1013 FSDP_BW_MOD_TYPE_RTCP_RECEIVERS;
1014 else
1015 {
1016 (*bw_modifiers)[index].b_mod_type = FSDP_BW_MOD_TYPE_UNKNOWN;
1017 (*bw_modifiers)[index].b_unknown_bw_modt =
1018 (char *) strdup (fsdp_buf);
1019 }
1020 (*bw_modifiers)[index].b_value = wuint;
1021 NEXT_LINE (*p);
1022 }
1023 else
1024 {
1025 *bw_modifiers_count -= i;
1026 return FSDPE_INVALID_BANDWIDTH;
1027 }
1028 i--;
1029 }
1030 return FSDPE_OK;
1031 }
1032
1033 static fsdp_error_t
1034 fsdp_parse_k (const char **p, fsdp_encryption_method_t * method,
1035 char **content)
1036 {
1037 char fsdp_buf[MAXSHORTFIELDLEN];
1038 char longfsdp_buf[MAXLONGFIELDLEN];
1039
1040 if (!strncmp (*p, "k=", 2))
1041 {
1042 if (sscanf (*p, "k=prompt"))
1043 {
1044 *method = FSDP_ENCRYPTION_METHOD_PROMPT;
1045 *content = NULL;
1046 NEXT_LINE (*p);
1047 }
1048 else
1049 {
1050 if (sscanf
1051 (*p, "k=%6[^:\r\n]:%" MLFLENS "s", fsdp_buf, longfsdp_buf))
1052 {
1053 if (!strncmp (fsdp_buf, "clear", 5))
1054 *method = FSDP_ENCRYPTION_METHOD_CLEAR;
1055 else if (!strncmp (fsdp_buf, "base64", 6))
1056 *method = FSDP_ENCRYPTION_METHOD_BASE64;
1057 else if (!strncmp (fsdp_buf, "uri", 3))
1058 *method = FSDP_ENCRYPTION_METHOD_URI;
1059 else
1060 return FSDPE_INVALID_ENCRYPTION_METHOD;
1061 *content = strdup (longfsdp_buf);
1062 NEXT_LINE (*p);
1063 }
1064 }
1065 }
1066 return FSDPE_OK;
1067 }
1068
1069 static fsdp_error_t
1070 fsdp_parse_rtpmap (fsdp_rtpmap_t *** rtpmap, unsigned int *counter,
1071 const char *value)
1072 {
1073 fsdp_error_t result = FSDPE_OK;
1074
1075 if (0 == *counter)
1076 {
1077 *counter = 0;
1078 *rtpmap = calloc (MEDIA_RTPMAPS_MAX_COUNT, sizeof (fsdp_rtpmap_t *));
1079 }
1080 if (*counter < MEDIA_RTPMAPS_MAX_COUNT)
1081 {
1082 unsigned int c = *counter;
1083 fsdp_rtpmap_t **map = *rtpmap;
1084 char fsdp_buf[MAXSHORTFIELDLEN];
1085 char longfsdp_buf[MAXLONGFIELDLEN];
1086 map[c] = calloc (1, sizeof (fsdp_rtpmap_t));
1087
1088 /* a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding
1089 parameters]> */
1090 if (2 == sscanf (value, "%s %s", fsdp_buf, longfsdp_buf))
1091 {
1092 char *slash1;
1093 map[c]->pt = strdup (fsdp_buf);
1094 /* parse <encoding name>/<clock rate>[/<encoding parameters>] */
1095 slash1 = strchr (longfsdp_buf, '/');
1096 if (NULL == slash1)
1097 {
1098 result = FSDPE_INVALID_ATTRIBUTE_RTPMAP;
1099 }
1100 else
1101 {
1102 char *slash2;
1103 *slash1 = '\0';
1104 slash1++;
1105 map[c]->encoding_name = strdup (longfsdp_buf);
1106 slash2 = strchr (slash1, '/');
1107 if (NULL != slash2)
1108 {
1109 *slash2 = '\0';
1110 slash2++;
1111 map[c]->parameters = strdup (slash2);
1112 }
1113 map[c]->clock_rate = strtol (slash1, NULL, 10);
1114 }
1115 (*counter)++;
1116 }
1117 }
1118 return result;
1119 }
1120
1121 static fsdp_error_t
1122 fsdp_repeat_time_to_uint (const char *time, unsigned long int *seconds)
1123 {
1124 const unsigned long SECONDS_PER_DAY = 86400;
1125 const unsigned long SECONDS_PER_HOUR = 3600;
1126 const unsigned long SECONDS_PER_MINUTE = 60;
1127 char c;
1128 unsigned long int wuint;
1129
1130 if (sscanf (time, "%lu%c", &wuint, &c) == 2)
1131 {
1132 /* time with unit specification character */
1133 switch (c)
1134 {
1135 case 'd':
1136 *seconds = wuint * SECONDS_PER_DAY;
1137 break;
1138 case 'h':
1139 *seconds = wuint * SECONDS_PER_HOUR;
1140 break;
1141 case 'm':
1142 *seconds = wuint * SECONDS_PER_MINUTE;
1143 break;
1144 case 's':
1145 *seconds = wuint;
1146 break;
1147 default:
1148 return FSDPE_INVALID_REPEAT;
1149 break;
1150 }
1151 }
1152 else if (sscanf (time, "%lu", &wuint) == 1)
1153 {
1154 /* time without unit specification character */
1155 *seconds = wuint;
1156 }
1157 else
1158 {
1159 return FSDPE_INVALID_REPEAT;
1160 }
1161 return FSDPE_OK;
1162 }
1163
1164 unsigned int
1165 fsdp_get_version (const fsdp_description_t * dsc)
1166 {
1167 if (!dsc)
1168 return 0;
1169 return dsc->version;
1170 }
1171
1172 const char *
1173 fsdp_get_owner_username (const fsdp_description_t * dsc)
1174 {
1175 if (!dsc)
1176 return NULL;
1177 return dsc->o_username;
1178 }
1179
1180 const char *
1181 fsdp_get_session_id (const fsdp_description_t * dsc)
1182 {
1183 if (!dsc)
1184 return NULL;
1185 return dsc->o_session_id;
1186 }
1187
1188 const char *
1189 fsdp_get_announcement_version (const fsdp_description_t * dsc)
1190 {
1191 if (!dsc)
1192 return NULL;
1193 return dsc->o_announcement_version;
1194 }
1195
1196 fsdp_network_type_t
1197 fsdp_get_owner_network_type (const fsdp_description_t * dsc)
1198 {
1199 if (!dsc)
1200 return FSDP_NETWORK_TYPE_UNDEFINED;
1201 return dsc->o_network_type;
1202 }
1203
1204 fsdp_address_type_t
1205 fsdp_get_owner_address_type (const fsdp_description_t * dsc)
1206 {
1207 if (!dsc)
1208 return FSDP_ADDRESS_TYPE_UNDEFINED;
1209 return dsc->o_address_type;
1210 }
1211
1212 const char *
1213 fsdp_get_owner_address (const fsdp_description_t * dsc)
1214 {
1215 if (!dsc)
1216 return NULL;
1217 return dsc->o_address;
1218 }
1219
1220 const char *
1221 fsdp_get_name (const fsdp_description_t * dsc)
1222 {
1223 if (!dsc)
1224 return NULL;
1225 return dsc->s_name;
1226 }
1227
1228 const char *
1229 fsdp_get_information (const fsdp_description_t * dsc)
1230 {
1231 if (!dsc)
1232 return NULL;
1233 return dsc->i_information;
1234 }
1235
1236 const char *
1237 fsdp_get_uri (const fsdp_description_t * dsc)
1238 {
1239 if (!dsc)
1240 return NULL;
1241 return dsc->u_uri;
1242 }
1243
1244 unsigned int
1245 fsdp_get_emails_count (const fsdp_description_t * dsc)
1246 {
1247 if (!dsc)
1248 return 0;
1249 return dsc->emails_count;
1250 }
1251
1252 const char *
1253 fsdp_get_email (const fsdp_description_t * dsc, unsigned int index)
1254 {
1255 if ((!dsc) || (index >= dsc->emails_count))
1256 return NULL;
1257 return dsc->emails[index];
1258 }
1259
1260 unsigned int
1261 fsdp_get_phones_count (const fsdp_description_t * dsc)
1262 {
1263 if (!dsc)
1264 return 0;
1265 return dsc->phones_count;
1266 }
1267
1268 const char *
1269 fsdp_get_phone (const fsdp_description_t * dsc, unsigned int index)
1270 {
1271 if ((!dsc) || (index >= dsc->phones_count))
1272 return NULL;
1273 return dsc->phones[index];
1274 }
1275
1276 fsdp_network_type_t
1277 fsdp_get_global_conn_network_type (const fsdp_description_t * dsc)
1278 {
1279 if (!dsc)
1280 return FSDP_NETWORK_TYPE_UNDEFINED;
1281 return dsc->c_network_type;
1282 }
1283
1284 fsdp_address_type_t
1285 fsdp_get_global_conn_address_type (const fsdp_description_t * dsc)
1286 {
1287 if (!dsc)
1288 return FSDP_ADDRESS_TYPE_UNDEFINED;
1289 return dsc->c_address_type;
1290 }
1291
1292 const char *
1293 fsdp_get_global_conn_address (const fsdp_description_t * dsc)
1294 {
1295 if (!dsc)
1296 return NULL;
1297 return dsc->c_address.address;
1298 }
1299
1300 unsigned int
1301 fsdp_get_global_conn_address_ttl (const fsdp_description_t * dsc)
1302 {
1303 if (!dsc)
1304 return 0;
1305 return dsc->c_address.address_ttl;
1306 }
1307
1308 unsigned int
1309 fsdp_get_global_conn_address_count (const fsdp_description_t * dsc)
1310 {
1311 if (!dsc)
1312 return 0;
1313 return dsc->c_address.address_count;
1314 }
1315
1316 unsigned int
1317 fsdp_get_bw_modifier_count (const fsdp_description_t * dsc)
1318 {
1319 if (!dsc)
1320 return 0;
1321 return dsc->bw_modifiers_count;
1322 }
1323
1324 fsdp_bw_modifier_type_t
1325 fsdp_get_bw_modifier_type (const fsdp_description_t * dsc, unsigned int index)
1326 {
1327 if ((!dsc) || (index >= dsc->bw_modifiers_count))
1328 return FSDP_BW_MOD_TYPE_UNDEFINED;
1329 return dsc->bw_modifiers[index].b_mod_type;
1330 }
1331
1332 const char *
1333 fsdp_get_bw_modifier_type_unknown (const fsdp_description_t * dsc,
1334 unsigned int index)
1335 {
1336 if ((!dsc) || (index >= dsc->bw_modifiers_count) ||
1337 (dsc->bw_modifiers[index].b_mod_type != FSDP_BW_MOD_TYPE_UNKNOWN))
1338 return NULL;
1339 return dsc->bw_modifiers[index].b_unknown_bw_modt;
1340 }
1341
1342 unsigned long int
1343 fsdp_get_bw_value (const fsdp_description_t * dsc, unsigned int index)
1344 {
1345 if ((!dsc) || (index >= dsc->bw_modifiers_count))
1346 return 0;
1347 return dsc->bw_modifiers[index].b_value;
1348 }
1349
1350 time_t
1351 fsdp_get_period_start (const fsdp_description_t * dsc, unsigned int index)
1352 {
1353 if ((!dsc) || (index >= dsc->time_periods_count))
1354 return 0;
1355 return dsc->time_periods[index]->start;
1356 }
1357
1358 time_t
1359 fsdp_get_period_stop (const fsdp_description_t * dsc, unsigned int index)
1360 {
1361 if ((!dsc) || (index >= dsc->time_periods_count))
1362 return 0;
1363 return dsc->time_periods[index]->stop;
1364 }
1365
1366 unsigned int
1367 fsdp_get_period_repeats_count (const fsdp_description_t * dsc,
1368 unsigned int index)
1369 {
1370 if ((!dsc) || (index >= dsc->time_periods_count))
1371 return 0;
1372 return dsc->time_periods[index]->repeats_count;
1373 }
1374
1375 unsigned long int
1376 fsdp_get_period_repeat_interval (const fsdp_description_t * dsc,
1377 unsigned int index, unsigned int rindex)
1378 {
1379 if ((!dsc) || (index >= dsc->time_periods_count))
1380 return 0;
1381 return dsc->time_periods[index]->repeats[rindex]->interval;
1382 }
1383
1384 unsigned long int
1385 fsdp_get_period_repeat_duration (const fsdp_description_t * dsc,
1386 unsigned int index, unsigned int rindex)
1387 {
1388 if ((!dsc) || (index >= dsc->time_periods_count))
1389 return 0;
1390 return dsc->time_periods[index]->repeats[rindex]->duration;
1391 }
1392
1393 const unsigned long int *
1394 fsdp_get_period_repeat_offsets (const fsdp_description_t * dsc,
1395 unsigned int index, unsigned int rindex)
1396 {
1397 if ((!dsc) || (index >= dsc->time_periods_count))
1398 return NULL;
1399 return dsc->time_periods[index]->repeats[rindex]->offsets;
1400 }
1401
1402 const char *
1403 fsdp_get_timezone_adj (const fsdp_description_t * dsc)
1404 {
1405 if (!dsc)
1406 return NULL;
1407 return dsc->timezone_adj;
1408 }
1409
1410 unsigned int
1411 fsdp_get_unidentified_attribute_count (const fsdp_description_t * dsc)
1412 {
1413 if (!dsc)
1414 return 0;
1415 return dsc->unidentified_attributes_count;
1416 }
1417
1418 const char *
1419 fsdp_get_unidentified_attribute (const fsdp_description_t * dsc,
1420 unsigned int index)
1421 {
1422 if (!dsc || (index < dsc->unidentified_attributes_count))
1423 return NULL;
1424 return dsc->unidentified_attributes[index];
1425 }
1426
1427 fsdp_encryption_method_t
1428 fsdp_get_encryption_method (const fsdp_description_t * dsc)
1429 {
1430 if (!dsc)
1431 return FSDP_ENCRYPTION_METHOD_UNDEFINED;
1432 return dsc->k_encryption_method;
1433 }
1434
1435 const char *
1436 fsdp_get_encryption_content (const fsdp_description_t * dsc)
1437 {
1438 if (!dsc || (dsc->k_encryption_method == FSDP_ENCRYPTION_METHOD_UNDEFINED))
1439 return NULL;
1440 return dsc->k_encryption_content;
1441 }
1442
1443 unsigned int
1444 fsdp_get_rtpmap_count (const fsdp_description_t * dsc)
1445 {
1446 if (!dsc)
1447 return 0;
1448 return dsc->a_rtpmaps_count;
1449 }
1450
1451 const char *
1452 fsdp_get_rtpmap_payload_type (const fsdp_description_t * dsc,
1453 unsigned int index)
1454 {
1455 if ((!dsc) || (index >= dsc->a_rtpmaps_count))
1456 return NULL;
1457 return dsc->a_rtpmaps[index]->pt;
1458 }
1459
1460 const char *
1461 fsdp_get_rtpmap_encoding_name (const fsdp_description_t * dsc,
1462 unsigned int index)
1463 {
1464 if ((!dsc) || (index >= dsc->a_rtpmaps_count))
1465 return NULL;
1466 return dsc->a_rtpmaps[index]->encoding_name;
1467 }
1468
1469 unsigned int
1470 fsdp_get_rtpmap_clock_rate (const fsdp_description_t * dsc,
1471 unsigned int index)
1472 {
1473 if ((!dsc) || (index >= dsc->a_rtpmaps_count))
1474 return 0;
1475 return dsc->a_rtpmaps[index]->clock_rate;
1476 }
1477
1478 const char *
1479 fsdp_get_rtpmap_encoding_parameters (const fsdp_description_t * dsc,
1480 unsigned int index)
1481 {
1482 if ((!dsc) || (index >= dsc->a_rtpmaps_count))
1483 return NULL;
1484 return dsc->a_rtpmaps[index]->parameters;
1485 }
1486
1487 const char *
1488 fsdp_get_str_att (const fsdp_description_t * dsc, fsdp_session_str_att_t att)
1489 {
1490 /*TODO: change these individual attributes with a table, thus
1491 avoiding this slow switch */
1492 char *result;
1493
1494 if (!dsc)
1495 return NULL;
1496
1497 switch (att)
1498 {
1499 case FSDP_SESSION_STR_ATT_CATEGORY:
1500 result = dsc->a_category;
1501 break;
1502 case FSDP_SESSION_STR_ATT_KEYWORDS:
1503 result = dsc->a_keywords;
1504 break;
1505 case FSDP_SESSION_STR_ATT_TOOL:
1506 result = dsc->a_tool;
1507 break;
1508 case FSDP_SESSION_STR_ATT_CHARSET:
1509 result = dsc->a_charset;
1510 break;
1511 default:
1512 result = NULL;
1513 }
1514 return result;
1515 }
1516
1517 unsigned int
1518 fsdp_get_sdplang_count (const fsdp_description_t * dsc)
1519 {
1520 if (!dsc)
1521 return 0;
1522 return dsc->a_sdplangs_count;
1523 }
1524
1525 const char *
1526 fsdp_get_sdplang (const fsdp_description_t * dsc, unsigned int index)
1527 {
1528 if ((!dsc) || (index >= dsc->a_sdplangs_count))
1529 return NULL;
1530 return dsc->a_sdplangs[index];
1531 }
1532
1533 unsigned int
1534 fsdp_get_lang_count (const fsdp_description_t * dsc)
1535 {
1536 if (!dsc)
1537 return 0;
1538 return dsc->a_langs_count;
1539 }
1540
1541 const char *
1542 fsdp_get_lang (const fsdp_description_t * dsc, unsigned int index)
1543 {
1544 if ((!dsc) || (index >= dsc->a_langs_count))
1545 return NULL;
1546 return dsc->a_langs[index];
1547 }
1548
1549 unsigned int
1550 fsdp_get_control_count (const fsdp_description_t * dsc)
1551 {
1552 if (!dsc)
1553 return 0;
1554 return dsc->a_controls_count;
1555 }
1556
1557 const char *
1558 fsdp_get_control (const fsdp_description_t * dsc, unsigned int index)
1559 {
1560 if ((!dsc) || (index >= dsc->a_controls_count))
1561 return NULL;
1562 return dsc->a_controls[index];
1563 }
1564
1565 const char *
1566 fsdp_get_range (const fsdp_description_t * dsc)
1567 {
1568 return dsc->a_range;
1569 }
1570
1571 fsdp_sendrecv_mode_t
1572 fsdp_get_sendrecv_mode (const fsdp_description_t * dsc)
1573 {
1574 if (!dsc)
1575 return FSDP_SENDRECV_UNDEFINED;
1576 return dsc->a_sendrecv_mode;
1577 }
1578
1579 fsdp_session_type_t
1580 fsdp_get_session_type (const fsdp_description_t * dsc)
1581 {
1582 if (!dsc)
1583 return FSDP_SESSION_TYPE_UNDEFINED;
1584 return dsc->a_type;
1585 }
1586
1587 unsigned int
1588 fsdp_get_media_count (const fsdp_description_t * dsc)
1589 {
1590 if (!dsc)
1591 return 0;
1592 return dsc->media_announcements_count;
1593 }
1594
1595 const fsdp_media_description_t *
1596 fsdp_get_media (const fsdp_description_t * dsc, unsigned int index)
1597 {
1598 if ((index >= dsc->media_announcements_count))
1599 return NULL;
1600 return dsc->media_announcements[index];
1601 }
1602
1603 fsdp_media_t
1604 fsdp_get_media_type (const fsdp_media_description_t * dsc)
1605 {
1606 if (!dsc)
1607 return FSDP_MEDIA_UNDEFINED;
1608 return dsc->media_type;
1609 }
1610
1611 unsigned int
1612 fsdp_get_media_port (const fsdp_media_description_t * dsc)
1613 {
1614 if (!dsc)
1615 return 0;
1616 return dsc->port;
1617 }
1618
1619 unsigned int
1620 fsdp_get_media_port_count (const fsdp_media_description_t * dsc)
1621 {
1622 if (!dsc)
1623 return 0;
1624 return dsc->port_count;
1625 }
1626
1627 fsdp_transport_protocol_t
1628 fsdp_get_media_transport_protocol (const fsdp_media_description_t * dsc)
1629 {
1630 if (!dsc)
1631 return FSDP_TP_UNDEFINED;
1632 return dsc->transport;
1633 }
1634
1635 unsigned int
1636 fsdp_get_media_formats_count (const fsdp_media_description_t * dsc)
1637 {
1638 if (!dsc)
1639 return 0;
1640 return dsc->formats_count;
1641 }
1642
1643 const char *
1644 fsdp_get_media_format (const fsdp_media_description_t * dsc,
1645 unsigned int index)
1646 {
1647 if (!dsc && (index < dsc->formats_count))
1648 return NULL;
1649 return dsc->formats[index];
1650 }
1651
1652 const char *
1653 fsdp_get_media_title (const fsdp_media_description_t * dsc)
1654 {
1655 if (!dsc)
1656 return NULL;
1657 return dsc->i_title;
1658 }
1659
1660 fsdp_network_type_t
1661 fsdp_get_media_network_type (const fsdp_media_description_t * dsc)
1662 {
1663 if (!dsc)
1664 return FSDP_NETWORK_TYPE_UNDEFINED;
1665 return dsc->c_network_type;
1666 }
1667
1668 fsdp_address_type_t
1669 fsdp_get_media_address_type (const fsdp_media_description_t * dsc)
1670 {
1671 if (!dsc)
1672 return FSDP_ADDRESS_TYPE_UNDEFINED;
1673 return dsc->c_address_type;
1674 }
1675
1676 const char *
1677 fsdp_get_media_address (const fsdp_media_description_t * dsc)
1678 {
1679 if (!dsc)
1680 return NULL;
1681 return dsc->c_address.address;
1682 }
1683
1684 unsigned int
1685 fsdp_get_media_address_ttl (const fsdp_media_description_t * mdsc)
1686 {
1687 if (!mdsc)
1688 return 0;
1689 return mdsc->c_address.address_ttl;
1690 }
1691
1692 unsigned int
1693 fsdp_get_media_address_count (const fsdp_media_description_t * mdsc)
1694 {
1695 if (!mdsc)
1696 return 0;
1697 return mdsc->c_address.address_count;
1698 }
1699
1700 fsdp_bw_modifier_type_t
1701 fsdp_get_media_bw_modifier_type (const fsdp_media_description_t * dsc,
1702 unsigned int index)
1703 {
1704 if (!dsc || (index >= dsc->bw_modifiers_count))
1705 return FSDP_BW_MOD_TYPE_UNDEFINED;
1706 return dsc->bw_modifiers[index].b_mod_type;
1707 }
1708
1709 const char *
1710 fsdp_get_media_bw_modifier_type_unknown (const fsdp_media_description_t * dsc,
1711 unsigned int index)
1712 {
1713 if (!dsc || (index >= dsc->bw_modifiers_count) ||
1714 (FSDP_BW_MOD_TYPE_UNKNOWN != dsc->bw_modifiers[index].b_mod_type))
1715 return NULL;
1716 return dsc->bw_modifiers[index].b_unknown_bw_modt;
1717 }
1718
1719 unsigned long int
1720 fsdp_get_media_bw_value (const fsdp_media_description_t * dsc,
1721 unsigned int index)
1722 {
1723 if (!dsc || (index >= dsc->bw_modifiers_count))
1724 return 0;
1725 return dsc->bw_modifiers[index].b_value;
1726 }
1727
1728 fsdp_encryption_method_t
1729 fsdp_get_media_encryption_method (const fsdp_media_description_t * dsc)
1730 {
1731 if (!dsc)
1732 return FSDP_ENCRYPTION_METHOD_UNDEFINED;
1733 return dsc->k_encryption_method;
1734 }
1735
1736 const char *
1737 fsdp_get_media_encryption_content (const fsdp_media_description_t * dsc)
1738 {
1739 if (!dsc)
1740 return NULL;
1741 return dsc->k_encryption_content;
1742 }
1743
1744 unsigned int
1745 fsdp_get_media_ptime (const fsdp_media_description_t * dsc)
1746 {
1747 if (!dsc)
1748 return 0;
1749 return dsc->a_ptime;
1750 }
1751
1752 unsigned int
1753 fsdp_get_media_maxptime (const fsdp_media_description_t * dsc)
1754 {
1755 if (!dsc)
1756 return 0;
1757 return dsc->a_maxptime;
1758 }
1759
1760 unsigned int
1761 fsdp_get_media_rtpmap_count (const fsdp_media_description_t * mdsc)
1762 {
1763 if (!mdsc)
1764 return 0;
1765 return mdsc->a_rtpmaps_count;
1766 }
1767
1768 const char *
1769 fsdp_get_media_rtpmap_payload_type (const fsdp_media_description_t * mdsc,
1770 unsigned int index)
1771 {
1772 if (!mdsc || (index >= mdsc->a_rtpmaps_count))
1773 return NULL;
1774 return mdsc->a_rtpmaps[index]->pt;
1775 }
1776
1777 const char *
1778 fsdp_get_media_rtpmap_encoding_name (const fsdp_media_description_t * mdsc,
1779 unsigned int index)
1780 {
1781 if (!mdsc || (index >= mdsc->a_rtpmaps_count))
1782 return NULL;
1783 return mdsc->a_rtpmaps[index]->encoding_name;
1784 }
1785
1786 unsigned int
1787 fsdp_get_media_rtpmap_clock_rate (const fsdp_media_description_t * mdsc,
1788 unsigned int index)
1789 {
1790 if (!mdsc || (index >= mdsc->a_rtpmaps_count))
1791 return 0;
1792 return mdsc->a_rtpmaps[index]->clock_rate;
1793 }
1794
1795 const char *
1796 fsdp_get_media_rtpmap_encoding_parameters (const fsdp_description_t * mdsc,
1797 unsigned int index)
1798 {
1799 if (!mdsc || (index >= mdsc->a_rtpmaps_count))
1800 return NULL;
1801 return mdsc->a_rtpmaps[index]->parameters;
1802 }
1803
1804 unsigned int
1805 fsdp_get_media_sdplang_count (const fsdp_media_description_t * mdsc)
1806 {
1807 if (!mdsc)
1808 return 0;
1809 return mdsc->a_sdplangs_count;
1810 }
1811
1812 const char *
1813 fsdp_get_media_sdplang (const fsdp_media_description_t * mdsc,
1814 unsigned int index)
1815 {
1816 if (!mdsc || (index >= mdsc->a_sdplangs_count))
1817 return NULL;
1818 return mdsc->a_sdplangs[index];
1819 }
1820
1821 unsigned int
1822 fsdp_get_media_lang_count (const fsdp_media_description_t * mdsc)
1823 {
1824 if (!mdsc)
1825 return 0;
1826 return mdsc->a_langs_count;
1827 }
1828
1829 const char *
1830 fsdp_get_media_lang (const fsdp_media_description_t * mdsc,
1831 unsigned int index)
1832 {
1833 if (!mdsc || (index >= mdsc->a_langs_count))
1834 return NULL;
1835 return mdsc->a_langs[index];
1836 }
1837
1838 unsigned int
1839 fsdp_get_media_control_count (const fsdp_media_description_t * mdsc)
1840 {
1841 if (!mdsc)
1842 return 0;
1843 return mdsc->a_controls_count;
1844 }
1845
1846 char *
1847 fsdp_get_media_control (const fsdp_media_description_t * mdsc,
1848 unsigned int index)
1849 {
1850 if (!mdsc || (index >= mdsc->a_controls_count))
1851 return NULL;
1852 return mdsc->a_controls[index];
1853 }
1854
1855 char *
1856 fsdp_get_media_range (const fsdp_media_description_t * mdsc)
1857 {
1858 return mdsc->a_range;
1859 }
1860
1861 unsigned int
1862 fsdp_get_media_fmtp_count (const fsdp_media_description_t * mdsc)
1863 {
1864 if (!mdsc)
1865 return 0;
1866 return mdsc->a_fmtps_count;
1867 }
1868
1869 const char *
1870 fsdp_get_media_fmtp (const fsdp_media_description_t * mdsc,
1871 unsigned int index)
1872 {
1873 if (!mdsc || (index >= mdsc->a_fmtps_count))
1874 return NULL;
1875 return mdsc->a_fmtps[index];
1876 }
1877
1878 fsdp_orient_t
1879 fsdp_get_media_orient (const fsdp_media_description_t * dsc)
1880 {
1881 if (!dsc)
1882 return FSDP_ORIENT_UNDEFINED;
1883 return dsc->a_orient;
1884 }
1885
1886 fsdp_sendrecv_mode_t
1887 fsdp_get_media_sendrecv (const fsdp_media_description_t * dsc)
1888 {
1889 if (!dsc)
1890 return FSDP_SENDRECV_UNDEFINED;
1891 return dsc->a_sendrecv_mode;
1892 }
1893
1894 float
1895 fsdp_get_media_framerate (const fsdp_media_description_t * dsc)
1896 {
1897 if (!dsc)
1898 return 0;
1899 return dsc->a_framerate;
1900 }
1901
1902 unsigned int
1903 fsdp_get_media_quality (const fsdp_media_description_t * dsc)
1904 {
1905 if (!dsc)
1906 return 0;
1907 return dsc->a_quality;
1908 }
1909
1910 unsigned int
1911 fsdp_get_media_rtcp_port (const fsdp_media_description_t * dsc)
1912 {
1913 if (!dsc)
1914 return 0;
1915 return dsc->a_rtcp_port;
1916 }
1917
1918 fsdp_network_type_t
1919 fsdp_get_media_rtcp_network_type (const fsdp_media_description_t * dsc)
1920 {
1921 if (!dsc)
1922 return FSDP_NETWORK_TYPE_UNDEFINED;
1923 return dsc->a_rtcp_network_type;
1924 }
1925
1926 fsdp_address_type_t
1927 fsdp_get_media_rtcp_address_type (const fsdp_media_description_t * dsc)
1928 {
1929 if (!dsc)
1930 return FSDP_ADDRESS_TYPE_UNDEFINED;
1931 return dsc->a_rtcp_address_type;
1932 }
1933
1934 const char *
1935 fsdp_get_media_rtcp_address (const fsdp_media_description_t * dsc)
1936 {
1937 if (!dsc)
1938 return NULL;
1939 return dsc->a_rtcp_address;
1940 }
1941
1942 unsigned int
1943 fsdp_get_media_unidentified_attribute_count (const fsdp_media_description_t
1944 * mdsc)
1945 {
1946 if (!mdsc)
1947 return 0;
1948 return mdsc->unidentified_attributes_count;
1949 }
1950
1951 const char *
1952 fsdp_get_media_unidentified_attribute (const fsdp_media_description_t * mdsc,
1953 unsigned int index)
1954 {
1955 if (!mdsc || (index < mdsc->unidentified_attributes_count))
1956 return NULL;
1957 return mdsc->unidentified_attributes[index];
1958 }