Commit 84ec3869 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

sdp: use vlc_memstream

parent 502e503e
......@@ -280,10 +280,19 @@ VLC_API void sout_AnnounceUnRegister(vlc_object_t *,session_descriptor_t* );
/** SDP */
struct sockaddr;
VLC_API 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 ) VLC_USED;
VLC_API char * sdp_AddMedia(char **sdp, const char *type, const char *protocol, int dport, unsigned pt, bool bw_indep, unsigned bw, const char *ptname, unsigned clockrate, unsigned channels, const char *fmtp);
VLC_API char * sdp_AddAttribute(char **sdp, const char *name, const char *fmt, ...) VLC_FORMAT( 3, 4 );
struct vlc_memstream;
VLC_API int vlc_sdp_Start(struct vlc_memstream *, vlc_object_t *obj,
const char *cfgpref,
const struct sockaddr *src, size_t slen,
const struct sockaddr *addr, size_t alen) VLC_USED;
VLC_API void sdp_AddMedia(struct vlc_memstream *, const char *type,
const char *protocol, int dport, unsigned pt,
bool bw_indep, unsigned bw, const char *ptname,
unsigned clockrate, unsigned channels,
const char *fmtp);
VLC_API void sdp_AddAttribute(struct vlc_memstream *, const char *name,
const char *fmt, ...) VLC_FORMAT(3, 4);
/** Description module */
typedef struct sout_description_data_t
......
......@@ -44,6 +44,7 @@
#include <vlc_charset.h>
#include <vlc_strings.h>
#include <vlc_rand.h>
#include <vlc_memstream.h>
#ifndef _WIN32
# include <locale.h>
......@@ -1499,7 +1500,8 @@ static int RtspCallbackES( httpd_callback_sys_t *p_args, httpd_client_t *cl,
*****************************************************************************/
static char *SDPGenerate( const vod_media_t *p_media, httpd_client_t *cl )
{
char *psz_sdp, ip[NI_MAXNUMERICHOST];
struct vlc_memstream sdp;
char ip[NI_MAXNUMERICHOST];
const char *psz_control;
int port;
......@@ -1521,15 +1523,14 @@ static char *SDPGenerate( const vod_media_t *p_media, httpd_client_t *cl )
dst.ss_len = dstlen;
#endif
psz_sdp = vlc_sdp_Start( VLC_OBJECT( p_media->p_vod ), "sout-rtp-",
NULL, 0, (struct sockaddr *)&dst, dstlen );
if( psz_sdp == NULL )
if( vlc_sdp_Start( &sdp, VLC_OBJECT( p_media->p_vod ), "sout-rtp-",
NULL, 0, (struct sockaddr *)&dst, dstlen ) )
return NULL;
if( p_media->i_length > 0 )
{
lldiv_t d = lldiv( p_media->i_length / 1000, 1000 );
sdp_AddAttribute( &psz_sdp, "range","npt=0-%lld.%03u", d.quot,
sdp_AddAttribute( &sdp, "range","npt=0-%lld.%03u", d.quot,
(unsigned)d.rem );
}
......@@ -1553,13 +1554,13 @@ static char *SDPGenerate( const vod_media_t *p_media, httpd_client_t *cl )
continue;
}
sdp_AddMedia( &psz_sdp, mime_major, "RTP/AVP", 0 /* p_es->i_port */,
sdp_AddMedia( &sdp, mime_major, "RTP/AVP", 0 /* p_es->i_port */,
p_es->i_payload_type, false, 0,
p_es->psz_ptname, p_es->i_clock_rate, p_es->i_channels,
p_es->psz_fmtp );
sdp_AddAttribute( &psz_sdp, "control", psz_control, ip, port, i );
sdp_AddAttribute( &sdp, "control", psz_control, ip, port, i );
}
return psz_sdp;
return vlc_memstream_close( &sdp ) ? NULL : sdp.ptr;
}
......@@ -41,6 +41,7 @@
#include <vlc_network.h>
#include <vlc_fs.h>
#include <vlc_rand.h>
#include <vlc_memstream.h>
#ifdef HAVE_SRTP
# include <srtp.h>
# include <gcrypt.h>
......@@ -780,8 +781,9 @@ out:
char *SDPGenerate( sout_stream_t *p_stream, const char *rtsp_url )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
char *psz_sdp = NULL;
struct vlc_memstream sdp;
struct sockaddr_storage dst;
char *psz_sdp = NULL;
socklen_t dstlen;
int i;
/*
......@@ -836,17 +838,16 @@ char *SDPGenerate( sout_stream_t *p_stream, const char *rtsp_url )
#endif
}
psz_sdp = vlc_sdp_Start( VLC_OBJECT( p_stream ), SOUT_CFG_PREFIX,
NULL, 0, (struct sockaddr *)&dst, dstlen );
if( psz_sdp == NULL )
if( vlc_sdp_Start( &sdp, VLC_OBJECT( p_stream ), SOUT_CFG_PREFIX,
NULL, 0, (struct sockaddr *)&dst, dstlen ) )
goto out;
/* TODO: a=source-filter */
if( p_sys->rtcp_mux )
sdp_AddAttribute( &psz_sdp, "rtcp-mux", NULL );
sdp_AddAttribute( &sdp, "rtcp-mux", NULL );
if( rtsp_url != NULL )
sdp_AddAttribute ( &psz_sdp, "control", "%s", rtsp_url );
sdp_AddAttribute ( &sdp, "control", "%s", rtsp_url );
const char *proto = "RTP/AVP"; /* protocol */
if( rtsp_url == NULL )
......@@ -887,34 +888,36 @@ char *SDPGenerate( sout_stream_t *p_stream, const char *rtsp_url )
continue;
}
sdp_AddMedia( &psz_sdp, mime_major, proto, inclport * id->i_port,
sdp_AddMedia( &sdp, mime_major, proto, inclport * id->i_port,
rtp_fmt->payload_type, false, rtp_fmt->bitrate,
rtp_fmt->ptname, rtp_fmt->clock_rate, rtp_fmt->channels,
rtp_fmt->fmtp);
/* cf RFC4566 §5.14 */
if( inclport && !p_sys->rtcp_mux && (id->i_port & 1) )
sdp_AddAttribute ( &psz_sdp, "rtcp", "%u", id->i_port + 1 );
sdp_AddAttribute( &sdp, "rtcp", "%u", id->i_port + 1 );
if( rtsp_url != NULL )
{
char *track_url = RtspAppendTrackPath( id->rtsp_id, rtsp_url );
if( track_url != NULL )
{
sdp_AddAttribute ( &psz_sdp, "control", "%s", track_url );
sdp_AddAttribute( &sdp, "control", "%s", track_url );
free( track_url );
}
}
else
{
if( id->listen.fd != NULL )
sdp_AddAttribute( &psz_sdp, "setup", "passive" );
sdp_AddAttribute( &sdp, "setup", "passive" );
if( p_sys->proto == IPPROTO_DCCP )
sdp_AddAttribute( &psz_sdp, "dccp-service-code",
"SC:RTP%c",
sdp_AddAttribute( &sdp, "dccp-service-code", "SC:RTP%c",
toupper( (unsigned char)mime_major[0] ) );
}
}
if( vlc_memstream_close( &sdp ) == 0 )
psz_sdp = sdp.ptr;
out:
vlc_mutex_unlock( &p_sys->lock_es );
return psz_sdp;
......
......@@ -34,6 +34,7 @@
#include <vlc_network.h>
#include <vlc_url.h>
#include <vlc_memstream.h>
/*****************************************************************************
* Module descriptor
......@@ -179,29 +180,25 @@ static void create_SDP(sout_stream_t *p_stream, sout_access_out_t *p_access)
freeaddrinfo (res);
}
char *head = vlc_sdp_Start (VLC_OBJECT (p_stream), SOUT_CFG_PREFIX,
(struct sockaddr *)&src, srclen,
(struct sockaddr *)&dst, dstlen);
free (shost);
struct vlc_memstream sdp;
if (head != NULL)
if (vlc_sdp_Start(&sdp, VLC_OBJECT (p_stream), SOUT_CFG_PREFIX,
(struct sockaddr *)&src, srclen,
(struct sockaddr *)&dst, dstlen) == 0)
{
char *psz_sdp = NULL;
if (asprintf (&psz_sdp, "%s"
"m=video %d udp mpeg\r\n", head, dport) == -1)
psz_sdp = NULL;
free (head);
vlc_memstream_printf(&sdp, "m=video %d udp mpeg\r\n", dport);
/* Register the SDP with the SAP thread */
if (psz_sdp)
if (vlc_memstream_close(&sdp))
{
msg_Dbg (p_stream, "Generated SDP:\n%s", psz_sdp);
msg_Dbg(p_stream, "Generated SDP:\n%s", sdp.ptr);
p_sys->p_session =
sout_AnnounceRegisterSDP (p_stream, psz_sdp, dhost);
free( psz_sdp );
sout_AnnounceRegisterSDP(p_stream, sdp.ptr, dhost);
free(sdp.ptr);
}
}
free (dhost);
free(shost);
free(dhost);
}
static const char *getMuxFromAlias( const char *psz_alias )
......
......@@ -40,6 +40,7 @@
#include <vlc_vod.h>
#include <vlc_url.h>
#include <vlc_network.h>
#include <vlc_memstream.h>
#include <assert.h>
......@@ -390,8 +391,6 @@ static void* CommandThread( void *obj )
*****************************************************************************/
char *SDPGenerateVoD( const vod_media_t *p_media, const char *rtsp_url )
{
char *psz_sdp;
assert(rtsp_url != NULL);
/* Check against URL format rtsp://[<ipv6>]:<port>/<path> */
bool ipv6 = strlen( rtsp_url ) > 7 && rtsp_url[7] == '[';
......@@ -406,19 +405,20 @@ char *SDPGenerateVoD( const vod_media_t *p_media, const char *rtsp_url )
dst.ss_len = dstlen;
#endif
psz_sdp = vlc_sdp_Start( VLC_OBJECT( p_media->p_vod ), "sout-rtp-",
NULL, 0, (struct sockaddr *)&dst, dstlen );
if( psz_sdp == NULL )
struct vlc_memstream sdp;
if( vlc_sdp_Start( &sdp, VLC_OBJECT( p_media->p_vod ), "sout-rtp-",
NULL, 0, (struct sockaddr *)&dst, dstlen ) )
return NULL;
if( p_media->i_length > 0 )
{
lldiv_t d = lldiv( p_media->i_length / 1000, 1000 );
sdp_AddAttribute( &psz_sdp, "range"," npt=0-%lld.%03u", d.quot,
sdp_AddAttribute( &sdp, "range"," npt=0-%lld.%03u", d.quot,
(unsigned)d.rem );
}
sdp_AddAttribute ( &psz_sdp, "control", "%s", rtsp_url );
sdp_AddAttribute( &sdp, "control", "%s", rtsp_url );
/* No locking needed, the ES table can't be modified now */
for( int i = 0; i < p_media->i_es; i++ )
......@@ -442,7 +442,7 @@ char *SDPGenerateVoD( const vod_media_t *p_media, const char *rtsp_url )
continue;
}
sdp_AddMedia( &psz_sdp, mime_major, "RTP/AVP", 0,
sdp_AddMedia( &sdp, mime_major, "RTP/AVP", 0,
rtp_fmt->payload_type, false, 0,
rtp_fmt->ptname, rtp_fmt->clock_rate, rtp_fmt->channels,
rtp_fmt->fmtp );
......@@ -450,12 +450,12 @@ char *SDPGenerateVoD( const vod_media_t *p_media, const char *rtsp_url )
char *track_url = RtspAppendTrackPath( p_es->rtsp_id, rtsp_url );
if( track_url != NULL )
{
sdp_AddAttribute ( &psz_sdp, "control", "%s", track_url );
sdp_AddAttribute( &sdp, "control", "%s", track_url );
free( track_url );
}
}
return psz_sdp;
return vlc_memstream_close( &sdp ) ? NULL : sdp.ptr;
}
int vod_check_range(vod_media_t *p_media, const char *psz_session,
......
......@@ -32,6 +32,7 @@
#include <assert.h>
#include <vlc_network.h>
#include <vlc_charset.h>
#include <vlc_memstream.h>
#include "stream_output.h"
......@@ -90,217 +91,186 @@ static bool IsSDPString (const char *str)
return true;
}
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)
static void vsdp_AddAttribute(struct vlc_memstream *restrict stream,
const char *name, const char *fmt, va_list ap)
{
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)
description = "N/A";
if (url == NULL)
preurl = url = "";
if (email == NULL)
premail = email = "";
if (phone == NULL)
prephone = phone = "";
if (!IsSDPString (name) || !IsSDPString (description)
|| !IsSDPString (url) || !IsSDPString (email) || !IsSDPString (phone)
|| (AddressToSDP (addr, addrlen, connection) == NULL))
return NULL;
strcpy (sfilter, "");
if (srclen > 0)
{
char machine[MAXSDPADDRESS];
vlc_memstream_printf(stream, "a=%s:", name);
vlc_memstream_vprintf(stream, fmt, ap);
vlc_memstream_puts(stream, "\r\n");
}
if (AddressToSDP (src, srclen, machine) != NULL)
sprintf (sfilter, "\r\na=source-filter: incl IN IP%c * %s",
machine[5], machine + 7);
}
void sdp_AddAttribute(struct vlc_memstream *restrict stream, const char *name,
const char *fmt, ...)
{
va_list ap;
if (asprintf (&sdp, "v=0"
"\r\no=- %"PRIu64" %"PRIu64" IN IP%c %s"
"\r\ns=%s"
"\r\ni=%s"
"%s%s" // optional URL
"%s%s" // optional email
"%s%s" // optional phone number
"\r\nc=%s"
// bandwidth not specified
"\r\nt=0 0" // one dummy time span
// no repeating
// no time zone adjustment (silly idea anyway)
// no encryption key (deprecated)
"\r\na=tool:"PACKAGE_STRING
"\r\na=recvonly"
"\r\na=type:broadcast"
"\r\na=charset:UTF-8"
"%s" // optional source filter
"\r\n",
/* o= */ now, now, connection[5], hostname,
/* s= */ name,
/* i= */ description,
/* u= */ preurl, url,
/* e= */ premail, email,
/* p= */ prephone, phone,
/* c= */ connection,
/* source-filter */ sfilter) == -1)
return NULL;
return sdp;
va_start(ap, fmt);
vsdp_AddAttribute(stream, name, fmt, ap);
va_end(ap);
}
static char *
vsdp_AddAttribute (char **sdp, const char *name, const char *fmt, va_list ap)
void sdp_AddMedia(struct vlc_memstream *restrict stream,
const char *type, const char *proto, int dport,
unsigned pt, bool bw_indep, unsigned bw,
const char *ptname, unsigned clock, unsigned chans,
const char *fmtp)
{
size_t oldlen = strlen (*sdp);
size_t addlen = sizeof ("a=\r\n") + strlen (name);
if (fmt != NULL)
{
va_list aq;
/* Some default values */
if (type == NULL)
type = "video";
if (proto == NULL)
proto = "RTP/AVP";
assert (pt < 128u);
va_copy (aq, ap);
addlen += 1 + vsnprintf (NULL, 0, fmt, aq);
va_end (aq);
}
vlc_memstream_printf(stream, "m=%s %u %s %u\r\n", type, dport, proto, pt);
char *ret = realloc (*sdp, oldlen + addlen);
if (ret == NULL)
return NULL;
if (bw > 0)
vlc_memstream_printf(stream, "b=%s:%u\r\n",
bw_indep ? "TIAS" : "AS", bw);
vlc_memstream_printf(stream, "b=%s:%u\r\n", "RR", 0);
oldlen += sprintf (ret + oldlen, "a=%s", name);
if (fmt != NULL)
/* RTP payload type map */
if (ptname != NULL)
{
ret[oldlen++] = ':';
oldlen += vsprintf (ret + oldlen, fmt, ap);
vlc_memstream_printf(stream, "a=rtpmap:%u %s/%u", pt, ptname, clock);
if ((strcmp(type, "audio") == 0) && (chans != 1))
vlc_memstream_printf(stream, "/%u", chans);
vlc_memstream_puts(stream, "\r\n");
}
strcpy (ret + oldlen, "\r\n");
return *sdp = ret;
/* Format parameters */
if (fmtp != NULL)
vlc_memstream_printf(stream, "a=fmtp:%u %s\r\n", pt, fmtp);
}
char *sdp_AddAttribute (char **sdp, const char *name, const char *fmt, ...)
int vlc_sdp_Start(struct vlc_memstream *restrict stream,
vlc_object_t *obj, const char *cfgpref,
const struct sockaddr *src, size_t srclen,
const struct sockaddr *addr, size_t addrlen)
{
char *ret;
va_list ap;
char connection[MAXSDPADDRESS];
char *str = NULL;
va_start (ap, fmt);
ret = vsdp_AddAttribute (sdp, name, fmt, ap);
va_end (ap);
size_t cfglen = strlen(cfgpref);
if (cfglen >= 128)
return -1;
return ret;
}
char varname[cfglen + sizeof ("description")];
char *subvar = varname + cfglen;
strcpy(varname, cfgpref);
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;
vlc_memstream_open(stream);
vlc_memstream_puts(stream, "v=0\r\n");
/* Some default values */
if (type == NULL)
type = "video";
if (protocol == NULL)
protocol = "RTP/AVP";
assert (pt < 128u);
if (AddressToSDP(addr, addrlen, connection) == NULL)
goto error;
{
const uint_fast64_t now = NTPtime64();
char hostname[256];
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);
gethostname(hostname, sizeof (hostname));
newsdp = realloc (*sdp, outlen + 1);
if (newsdp == NULL)
return NULL;
vlc_memstream_printf(stream, "o=- %"PRIu64" %"PRIu64" IN IP%c %s\r\n",
now, now, connection[5], hostname);
}
*sdp = newsdp;
ptr = newsdp + inlen;
strcpy(subvar, "name");
str = var_GetNonEmptyString(obj, varname);
if (str != NULL)
{
if (!IsSDPString(str))
goto error;
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");
vlc_memstream_printf(stream, "s=%s\r\n", str);
free(str);
}
else
vlc_memstream_printf(stream, "s=%s\r\n", "Unnamed");
/* RTP payload type map */
if (ptname != NULL)
strcpy(subvar, "description");
str = var_GetNonEmptyString(obj, varname);
if (str != 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);
if (!IsSDPString(str))
goto error;
vlc_memstream_printf(stream, "i=%s\r\n", str);
free(str);
}
/* Format parameters */
if (fmtp != NULL)
sdp_AddAttribute (sdp, "fmtp", "%u %s", pt, fmtp);
else
vlc_memstream_printf(stream, "i=%s\r\n", "N/A");
return newsdp;
}
strcpy(subvar, "url");
str = var_GetNonEmptyString(obj, varname);
if (str != NULL)
{
if (!IsSDPString(str))
goto error;
vlc_memstream_printf(stream, "u=%s\r\n", str);
free(str);
}
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;
strcpy(subvar, "email");
str = var_GetNonEmptyString(obj, varname);
if (str != NULL)
{
if (!IsSDPString(str))
goto error;
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;
vlc_memstream_printf(stream, "e=%s\r\n", str);
free(str);
}
strcpy(subvar, "phone");
str = var_GetNonEmptyString(obj, varname);
if (str != NULL)
{
if (!IsSDPString(str))
goto error;
vlc_memstream_printf(stream, "p=%s\r\n", str);
free(str);
}
strcpy (subvar, "cat");
char *cat = var_GetNonEmptyString (obj, varname);
if (cat != NULL)
vlc_memstream_printf(stream, "c=%s\r\n", connection);
// bandwidth not specified
vlc_memstream_puts(stream, "t=0 0\r\n"); // one dummy time span
// no repeating
// no time zone adjustment (silly idea anyway)
// no encryption key (deprecated)
vlc_memstream_printf(stream, "a=tool:%s\r\n", PACKAGE_STRING);
vlc_memstream_puts(stream, "a=recvonly\r\n");
vlc_memstream_puts(stream, "a=type:broadcast\r\n");
vlc_memstream_puts(stream, "a=charset:UTF-8\r\n");
if (srclen > 0)
{
sdp_AddAttribute (&sdp, "cat", "%s", cat);
/* Totally non-standard */
sdp_AddAttribute (&sdp, "x-plgroup", "%s", cat);
free (cat);
char machine[MAXSDPADDRESS];
if (AddressToSDP(src, srclen, machine) != NULL)
vlc_memstream_printf(stream,
"a=source-filter: incl IN IP%c * %s\r\n",
machine[5], machine + 7);
}
return sdp;
strcpy(subvar, "cat");
str = var_GetNonEmptyString(obj, varname);
if (str != NULL)
{
if (IsSDPString(str))
goto error;
vlc_memstream_printf(stream, "a=cat:%s\r\n", str);
vlc_memstream_printf(stream, "a=x-plgroup:%s\r\n", str);
free(str);
}
return 0;
error:
free(str);
if (vlc_memstream_close(stream) == 0)
free(stream->ptr);
return -1;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment