LCOV - code coverage report
Current view: top level - ietf - sdp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 298 438 68.0 %
Date: 2021-04-29 23:48:07 Functions: 14 14 100.0 %

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

Generated by: LCOV version 1.13