1 /*****************************************************************************
2 * sdp.c : SDP creation helpers
3 *****************************************************************************
4 * Copyright © 2007 Rémi Denis-Courmont
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
33 #include <vlc_network.h>
34 #include <vlc_charset.h>
36 #include "stream_output.h"
38 #define MAXSDPADDRESS 47
41 char *AddressToSDP (const struct sockaddr
*addr
, socklen_t addrlen
, char *buf
)
43 if (addrlen
< offsetof (struct sockaddr
, sa_family
)
44 + sizeof (addr
->sa_family
))
47 strcpy (buf
, "IN IP* ");
49 if (vlc_getnameinfo (addr
, addrlen
, buf
+ 7, MAXSDPADDRESS
- 7, NULL
,
53 switch (addr
->sa_family
)
57 if (net_SockAddrIsMulticast (addr
, addrlen
))
58 strcat (buf
, "/255"); // obsolete in RFC4566, dummy value
66 char *ptr
= strchr (buf
, '%');
68 *ptr
= '\0'; // remove scope ID
82 static bool IsSDPString (const char *str
)
84 if (strchr (str
, '\r') != NULL
)
86 if (strchr (str
, '\n') != NULL
)
95 char *sdp_Start (const char *name
, const char *description
, const char *url
,
96 const char *email
, const char *phone
,
97 const struct sockaddr
*src
, size_t srclen
,
98 const struct sockaddr
*addr
, size_t addrlen
)
100 uint64_t now
= NTPtime64 ();
102 char connection
[MAXSDPADDRESS
], hostname
[256],
103 sfilter
[MAXSDPADDRESS
+ sizeof ("\r\na=source-filter: incl * ")];
104 const char *preurl
= "\r\nu=", *premail
= "\r\ne=", *prephone
= "\r\np=";
106 gethostname (hostname
, sizeof (hostname
));
110 if (description
== NULL
)
115 premail
= email
= "";
117 prephone
= phone
= "";
119 if (!IsSDPString (name
) || !IsSDPString (description
)
120 || !IsSDPString (url
) || !IsSDPString (email
) || !IsSDPString (phone
)
121 || (AddressToSDP (addr
, addrlen
, connection
) == NULL
))
124 strcpy (sfilter
, "");
127 char machine
[MAXSDPADDRESS
];
129 if (AddressToSDP (src
, srclen
, machine
) != NULL
)
130 sprintf (sfilter
, "\r\na=source-filter: incl IN IP%c * %s",
131 machine
[5], machine
+ 7);
134 if (asprintf (&sdp
, "v=0"
135 "\r\no=- "I64Fu
" "I64Fu
" IN IP%c %s"
138 "%s%s" // optional URL
139 "%s%s" // optional email
140 "%s%s" // optional phone number
142 // bandwidth not specified
143 "\r\nt=0 0" // one dummy time span
145 // no time zone adjustment (silly idea anyway)
146 // no encryption key (deprecated)
147 "\r\na=tool:"PACKAGE_STRING
149 "\r\na=type:broadcast"
150 "\r\na=charset:UTF-8"
151 "%s" // optional source filter
153 /* o= */ now
, now
, connection
[5], hostname
,
155 /* i= */ description
,
156 /* u= */ preurl
, url
,
157 /* e= */ premail
, email
,
158 /* p= */ prephone
, phone
,
160 /* source-filter */ sfilter
) == -1)
167 vsdp_AddAttribute (char **sdp
, const char *name
, const char *fmt
, va_list ap
)
169 size_t oldlen
= strlen (*sdp
);
170 size_t addlen
= sizeof ("a=\r\n") + strlen (name
);
177 addlen
+= 1 + vsnprintf (NULL
, 0, fmt
, aq
);
181 char *ret
= realloc (*sdp
, oldlen
+ addlen
);
185 oldlen
+= sprintf (ret
+ oldlen
, "a=%s", name
);
189 oldlen
+= vsprintf (ret
+ oldlen
, fmt
, ap
);
192 strcpy (ret
+ oldlen
, "\r\n");
197 char *sdp_AddAttribute (char **sdp
, const char *name
, const char *fmt
, ...)
203 ret
= vsdp_AddAttribute (sdp
, name
, fmt
, ap
);
210 char *sdp_AddMedia (char **sdp
,
211 const char *type
, const char *protocol
, int dport
,
212 unsigned pt
, bool bw_indep
, unsigned bw
,
213 const char *ptname
, unsigned clock
, unsigned chans
,
217 size_t inlen
= strlen (*sdp
), outlen
= inlen
;
219 /* Some default values */
222 if (protocol
== NULL
)
223 protocol
= "RTP/AVP";
226 outlen
+= snprintf (NULL
, 0,
230 type
, dport
, protocol
, pt
, bw
);
232 newsdp
= realloc (*sdp
, outlen
+ 1);
237 ptr
= newsdp
+ inlen
;
239 ptr
+= sprintf (ptr
, "m=%s %u %s %u\r\n",
240 type
, dport
, protocol
, pt
);
242 ptr
+= sprintf (ptr
, "b=%s:%u\r\n", bw_indep
? "TIAS" : "AS", bw
);
243 ptr
+= sprintf (ptr
, "b=RR:0\r\n");
245 /* RTP payload type map */
248 if ((strcmp (type
, "audio") == 0) && (chans
!= 1))
249 sdp_AddAttribute (sdp
, "rtpmap", "%u %s/%u/%u", pt
, ptname
, clock
,
252 sdp_AddAttribute (sdp
, "rtpmap", "%u %s/%u", pt
, ptname
, clock
);
254 /* Format parameters */
256 sdp_AddAttribute (sdp
, "fmtp", "%u %s", pt
, fmtp
);
262 char *vlc_sdp_Start (vlc_object_t
*obj
, const char *cfgpref
,
263 const struct sockaddr
*src
, size_t srclen
,
264 const struct sockaddr
*addr
, size_t addrlen
)
266 size_t cfglen
= strlen (cfgpref
);
270 char varname
[cfglen
+ sizeof ("description")], *subvar
= varname
+ cfglen
;
271 strcpy (varname
, cfgpref
);
273 session_descriptor_t
*p_session
= calloc (1, sizeof (*p_session
));
274 if (p_session
== NULL
)
277 strcpy (subvar
, "name");
278 char *name
= var_GetNonEmptyString (obj
, varname
);
279 strcpy (subvar
, "description");
280 char *description
= var_GetNonEmptyString (obj
, varname
);
281 strcpy (subvar
, "url");
282 char *url
= var_GetNonEmptyString (obj
, varname
);
283 strcpy (subvar
, "email");
284 char *email
= var_GetNonEmptyString (obj
, varname
);
285 strcpy (subvar
, "phone");
286 char *phone
= var_GetNonEmptyString (obj
, varname
);
288 char *sdp
= sdp_Start (name
, description
, url
, email
, phone
,
289 src
, srclen
, addr
, addrlen
);
299 /* Totally non-standard */
300 strcpy (subvar
, "group");
301 char *group
= var_GetNonEmptyString (obj
, varname
);
304 sdp_AddAttribute (&sdp
, "x-plgroup", "%s", group
);