X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fstream_output%2Fsdp.c;h=d2c0610655df1ac88588dc4120ba48bdf1fcebca;hb=e7d54bc7d7e5fb3faf69b09d3fd157eec7139de7;hp=38c32ff3f3b5eea4fb1baba353c5376fea4b765d;hpb=08cb8e62e928457d00602f9b96cb8c4755a74305;p=vlc diff --git a/src/stream_output/sdp.c b/src/stream_output/sdp.c index 38c32ff3f3..d2c0610655 100644 --- a/src/stream_output/sdp.c +++ b/src/stream_output/sdp.c @@ -4,26 +4,32 @@ * Copyright © 2007 Rémi Denis-Courmont * $Id$ * - * Authors: Rémi Denis-Courmont - * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include #include +#include +#include +#include #include #include @@ -34,61 +40,71 @@ static char *AddressToSDP (const struct sockaddr *addr, socklen_t addrlen, char *buf) { - const char *ttl = NULL; + if (addrlen < offsetof (struct sockaddr, sa_family) + + sizeof (addr->sa_family)) + return NULL; + strcpy (buf, "IN IP* "); + if (vlc_getnameinfo (addr, addrlen, buf + 7, MAXSDPADDRESS - 7, NULL, + NI_NUMERICHOST)) + return NULL; + switch (addr->sa_family) { case AF_INET: { if (net_SockAddrIsMulticast (addr, addrlen)) - ttl = "/255"; // obsolete in RFC4566, dummy value + strcat (buf, "/255"); // obsolete in RFC4566, dummy value buf[5] = '4'; break; } #ifdef AF_INET6 case AF_INET6: + { + char *ptr = strchr (buf, '%'); + if (ptr != NULL) + *ptr = '\0'; // remove scope ID buf[5] = '6'; break; + } #endif default: return NULL; } - if (vlc_getnameinfo (addr, addrlen, buf + 4, MAXSDPADDRESS - 4, NULL, - NI_NUMERICHOST)) - return NULL; - - if (ttl != NULL) - strcat (buf, ttl); - return buf; } -static vlc_bool_t IsSDPString (const char *str) +static bool IsSDPString (const char *str) { if (strchr (str, '\r') != NULL) - return VLC_FALSE; + return false; if (strchr (str, '\n') != NULL) - return VLC_FALSE; + return false; if (!IsUTF8 (str)) - return VLC_FALSE; - return VLC_TRUE; + return false; + return true; } -char *StartSDP (const char *name, const char *description, const char *url, - const char *email, const char *phone, - const struct sockaddr *orig, socklen_t origlen, - const struct sockaddr *addr, socklen_t addrlen) +static +char *sdp_Start (const char *name, const char *description, const char *url, + const char *email, const char *phone, + const struct sockaddr *src, size_t srclen, + const struct sockaddr *addr, size_t addrlen) { - uint64_t t = NTPtime64 (); - char *sdp, machine[MAXSDPADDRESS], conn[MAXSDPADDRESS]; + uint64_t now = NTPtime64 (); + char *sdp; + char connection[MAXSDPADDRESS], hostname[256], + sfilter[MAXSDPADDRESS + sizeof ("\r\na=source-filter: incl * ")]; const char *preurl = "\r\nu=", *premail = "\r\ne=", *prephone = "\r\np="; + gethostname (hostname, sizeof (hostname)); + if (name == NULL) name = "Unnamed"; if (description == NULL) @@ -102,12 +118,21 @@ char *StartSDP (const char *name, const char *description, const char *url, if (!IsSDPString (name) || !IsSDPString (description) || !IsSDPString (url) || !IsSDPString (email) || !IsSDPString (phone) - || (AddressToSDP ((struct sockaddr *)&orig, origlen, machine) == NULL) - || (AddressToSDP ((struct sockaddr *)&addr, addrlen, conn) == NULL)) + || (AddressToSDP (addr, addrlen, connection) == NULL)) return NULL; + strcpy (sfilter, ""); + if (srclen > 0) + { + char machine[MAXSDPADDRESS]; + + if (AddressToSDP (src, srclen, machine) != NULL) + sprintf (sfilter, "\r\na=source-filter: incl IN IP%c * %s", + machine[5], machine + 7); + } + if (asprintf (&sdp, "v=0" - "\r\no=- "I64Fu" "I64Fu" %s" + "\r\no=- %"PRIu64" %"PRIu64" IN IP%c %s" "\r\ns=%s" "\r\ni=%s" "%s%s" // optional URL @@ -115,7 +140,7 @@ char *StartSDP (const char *name, const char *description, const char *url, "%s%s" // optional phone number "\r\nc=%s" // bandwidth not specified - "\r\nt= 0 0" // one dummy time span + "\r\nt=0 0" // one dummy time span // no repeating // no time zone adjustment (silly idea anyway) // no encryption key (deprecated) @@ -123,15 +148,158 @@ char *StartSDP (const char *name, const char *description, const char *url, "\r\na=recvonly" "\r\na=type:broadcast" "\r\na=charset:UTF-8" + "%s" // optional source filter "\r\n", - /* o= */ t, t, machine, + /* o= */ now, now, connection[5], hostname, /* s= */ name, /* i= */ description, /* u= */ preurl, url, /* e= */ premail, email, /* p= */ prephone, phone, - /* c= */ conn) == -1) + /* c= */ connection, + /* source-filter */ sfilter) == -1) return NULL; return sdp; } + +static char * +vsdp_AddAttribute (char **sdp, const char *name, const char *fmt, va_list ap) +{ + size_t oldlen = strlen (*sdp); + size_t addlen = sizeof ("a=\r\n") + strlen (name); + + if (fmt != NULL) + { + va_list aq; + + va_copy (aq, ap); + addlen += 1 + vsnprintf (NULL, 0, fmt, aq); + va_end (aq); + } + + char *ret = realloc (*sdp, oldlen + addlen); + if (ret == NULL) + return NULL; + + oldlen += sprintf (ret + oldlen, "a=%s", name); + if (fmt != NULL) + { + ret[oldlen++] = ':'; + oldlen += vsprintf (ret + oldlen, fmt, ap); + } + + strcpy (ret + oldlen, "\r\n"); + return *sdp = ret; +} + + +char *sdp_AddAttribute (char **sdp, const char *name, const char *fmt, ...) +{ + char *ret; + va_list ap; + + va_start (ap, fmt); + ret = vsdp_AddAttribute (sdp, name, fmt, ap); + va_end (ap); + + return ret; +} + + +char *sdp_AddMedia (char **sdp, + const char *type, const char *protocol, int dport, + unsigned pt, bool bw_indep, unsigned bw, + const char *ptname, unsigned clock, unsigned chans, + const char *fmtp) +{ + char *newsdp, *ptr; + size_t inlen = strlen (*sdp), outlen = inlen; + + /* Some default values */ + if (type == NULL) + type = "video"; + if (protocol == NULL) + protocol = "RTP/AVP"; + assert (pt < 128u); + + outlen += snprintf (NULL, 0, + "m=%s %u %s %d\r\n" + "b=TIAS:%u\r\n" + "b=RR:0\r\n", + type, dport, protocol, pt, bw); + + newsdp = realloc (*sdp, outlen + 1); + if (newsdp == NULL) + return NULL; + + *sdp = newsdp; + ptr = newsdp + inlen; + + ptr += sprintf (ptr, "m=%s %u %s %u\r\n", + type, dport, protocol, pt); + if (bw > 0) + ptr += sprintf (ptr, "b=%s:%u\r\n", bw_indep ? "TIAS" : "AS", bw); + ptr += sprintf (ptr, "b=RR:0\r\n"); + + /* RTP payload type map */ + if (ptname != NULL) + { + if ((strcmp (type, "audio") == 0) && (chans != 1)) + sdp_AddAttribute (sdp, "rtpmap", "%u %s/%u/%u", pt, ptname, clock, + chans); + else + sdp_AddAttribute (sdp, "rtpmap", "%u %s/%u", pt, ptname, clock); + } + /* Format parameters */ + if (fmtp != NULL) + sdp_AddAttribute (sdp, "fmtp", "%u %s", pt, fmtp); + + return newsdp; +} + + +char *vlc_sdp_Start (vlc_object_t *obj, const char *cfgpref, + const struct sockaddr *src, size_t srclen, + const struct sockaddr *addr, size_t addrlen) +{ + size_t cfglen = strlen (cfgpref); + if (cfglen > 100) + return NULL; + + char varname[cfglen + sizeof ("description")], *subvar = varname + cfglen; + strcpy (varname, cfgpref); + + strcpy (subvar, "name"); + char *name = var_GetNonEmptyString (obj, varname); + strcpy (subvar, "description"); + char *description = var_GetNonEmptyString (obj, varname); + strcpy (subvar, "url"); + char *url = var_GetNonEmptyString (obj, varname); + strcpy (subvar, "email"); + char *email = var_GetNonEmptyString (obj, varname); + strcpy (subvar, "phone"); + char *phone = var_GetNonEmptyString (obj, varname); + + char *sdp = sdp_Start (name, description, url, email, phone, + src, srclen, addr, addrlen); + free (name); + free (description); + free (url); + free (email); + free (phone); + + if (sdp == NULL) + return NULL; + + /* Totally non-standard */ + strcpy (subvar, "group"); + char *group = var_GetNonEmptyString (obj, varname); + if (group != NULL) + { + sdp_AddAttribute (&sdp, "x-plgroup", "%s", group); + free (group); + } + + return sdp; +}