x11 factory: use vlc_readdir
[vlc/solaris.git] / src / stream_output / sdp.c
blob2363d344ba6fe9ddb476e69bbdd6a8954651c680
1 /*****************************************************************************
2 * sdp.c : SDP creation helpers
3 *****************************************************************************
4 * Copyright © 2007 Rémi Denis-Courmont
5 * $Id$
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 *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include <vlc_common.h>
28 #include <stddef.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <assert.h>
33 #include <vlc_network.h>
34 #include <vlc_charset.h>
36 #include "stream_output.h"
38 #define MAXSDPADDRESS 47
40 static
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))
45 return NULL;
47 strcpy (buf, "IN IP* ");
49 if (vlc_getnameinfo (addr, addrlen, buf + 7, MAXSDPADDRESS - 7, NULL,
50 NI_NUMERICHOST))
51 return NULL;
53 switch (addr->sa_family)
55 case AF_INET:
57 if (net_SockAddrIsMulticast (addr, addrlen))
58 strcat (buf, "/255"); // obsolete in RFC4566, dummy value
59 buf[5] = '4';
60 break;
63 #ifdef AF_INET6
64 case AF_INET6:
66 char *ptr = strchr (buf, '%');
67 if (ptr != NULL)
68 *ptr = '\0'; // remove scope ID
69 buf[5] = '6';
70 break;
72 #endif
74 default:
75 return NULL;
78 return buf;
82 static bool IsSDPString (const char *str)
84 if (strchr (str, '\r') != NULL)
85 return false;
86 if (strchr (str, '\n') != NULL)
87 return false;
88 if (!IsUTF8 (str))
89 return false;
90 return true;
94 static
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 ();
101 char *sdp;
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));
108 if (name == NULL)
109 name = "Unnamed";
110 if (description == NULL)
111 description = "N/A";
112 if (url == NULL)
113 preurl = url = "";
114 if (email == NULL)
115 premail = email = "";
116 if (phone == NULL)
117 prephone = phone = "";
119 if (!IsSDPString (name) || !IsSDPString (description)
120 || !IsSDPString (url) || !IsSDPString (email) || !IsSDPString (phone)
121 || (AddressToSDP (addr, addrlen, connection) == NULL))
122 return NULL;
124 strcpy (sfilter, "");
125 if (srclen > 0)
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"
136 "\r\ns=%s"
137 "\r\ni=%s"
138 "%s%s" // optional URL
139 "%s%s" // optional email
140 "%s%s" // optional phone number
141 "\r\nc=%s"
142 // bandwidth not specified
143 "\r\nt=0 0" // one dummy time span
144 // no repeating
145 // no time zone adjustment (silly idea anyway)
146 // no encryption key (deprecated)
147 "\r\na=tool:"PACKAGE_STRING
148 "\r\na=recvonly"
149 "\r\na=type:broadcast"
150 "\r\na=charset:UTF-8"
151 "%s" // optional source filter
152 "\r\n",
153 /* o= */ now, now, connection[5], hostname,
154 /* s= */ name,
155 /* i= */ description,
156 /* u= */ preurl, url,
157 /* e= */ premail, email,
158 /* p= */ prephone, phone,
159 /* c= */ connection,
160 /* source-filter */ sfilter) == -1)
161 return NULL;
162 return sdp;
166 static char *
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);
172 if (fmt != NULL)
174 va_list aq;
176 va_copy (aq, ap);
177 addlen += 1 + vsnprintf (NULL, 0, fmt, aq);
178 va_end (aq);
181 char *ret = realloc (*sdp, oldlen + addlen);
182 if (ret == NULL)
183 return NULL;
185 oldlen += sprintf (ret + oldlen, "a=%s", name);
186 if (fmt != NULL)
188 ret[oldlen++] = ':';
189 oldlen += vsprintf (ret + oldlen, fmt, ap);
192 strcpy (ret + oldlen, "\r\n");
193 return *sdp = ret;
197 char *sdp_AddAttribute (char **sdp, const char *name, const char *fmt, ...)
199 char *ret;
200 va_list ap;
202 va_start (ap, fmt);
203 ret = vsdp_AddAttribute (sdp, name, fmt, ap);
204 va_end (ap);
206 return ret;
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,
214 const char *fmtp)
216 char *newsdp, *ptr;
217 size_t inlen = strlen (*sdp), outlen = inlen;
219 /* Some default values */
220 if (type == NULL)
221 type = "video";
222 if (protocol == NULL)
223 protocol = "RTP/AVP";
224 assert (pt < 128u);
226 outlen += snprintf (NULL, 0,
227 "m=%s %u %s %d\r\n"
228 "b=TIAS:%u\r\n"
229 "b=RR:0\r\n",
230 type, dport, protocol, pt, bw);
232 newsdp = realloc (*sdp, outlen + 1);
233 if (newsdp == NULL)
234 return NULL;
236 *sdp = newsdp;
237 ptr = newsdp + inlen;
239 ptr += sprintf (ptr, "m=%s %u %s %u\r\n",
240 type, dport, protocol, pt);
241 if (bw > 0)
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 */
246 if (ptname != NULL)
248 if ((strcmp (type, "audio") == 0) && (chans != 1))
249 sdp_AddAttribute (sdp, "rtpmap", "%u %s/%u/%u", pt, ptname, clock,
250 chans);
251 else
252 sdp_AddAttribute (sdp, "rtpmap", "%u %s/%u", pt, ptname, clock);
254 /* Format parameters */
255 if (fmtp != NULL)
256 sdp_AddAttribute (sdp, "fmtp", "%u %s", pt, fmtp);
258 return newsdp;
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);
267 if (cfglen > 100)
268 return NULL;
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);
286 free (name);
287 free (description);
288 free (url);
289 free (email);
290 free (phone);
292 if (sdp == NULL)
293 return NULL;
295 /* Totally non-standard */
296 strcpy (subvar, "group");
297 char *group = var_GetNonEmptyString (obj, varname);
298 if (group != NULL)
300 sdp_AddAttribute (&sdp, "x-plgroup", "%s", group);
301 free (group);
304 return sdp;