X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fstream_out%2Frtp.c;h=e96139ec7103b8194890120b4268033fda9c24da;hb=3df8b1ab5a654ea95d4e550894ad292a78375132;hp=8ec54d9cd807195fd2b33c2e5f342f9e811949f0;hpb=eb3d87723c1ab9d5f695550e4b071e92b2ef2118;p=vlc diff --git a/modules/stream_out/rtp.c b/modules/stream_out/rtp.c index 8ec54d9cd8..e96139ec71 100644 --- a/modules/stream_out/rtp.c +++ b/modules/stream_out/rtp.c @@ -167,47 +167,47 @@ vlc_module_begin () set_subcategory( SUBCAT_SOUT_STREAM ) add_string( SOUT_CFG_PREFIX "dst", "", NULL, DEST_TEXT, - DEST_LONGTEXT, true ); + DEST_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "sdp", "", NULL, SDP_TEXT, - SDP_LONGTEXT, true ); + SDP_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "mux", "", NULL, MUX_TEXT, - MUX_LONGTEXT, true ); + MUX_LONGTEXT, true ) add_bool( SOUT_CFG_PREFIX "sap", false, NULL, SAP_TEXT, SAP_LONGTEXT, - true ); + true ) add_string( SOUT_CFG_PREFIX "name", "", NULL, NAME_TEXT, - NAME_LONGTEXT, true ); + NAME_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "description", "", NULL, DESC_TEXT, - DESC_LONGTEXT, true ); + DESC_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "url", "", NULL, URL_TEXT, - URL_LONGTEXT, true ); + URL_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "email", "", NULL, EMAIL_TEXT, - EMAIL_LONGTEXT, true ); + EMAIL_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "phone", "", NULL, PHONE_TEXT, - PHONE_LONGTEXT, true ); + PHONE_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "proto", "udp", NULL, PROTO_TEXT, - PROTO_LONGTEXT, false ); - change_string_list( ppsz_protos, ppsz_protocols, NULL ); + PROTO_LONGTEXT, false ) + change_string_list( ppsz_protos, ppsz_protocols, NULL ) add_integer( SOUT_CFG_PREFIX "port", 5004, NULL, PORT_TEXT, - PORT_LONGTEXT, true ); + PORT_LONGTEXT, true ) add_integer( SOUT_CFG_PREFIX "port-audio", 0, NULL, PORT_AUDIO_TEXT, - PORT_AUDIO_LONGTEXT, true ); + PORT_AUDIO_LONGTEXT, true ) add_integer( SOUT_CFG_PREFIX "port-video", 0, NULL, PORT_VIDEO_TEXT, - PORT_VIDEO_LONGTEXT, true ); + PORT_VIDEO_LONGTEXT, true ) add_integer( SOUT_CFG_PREFIX "ttl", -1, NULL, TTL_TEXT, - TTL_LONGTEXT, true ); + TTL_LONGTEXT, true ) add_bool( SOUT_CFG_PREFIX "rtcp-mux", false, NULL, - RTCP_MUX_TEXT, RTCP_MUX_LONGTEXT, false ); + RTCP_MUX_TEXT, RTCP_MUX_LONGTEXT, false ) add_string( SOUT_CFG_PREFIX "key", "", NULL, - SRTP_KEY_TEXT, SRTP_KEY_LONGTEXT, false ); + SRTP_KEY_TEXT, SRTP_KEY_LONGTEXT, false ) add_string( SOUT_CFG_PREFIX "salt", "", NULL, - SRTP_SALT_TEXT, SRTP_SALT_LONGTEXT, false ); + SRTP_SALT_TEXT, SRTP_SALT_LONGTEXT, false ) add_bool( SOUT_CFG_PREFIX "mp4a-latm", 0, NULL, RFC3016_TEXT, - RFC3016_LONGTEXT, false ); + RFC3016_LONGTEXT, false ) set_callbacks( Open, Close ) vlc_module_end () @@ -350,13 +350,15 @@ static int Open( vlc_object_t *p_this ) p_sys->i_port = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port" ); p_sys->i_port_audio = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-audio" ); p_sys->i_port_video = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-video" ); - p_sys->rtcp_mux = var_GetBool( p_stream, SOUT_CFG_PREFIX "rtcp-mux" ); + p_sys->rtcp_mux = var_GetBool( p_stream, SOUT_CFG_PREFIX "rtcp-mux" ); p_sys->psz_sdp_file = NULL; if( p_sys->i_port_audio && p_sys->i_port_video == p_sys->i_port_audio ) { msg_Err( p_stream, "audio and video RTP port must be distinct" ); + free( p_sys->psz_destination ); + free( p_sys ); return VLC_EGENERIC; } @@ -469,6 +471,7 @@ static int Open( vlc_object_t *p_this ) free( psz ); vlc_mutex_destroy( &p_sys->lock_sdp ); vlc_mutex_destroy( &p_sys->lock_es ); + free( p_sys->psz_destination ); free( p_sys ); return VLC_EGENERIC; } @@ -483,6 +486,7 @@ static int Open( vlc_object_t *p_this ) sout_AccessOutDelete( p_sys->p_grab ); vlc_mutex_destroy( &p_sys->lock_sdp ); vlc_mutex_destroy( &p_sys->lock_es ); + free( p_sys->psz_destination ); free( p_sys ); return VLC_EGENERIC; } @@ -494,6 +498,7 @@ static int Open( vlc_object_t *p_this ) sout_AccessOutDelete( p_sys->p_grab ); vlc_mutex_destroy( &p_sys->lock_sdp ); vlc_mutex_destroy( &p_sys->lock_es ); + free( p_sys->psz_destination ); free( p_sys ); return VLC_EGENERIC; } @@ -783,6 +788,9 @@ char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url ) id->psz_enc, id->i_clock_rate, id->i_channels, id->psz_fmtp); + if( !p_sys->rtcp_mux && (id->i_port & 1) ) /* cf RFC4566 §5.14 */ + sdp_AddAttribute ( &psz_sdp, "rtcp", "%u", id->i_port + 1 ); + if( rtsp_url != NULL ) { assert( strlen( rtsp_url ) > 0 ); @@ -845,10 +853,8 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) * mux (TS/PS), then p_fmt is NULL. */ sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_id_t *id; - int i_port, cscov = -1; + int cscov = -1; char *psz_sdp; - int i_port_audio_option = var_GetInteger( p_stream, "port-audio" ); - int i_port_video_option = var_GetInteger( p_stream, "port-video" ); if (0xffffffff == p_sys->payload_bitmap) { @@ -856,38 +862,41 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) return NULL; } - id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) ); - if( id == NULL ) - return NULL; - vlc_object_attach( id, p_stream ); - /* Choose the port */ - i_port = 0; + uint16_t i_port = 0; if( p_fmt == NULL ) ; else if( p_fmt->i_cat == AUDIO_ES && p_sys->i_port_audio > 0 ) - { i_port = p_sys->i_port_audio; - p_sys->i_port_audio = 0; - } else if( p_fmt->i_cat == VIDEO_ES && p_sys->i_port_video > 0 ) - { i_port = p_sys->i_port_video; - p_sys->i_port_video = 0; - } - while( i_port == 0 ) + /* We do not need the ES lock (p_sys->lock_es) here, because this is the + * only one thread that can *modify* the ES table. The ES lock protects + * the other threads from our modifications (TAB_APPEND, TAB_REMOVE). */ + for (int i = 0; i_port && (i < p_sys->i_es); i++) + if (i_port == p_sys->es[i]->i_port) + i_port = 0; /* Port already in use! */ + for (uint16_t p = p_sys->i_port; i_port == 0; p += 2) { - if( p_sys->i_port != i_port_audio_option - && p_sys->i_port != i_port_video_option ) + if (p == 0) { - i_port = p_sys->i_port; + msg_Err (p_stream, "too many RTP elementary streams"); + return NULL; } - p_sys->i_port += 2; + i_port = p; + for (int i = 0; i_port && (i < p_sys->i_es); i++) + if (p == p_sys->es[i]->i_port) + i_port = 0; } + id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) ); + if( id == NULL ) + return NULL; + vlc_object_attach( id, p_stream ); + id->p_stream = p_stream; /* Look for free dymanic payload type */ @@ -1022,21 +1031,21 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) else switch( p_fmt->i_codec ) { - case VLC_FOURCC( 'u', 'l', 'a', 'w' ): + case VLC_CODEC_MULAW: if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 8000 ) id->i_payload_type = 0; id->psz_enc = "PCMU"; id->pf_packetize = rtp_packetize_split; rtp_set_ptime (id, 20, 1); break; - case VLC_FOURCC( 'a', 'l', 'a', 'w' ): + case VLC_CODEC_ALAW: if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 8000 ) id->i_payload_type = 8; id->psz_enc = "PCMA"; id->pf_packetize = rtp_packetize_split; rtp_set_ptime (id, 20, 1); break; - case VLC_FOURCC( 's', '1', '6', 'b' ): + case VLC_CODEC_S16B: if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 44100 ) { id->i_payload_type = 11; @@ -1050,25 +1059,23 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) id->pf_packetize = rtp_packetize_split; rtp_set_ptime (id, 20, 2); break; - case VLC_FOURCC( 'u', '8', ' ', ' ' ): + case VLC_CODEC_U8: id->psz_enc = "L8"; id->pf_packetize = rtp_packetize_split; rtp_set_ptime (id, 20, 1); break; - case VLC_FOURCC( 'm', 'p', 'g', 'a' ): - case VLC_FOURCC( 'm', 'p', '3', ' ' ): + case VLC_CODEC_MPGA: id->i_payload_type = 14; id->psz_enc = "MPA"; id->i_clock_rate = 90000; /* not 44100 */ id->pf_packetize = rtp_packetize_mpa; break; - case VLC_FOURCC( 'm', 'p', 'g', 'v' ): + case VLC_CODEC_MPGV: id->i_payload_type = 32; id->psz_enc = "MPV"; id->pf_packetize = rtp_packetize_mpv; break; - case VLC_FOURCC( 'G', '7', '2', '6' ): - case VLC_FOURCC( 'g', '7', '2', '6' ): + case VLC_CODEC_ADPCM_G726: switch( p_fmt->i_bitrate / 1000 ) { case 16: @@ -1089,15 +1096,15 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) break; } break; - case VLC_FOURCC( 'a', '5', '2', ' ' ): + case VLC_CODEC_A52: id->psz_enc = "ac3"; id->pf_packetize = rtp_packetize_ac3; break; - case VLC_FOURCC( 'H', '2', '6', '3' ): + case VLC_CODEC_H263: id->psz_enc = "H263-1998"; id->pf_packetize = rtp_packetize_h263; break; - case VLC_FOURCC( 'h', '2', '6', '4' ): + case VLC_CODEC_H264: id->psz_enc = "H264"; id->pf_packetize = rtp_packetize_h264; id->psz_fmtp = NULL; @@ -1156,7 +1163,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) id->psz_fmtp = strdup( "packetization-mode=1" ); break; - case VLC_FOURCC( 'm', 'p', '4', 'v' ): + case VLC_CODEC_MP4V: { char hexa[2*p_fmt->i_extra +1]; @@ -1171,7 +1178,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) } break; } - case VLC_FOURCC( 'm', 'p', '4', 'a' ): + case VLC_CODEC_MP4A: { if(!p_sys->b_latm) { @@ -1216,21 +1223,21 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) } break; } - case VLC_FOURCC( 's', 'a', 'm', 'r' ): + case VLC_CODEC_AMR_NB: id->psz_enc = "AMR"; id->psz_fmtp = strdup( "octet-align=1" ); id->pf_packetize = rtp_packetize_amr; break; - case VLC_FOURCC( 's', 'a', 'w', 'b' ): + case VLC_CODEC_AMR_WB: id->psz_enc = "AMR-WB"; id->psz_fmtp = strdup( "octet-align=1" ); id->pf_packetize = rtp_packetize_amr; break; - case VLC_FOURCC( 's', 'p', 'x', ' ' ): + case VLC_CODEC_SPEEX: id->psz_enc = "SPEEX"; id->pf_packetize = rtp_packetize_spx; break; - case VLC_FOURCC( 't', '1', '4', '0' ): + case VLC_CODEC_ITU_T140: id->psz_enc = "t140" ; id->i_clock_rate = 1000; id->pf_packetize = rtp_packetize_t140; @@ -1260,7 +1267,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) id->p_fifo = block_FifoNew(); if( vlc_thread_create( id, "RTP send thread", ThreadSend, - VLC_THREAD_PRIORITY_HIGHEST, false ) ) + VLC_THREAD_PRIORITY_HIGHEST ) ) goto error; /* Update p_sys context */ @@ -1303,11 +1310,6 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id ) TAB_REMOVE( p_sys->i_es, p_sys->es, id ); vlc_mutex_unlock( &p_sys->lock_es ); - /* Release port */ - if( id->i_port == var_GetInteger( p_stream, "port-audio" ) ) - p_sys->i_port_audio = id->i_port; - if( id->i_port == var_GetInteger( p_stream, "port-video" ) ) - p_sys->i_port_video = id->i_port; /* Release dynamic payload type */ if (id->i_payload_type >= 96) p_sys->payload_bitmap &= ~(1 << (id->i_payload_type - 96)); @@ -1460,6 +1462,16 @@ static int HttpCallback( httpd_file_sys_t *p_args, ****************************************************************************/ static void* ThreadSend( vlc_object_t *p_this ) { +#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 +#endif sout_stream_id_t *id = (sout_stream_id_t *)p_this; unsigned i_caching = id->i_caching; @@ -1508,9 +1520,27 @@ static void* ThreadSend( vlc_object_t *p_this ) if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 ) continue; - /* Retry sending to root out soft-errors */ - if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 ) - continue; + switch( net_errno ) + { + /* 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 */ + 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; + } deadv[deadc++] = id->sinkv[i].rtp_fd; } @@ -1601,7 +1631,7 @@ unsigned rtp_get_num( const sout_stream_id_t *id ) void rtp_packetize_common( sout_stream_id_t *id, block_t *out, int b_marker, int64_t i_pts ) { - uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / INT64_C(1000000); + uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / INT64_C(CLOCK_FREQ); out->p_buffer[0] = 0x80; out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type;