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>
35 #include <vlc_memstream.h>
37 #include "stream_output.h"
39 #define MAXSDPADDRESS 47
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
))
48 strcpy (buf
, "IN IP* ");
50 if (vlc_getnameinfo (addr
, addrlen
, buf
+ 7, MAXSDPADDRESS
- 7, NULL
,
54 switch (addr
->sa_family
)
58 if (net_SockAddrIsMulticast (addr
, addrlen
))
59 strcat (buf
, "/255"); // obsolete in RFC4566, dummy value
67 char *ptr
= strchr (buf
, '%');
69 *ptr
= '\0'; // remove scope ID
83 static bool IsSDPString (const char *str
)
85 if (strchr (str
, '\r') != NULL
)
87 if (strchr (str
, '\n') != NULL
)
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
, ...)
108 vsdp_AddAttribute(stream
, name
, fmt
, 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
,
118 /* Some default values */
125 vlc_memstream_printf(stream
, "m=%s %u %s %u\r\n", type
, dport
, proto
, pt
);
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 */
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 */
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
];
154 size_t cfglen
= strlen(cfgpref
);
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
)
169 const uint_fast64_t now
= NTPtime64();
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
);
182 if (!IsSDPString(str
))
185 vlc_memstream_printf(stream
, "s=%s\r\n", str
);
189 vlc_memstream_printf(stream
, "s=%s\r\n", "Unnamed");
191 strcpy(subvar
, "description");
192 str
= var_GetNonEmptyString(obj
, varname
);
195 if (!IsSDPString(str
))
198 vlc_memstream_printf(stream
, "i=%s\r\n", str
);
202 vlc_memstream_printf(stream
, "i=%s\r\n", "N/A");
204 strcpy(subvar
, "url");
205 str
= var_GetNonEmptyString(obj
, varname
);
208 if (!IsSDPString(str
))
211 vlc_memstream_printf(stream
, "u=%s\r\n", str
);
215 strcpy(subvar
, "email");
216 str
= var_GetNonEmptyString(obj
, varname
);
219 if (!IsSDPString(str
))
222 vlc_memstream_printf(stream
, "e=%s\r\n", 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
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");
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
);
254 if (IsSDPString(str
))
257 vlc_memstream_printf(stream
, "a=cat:%s\r\n", str
);
258 vlc_memstream_printf(stream
, "a=x-plgroup:%s\r\n", str
);
264 if (vlc_memstream_close(stream
) == 0)