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 it
8 * 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 Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
26 #include <vlc_common.h>
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=- %"PRIu64" %"PRIu64" 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 strcpy (subvar, "name");
274 char *name = var_GetNonEmptyString (obj, varname);
275 strcpy (subvar, "description");
276 char *description = var_GetNonEmptyString (obj, varname);
277 strcpy (subvar, "url");
278 char *url = var_GetNonEmptyString (obj, varname);
279 strcpy (subvar, "email");
280 char *email = var_GetNonEmptyString (obj, varname);
281 strcpy (subvar, "phone");
282 char *phone = var_GetNonEmptyString (obj, varname);
284 char *sdp = sdp_Start (name, description, url, email, phone,
285 src, srclen, addr, addrlen);
295 strcpy (subvar, "cat");
296 char *cat = var_GetNonEmptyString (obj, varname);
299 sdp_AddAttribute (&sdp, "cat", "%s", cat);
300 /* Totally non-standard */
301 sdp_AddAttribute (&sdp, "x-plgroup", "%s", cat);