X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fstream_out%2Frtp.c;h=25ac644a12bcca702977c2c664710f87d1c7d7da;hb=a799659d60ca3c17cafc4b7e2bd9203ab7d5e0e0;hp=4d1648a21cb2468e96e3fd9b40923f8d83922e32;hpb=ec37907e589dbe5656d288c58cab7b8455042caa;p=vlc diff --git a/modules/stream_out/rtp.c b/modules/stream_out/rtp.c index 4d1648a21c..25ac644a12 100644 --- a/modules/stream_out/rtp.c +++ b/modules/stream_out/rtp.c @@ -42,6 +42,8 @@ #include #ifdef HAVE_SRTP # include +# include +# include #endif #include "rtp.h" @@ -63,8 +65,8 @@ # define IPPROTO_UDPLITE 136 #endif +#include #include - #include /***************************************************************************** @@ -77,7 +79,7 @@ #define SDP_TEXT N_("SDP") #define SDP_LONGTEXT N_( \ "This allows you to specify how the SDP (Session Descriptor) for this RTP "\ - "session will be made available. You must use an url: http://location to " \ + "session will be made available. You must use a url: http://location to " \ "access the SDP via HTTP, rtsp://location for RTSP access, and sap:// " \ "for the SDP to be announced via SAP." ) #define SAP_TEXT N_("SAP announcing") @@ -91,13 +93,17 @@ #define NAME_LONGTEXT N_( \ "This is the name of the session that will be announced in the SDP " \ "(Session Descriptor)." ) +#define CAT_TEXT N_("Session category") +#define CAT_LONGTEXT N_( \ + "This allows you to specify a category for the session, " \ + "that will be announced if you choose to use SAP." ) #define DESC_TEXT N_("Session description") #define DESC_LONGTEXT N_( \ "This allows you to give a short description with details about the stream, " \ "that will be announced in the SDP (Session Descriptor)." ) #define URL_TEXT N_("Session URL") #define URL_LONGTEXT N_( \ - "This allows you to give an URL with more details about the stream " \ + "This allows you to give a URL with more details about the stream " \ "(often the website of the streaming organization), that will " \ "be announced in the SDP (Session Descriptor)." ) #define EMAIL_TEXT N_("Session email") @@ -142,11 +148,13 @@ #define SRTP_KEY_TEXT N_("SRTP key (hexadecimal)") #define SRTP_KEY_LONGTEXT N_( \ "RTP packets will be integrity-protected and ciphered "\ - "with this Secure RTP master shared secret key.") + "with this Secure RTP master shared secret key. "\ + "This must be a 32-character-long hexadecimal string.") #define SRTP_SALT_TEXT N_("SRTP salt (hexadecimal)") #define SRTP_SALT_LONGTEXT N_( \ - "Secure RTP requires a (non-secret) master salt value.") + "Secure RTP requires a (non-secret) master salt value. " \ + "This must be a 28-character-long hexadecimal string.") static const char *const ppsz_protos[] = { "dccp", "sctp", "tcp", "udp", "udplite", @@ -160,19 +168,19 @@ static const char *const ppsz_protocols[] = { #define RFC3016_LONGTEXT N_( \ "This allows you to stream MPEG4 LATM audio streams (see RFC3016)." ) -#define RTSP_HOST_TEXT N_( "RTSP host address" ) -#define RTSP_HOST_LONGTEXT N_( \ - "This defines the address, port and path the RTSP VOD server will listen " \ - "on.\nSyntax is address:port/path. The default is to listen on all "\ - "interfaces (address 0.0.0.0), on port 554, with no path.\nTo listen " \ - "only on the local interface, use \"localhost\" as address." ) - #define RTSP_TIMEOUT_TEXT N_( "RTSP session timeout (s)" ) #define RTSP_TIMEOUT_LONGTEXT N_( "RTSP sessions will be closed after " \ "not receiving any RTSP request for this long. Setting it to a " \ "negative value or zero disables timeouts. The default is 60 (one " \ "minute)." ) +#define RTSP_USER_TEXT N_("Username") +#define RTSP_USER_LONGTEXT N_("User name that will be " \ + "requested to access the stream." ) +#define RTSP_PASS_TEXT N_("Password") +#define RTSP_PASS_LONGTEXT N_("Password that will be " \ + "requested to access the stream." ) + static int Open ( vlc_object_t * ); static void Close( vlc_object_t * ); @@ -198,6 +206,7 @@ vlc_module_begin () add_string( SOUT_CFG_PREFIX "name", "", NAME_TEXT, NAME_LONGTEXT, true ) + add_string( SOUT_CFG_PREFIX "cat", "", CAT_TEXT, CAT_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "description", "", DESC_TEXT, DESC_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "url", "", URL_TEXT, @@ -209,7 +218,7 @@ vlc_module_begin () add_string( SOUT_CFG_PREFIX "proto", "udp", PROTO_TEXT, PROTO_LONGTEXT, false ) - change_string_list( ppsz_protos, ppsz_protocols, NULL ) + change_string_list( ppsz_protos, ppsz_protocols ) add_integer( SOUT_CFG_PREFIX "port", 5004, PORT_TEXT, PORT_LONGTEXT, true ) add_integer( SOUT_CFG_PREFIX "port-audio", 0, PORT_AUDIO_TEXT, @@ -244,10 +253,12 @@ vlc_module_begin () set_capability( "vod server", 10 ) set_callbacks( OpenVoD, CloseVoD ) add_shortcut( "rtsp" ) - add_string ( "rtsp-host", NULL, RTSP_HOST_TEXT, - RTSP_HOST_LONGTEXT, true ) add_integer( "rtsp-timeout", 60, RTSP_TIMEOUT_TEXT, RTSP_TIMEOUT_LONGTEXT, true ) + add_string( "sout-rtsp-user", "", + RTSP_USER_TEXT, RTSP_USER_LONGTEXT, true ) + add_password( "sout-rtsp-pwd", "", + RTSP_PASS_TEXT, RTSP_PASS_LONGTEXT, true ) vlc_module_end () @@ -255,9 +266,12 @@ vlc_module_end () * Exported prototypes *****************************************************************************/ static const char *const ppsz_sout_options[] = { - "dst", "name", "port", "port-audio", "port-video", "*sdp", "ttl", "mux", - "sap", "description", "url", "email", "phone", - "proto", "rtcp-mux", "caching", "key", "salt", + "dst", "name", "cat", "port", "port-audio", "port-video", "*sdp", "ttl", + "mux", "sap", "description", "url", "email", "phone", + "proto", "rtcp-mux", "caching", +#ifdef HAVE_SRTP + "key", "salt", +#endif "mp4a-latm", NULL }; @@ -383,7 +397,6 @@ struct sout_stream_id_t static int Open( vlc_object_t *p_this ) { sout_stream_t *p_stream = (sout_stream_t*)p_this; - sout_instance_t *p_sout = p_stream->p_sout; sout_stream_sys_t *p_sys = NULL; config_chain_t *p_cfg = NULL; char *psz; @@ -557,7 +570,7 @@ static int Open( vlc_object_t *p_this ) } p_sys->p_grab = GrabberCreate( p_stream ); - p_sys->p_mux = sout_MuxNew( p_sout, psz, p_sys->p_grab ); + p_sys->p_mux = sout_MuxNew( p_stream->p_sout, psz, p_sys->p_grab ); free( psz ); if( p_sys->p_mux == NULL ) @@ -588,6 +601,7 @@ static int Open( vlc_object_t *p_this ) p_stream->pf_del = Del; p_stream->pf_send = Send; } + p_stream->pace_nocontrol = true; if( var_GetBool( p_stream, SOUT_CFG_PREFIX"sap" ) ) SDPHandleUrl( p_stream, "sap" ); @@ -616,9 +630,6 @@ static int Open( vlc_object_t *p_this ) free( psz ); } - /* update p_sout->i_out_pace_nocontrol */ - p_stream->p_sout->i_out_pace_nocontrol++; - if( p_sys->p_mux != NULL ) { sout_stream_id_t *id = Add( p_stream, NULL ); @@ -640,9 +651,6 @@ static void Close( vlc_object_t * p_this ) sout_stream_t *p_stream = (sout_stream_t*)p_this; sout_stream_sys_t *p_sys = p_stream->p_sys; - /* update p_sout->i_out_pace_nocontrol */ - p_stream->p_sout->i_out_pace_nocontrol--; - if( p_sys->p_mux ) { assert( p_sys->i_es <= 1 ); @@ -715,7 +723,27 @@ static void SDPHandleUrl( sout_stream_t *p_stream, const char *psz_url ) goto out; } - p_sys->rtsp = RtspSetup( VLC_OBJECT(p_stream), NULL, &url ); + if( url.psz_host != NULL && *url.psz_host ) + { + msg_Warn( p_stream, "\"%s\" RTSP host might be ignored in " + "multiple-host configurations, use at your own risks.", + url.psz_host ); + msg_Info( p_stream, "Consider passing --rtsp-host=IP on the " + "command line instead." ); + + var_Create( p_stream, "rtsp-host", VLC_VAR_STRING ); + var_SetString( p_stream, "rtsp-host", url.psz_host ); + } + if( url.i_port != 0 ) + { + /* msg_Info( p_stream, "Consider passing --rtsp-port=%u on " + "the command line instead.", url.i_port ); */ + + var_Create( p_stream, "rtsp-port", VLC_VAR_INTEGER ); + var_SetInteger( p_stream, "rtsp-port", url.i_port ); + } + + p_sys->rtsp = RtspSetup( VLC_OBJECT(p_stream), NULL, url.psz_path ); if( p_sys->rtsp == NULL ) msg_Err( p_stream, "cannot export SDP as RTSP" ); } @@ -885,7 +913,8 @@ char *SDPGenerate( sout_stream_t *p_stream, const char *rtsp_url ) sdp_AddAttribute( &psz_sdp, "setup", "passive" ); if( p_sys->proto == IPPROTO_DCCP ) sdp_AddAttribute( &psz_sdp, "dccp-service-code", - "SC:RTP%c", toupper( mime_major[0] ) ); + "SC:RTP%c", + toupper( (unsigned char)mime_major[0] ) ); } } out: @@ -916,9 +945,14 @@ rtp_set_ptime (sout_stream_id_t *id, unsigned ptime_ms, size_t bytes) uint32_t rtp_compute_ts( unsigned i_clock_rate, int64_t i_pts ) { - /* NOTE: this plays nice with offsets because the calculations are - * linear. */ - return i_pts * (int64_t)i_clock_rate / CLOCK_FREQ; + /* This is an overflow-proof way of doing: + * return i_pts * (int64_t)i_clock_rate / CLOCK_FREQ; + * + * NOTE: this plays nice with offsets because the (equivalent) + * calculations are linear. */ + lldiv_t q = lldiv(i_pts, CLOCK_FREQ); + return q.quot * (int64_t)i_clock_rate + + q.rem * (int64_t)i_clock_rate / CLOCK_FREQ; } /** Add an ES as a new RTP stream */ @@ -995,6 +1029,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) char *key = var_GetNonEmptyString (p_stream, SOUT_CFG_PREFIX"key"); if (key) { + vlc_gcrypt_init (); id->srtp = srtp_create (SRTP_ENCR_AES_CM, SRTP_AUTH_HMAC_SHA1, 10, SRTP_PRF_AES_CM, SRTP_RCC_MODE1); if (id->srtp == NULL) @@ -1265,17 +1300,16 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id, static int SapSetup( sout_stream_t *p_stream ) { sout_stream_sys_t *p_sys = p_stream->p_sys; - sout_instance_t *p_sout = p_stream->p_sout; /* Remove the previous session */ if( p_sys->p_session != NULL) { - sout_AnnounceUnRegister( p_sout, p_sys->p_session); + sout_AnnounceUnRegister( p_stream, p_sys->p_session); p_sys->p_session = NULL; } if( p_sys->i_es > 0 && p_sys->psz_sdp && *p_sys->psz_sdp ) - p_sys->p_session = sout_AnnounceRegisterSDP( p_sout, + p_sys->p_session = sout_AnnounceRegisterSDP( p_stream, p_sys->psz_sdp, p_sys->psz_destination ); @@ -1317,14 +1351,13 @@ static int HttpSetup( sout_stream_t *p_stream, const vlc_url_t *url) { sout_stream_sys_t *p_sys = p_stream->p_sys; - p_sys->p_httpd_host = httpd_HostNew( VLC_OBJECT(p_stream), url->psz_host, - url->i_port > 0 ? url->i_port : 80 ); + p_sys->p_httpd_host = vlc_http_HostNew( VLC_OBJECT(p_stream) ); if( p_sys->p_httpd_host ) { p_sys->p_httpd_file = httpd_FileNew( p_sys->p_httpd_host, url->psz_path ? url->psz_path : "/", "application/sdp", - NULL, NULL, NULL, + NULL, NULL, HttpCallback, (void*)p_sys ); } if( p_sys->p_httpd_file == NULL ) @@ -1364,11 +1397,6 @@ static int HttpCallback( httpd_file_sys_t *p_args, static void* ThreadSend( void *data ) { #ifdef WIN32 -# define ECONNREFUSED WSAECONNREFUSED -# define ENOPROTOOPT WSAENOPROTOOPT -# define EHOSTUNREACH WSAEHOSTUNREACH -# define ENETUNREACH WSAENETUNREACH -# define ENETDOWN WSAENETDOWN # define ENOBUFS WSAENOBUFS # define EAGAIN WSAEWOULDBLOCK # define EWOULDBLOCK WSAEWOULDBLOCK @@ -1402,11 +1430,14 @@ static void* ThreadSend( void *data ) out->i_buffer = len; } if (out) -#endif mwait (out->i_dts + i_caching); vlc_cleanup_pop (); if (out == NULL) continue; +#else + mwait (out->i_dts + i_caching); + vlc_cleanup_pop (); +#endif ssize_t len = out->i_buffer; int canc = vlc_savecancel (); @@ -1422,31 +1453,20 @@ static void* ThreadSend( void *data ) #endif SendRTCP( id->sinkv[i].rtcp, out ); - if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 ) - continue; - switch( net_errno ) + if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) == -1 + && net_errno != EAGAIN && net_errno != EWOULDBLOCK + && net_errno != ENOBUFS && net_errno != ENOMEM ) { - /* Soft errors (e.g. ICMP): */ - case ECONNREFUSED: /* Port unreachable */ - case ENOPROTOOPT: -#ifdef EPROTO - case EPROTO: /* Protocol unreachable */ -#endif - case EHOSTUNREACH: /* Host unreachable */ - case ENETUNREACH: /* Network unreachable */ - case ENETDOWN: /* Entire network down */ + int type; + getsockopt( id->sinkv[i].rtp_fd, SOL_SOCKET, SO_TYPE, + &type, &(socklen_t){ sizeof(type) }); + if( type == SOCK_DGRAM ) + /* ICMP soft error: ignore and retry */ send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ); - /* Transient congestion: */ - case ENOMEM: /* out of socket buffers */ - case ENOBUFS: - case EAGAIN: -#if (EAGAIN != EWOULDBLOCK) - case EWOULDBLOCK: -#endif - continue; + else + /* Broken connection */ + deadv[deadc++] = id->sinkv[i].rtp_fd; } - - deadv[deadc++] = id->sinkv[i].rtp_fd; } id->i_seq_sent_next = ntohs(((uint16_t *) out->p_buffer)[1]) + 1; vlc_mutex_unlock( &id->lock_sink ); @@ -1548,8 +1568,8 @@ static int64_t rtp_init_ts( const vod_media_t *p_media, uint64_t i_ts_init; /* As per RFC 2326, session identifiers are at least 8 bytes long */ strncpy((char *)&i_ts_init, psz_vod_session, sizeof(uint64_t)); - i_ts_init ^= (uint64_t) p_media; - /* Limit the timestamp to 48 bytes, this is enough and allows us + i_ts_init ^= (uintptr_t)p_media; + /* Limit the timestamp to 48 bits, this is enough and allows us * to stay away from overflows */ i_ts_init &= 0xFFFFFFFFFFFF; return i_ts_init; @@ -1722,7 +1742,7 @@ static ssize_t AccessOutGrabberWriteBuffer( sout_stream_t *p_stream, if( p_sys->packet == NULL ) { /* allocate a new packet */ - p_sys->packet = block_New( p_stream, id->i_mtu ); + p_sys->packet = block_Alloc( id->i_mtu ); rtp_packetize_common( id, p_sys->packet, 1, i_dts ); p_sys->packet->i_dts = i_dts; p_sys->packet->i_length = p_buffer->i_length / i_packet; @@ -1768,7 +1788,7 @@ static sout_access_out_t *GrabberCreate( sout_stream_t *p_stream ) { sout_access_out_t *p_grab; - p_grab = vlc_object_create( p_stream->p_sout, sizeof( *p_grab ) ); + p_grab = vlc_object_create( p_stream, sizeof( *p_grab ) ); if( p_grab == NULL ) return NULL; @@ -1779,6 +1799,5 @@ static sout_access_out_t *GrabberCreate( sout_stream_t *p_stream ) p_grab->p_sys = (sout_access_out_sys_t *)p_stream; p_grab->pf_seek = NULL; p_grab->pf_write = AccessOutGrabberWrite; - vlc_object_attach( p_grab, p_stream ); return p_grab; }