Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

udp.c

00001 /*****************************************************************************
00002  * udp.c: raw UDP & RTP input module
00003  *****************************************************************************
00004  * Copyright (C) 2001-2005 the VideoLAN team
00005  * $Id: udp.c 13312 2005-11-22 07:51:20Z md $
00006  *
00007  * Authors: Christophe Massiot <[email protected]>
00008  *          Tristan Leteurtre <[email protected]>
00009  *          Laurent Aimar <[email protected]>
00010  *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
00011  *
00012  * Reviewed: 23 October 2003, Jean-Paul Saman <[email protected]>
00013  *
00014  * This program is free software; you can redistribute it and/or modify
00015  * it under the terms of the GNU General Public License as published by
00016  * the Free Software Foundation; either version 2 of the License, or
00017  * (at your option) any later version.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00027  *****************************************************************************/
00028 
00029 /*****************************************************************************
00030  * Preamble
00031  *****************************************************************************/
00032 #include <stdlib.h>
00033 
00034 #include <vlc/vlc.h>
00035 #include <vlc/input.h>
00036 
00037 #include "network.h"
00038 
00039 /*****************************************************************************
00040  * Module descriptor
00041  *****************************************************************************/
00042 #define CACHING_TEXT N_("Caching value in ms")
00043 #define CACHING_LONGTEXT N_( \
00044     "Allows you to modify the default caching value for UDP streams. This " \
00045     "value should be set in millisecond units." )
00046 
00047 #define AUTO_MTU_TEXT N_("Autodetection of MTU")
00048 #define AUTO_MTU_LONGTEXT N_( \
00049     "Allows growing the MTU if truncated packets are found" )
00050 
00051 #define RTP_LATE_TEXT N_("RTP reordering timeout in ms")
00052 #define RTP_LATE_LONGTEXT N_( \
00053     "Allows you to modify the RTP reordering behaviour. " \
00054     "RTP input will wait for late packets upto " \
00055     "the specified timeout in milisecond units." )
00056 
00057 static int  Open ( vlc_object_t * );
00058 static void Close( vlc_object_t * );
00059 
00060 vlc_module_begin();
00061     set_shortname( _("UDP/RTP" ) );
00062     set_description( _("UDP/RTP input") );
00063     set_category( CAT_INPUT );
00064     set_subcategory( SUBCAT_INPUT_ACCESS );
00065 
00066     add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
00067                  CACHING_LONGTEXT, VLC_TRUE );
00068     add_integer( "rtp-late", 100, NULL, RTP_LATE_TEXT, RTP_LATE_LONGTEXT, VLC_TRUE );
00069 
00070     add_bool( "udp-auto-mtu", 1, NULL,
00071               AUTO_MTU_TEXT, AUTO_MTU_LONGTEXT, VLC_TRUE );
00072 
00073     set_capability( "access2", 0 );
00074     add_shortcut( "udp" );
00075     add_shortcut( "udpstream" );
00076     add_shortcut( "udp4" );
00077     add_shortcut( "udp6" );
00078     add_shortcut( "rtp" );
00079     add_shortcut( "rtp4" );
00080     add_shortcut( "rtp6" );
00081     set_callbacks( Open, Close );
00082 vlc_module_end();
00083 
00084 /*****************************************************************************
00085  * Local prototypes
00086  *****************************************************************************/
00087 #define RTP_HEADER_LEN 12
00088 
00089 static block_t *BlockUDP( access_t * );
00090 static block_t *BlockRTP( access_t * );
00091 static block_t *BlockChoose( access_t * );
00092 static int Control( access_t *, int, va_list );
00093 
00094 struct access_sys_t
00095 {
00096     int fd;
00097 
00098     int i_mtu;
00099     vlc_bool_t b_auto_mtu;
00100 
00101     /* reorder rtp packets when out-of-sequence */
00102     mtime_t i_rtp_late;
00103     uint16_t i_last_seqno;
00104     block_t *p_list;
00105     block_t *p_end;
00106 };
00107 
00108 /*****************************************************************************
00109  * Open: open the socket
00110  *****************************************************************************/
00111 static int Open( vlc_object_t *p_this )
00112 {
00113     access_t     *p_access = (access_t*)p_this;
00114     access_sys_t *p_sys;
00115 
00116     char *psz_name = strdup( p_access->psz_path );
00117     char *psz_parser, *psz_server_addr, *psz_bind_addr = "";
00118     int  i_bind_port, i_server_port = 0;
00119 
00120     /* First set ipv4/ipv6 */
00121     var_Create( p_access, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00122     var_Create( p_access, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00123 
00124     if( *p_access->psz_access )
00125     {
00126         vlc_value_t val;
00127         /* Find out which shortcut was used */
00128         if( !strncmp( p_access->psz_access, "udp4", 6 ) ||
00129             !strncmp( p_access->psz_access, "rtp4", 6 ))
00130         {
00131             val.b_bool = VLC_TRUE;
00132             var_Set( p_access, "ipv4", val );
00133 
00134             val.b_bool = VLC_FALSE;
00135             var_Set( p_access, "ipv6", val );
00136         }
00137         else if( !strncmp( p_access->psz_access, "udp6", 6 ) ||
00138                  !strncmp( p_access->psz_access, "rtp6", 6 ) )
00139         {
00140             val.b_bool = VLC_TRUE;
00141             var_Set( p_access, "ipv6", val );
00142 
00143             val.b_bool = VLC_FALSE;
00144             var_Set( p_access, "ipv4", val );
00145         }
00146     }
00147 
00148     i_bind_port = var_CreateGetInteger( p_access, "server-port" );
00149 
00150     /* Parse psz_name syntax :
00151      * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
00152     psz_parser = strchr( psz_name, '@' );
00153     if( psz_parser != NULL )
00154     {
00155         /* Found bind address and/or bind port */
00156         *psz_parser++ = '\0';
00157         psz_bind_addr = psz_parser;
00158 
00159         if( *psz_parser == '[' )
00160             /* skips bracket'd IPv6 address */
00161             psz_parser = strchr( psz_parser, ']' );
00162 
00163         if( psz_parser != NULL )
00164         {
00165             psz_parser = strchr( psz_parser, ':' );
00166             if( psz_parser != NULL )
00167             {
00168                 *psz_parser++ = '\0';
00169                 i_bind_port = atoi( psz_parser );
00170             }
00171         }
00172     }
00173 
00174     psz_server_addr = psz_name;
00175     if( *psz_server_addr == '[' )
00176         /* skips bracket'd IPv6 address */
00177         psz_parser = strchr( psz_name, ']' );
00178 
00179     if( psz_parser != NULL )
00180     {
00181         psz_parser = strchr( psz_parser, ':' );
00182         if( psz_parser != NULL )
00183         {
00184             *psz_parser++ = '\0';
00185             i_server_port = atoi( psz_parser );
00186         }
00187     }
00188 
00189     msg_Dbg( p_access, "opening server=%s:%d local=%s:%d",
00190              psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
00191 
00192     /* Set up p_access */
00193     p_access->pf_read = NULL;
00194     p_access->pf_block = BlockChoose;
00195     p_access->pf_control = Control;
00196     p_access->pf_seek = NULL;
00197     p_access->info.i_update = 0;
00198     p_access->info.i_size = 0;
00199     p_access->info.i_pos = 0;
00200     p_access->info.b_eof = VLC_FALSE;
00201     p_access->info.b_prebuffered = VLC_FALSE;
00202     p_access->info.i_title = 0;
00203     p_access->info.i_seekpoint = 0;
00204 
00205     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
00206     p_sys->fd = net_OpenUDP( p_access, psz_bind_addr, i_bind_port,
00207                                       psz_server_addr, i_server_port );
00208     if( p_sys->fd < 0 )
00209     {
00210         msg_Err( p_access, "cannot open socket" );
00211         free( psz_name );
00212         free( p_sys );
00213         return VLC_EGENERIC;
00214     }
00215     free( psz_name );
00216 
00217     net_StopSend( p_sys->fd );
00218 
00219     /* FIXME */
00220     p_sys->i_mtu = var_CreateGetInteger( p_access, "mtu" );
00221     if( p_sys->i_mtu <= 1 )
00222         p_sys->i_mtu  = 1500;   /* Avoid problem */
00223 
00224     p_sys->b_auto_mtu = var_CreateGetBool( p_access, "udp-auto-mtu" );;
00225 
00226     /* Update default_pts to a suitable value for udp access */
00227     var_Create( p_access, "udp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00228 
00229 
00230     /* RTP reordering for out-of-sequence packets */
00231     p_sys->i_rtp_late = var_CreateGetInteger( p_access, "rtp-late" ) * 1000;
00232     p_sys->i_last_seqno = 0;
00233     p_sys->p_list = NULL;
00234     p_sys->p_end = NULL;
00235     return VLC_SUCCESS;
00236 }
00237 
00238 /*****************************************************************************
00239  * Close: free unused data structures
00240  *****************************************************************************/
00241 static void Close( vlc_object_t *p_this )
00242 {
00243     access_t     *p_access = (access_t*)p_this;
00244     access_sys_t *p_sys = p_access->p_sys;
00245 
00246     block_ChainRelease( p_sys->p_list );
00247     net_Close( p_sys->fd );
00248     free( p_sys );
00249 }
00250 
00251 /*****************************************************************************
00252  * Control:
00253  *****************************************************************************/
00254 static int Control( access_t *p_access, int i_query, va_list args )
00255 {
00256     access_sys_t *p_sys = p_access->p_sys;
00257     vlc_bool_t   *pb_bool;
00258     int          *pi_int;
00259     int64_t      *pi_64;
00260 
00261     switch( i_query )
00262     {
00263         /* */
00264         case ACCESS_CAN_SEEK:
00265         case ACCESS_CAN_FASTSEEK:
00266         case ACCESS_CAN_PAUSE:
00267         case ACCESS_CAN_CONTROL_PACE:
00268             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00269             *pb_bool = VLC_FALSE;
00270             break;
00271         /* */
00272         case ACCESS_GET_MTU:
00273             pi_int = (int*)va_arg( args, int * );
00274             *pi_int = p_sys->i_mtu;
00275             break;
00276 
00277         case ACCESS_GET_PTS_DELAY:
00278             pi_64 = (int64_t*)va_arg( args, int64_t * );
00279             *pi_64 = var_GetInteger( p_access, "udp-caching" ) * 1000;
00280             break;
00281 
00282         /* */
00283         case ACCESS_SET_PAUSE_STATE:
00284         case ACCESS_GET_TITLE_INFO:
00285         case ACCESS_SET_TITLE:
00286         case ACCESS_SET_SEEKPOINT:
00287         case ACCESS_SET_PRIVATE_ID_STATE:
00288             return VLC_EGENERIC;
00289 
00290         default:
00291             msg_Warn( p_access, "unimplemented query in control" );
00292             return VLC_EGENERIC;
00293 
00294     }
00295     return VLC_SUCCESS;
00296 }
00297 
00298 /*****************************************************************************
00299  * BlockUDP:
00300  *****************************************************************************/
00301 static block_t *BlockUDP( access_t *p_access )
00302 {
00303     access_sys_t *p_sys = p_access->p_sys;
00304     block_t      *p_block;
00305 
00306     /* Read data */
00307     p_block = block_New( p_access, p_sys->i_mtu );
00308     p_block->i_buffer = net_Read( p_access, p_sys->fd, NULL,
00309                                   p_block->p_buffer, p_sys->i_mtu,
00310                                   VLC_FALSE );
00311     if( p_block->i_buffer <= 0 )
00312     {
00313         block_Release( p_block );
00314         return NULL;
00315     }
00316 
00317     if( (p_block->i_buffer >= p_sys->i_mtu) && p_sys->b_auto_mtu &&
00318         p_sys->i_mtu < 32767 )
00319     {
00320         /* Increase by 100% */
00321         p_sys->i_mtu *= 2;
00322         msg_Dbg( p_access, "increasing MTU to %d", p_sys->i_mtu );
00323     }
00324 
00325     return p_block;
00326 }
00327 
00328 /*
00329  * rtp_ChainInsert - insert a p_block in the chain and
00330  * look at the sequence numbers.
00331  */
00332 static inline vlc_bool_t rtp_ChainInsert( access_t *p_access, block_t *p_block )
00333 {
00334     access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
00335     block_t *p_prev = NULL;
00336     block_t *p = p_sys->p_end;
00337     uint16_t i_new = (uint16_t) p_block->i_dts;
00338     uint16_t i_tmp = 0;
00339 
00340     if( !p_sys->p_list )
00341     {
00342         p_sys->p_list = p_block;
00343         p_sys->p_end = p_block;
00344         return VLC_TRUE;
00345     }
00346     /* walk through the queue from top down since the new packet is in 
00347     most cases just appended to the end */
00348 
00349     for( ;; )
00350     {
00351         i_tmp = i_new - (uint16_t) p->i_dts;
00352 
00353         if( !i_tmp )   /* trash duplicate */
00354             break; 
00355 
00356         if ( i_tmp < 32768 )
00357         {   /* insert after this block ( i_new > p->i_dts ) */
00358             p_block->p_next = p->p_next;
00359             p->p_next = p_block;
00360             p_block->p_prev = p;
00361             if (p_prev)
00362             {
00363                 p_prev->p_prev = p_block;
00364                 msg_Dbg(p_access, "RTP reordering: insert after %d, new %d", 
00365                     (uint16_t) p->i_dts, i_new );
00366             }
00367             else 
00368             {
00369                 p_sys->p_end = p_block;
00370             }
00371             return VLC_TRUE;
00372         }
00373         if( p == p_sys->p_list )
00374         {   /* we've reached bottom of chain */
00375             i_tmp = p_sys->i_last_seqno - i_new;
00376             if( !p_access->info.b_prebuffered || (i_tmp > 32767) )
00377             {
00378                 msg_Dbg(p_access, "RTP reordering: prepend %d before %d", 
00379                         i_new, (uint16_t) p->i_dts );
00380                 p_block->p_next = p;
00381                 p->p_prev = p_block;
00382                 p_sys->p_list = p_block;
00383                 return VLC_TRUE;
00384             }
00385 
00386             if( !i_tmp )   /* trash duplicate */
00387                 break;    
00388 
00389             /* reordering failed - append the packet to the end of queue */
00390             msg_Dbg(p_access, "RTP: sequence changed (or buffer too small) "
00391                 "new: %d, buffer %d...%d", i_new, (uint16_t) p->i_dts, 
00392                 (uint16_t) p_sys->p_end->i_dts);
00393             p_sys->p_end->p_next = p_block;
00394             p_block->p_prev = p_sys->p_end;
00395             p_sys->p_end = p_block;
00396             return VLC_TRUE;
00397         }
00398         p_prev = p;
00399         p = p->p_prev;
00400     }
00401     block_Release( p_block );
00402     return VLC_FALSE;
00403 }
00404 
00405 /*****************************************************************************
00406  * BlockParseRTP/BlockRTP:
00407  *****************************************************************************/
00408 static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
00409 {
00410     int      i_rtp_version;
00411     int      i_CSRC_count;
00412     int      i_payload_type;
00413     int      i_skip = 0;
00414     int      i_extension_flag = 0;
00415     int      i_extension_length = 0;
00416     uint16_t i_sequence_number = 0;
00417 
00418     if( p_block == NULL )
00419         return NULL;
00420 
00421     if( p_block->i_buffer < RTP_HEADER_LEN )
00422         goto trash;
00423 
00424     /* Parse the header and make some verifications.
00425      * See RFC 3550. */
00426     i_rtp_version     = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
00427     i_CSRC_count      = p_block->p_buffer[0] & 0x0F;
00428     i_extension_flag  = p_block->p_buffer[0] & 0x10;
00429     i_payload_type    = p_block->p_buffer[1] & 0x7F;
00430     i_sequence_number = (p_block->p_buffer[2] << 8 ) + p_block->p_buffer[3];
00431 
00432     if( i_rtp_version != 2 )
00433         msg_Dbg( p_access, "RTP version is %u, should be 2", i_rtp_version );
00434 
00435     if( i_payload_type == 14 || i_payload_type == 32)
00436         i_skip = 4;
00437     else if( i_payload_type !=  33 )
00438         msg_Dbg( p_access, "unsupported RTP payload type (%u)", i_payload_type );
00439     if( i_extension_flag )
00440         i_extension_length = 4 +
00441             4 * ( (p_block->p_buffer[14] << 8) + p_block->p_buffer[15] );
00442 
00443     /* Skip header + CSRC extension field n*(32 bits) + extension */
00444     i_skip += RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length;
00445 
00446     if( i_skip >= p_block->i_buffer )
00447         goto trash;
00448 
00449     /* Return the packet without the RTP header, remember seqno in i_dts */
00450     p_block->i_buffer -= i_skip;
00451     p_block->p_buffer += i_skip;
00452     p_block->i_pts = mdate();
00453     p_block->i_dts = (mtime_t) i_sequence_number;
00454 
00455 #if 0
00456     /* Emulate packet loss */
00457     if ( (i_sequence_number % 4000) == 0)
00458     {
00459         msg_Warn( p_access, "Emulating packet drop" );
00460         block_Release( p_block );
00461         return NULL;
00462     }
00463 #endif
00464 
00465     return p_block;
00466 
00467 
00468 trash:
00469     msg_Warn( p_access, "received a too short packet for RTP" );
00470     block_Release( p_block );
00471     return NULL;
00472 }
00473 
00474 static block_t *BlockPrebufferRTP( access_t *p_access, block_t *p_block )
00475 {
00476     access_sys_t *p_sys = p_access->p_sys;
00477     mtime_t   i_first = mdate();
00478     int       i_count = 0;
00479     block_t   *p = p_block;
00480 
00481     for( ;; )
00482     {
00483         mtime_t i_date = mdate();
00484 
00485         if( p && rtp_ChainInsert( p_access, p ))
00486             i_count++;
00487 
00488         /* Require at least 2 packets in the buffer */
00489         if( i_count > 2 && (i_date - i_first) > p_sys->i_rtp_late )
00490             break;
00491 
00492         p = BlockParseRTP( p_access, BlockUDP( p_access ));
00493         if( !p && (i_date - i_first) > p_sys->i_rtp_late ) 
00494         {
00495             msg_Err( p_access, "Error in RTP prebuffering!" );
00496             break;
00497         }
00498     }
00499 
00500     msg_Dbg( p_access, "RTP: prebuffered %d packets", i_count - 1 );
00501     p_access->info.b_prebuffered = VLC_TRUE;
00502     p = p_sys->p_list;
00503     p_sys->p_list = p_sys->p_list->p_next;
00504     p_sys->i_last_seqno = (uint16_t) p->i_dts;
00505     p->p_next = NULL;
00506     return p;
00507 }
00508 
00509 static block_t *BlockRTP( access_t *p_access )
00510 {
00511     access_sys_t *p_sys = p_access->p_sys;
00512     block_t *p;
00513 
00514     while ( !p_sys->p_list || 
00515              ( mdate() - p_sys->p_list->i_pts ) < p_sys->i_rtp_late )
00516     {
00517         p = BlockParseRTP( p_access, BlockUDP( p_access ));
00518 
00519         if ( !p ) 
00520             return NULL;
00521 
00522         rtp_ChainInsert( p_access, p );
00523     }
00524 
00525     p = p_sys->p_list;
00526     p_sys->p_list = p_sys->p_list->p_next;
00527     p_sys->i_last_seqno++;
00528     if( p_sys->i_last_seqno != (uint16_t) p->i_dts )
00529     {
00530         msg_Dbg( p_access, "RTP: packet(s) lost, expected %d, got %d",
00531                  p_sys->i_last_seqno, (uint16_t) p->i_dts );
00532         p_sys->i_last_seqno = (uint16_t) p->i_dts;
00533     }
00534     p->p_next = NULL;
00535     return p;
00536 }
00537 
00538 /*****************************************************************************
00539  * BlockChoose: decide between RTP and UDP
00540  *****************************************************************************/
00541 static block_t *BlockChoose( access_t *p_access )
00542 {
00543     block_t *p_block;
00544     int     i_rtp_version;
00545     int     i_CSRC_count;
00546     int     i_payload_type;
00547 
00548     if( ( p_block = BlockUDP( p_access ) ) == NULL )
00549         return NULL;
00550 
00551     if( p_block->p_buffer[0] == 0x47 )
00552     {
00553         msg_Dbg( p_access, "detected TS over raw UDP" );
00554         p_access->pf_block = BlockUDP;
00555         p_access->info.b_prebuffered = VLC_TRUE;
00556         return p_block;
00557     }
00558 
00559     if( p_block->i_buffer < RTP_HEADER_LEN )
00560         return p_block;
00561 
00562     /* Parse the header and make some verifications.
00563      * See RFC 3550. */
00564 
00565     i_rtp_version  = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
00566     i_CSRC_count   = ( p_block->p_buffer[0] & 0x0F );
00567     i_payload_type = ( p_block->p_buffer[1] & 0x7F );
00568 
00569     if( i_rtp_version != 2 )
00570     {
00571         msg_Dbg( p_access, "no supported RTP header detected" );
00572         p_access->pf_block = BlockUDP;
00573         p_access->info.b_prebuffered = VLC_TRUE;
00574         return p_block;
00575     }
00576 
00577     switch( i_payload_type )
00578     {
00579         case 33:
00580             msg_Dbg( p_access, "detected TS over RTP" );
00581             p_access->psz_demux = strdup( "ts" );
00582             break;
00583 
00584         case 14:
00585             msg_Dbg( p_access, "detected MPEG audio over RTP" );
00586             p_access->psz_demux = strdup( "mpga" );
00587             break;
00588 
00589         case 32:
00590             msg_Dbg( p_access, "detected MPEG video over RTP" );
00591             p_access->psz_demux = strdup( "mpgv" );
00592             break;
00593 
00594         default:
00595             msg_Dbg( p_access, "no RTP header detected" );
00596             p_access->pf_block = BlockUDP;
00597             p_access->info.b_prebuffered = VLC_TRUE;
00598             return p_block;
00599     }
00600 
00601     if( !BlockParseRTP( p_access, p_block )) return NULL;
00602 
00603     p_access->pf_block = BlockRTP;
00604 
00605     return BlockPrebufferRTP( p_access, p_block );
00606 }

Generated on Tue Dec 20 10:14:26 2005 for vlc-0.8.4a by  doxygen 1.4.2