Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 :
28 : #include <gpac/ietf.h>
29 :
30 : #ifndef GPAC_DISABLE_STREAMING
31 :
32 : #include <gpac/token.h>
33 :
34 :
35 : #define SDP_WRITE_STEPALLOC 2048
36 :
37 :
38 : GF_EXPORT
39 15 : GF_SDP_FMTP *gf_sdp_fmtp_new()
40 : {
41 15 : GF_SDP_FMTP *tmp = (GF_SDP_FMTP*)gf_malloc(sizeof(GF_SDP_FMTP));
42 15 : tmp->PayloadType = 0;
43 15 : tmp->Attributes = gf_list_new();
44 15 : return tmp;
45 : }
46 :
47 : GF_EXPORT
48 15 : void gf_sdp_fmtp_del(GF_SDP_FMTP *fmtp)
49 : {
50 15 : if (!fmtp) return;
51 105 : while (gf_list_count(fmtp->Attributes)) {
52 90 : GF_X_Attribute *att = (GF_X_Attribute*)gf_list_get(fmtp->Attributes, 0);
53 90 : gf_list_rem(fmtp->Attributes, 0);
54 90 : if (att->Name) gf_free(att->Name);
55 90 : if (att->Value) gf_free(att->Value);
56 90 : gf_free(att);
57 : }
58 15 : gf_list_del(fmtp->Attributes);
59 15 : gf_free(fmtp);
60 : }
61 :
62 15 : GF_SDP_FMTP *SDP_GetFMTPForPayload(GF_SDPMedia *media, u32 PayloadType)
63 : {
64 : GF_SDP_FMTP *tmp;
65 : u32 i;
66 15 : if (!media) return NULL;
67 15 : i=0;
68 30 : while ((tmp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &i))) {
69 0 : if (tmp->PayloadType == PayloadType) return tmp;
70 : }
71 : return NULL;
72 : }
73 :
74 94 : void SDP_ParseAttribute(GF_SDPInfo *sdp, char *buffer, GF_SDPMedia *media)
75 : {
76 : s32 pos;
77 : u32 PayT;
78 : char comp[3000];
79 : GF_X_Attribute *att;
80 :
81 94 : pos = gf_token_get(buffer, 0, " :\t\r\n", comp, 3000);
82 :
83 94 : if (!strcmp(comp, "cat")) {
84 35 : if (media) return;
85 0 : /*pos = */gf_token_get(buffer, pos, ":\t\r\n", comp, 3000);
86 0 : sdp->a_cat = gf_strdup(comp);
87 0 : return;
88 : }
89 94 : if (!strcmp(comp, "keywds")) {
90 0 : if (media) return;
91 0 : /*pos = */gf_token_get(buffer, pos, ":\t\r\n", comp, 3000);
92 0 : sdp->a_keywds = gf_strdup(comp);
93 0 : return;
94 : }
95 94 : if (!strcmp(comp, "tool")) {
96 0 : if (media) return;
97 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
98 0 : sdp->a_tool = gf_strdup(comp);
99 0 : return;
100 : }
101 :
102 94 : if (!strcmp(comp, "ptime")) {
103 0 : if (!media) return;
104 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
105 0 : media->PacketTime = atoi(comp);
106 0 : return;
107 : }
108 94 : if (!strcmp(comp, "recvonly")) {
109 0 : if (!media) {
110 0 : sdp->a_SendReceive = 1;
111 : } else {
112 0 : media->SendReceive = 1;
113 : }
114 : return;
115 : }
116 94 : if (!strcmp(comp, "sendonly")) {
117 0 : if (!media) {
118 0 : sdp->a_SendReceive = 2;
119 : } else {
120 0 : media->SendReceive = 2;
121 : }
122 : return;
123 : }
124 94 : if (!strcmp(comp, "sendrecv")) {
125 0 : if (!media) {
126 0 : sdp->a_SendReceive = 3;
127 : } else {
128 0 : media->SendReceive = 3;
129 : }
130 : return;
131 : }
132 94 : if (!strcmp(comp, "orient")) {
133 0 : if (!media || media->Type) return;
134 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
135 0 : media->orientation = gf_strdup(comp);
136 0 : return;
137 : }
138 94 : if (!strcmp(comp, "type")) {
139 0 : if (media) return;
140 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
141 0 : sdp->a_type = gf_strdup(comp);
142 0 : return;
143 : }
144 94 : if (!strcmp(comp, "charset")) {
145 0 : if (media) return;
146 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
147 0 : sdp->a_charset = gf_strdup(comp);
148 0 : return;
149 : }
150 94 : if (!strcmp(comp, "sdplang")) {
151 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
152 0 : if (media) {
153 0 : media->sdplang = gf_strdup(comp);
154 : } else {
155 0 : sdp->a_sdplang = gf_strdup(comp);
156 : }
157 : return;
158 : }
159 94 : if (!strcmp(comp, "lang")) {
160 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
161 0 : if (media) {
162 0 : media->lang = gf_strdup(comp);
163 : } else {
164 0 : sdp->a_lang = gf_strdup(comp);
165 : }
166 : return;
167 : }
168 94 : if (!strcmp(comp, "framerate")) {
169 : //only for video
170 0 : if (!media || (media->Type != 1)) return;
171 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
172 0 : media->FrameRate = atof(comp);
173 0 : return;
174 : }
175 94 : if (!strcmp(comp, "quality")) {
176 0 : if (!media) return;
177 0 : /*pos = */gf_token_get(buffer, pos, ":\r\n", comp, 3000);
178 0 : media->Quality = atoi(comp);
179 0 : return;
180 : }
181 94 : if (!strcmp(comp, "rtpmap")) {
182 : GF_RTPMap *map;
183 20 : if (!media) return;
184 20 : map = (GF_RTPMap*)gf_malloc(sizeof(GF_RTPMap));
185 20 : pos = gf_token_get(buffer, pos, ": \r\n", comp, 3000);
186 20 : map->PayloadType = atoi(comp);
187 20 : pos = gf_token_get(buffer, pos, " /\r\n", comp, 3000);
188 20 : map->payload_name = gf_strdup(comp);
189 20 : pos = gf_token_get(buffer, pos, " /\r\n", comp, 3000);
190 20 : map->ClockRate = atoi(comp);
191 20 : pos = gf_token_get(buffer, pos, " /\r\n", comp, 3000);
192 20 : map->AudioChannels = (pos > 0) ? atoi(comp) : 0;
193 20 : gf_list_add(media->RTPMaps, map);
194 20 : return;
195 : }
196 : //FMTP
197 74 : if (!strcmp(comp, "fmtp")) {
198 : GF_SDP_FMTP *fmtp;
199 15 : if (!media) return;
200 15 : pos = gf_token_get(buffer, pos, ": \r\n", comp, 3000);
201 15 : PayT = atoi(comp);
202 15 : fmtp = SDP_GetFMTPForPayload(media, PayT);
203 15 : if (!fmtp) {
204 15 : fmtp = gf_sdp_fmtp_new();
205 15 : fmtp->PayloadType = PayT;
206 15 : gf_list_add(media->FMTP, fmtp);
207 : }
208 : while (1) {
209 195 : pos = gf_token_get(buffer, pos, "; =\r\n", comp, 3000);
210 105 : if (pos <= 0) break;
211 90 : att = (GF_X_Attribute*)gf_malloc(sizeof(GF_X_Attribute));
212 90 : att->Name = gf_strdup(comp);
213 90 : att->Value = NULL;
214 90 : pos ++;
215 90 : pos = gf_token_get(buffer, pos, ";\r\n", comp, 3000);
216 90 : if (pos > 0) att->Value = gf_strdup(comp);
217 90 : gf_list_add(fmtp->Attributes, att);
218 : }
219 : return;
220 : }
221 : //the rest cannot be discarded that way as it may be application-specific
222 : //so keep it.
223 : //a= <attribute> || <attribute>:<value>
224 : //we add <attribute> <value> in case ...
225 59 : pos = gf_token_get(buffer, 0, " :\r\n", comp, 3000);
226 59 : att = (GF_X_Attribute*)gf_malloc(sizeof(GF_X_Attribute));
227 59 : att->Name = gf_strdup(comp);
228 59 : att->Value = NULL;
229 59 : pos += 1;
230 59 : if (buffer[pos] == ' ') pos += 1;
231 59 : pos = gf_token_get(buffer, pos, "\r\n", comp, 3000);
232 59 : if (pos > 0) att->Value = gf_strdup(comp);
233 :
234 59 : if (media) {
235 30 : gf_list_add(media->Attributes, att);
236 : } else {
237 29 : gf_list_add(sdp->Attributes, att);
238 : }
239 : }
240 :
241 :
242 :
243 : #define SDPM_DESTROY(p) if (media->p) gf_free(media->p)
244 : GF_EXPORT
245 20 : void gf_sdp_media_del(GF_SDPMedia *media)
246 : {
247 20 : if (!media) return;
248 :
249 35 : while (gf_list_count(media->FMTP)) {
250 15 : GF_SDP_FMTP *fmtp = (GF_SDP_FMTP*)gf_list_get(media->FMTP, 0);
251 15 : gf_list_rem(media->FMTP, 0);
252 15 : gf_sdp_fmtp_del(fmtp);
253 : }
254 20 : gf_list_del(media->FMTP);
255 :
256 70 : while (gf_list_count(media->Attributes)) {
257 30 : GF_X_Attribute *att = (GF_X_Attribute*)gf_list_get(media->Attributes, 0);
258 30 : gf_list_rem(media->Attributes, 0);
259 30 : if (att->Name) gf_free(att->Name);
260 30 : if (att->Value) gf_free(att->Value);
261 30 : gf_free(att);
262 : }
263 20 : gf_list_del(media->Attributes);
264 :
265 60 : while (gf_list_count(media->RTPMaps)) {
266 20 : GF_RTPMap *map = (GF_RTPMap*)gf_list_get(media->RTPMaps, 0);
267 20 : gf_free(map->payload_name);
268 20 : gf_free(map);
269 20 : gf_list_rem(media->RTPMaps, 0);
270 : }
271 20 : gf_list_del(media->RTPMaps);
272 :
273 40 : while (gf_list_count(media->Connections)) {
274 0 : GF_SDPConnection *conn = (GF_SDPConnection*)gf_list_get(media->Connections, 0);
275 0 : gf_list_rem(media->Connections, 0);
276 0 : gf_sdp_conn_del(conn);
277 : }
278 20 : gf_list_del(media->Connections);
279 :
280 40 : while (gf_list_count(media->Bandwidths)) {
281 0 : GF_SDPBandwidth *bw = (GF_SDPBandwidth*)gf_list_get(media->Bandwidths, 0);
282 0 : gf_list_rem(media->Bandwidths, 0);
283 0 : if (bw->name) gf_free(bw->name);
284 0 : gf_free(bw);
285 : }
286 20 : gf_list_del(media->Bandwidths);
287 :
288 20 : SDPM_DESTROY(orientation);
289 20 : SDPM_DESTROY(sdplang);
290 20 : SDPM_DESTROY(lang);
291 20 : SDPM_DESTROY(Profile);
292 20 : SDPM_DESTROY(fmt_list);
293 20 : SDPM_DESTROY(k_method);
294 20 : SDPM_DESTROY(k_key);
295 20 : gf_free(media);
296 : }
297 :
298 :
299 : GF_EXPORT
300 19 : GF_SDPConnection *gf_sdp_conn_new()
301 : {
302 : GF_SDPConnection *conn;
303 19 : GF_SAFEALLOC(conn, GF_SDPConnection);
304 19 : if (!conn) return NULL;
305 19 : conn->TTL = -1;
306 19 : return conn;
307 : }
308 :
309 : GF_EXPORT
310 19 : void gf_sdp_conn_del(GF_SDPConnection *conn)
311 : {
312 19 : if (conn->add_type) gf_free(conn->add_type);
313 19 : if (conn->host) gf_free(conn->host);
314 19 : if (conn->net_type) gf_free(conn->net_type);
315 19 : gf_free(conn);
316 19 : }
317 :
318 : GF_EXPORT
319 20 : GF_SDPMedia *gf_sdp_media_new()
320 : {
321 : GF_SDPMedia *tmp;
322 20 : GF_SAFEALLOC(tmp, GF_SDPMedia);
323 20 : if (!tmp) return NULL;
324 20 : tmp->FMTP = gf_list_new();
325 20 : tmp->RTPMaps = gf_list_new();
326 20 : tmp->Attributes = gf_list_new();
327 20 : tmp->Connections = gf_list_new();
328 20 : tmp->Bandwidths = gf_list_new();
329 20 : tmp->Quality = -1;
330 20 : return tmp;
331 : }
332 :
333 : GF_EXPORT
334 19 : GF_SDPInfo *gf_sdp_info_new()
335 : {
336 : GF_SDPInfo *sdp;
337 19 : GF_SAFEALLOC(sdp, GF_SDPInfo);
338 19 : if (!sdp) return NULL;
339 19 : sdp->b_bandwidth = gf_list_new();
340 19 : sdp->media_desc = gf_list_new();
341 19 : sdp->Attributes = gf_list_new();
342 19 : sdp->Timing = gf_list_new();
343 19 : return sdp;
344 : }
345 :
346 : #define SDP_DESTROY(p) if (sdp->p) \
347 : gf_free(sdp->p); \
348 : sdp->p = NULL;
349 :
350 :
351 : GF_EXPORT
352 38 : void gf_sdp_info_reset(GF_SDPInfo *sdp)
353 : {
354 38 : if (!sdp) return;
355 :
356 58 : while (gf_list_count(sdp->media_desc)) {
357 20 : GF_SDPMedia *media = (GF_SDPMedia*)gf_list_get(sdp->media_desc, 0);
358 20 : gf_list_rem(sdp->media_desc, 0);
359 20 : gf_sdp_media_del(media);
360 : }
361 67 : while (gf_list_count(sdp->Attributes)) {
362 29 : GF_X_Attribute *att = (GF_X_Attribute*)gf_list_get(sdp->Attributes, 0);
363 29 : gf_list_rem(sdp->Attributes, 0);
364 29 : if (att->Name) gf_free(att->Name);
365 29 : if (att->Value) gf_free(att->Value);
366 29 : gf_free(att);
367 : }
368 38 : while (gf_list_count(sdp->b_bandwidth)) {
369 0 : GF_SDPBandwidth *bw = (GF_SDPBandwidth*)gf_list_get(sdp->b_bandwidth, 0);
370 0 : gf_list_rem(sdp->b_bandwidth, 0);
371 0 : if (bw->name) gf_free(bw->name);
372 0 : gf_free(bw);
373 : }
374 57 : while (gf_list_count(sdp->Timing)) {
375 19 : GF_SDPTiming *timing = (GF_SDPTiming*)gf_list_get(sdp->Timing, 0);
376 19 : gf_list_rem(sdp->Timing, 0);
377 19 : gf_free(timing);
378 : }
379 :
380 : //then delete all info ...
381 38 : SDP_DESTROY(o_username);
382 38 : SDP_DESTROY(o_session_id);
383 38 : SDP_DESTROY(o_version);
384 38 : SDP_DESTROY(o_address);
385 38 : SDP_DESTROY(o_net_type);
386 38 : SDP_DESTROY(o_add_type);
387 38 : SDP_DESTROY(s_session_name);
388 38 : SDP_DESTROY(i_description);
389 38 : SDP_DESTROY(u_uri);
390 38 : SDP_DESTROY(e_email);
391 38 : SDP_DESTROY(p_phone);
392 38 : SDP_DESTROY(k_method);
393 38 : SDP_DESTROY(k_key);
394 38 : SDP_DESTROY(a_cat);
395 38 : SDP_DESTROY(a_keywds);
396 38 : SDP_DESTROY(a_tool);
397 38 : SDP_DESTROY(a_type);
398 38 : SDP_DESTROY(a_charset);
399 38 : SDP_DESTROY(a_sdplang);
400 38 : SDP_DESTROY(a_lang);
401 :
402 38 : if (sdp->c_connection) {
403 19 : gf_sdp_conn_del(sdp->c_connection);
404 19 : sdp->c_connection = NULL;
405 : }
406 38 : sdp->a_SendReceive = 0;
407 : }
408 :
409 : GF_EXPORT
410 19 : void gf_sdp_info_del(GF_SDPInfo *sdp)
411 : {
412 19 : if (!sdp) return;
413 19 : gf_sdp_info_reset(sdp);
414 19 : gf_list_del(sdp->media_desc);
415 19 : gf_list_del(sdp->Attributes);
416 19 : gf_list_del(sdp->b_bandwidth);
417 19 : gf_list_del(sdp->Timing);
418 19 : gf_free(sdp);
419 : }
420 :
421 :
422 20 : Bool SDP_IsDynamicPayload(GF_SDPMedia *media, char *payt)
423 : {
424 : u32 i;
425 : GF_RTPMap *map;
426 : char buf[10];
427 20 : i=0;
428 40 : while ((map = (GF_RTPMap*)gf_list_enum(media->RTPMaps, &i))) {
429 20 : sprintf(buf, "%d", map->PayloadType);
430 20 : if (!strcmp(payt, buf)) return GF_TRUE;
431 : }
432 : return GF_FALSE;
433 : }
434 :
435 : //translate h || m || d in sec. Fractions are not allowed with this writing
436 19 : static s32 SDP_MakeSeconds(char *buf)
437 : {
438 : s32 sign;
439 : char num[30], *test;
440 : sign = 1;
441 19 : if (buf[0] == '-') {
442 : sign = -1;
443 0 : buf += 1;
444 : }
445 : memset(num, 0, 30);
446 19 : test = strstr(buf, "d");
447 19 : if (test) {
448 : assert(strlen(buf)-strlen(test) < sizeof(num));
449 0 : memcpy(num, buf, MIN(sizeof(num)-1, strlen(buf)-strlen(test)));
450 0 : return (atoi(num)*sign*86400);
451 : }
452 19 : test = strstr(buf, "h");
453 19 : if (test) {
454 : assert(strlen(buf)-strlen(test) < sizeof(num));
455 0 : memcpy(num, buf, MIN(sizeof(num)-1, strlen(buf)-strlen(test)));
456 0 : return (atoi(num)*sign*3600);
457 : }
458 19 : test = strstr(buf, "m");
459 19 : if (test) {
460 : assert(strlen(buf)-strlen(test) < sizeof(num));
461 19 : memcpy(num, buf, MIN(sizeof(num)-1, strlen(buf)-strlen(test)));
462 19 : return (atoi(num)*sign*60);
463 : }
464 0 : return (atoi(buf) * sign);
465 : }
466 :
467 :
468 : GF_EXPORT
469 19 : GF_Err gf_sdp_info_parse(GF_SDPInfo *sdp, char *sdp_text, u32 text_size)
470 : {
471 : GF_SDPBandwidth *bw;
472 : GF_SDPConnection *conn;
473 : GF_SDPMedia *media;
474 : GF_SDPTiming *timing;
475 : u32 i;
476 : s32 pos, LinePos;
477 : char LineBuf[3000], comp[3000];
478 :
479 : media = NULL;
480 : timing = NULL;
481 :
482 19 : if (!sdp) return GF_BAD_PARAM;
483 :
484 : #ifdef GPAC_ENABLE_COVERAGE
485 19 : if (gf_sys_is_cov_mode()) {
486 19 : SDP_MakeSeconds("30m");
487 : }
488 : #endif
489 :
490 : //Clean SDP info
491 19 : gf_sdp_info_reset(sdp);
492 :
493 : LinePos = 0;
494 : while (1) {
495 285 : LinePos = gf_token_get_line(sdp_text, LinePos, text_size, LineBuf, 3000);
496 285 : if (LinePos <= 0) break;
497 266 : if (!strcmp(LineBuf, "\r\n") || !strcmp(LineBuf, "\n") || !strcmp(LineBuf, "\r")) continue;
498 :
499 :
500 247 : switch (LineBuf[0]) {
501 19 : case 'v':
502 19 : /*pos = */gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
503 19 : sdp->Version = atoi(comp);
504 19 : break;
505 19 : case 'o':
506 19 : pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
507 19 : sdp->o_username = gf_strdup(comp);
508 19 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
509 19 : sdp->o_session_id = gf_strdup(comp);
510 19 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
511 19 : sdp->o_version = gf_strdup(comp);
512 :
513 19 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
514 19 : sdp->o_net_type = gf_strdup(comp);
515 :
516 19 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
517 19 : sdp->o_add_type = gf_strdup(comp);
518 :
519 19 : /*pos = */gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
520 19 : sdp->o_address = gf_strdup(comp);
521 19 : break;
522 19 : case 's':
523 19 : /*pos = */gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
524 19 : sdp->s_session_name = gf_strdup(comp);
525 19 : break;
526 19 : case 'i':
527 19 : /*pos = */gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
528 19 : sdp->i_description = gf_strdup(comp);
529 19 : break;
530 19 : case 'u':
531 19 : /*pos = */gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
532 19 : sdp->u_uri = gf_strdup(comp);
533 19 : break;
534 0 : case 'e':
535 0 : /*pos = */gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
536 0 : sdp->e_email = gf_strdup(comp);
537 0 : break;
538 0 : case 'p':
539 0 : /*pos = */gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
540 0 : sdp->p_phone = gf_strdup(comp);
541 0 : break;
542 19 : case 'c':
543 : //if at session level, only 1 is allowed for all SDP
544 19 : if (sdp->c_connection) break;
545 :
546 19 : conn = gf_sdp_conn_new();
547 :
548 19 : pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
549 19 : conn->net_type = gf_strdup(comp);
550 :
551 19 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
552 19 : conn->add_type = gf_strdup(comp);
553 :
554 19 : pos = gf_token_get(LineBuf, pos, " /\r\n", comp, 3000);
555 19 : conn->host = gf_strdup(comp);
556 19 : if (gf_sk_is_multicast_address(conn->host)) {
557 : //a valid SDP will have TTL if address is multicast
558 0 : pos = gf_token_get(LineBuf, pos, "/\r\n", comp, 3000);
559 0 : if (pos > 0) {
560 0 : conn->TTL = atoi(comp);
561 : //multiple address indication is only valid for media
562 0 : pos = gf_token_get(LineBuf, pos, "/\r\n", comp, 3000);
563 : }
564 0 : if (pos > 0) {
565 0 : if (!media) {
566 0 : gf_sdp_conn_del(conn);
567 0 : break;
568 : }
569 0 : conn->add_count = atoi(comp);
570 : }
571 : }
572 19 : if (!media)
573 19 : sdp->c_connection = conn;
574 : else
575 0 : gf_list_add(media->Connections, conn);
576 :
577 : break;
578 0 : case 'b':
579 0 : pos = gf_token_get(LineBuf, 2, ":\r\n", comp, 3000);
580 0 : if (strcmp(comp, "CT") && strcmp(comp, "AS") && (comp[0] != 'X')) break;
581 :
582 0 : GF_SAFEALLOC(bw, GF_SDPBandwidth);
583 0 : if (!bw) return GF_OUT_OF_MEM;
584 0 : bw->name = gf_strdup(comp);
585 0 : /*pos = */gf_token_get(LineBuf, pos, ":\r\n", comp, 3000);
586 0 : bw->value = atoi(comp);
587 0 : if (media) {
588 0 : gf_list_add(media->Bandwidths, bw);
589 : } else {
590 0 : gf_list_add(sdp->b_bandwidth, bw);
591 : }
592 : break;
593 :
594 19 : case 't':
595 19 : if (media) break;
596 : //create a new time structure for each entry
597 19 : GF_SAFEALLOC(timing, GF_SDPTiming);
598 19 : if (!timing) return GF_OUT_OF_MEM;
599 19 : pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
600 19 : timing->StartTime = atoi(comp);
601 19 : /*pos = */gf_token_get(LineBuf, pos, "\r\n", comp, 3000);
602 19 : timing->StopTime = atoi(comp);
603 19 : gf_list_add(sdp->Timing, timing);
604 19 : break;
605 0 : case 'r':
606 0 : if (media) break;
607 0 : pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
608 0 : if (!timing) return GF_NON_COMPLIANT_BITSTREAM;
609 0 : timing->RepeatInterval = SDP_MakeSeconds(comp);
610 0 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
611 0 : timing->ActiveDuration = SDP_MakeSeconds(comp);
612 0 : while (pos>=0) {
613 0 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
614 0 : if (pos <= 0) break;
615 0 : timing->OffsetFromStart[timing->NbRepeatOffsets] = SDP_MakeSeconds(comp);
616 0 : timing->NbRepeatOffsets += 1;
617 : }
618 : break;
619 0 : case 'z':
620 0 : if (media) break;
621 : pos = 2;
622 0 : if (!timing) return GF_NON_COMPLIANT_BITSTREAM;
623 : while (1) {
624 0 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
625 0 : if (pos <= 0) break;
626 0 : timing->AdjustmentTime[timing->NbZoneOffsets] = atoi(comp);
627 0 : pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
628 0 : timing->AdjustmentOffset[timing->NbZoneOffsets] = SDP_MakeSeconds(comp);
629 0 : timing->NbZoneOffsets += 1;
630 : }
631 : break;
632 0 : case 'k':
633 0 : pos = gf_token_get(LineBuf, 2, ":\t\r\n", comp, 3000);
634 0 : if (media) {
635 0 : media->k_method = gf_strdup(comp);
636 : } else {
637 0 : sdp->k_method = gf_strdup(comp);
638 : }
639 0 : pos = gf_token_get(LineBuf, pos, ":\r\n", comp, 3000);
640 0 : if (pos > 0) {
641 0 : if (media) {
642 0 : media->k_key = gf_strdup(comp);
643 : } else {
644 0 : sdp->k_key = gf_strdup(comp);
645 : }
646 : }
647 : break;
648 94 : case 'a':
649 94 : SDP_ParseAttribute(sdp, LineBuf+2, media);
650 94 : break;
651 20 : case 'm':
652 20 : pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
653 20 : if (strcmp(comp, "audio")
654 8 : && strcmp(comp, "data")
655 8 : && strcmp(comp, "control")
656 8 : && strcmp(comp, "video")
657 1 : && strcmp(comp, "text")
658 0 : && strcmp(comp, "application")) {
659 : return GF_SERVICE_ERROR;
660 : }
661 20 : media = gf_sdp_media_new();
662 : //media type
663 20 : if (!strcmp(comp, "video")) media->Type = 1;
664 13 : else if (!strcmp(comp, "audio")) media->Type = 2;
665 1 : else if (!strcmp(comp, "text")) media->Type = 3;
666 0 : else if (!strcmp(comp, "data")) media->Type = 4;
667 0 : else if (!strcmp(comp, "control")) media->Type = 5;
668 0 : else media->Type = 0;
669 : //port numbers
670 20 : gf_token_get(LineBuf, pos, " ", comp, 3000);
671 20 : if (!strstr(comp, "/")) {
672 20 : pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
673 20 : media->PortNumber = atoi(comp);
674 20 : media->NumPorts = 0;
675 : } else {
676 0 : pos = gf_token_get(LineBuf, pos, " /\r\n", comp, 3000);
677 0 : media->PortNumber = atoi(comp);
678 0 : pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
679 0 : media->NumPorts = atoi(comp);
680 : }
681 : //transport Profile
682 20 : pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
683 20 : media->Profile = gf_strdup(comp);
684 20 : /*pos = */gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
685 20 : media->fmt_list = gf_strdup(comp);
686 :
687 20 : gf_list_add(sdp->media_desc, media);
688 20 : break;
689 : }
690 : }
691 : //finally rewrite the fmt_list for all media, and remove dynamic payloads
692 : //from the list
693 19 : i=0;
694 58 : while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) {
695 : pos = 0;
696 : LinePos = 1;
697 : strcpy(LineBuf, "");
698 : while (1) {
699 40 : if (!media->fmt_list) break;
700 20 : pos = gf_token_get(media->fmt_list, pos, " ", comp, 3000);
701 20 : if (pos <= 0) break;
702 20 : if (!SDP_IsDynamicPayload(media, comp)) {
703 0 : if (!LinePos) {
704 : strcat(LineBuf, " ");
705 : } else {
706 : LinePos = 0;
707 : }
708 : strcat(LineBuf, comp);
709 : }
710 20 : gf_free(media->fmt_list);
711 20 : media->fmt_list = NULL;
712 20 : if (strlen(LineBuf)) {
713 0 : media->fmt_list = gf_strdup(LineBuf);
714 : }
715 : }
716 : }
717 : return GF_OK;
718 : }
719 :
720 :
721 : #if 0 //unused
722 :
723 : static GF_Err SDP_CheckConnection(GF_SDPConnection *conn)
724 : {
725 : if (!conn) return GF_BAD_PARAM;
726 : if (!conn->host || !conn->add_type || !conn->net_type) return GF_REMOTE_SERVICE_ERROR;
727 : if (gf_sk_is_multicast_address(conn->host)) {
728 : if (conn->TTL < 0 || conn->TTL > 255) return GF_REMOTE_SERVICE_ERROR;
729 : } else {
730 : conn->TTL = -1;
731 : conn->add_count = 0;
732 : }
733 : return GF_OK;
734 : }
735 :
736 : //return GF_BAD_PARAM if invalid structure, GF_REMOTE_SERVICE_ERROR if bad formatting
737 : //or GF_OK
738 : GF_Err gf_sdp_info_check(GF_SDPInfo *sdp)
739 : {
740 : GF_Err e;
741 : u32 i, j, count;
742 : GF_SDPMedia *media;
743 : GF_SDPConnection *conn;
744 : GF_RTPMap *map;
745 : Bool HasGlobalConnection, HasSeveralPorts;
746 :
747 : if (!sdp || !sdp->media_desc || !sdp->Attributes) return GF_BAD_PARAM;
748 : //we force at least one media per SDP
749 : if (!gf_list_count(sdp->media_desc)) return GF_REMOTE_SERVICE_ERROR;
750 :
751 : //normative fields
752 : //o=
753 : if (!sdp->o_add_type || !sdp->o_address || !sdp->o_username || !sdp->o_session_id || !sdp->o_version)
754 : return GF_REMOTE_SERVICE_ERROR;
755 : //s=
756 : //commented for intermedia demos
757 : // if (!sdp->s_session_name) return GF_REMOTE_SERVICE_ERROR;
758 : //t=
759 : // if () return GF_REMOTE_SERVICE_ERROR;
760 : //c=
761 : if (sdp->c_connection) {
762 : e = SDP_CheckConnection(sdp->c_connection);
763 : if (e) return e;
764 : //multiple addresses are only for media desc
765 : if (sdp->c_connection->add_count >= 2) return GF_REMOTE_SERVICE_ERROR;
766 : HasGlobalConnection = GF_TRUE;
767 : } else {
768 : HasGlobalConnection = GF_FALSE;
769 : }
770 :
771 : //then check all media
772 : i=0;
773 : while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) {
774 : HasSeveralPorts = GF_FALSE;
775 :
776 : //m= : force non-null port, profile and fmt_list
777 : if (/*!media->PortNumber || */ !media->Profile) return GF_REMOTE_SERVICE_ERROR;
778 : if (media->NumPorts) HasSeveralPorts = GF_TRUE;
779 :
780 : //no connections specified - THIS IS AN ERROR IN SDP BUT NOT IN ALL RTSP SESSIONS...
781 : // if (!HasGlobalConnection && !gf_list_count(media->Connections)) return GF_REMOTE_SERVICE_ERROR;
782 : //too many connections specified
783 : if (HasGlobalConnection && gf_list_count(media->Connections)) return GF_REMOTE_SERVICE_ERROR;
784 :
785 : //check all connections, and make sure we don't have multiple addresses
786 : //and multiple ports at the same time
787 : count = gf_list_count(media->Connections);
788 : if (count>1 && HasSeveralPorts) return GF_REMOTE_SERVICE_ERROR;
789 :
790 : for (j=0; j<count; j++) {
791 : conn = (GF_SDPConnection*)gf_list_get(media->Connections, j);
792 : e = SDP_CheckConnection(conn);
793 : if (e) return e;
794 : if ((conn->add_count >= 2) && HasSeveralPorts) return GF_REMOTE_SERVICE_ERROR;
795 : }
796 : //RTPMaps. 0 is tolerated, but if some are specified check them
797 : j=0;
798 : while ((map = (GF_RTPMap*)gf_list_enum(media->RTPMaps, &j))) {
799 : //RFC2327 is not clear here, but we assume the PayloadType should be a DYN one
800 : //however this depends on the profile (RTP/AVP or others) so don't check it
801 : //ClockRate SHALL NOT be NULL
802 : if (!map->payload_name || !map->ClockRate) return GF_REMOTE_SERVICE_ERROR;
803 : }
804 : }
805 : //Encryption: nothing tells wether the scope of the global key is eclusive or not.
806 : //we accept a global key + keys per media entry, assuming that the media key primes
807 : //on the global key
808 :
809 : return GF_OK;
810 : }
811 :
812 :
813 : #define SDP_WRITE_ALLOC_STR_WITHOUT_CHECK(str, space) \
814 : if (strlen(str)+pos + (space ? 1 : 0) >= buf_size) { \
815 : buf_size += SDP_WRITE_STEPALLOC; \
816 : buf = (char*)gf_realloc(buf, sizeof(char)*buf_size); \
817 : } \
818 : strcpy(buf+pos, str); \
819 : pos += (u32) strlen(str); \
820 : if (space) { \
821 : strcat(buf+pos, " "); \
822 : pos += 1; \
823 : }
824 :
825 : #define SDP_WRITE_ALLOC_STR(str, space) \
826 : if (str) { \
827 : SDP_WRITE_ALLOC_STR_WITHOUT_CHECK(str, space); \
828 : } \
829 :
830 : #define SDP_WRITE_ALLOC_INT(d, spa, sig) \
831 : if (sig < 0) { \
832 : sprintf(temp, "%d", d); \
833 : } else { \
834 : sprintf(temp, "%u", d); \
835 : } \
836 : SDP_WRITE_ALLOC_STR_WITHOUT_CHECK(temp, spa);
837 :
838 : #define SDP_WRITE_ALLOC_FLOAT(d, spa) \
839 : sprintf(temp, "%.2f", d); \
840 : SDP_WRITE_ALLOC_STR_WITHOUT_CHECK(temp, spa);
841 :
842 : #define TEST_SDP_WRITE_SINGLE(type, str, sep) \
843 : if (str) { \
844 : SDP_WRITE_ALLOC_STR(type, 0); \
845 : if (sep) SDP_WRITE_ALLOC_STR(":", 0); \
846 : SDP_WRITE_ALLOC_STR(str, 0); \
847 : SDP_WRITE_ALLOC_STR("\r\n", 0); \
848 : }
849 :
850 :
851 : #define SDP_WRITE_CONN(conn) \
852 : if (conn) { \
853 : SDP_WRITE_ALLOC_STR("c=", 0); \
854 : SDP_WRITE_ALLOC_STR(conn->net_type, 1); \
855 : SDP_WRITE_ALLOC_STR(conn->add_type, 1); \
856 : SDP_WRITE_ALLOC_STR(conn->host, 0); \
857 : if (gf_sk_is_multicast_address(conn->host)) { \
858 : SDP_WRITE_ALLOC_STR("/", 0); \
859 : SDP_WRITE_ALLOC_INT(conn->TTL, 0, 0); \
860 : if (conn->add_count >= 2) { \
861 : SDP_WRITE_ALLOC_STR("/", 0); \
862 : SDP_WRITE_ALLOC_INT(conn->add_count, 0, 0); \
863 : } \
864 : } \
865 : SDP_WRITE_ALLOC_STR("\r\n", 0); \
866 : }
867 :
868 : GF_Err gf_sdp_info_write(GF_SDPInfo *sdp, char **out_str_buf)
869 : {
870 : char *buf;
871 : GF_SDP_FMTP *fmtp;
872 : char temp[50];
873 : GF_SDPMedia *media;
874 : GF_SDPBandwidth *bw;
875 : u32 buf_size, pos, i, j, k;
876 : GF_RTPMap *map;
877 : GF_SDPConnection *conn;
878 : GF_Err e;
879 : GF_SDPTiming *timing;
880 : GF_X_Attribute *att;
881 :
882 : e = gf_sdp_info_check(sdp);
883 : if (e) return e;
884 :
885 : buf = (char *)gf_malloc(SDP_WRITE_STEPALLOC);
886 : buf_size = SDP_WRITE_STEPALLOC;
887 : pos = 0;
888 :
889 : //v
890 : SDP_WRITE_ALLOC_STR("v=", 0);
891 : SDP_WRITE_ALLOC_INT(sdp->Version, 0, 0);
892 : SDP_WRITE_ALLOC_STR("\r\n", 0);
893 : //o
894 : SDP_WRITE_ALLOC_STR("o=", 0);
895 : SDP_WRITE_ALLOC_STR(sdp->o_username, 1);
896 : SDP_WRITE_ALLOC_STR(sdp->o_session_id, 1);
897 : SDP_WRITE_ALLOC_STR(sdp->o_version, 1);
898 : SDP_WRITE_ALLOC_STR(sdp->o_net_type, 1);
899 : SDP_WRITE_ALLOC_STR(sdp->o_add_type, 1);
900 : SDP_WRITE_ALLOC_STR(sdp->o_address, 0);
901 : SDP_WRITE_ALLOC_STR("\r\n", 0);
902 : //s
903 : TEST_SDP_WRITE_SINGLE("s=", sdp->s_session_name, 0);
904 : //i
905 : TEST_SDP_WRITE_SINGLE("i=", sdp->i_description, 0);
906 : //u
907 : TEST_SDP_WRITE_SINGLE("u=", sdp->u_uri, 0);
908 : //e
909 : TEST_SDP_WRITE_SINGLE("e=", sdp->e_email, 0);
910 : //p
911 : TEST_SDP_WRITE_SINGLE("p=", sdp->p_phone, 0);
912 : //c
913 : SDP_WRITE_CONN(sdp->c_connection);
914 : //b
915 : i=0;
916 : while ((bw = (GF_SDPBandwidth*)gf_list_enum(sdp->b_bandwidth, &i))) {
917 : SDP_WRITE_ALLOC_STR("b=", 0);
918 : SDP_WRITE_ALLOC_STR(bw->name, 0);
919 : SDP_WRITE_ALLOC_STR(":", 0);
920 : SDP_WRITE_ALLOC_INT(bw->value, 0, 0);
921 : SDP_WRITE_ALLOC_STR("\r\n", 0);
922 : }
923 : //t+r+z
924 : i=0;
925 : while ((timing = (GF_SDPTiming*)gf_list_enum(sdp->Timing, &i))) {
926 : if (timing->NbRepeatOffsets > GF_SDP_MAX_TIMEOFFSET) timing->NbRepeatOffsets = GF_SDP_MAX_TIMEOFFSET;
927 : if (timing->NbZoneOffsets > GF_SDP_MAX_TIMEOFFSET) timing->NbZoneOffsets = GF_SDP_MAX_TIMEOFFSET;
928 : //t
929 : SDP_WRITE_ALLOC_STR("t=", 0);
930 : SDP_WRITE_ALLOC_INT(timing->StartTime, 1, 0);
931 : SDP_WRITE_ALLOC_INT(timing->StopTime, 0, 0);
932 : SDP_WRITE_ALLOC_STR("\r\n", 0);
933 : if (timing->NbRepeatOffsets) {
934 : SDP_WRITE_ALLOC_STR("r=", 0);
935 : SDP_WRITE_ALLOC_INT(timing->RepeatInterval, 1, 0);
936 : SDP_WRITE_ALLOC_INT(timing->ActiveDuration, 0, 0);
937 : for (j=0; j<timing->NbRepeatOffsets; j++) {
938 : SDP_WRITE_ALLOC_STR(" ", 0);
939 : SDP_WRITE_ALLOC_INT(timing->OffsetFromStart[j], 0, 0);
940 : }
941 : SDP_WRITE_ALLOC_STR("\r\n", 0);
942 : }
943 : if (timing->NbZoneOffsets) {
944 : SDP_WRITE_ALLOC_STR("z=", 0);
945 : for (j=0; j<timing->NbZoneOffsets; j++) {
946 : SDP_WRITE_ALLOC_INT(timing->AdjustmentTime[j], 1, 0);
947 : if (j+1 == timing->NbRepeatOffsets) {
948 : SDP_WRITE_ALLOC_INT(timing->AdjustmentOffset[j], 0, 1);
949 : } else {
950 : SDP_WRITE_ALLOC_INT(timing->AdjustmentOffset[j], 1, 1);
951 : }
952 : }
953 : SDP_WRITE_ALLOC_STR("\r\n", 0);
954 : }
955 : }
956 : //k
957 : if (sdp->k_method) {
958 : SDP_WRITE_ALLOC_STR("k=", 0);
959 : SDP_WRITE_ALLOC_STR(sdp->k_method, 0);
960 : if (sdp->k_key) {
961 : SDP_WRITE_ALLOC_STR(":", 0);
962 : SDP_WRITE_ALLOC_STR(sdp->k_key, 0);
963 : }
964 : SDP_WRITE_ALLOC_STR("\r\n", 0);
965 : }
966 : //a=cat
967 : TEST_SDP_WRITE_SINGLE("a=cat", sdp->a_cat, 1);
968 : //a=keywds
969 : TEST_SDP_WRITE_SINGLE("a=keywds", sdp->a_keywds, 1);
970 : //a=tool
971 : TEST_SDP_WRITE_SINGLE("a=tool", sdp->a_tool, 1);
972 : //a=SendRecv
973 : switch (sdp->a_SendReceive) {
974 : case 1:
975 : TEST_SDP_WRITE_SINGLE("a=", "recvonly", 0);
976 : break;
977 : case 2:
978 : TEST_SDP_WRITE_SINGLE("a=", "sendonly", 0);
979 : break;
980 : case 3:
981 : TEST_SDP_WRITE_SINGLE("a=", "sendrecv", 0);
982 : break;
983 : default:
984 : break;
985 : }
986 : //a=type
987 : TEST_SDP_WRITE_SINGLE("a=type", sdp->a_type, 1);
988 : //a=charset
989 : TEST_SDP_WRITE_SINGLE("a=charset", sdp->a_charset, 1);
990 : //a=sdplang
991 : TEST_SDP_WRITE_SINGLE("a=sdplang", sdp->a_sdplang, 1);
992 : //a=lang
993 : TEST_SDP_WRITE_SINGLE("a=lang", sdp->a_lang, 1);
994 :
995 : //the rest
996 : i=0;
997 : while ((att = (GF_X_Attribute*)gf_list_enum(sdp->Attributes, &i))) {
998 : SDP_WRITE_ALLOC_STR("a=", 0);
999 : SDP_WRITE_ALLOC_STR(att->Name, 0);
1000 : if (att->Value) {
1001 : SDP_WRITE_ALLOC_STR(":", 0);
1002 : SDP_WRITE_ALLOC_STR(att->Value, 0);
1003 : }
1004 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1005 : }
1006 :
1007 : //now write media specific
1008 : i=0;
1009 : while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) {
1010 : //m=
1011 : SDP_WRITE_ALLOC_STR("m=", 0);
1012 : switch (media->Type) {
1013 : case 1:
1014 : SDP_WRITE_ALLOC_STR("video", 1);
1015 : break;
1016 : case 2:
1017 : SDP_WRITE_ALLOC_STR("audio", 1);
1018 : break;
1019 : case 3:
1020 : SDP_WRITE_ALLOC_STR("data", 1);
1021 : break;
1022 : case 4:
1023 : SDP_WRITE_ALLOC_STR("control", 1);
1024 : break;
1025 : default:
1026 : SDP_WRITE_ALLOC_STR("application", 1);
1027 : break;
1028 : }
1029 : SDP_WRITE_ALLOC_INT(media->PortNumber, 0, 0);
1030 : if (media->NumPorts >= 2) {
1031 : SDP_WRITE_ALLOC_STR("/", 0);
1032 : SDP_WRITE_ALLOC_INT(media->NumPorts, 1, 0);
1033 : } else {
1034 : SDP_WRITE_ALLOC_STR(" ", 0);
1035 : }
1036 : SDP_WRITE_ALLOC_STR(media->Profile, 1);
1037 : SDP_WRITE_ALLOC_STR(media->fmt_list, 0);
1038 :
1039 : j=0;
1040 : while ((map = (GF_RTPMap*)gf_list_enum(media->RTPMaps, &j))) {
1041 : SDP_WRITE_ALLOC_STR(" ", 0);
1042 : SDP_WRITE_ALLOC_INT(map->PayloadType, 0, 0);
1043 : }
1044 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1045 :
1046 : //c=
1047 : j=0;
1048 : while ((conn = (GF_SDPConnection*)gf_list_enum(media->Connections, &j))) {
1049 : SDP_WRITE_CONN(conn);
1050 : }
1051 :
1052 : //k=
1053 : if (media->k_method) {
1054 : SDP_WRITE_ALLOC_STR("k=", 0);
1055 : SDP_WRITE_ALLOC_STR(media->k_method, 0);
1056 : if (media->k_key) {
1057 : SDP_WRITE_ALLOC_STR(":", 0);
1058 : SDP_WRITE_ALLOC_STR(media->k_key, 0);
1059 : }
1060 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1061 : }
1062 : //b
1063 : j=0;
1064 : while ((bw = (GF_SDPBandwidth*)gf_list_enum(media->Bandwidths, &j))) {
1065 : SDP_WRITE_ALLOC_STR("b=", 0);
1066 : SDP_WRITE_ALLOC_STR(bw->name, 0);
1067 : SDP_WRITE_ALLOC_STR(":", 0);
1068 : SDP_WRITE_ALLOC_INT(bw->value, 0, 0);
1069 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1070 : }
1071 :
1072 : //a=rtpmap
1073 : j=0;
1074 : while ((map = (GF_RTPMap*)gf_list_enum(media->RTPMaps, &j))) {
1075 :
1076 : SDP_WRITE_ALLOC_STR("a=rtpmap", 0);
1077 : SDP_WRITE_ALLOC_STR(":", 0);
1078 : SDP_WRITE_ALLOC_INT(map->PayloadType, 1, 0);
1079 : SDP_WRITE_ALLOC_STR(map->payload_name, 0);
1080 : SDP_WRITE_ALLOC_STR("/", 0);
1081 : SDP_WRITE_ALLOC_INT(map->ClockRate, 0, 0);
1082 : if (map->AudioChannels > 1) {
1083 : SDP_WRITE_ALLOC_STR("/", 0);
1084 : SDP_WRITE_ALLOC_INT(map->AudioChannels, 0, 0);
1085 : }
1086 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1087 : }
1088 : //a=fmtp
1089 : j=0;
1090 : while ((fmtp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &j))) {
1091 : SDP_WRITE_ALLOC_STR("a=fmtp:", 0);
1092 : SDP_WRITE_ALLOC_INT(fmtp->PayloadType, 1 , 0);
1093 : k=0;
1094 : while ((att = (GF_X_Attribute*)gf_list_enum(fmtp->Attributes, &k)) ) {
1095 : if (k>1) SDP_WRITE_ALLOC_STR(";", 0);
1096 : SDP_WRITE_ALLOC_STR(att->Name, 0);
1097 : if (att->Value) {
1098 : SDP_WRITE_ALLOC_STR("=", 0);
1099 : SDP_WRITE_ALLOC_STR(att->Value, 0);
1100 : }
1101 : }
1102 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1103 : }
1104 : //a=ptime
1105 : if (media->PacketTime) {
1106 : SDP_WRITE_ALLOC_STR("a=ptime:", 0);
1107 : SDP_WRITE_ALLOC_INT(media->PacketTime, 0, 0);
1108 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1109 : }
1110 : //a=FrameRate
1111 : if (media->Type == 1 && media->FrameRate) {
1112 : SDP_WRITE_ALLOC_STR("a=framerate:", 0);
1113 : SDP_WRITE_ALLOC_FLOAT(media->FrameRate, 0);
1114 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1115 : }
1116 : //a=SendRecv
1117 : switch (media->SendReceive) {
1118 : case 1:
1119 : TEST_SDP_WRITE_SINGLE("a=", "recvonly", 0);
1120 : break;
1121 : case 2:
1122 : TEST_SDP_WRITE_SINGLE("a=", "sendonly", 0);
1123 : break;
1124 : case 3:
1125 : TEST_SDP_WRITE_SINGLE("a=", "sendrecv", 0);
1126 : break;
1127 : default:
1128 : break;
1129 : }
1130 : //a=orient
1131 : TEST_SDP_WRITE_SINGLE("a=orient", media->orientation, 1);
1132 : //a=sdplang
1133 : TEST_SDP_WRITE_SINGLE("a=sdplang", media->sdplang, 1);
1134 : //a=lang
1135 : TEST_SDP_WRITE_SINGLE("a=lang", media->lang, 1);
1136 : //a=quality
1137 : if (media->Quality >= 0) {
1138 : SDP_WRITE_ALLOC_STR("a=quality:", 0);
1139 : SDP_WRITE_ALLOC_INT(media->Quality, 0, 0);
1140 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1141 : }
1142 : //the rest
1143 : j=0;
1144 : while ((att = (GF_X_Attribute*)gf_list_enum(media->Attributes, &j))) {
1145 : SDP_WRITE_ALLOC_STR("a=", 0);
1146 : SDP_WRITE_ALLOC_STR(att->Name, 0);
1147 : if (att->Value) {
1148 : SDP_WRITE_ALLOC_STR(":", 0);
1149 : SDP_WRITE_ALLOC_STR(att->Value, 0);
1150 : }
1151 : SDP_WRITE_ALLOC_STR("\r\n", 0);
1152 : }
1153 : }
1154 :
1155 : //finally gf_realloc
1156 : //finall NULL char
1157 : pos += 1;
1158 : buf = (char *)gf_realloc(buf, pos);
1159 : *out_str_buf = buf;
1160 : return GF_OK;
1161 : }
1162 : #endif
1163 :
1164 :
1165 : #endif /*GPAC_DISABLE_STREAMING*/
|