player: fix crash on playlist clear
[vlc.git] / src / stream_output / sdp.c
blobab43de02086af009d8fc666814598d2fb1f5c0d6
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>
35 #include <vlc_memstream.h>
37 #include "stream_output.h"
39 #define MAXSDPADDRESS 47
41 static
42 char *AddressToSDP (const struct sockaddr *addr, socklen_t addrlen, char *buf)
44 if (addrlen < offsetof (struct sockaddr, sa_family)
45 + sizeof (addr->sa_family))
46 return NULL;
48 strcpy (buf, "IN IP* ");
50 if (vlc_getnameinfo (addr, addrlen, buf + 7, MAXSDPADDRESS - 7, NULL,
51 NI_NUMERICHOST))
52 return NULL;
54 switch (addr->sa_family)
56 case AF_INET:
58 if (net_SockAddrIsMulticast (addr, addrlen))
59 strcat (buf, "/255"); // obsolete in RFC4566, dummy value
60 buf[5] = '4';
61 break;
64 #ifdef AF_INET6
65 case AF_INET6:
67 char *ptr = strchr (buf, '%');
68 if (ptr != NULL)
69 *ptr = '\0'; // remove scope ID
70 buf[5] = '6';
71 break;
73 #endif
75 default:
76 return NULL;
79 return buf;
83 static bool IsSDPString (const char *str)
85 if (strchr (str, '\r') != NULL)
86 return false;
87 if (strchr (str, '\n') != NULL)
88 return false;
89 if (!IsUTF8 (str))
90 return false;
91 return true;
94 static void vsdp_AddAttribute(struct vlc_memstream *restrict stream,
95 const char *name, const char *fmt, va_list ap)
97 vlc_memstream_printf(stream, "a=%s:", name);
98 vlc_memstream_vprintf(stream, fmt, ap);
99 vlc_memstream_puts(stream, "\r\n");
102 void sdp_AddAttribute(struct vlc_memstream *restrict stream, const char *name,
103 const char *fmt, ...)
105 va_list ap;
107 va_start(ap, fmt);
108 vsdp_AddAttribute(stream, name, fmt, ap);
109 va_end(ap);
112 void sdp_AddMedia(struct vlc_memstream *restrict stream,
113 const char *type, const char *proto, int dport,
114 unsigned pt, bool bw_indep, unsigned bw,
115 const char *ptname, unsigned clock, unsigned chans,
116 const char *fmtp)
118 /* Some default values */
119 if (type == NULL)
120 type = "video";
121 if (proto == NULL)
122 proto = "RTP/AVP";
123 assert (pt < 128u);
125 vlc_memstream_printf(stream, "m=%s %u %s %u\r\n", type, dport, proto, pt);
127 if (bw > 0)
128 vlc_memstream_printf(stream, "b=%s:%u\r\n",
129 bw_indep ? "TIAS" : "AS", bw);
130 vlc_memstream_printf(stream, "b=%s:%u\r\n", "RR", 0);
132 /* RTP payload type map */
133 if (ptname != NULL)
135 vlc_memstream_printf(stream, "a=rtpmap:%u %s/%u", pt, ptname, clock);
136 if ((strcmp(type, "audio") == 0) && (chans != 1))
137 vlc_memstream_printf(stream, "/%u", chans);
138 vlc_memstream_puts(stream, "\r\n");
141 /* Format parameters */
142 if (fmtp != NULL)
143 vlc_memstream_printf(stream, "a=fmtp:%u %s\r\n", pt, fmtp);
146 int vlc_sdp_Start(struct vlc_memstream *restrict stream,
147 vlc_object_t *obj, const char *cfgpref,
148 const struct sockaddr *src, size_t srclen,
149 const struct sockaddr *addr, size_t addrlen)
151 char connection[MAXSDPADDRESS];
152 char *str = NULL;
154 size_t cfglen = strlen(cfgpref);
155 if (cfglen >= 128)
156 return -1;
158 char varname[cfglen + sizeof ("description")];
159 char *subvar = varname + cfglen;
161 strcpy(varname, cfgpref);
163 vlc_memstream_open(stream);
164 vlc_memstream_puts(stream, "v=0\r\n");
166 if (AddressToSDP(addr, addrlen, connection) == NULL)
167 goto error;
169 const uint_fast64_t now = NTPtime64();
170 char hostname[256];
172 gethostname(hostname, sizeof (hostname));
174 vlc_memstream_printf(stream, "o=- %"PRIu64" %"PRIu64" IN IP%c %s\r\n",
175 now, now, connection[5], hostname);
178 strcpy(subvar, "name");
179 str = var_GetNonEmptyString(obj, varname);
180 if (str != NULL)
182 if (!IsSDPString(str))
183 goto error;
185 vlc_memstream_printf(stream, "s=%s\r\n", str);
186 free(str);
188 else
189 vlc_memstream_printf(stream, "s=%s\r\n", "Unnamed");
191 strcpy(subvar, "description");
192 str = var_GetNonEmptyString(obj, varname);
193 if (str != NULL)
195 if (!IsSDPString(str))
196 goto error;
198 vlc_memstream_printf(stream, "i=%s\r\n", str);
199 free(str);
201 else
202 vlc_memstream_printf(stream, "i=%s\r\n", "N/A");
204 strcpy(subvar, "url");
205 str = var_GetNonEmptyString(obj, varname);
206 if (str != NULL)
208 if (!IsSDPString(str))
209 goto error;
211 vlc_memstream_printf(stream, "u=%s\r\n", str);
212 free(str);
215 strcpy(subvar, "email");
216 str = var_GetNonEmptyString(obj, varname);
217 if (str != NULL)
219 if (!IsSDPString(str))
220 goto error;
222 vlc_memstream_printf(stream, "e=%s\r\n", str);
223 free(str);
226 // no phone (useless)
228 vlc_memstream_printf(stream, "c=%s\r\n", connection);
229 // bandwidth not specified
230 vlc_memstream_puts(stream, "t=0 0\r\n"); // one dummy time span
231 // no repeating
232 // no time zone adjustment (silly idea anyway)
233 // no encryption key (deprecated)
235 vlc_memstream_printf(stream, "a=tool:%s\r\n", PACKAGE_STRING);
236 vlc_memstream_puts(stream, "a=recvonly\r\n");
237 vlc_memstream_puts(stream, "a=type:broadcast\r\n");
238 vlc_memstream_puts(stream, "a=charset:UTF-8\r\n");
240 if (srclen > 0)
242 char machine[MAXSDPADDRESS];
244 if (AddressToSDP(src, srclen, machine) != NULL)
245 vlc_memstream_printf(stream,
246 "a=source-filter: incl IN IP%c * %s\r\n",
247 machine[5], machine + 7);
250 strcpy(subvar, "cat");
251 str = var_GetNonEmptyString(obj, varname);
252 if (str != NULL)
254 if (IsSDPString(str))
255 goto error;
257 vlc_memstream_printf(stream, "a=cat:%s\r\n", str);
258 vlc_memstream_printf(stream, "a=x-plgroup:%s\r\n", str);
259 free(str);
261 return 0;
262 error:
263 free(str);
264 if (vlc_memstream_close(stream) == 0)
265 free(stream->ptr);
266 return -1;