]> git.sesse.net Git - vlc/blob - modules/access/udp.c
Fix typo in previous commit
[vlc] / modules / access / udp.c
1 /*****************************************************************************
2  * udp.c: raw UDP & RTP input module
3  *****************************************************************************
4  * Copyright (C) 2001-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Tristan Leteurtre <tooney@via.ecp.fr>
9  *          Laurent Aimar <fenrir@via.ecp.fr>
10  *
11  * Reviewed: 23 October 2003, Jean-Paul Saman <jpsaman@wxs.nl>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <stdlib.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/input.h>
35
36 #include "network.h"
37
38 /*****************************************************************************
39  * Module descriptor
40  *****************************************************************************/
41 #define CACHING_TEXT N_("Caching value in ms")
42 #define CACHING_LONGTEXT N_( \
43     "Allows you to modify the default caching value for UDP streams. This " \
44     "value should be set in millisecond units." )
45
46 #define AUTO_MTU_TEXT N_("Autodetection of MTU")
47 #define AUTO_MTU_LONGTEXT N_( \
48     "Allows growing the MTU if truncated packets are found" )
49
50 static int  Open ( vlc_object_t * );
51 static void Close( vlc_object_t * );
52
53 vlc_module_begin();
54     set_shortname( _("UDP/RTP" ) );
55     set_description( _("UDP/RTP input") );
56     set_category( CAT_INPUT );
57     set_subcategory( SUBCAT_INPUT_ACCESS );
58
59     add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
60                  CACHING_LONGTEXT, VLC_TRUE );
61     add_bool( "udp-auto-mtu", 1, NULL,
62               AUTO_MTU_TEXT, AUTO_MTU_LONGTEXT, VLC_TRUE );
63
64     set_capability( "access2", 0 );
65     add_shortcut( "udp" );
66     add_shortcut( "udpstream" );
67     add_shortcut( "udp4" );
68     add_shortcut( "udp6" );
69     add_shortcut( "rtp" );
70     add_shortcut( "rtp4" );
71     add_shortcut( "rtp6" );
72     set_callbacks( Open, Close );
73 vlc_module_end();
74
75 /*****************************************************************************
76  * Local prototypes
77  *****************************************************************************/
78 #define RTP_HEADER_LEN 12
79
80 static block_t *BlockUDP( access_t * );
81 static block_t *BlockRTP( access_t * );
82 static block_t *BlockChoose( access_t * );
83 static int Control( access_t *, int, va_list );
84
85 struct access_sys_t
86 {
87     int fd;
88
89     int i_mtu;
90     vlc_bool_t b_auto_mtu;
91 };
92
93 /*****************************************************************************
94  * Open: open the socket
95  *****************************************************************************/
96 static int Open( vlc_object_t *p_this )
97 {
98     access_t     *p_access = (access_t*)p_this;
99     access_sys_t *p_sys;
100
101     char *psz_name = strdup( p_access->psz_path );
102     char *psz_parser, *psz_server_addr, *psz_bind_addr = "";
103     int  i_bind_port, i_server_port = 0;
104
105
106     /* First set ipv4/ipv6 */
107     var_Create( p_access, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
108     var_Create( p_access, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
109
110     if( *p_access->psz_access )
111     {
112         vlc_value_t val;
113         /* Find out which shortcut was used */
114         if( !strncmp( p_access->psz_access, "udp4", 6 ) ||
115             !strncmp( p_access->psz_access, "rtp4", 6 ))
116         {
117             val.b_bool = VLC_TRUE;
118             var_Set( p_access, "ipv4", val );
119
120             val.b_bool = VLC_FALSE;
121             var_Set( p_access, "ipv6", val );
122         }
123         else if( !strncmp( p_access->psz_access, "udp6", 6 ) ||
124                  !strncmp( p_access->psz_access, "rtp6", 6 ) )
125         {
126             val.b_bool = VLC_TRUE;
127             var_Set( p_access, "ipv6", val );
128
129             val.b_bool = VLC_FALSE;
130             var_Set( p_access, "ipv4", val );
131         }
132     }
133
134     i_bind_port = var_CreateGetInteger( p_access, "server-port" );
135
136     /* Parse psz_name syntax :
137      * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
138     psz_parser = strchr( psz_name, '@' );
139     if( psz_parser != NULL )
140     {
141         /* Found bind address and/or bind port */
142         *psz_parser++ = '\0';
143         psz_bind_addr = psz_parser;
144
145         if( *psz_parser == '[' )
146             /* skips bracket'd IPv6 address */
147             psz_parser = strchr( psz_parser, ']' );
148
149         if( psz_parser != NULL )
150         {
151             psz_parser = strchr( psz_parser, ':' );
152             if( psz_parser != NULL )
153             {
154                 *psz_parser++ = '\0';
155                 i_bind_port = atoi( psz_parser );
156             }
157         }
158   
159     }
160
161     psz_server_addr = psz_name;
162     if( *psz_server_addr == '[' )
163         /* skips bracket'd IPv6 address */
164         psz_parser = strchr( psz_name, ']' );
165
166     if( psz_parser != NULL )
167     {
168         psz_parser = strchr( psz_parser, ':' );
169         if( psz_parser != NULL )
170         {
171             *psz_parser++ = '\0';
172             i_server_port = atoi( psz_parser );
173         }
174     }
175
176     msg_Dbg( p_access, "opening server=%s:%d local=%s:%d",
177              psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
178
179     /* Set up p_access */
180     p_access->pf_read = NULL;
181     if( !strcasecmp( p_access->psz_access, "rtp" )
182           || !strcasecmp( p_access->psz_access, "rtp4" )
183           || !strcasecmp( p_access->psz_access, "rtp6" ) )
184     {
185         p_access->pf_block = BlockRTP;
186     }
187     else
188     {
189         p_access->pf_block = BlockChoose;
190     }
191     p_access->pf_control = Control;
192     p_access->pf_seek = NULL;
193     p_access->info.i_update = 0;
194     p_access->info.i_size = 0;
195     p_access->info.i_pos = 0;
196     p_access->info.b_eof = VLC_FALSE;
197     p_access->info.i_title = 0;
198     p_access->info.i_seekpoint = 0;
199
200     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
201     p_sys->fd = net_OpenUDP( p_access, psz_bind_addr, i_bind_port,
202                                       psz_server_addr, i_server_port );
203     if( p_sys->fd < 0 )
204     {
205         msg_Err( p_access, "cannot open socket" );
206         free( psz_name );
207         free( p_sys );
208         return VLC_EGENERIC;
209     }
210     free( psz_name );
211
212     net_StopSend( p_sys->fd );
213
214     /* FIXME */
215     p_sys->i_mtu = var_CreateGetInteger( p_access, "mtu" );
216     if( p_sys->i_mtu <= 1 )
217         p_sys->i_mtu  = 1500;   /* Avoid problem */
218
219     p_sys->b_auto_mtu = var_CreateGetBool( p_access, "udp-auto-mtu" );;
220
221     /* Update default_pts to a suitable value for udp access */
222     var_Create( p_access, "udp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
223
224     return VLC_SUCCESS;
225 }
226
227 /*****************************************************************************
228  * Close: free unused data structures
229  *****************************************************************************/
230 static void Close( vlc_object_t *p_this )
231 {
232     access_t     *p_access = (access_t*)p_this;
233     access_sys_t *p_sys = p_access->p_sys;
234
235     net_Close( p_sys->fd );
236     free( p_sys );
237 }
238
239 /*****************************************************************************
240  * Control:
241  *****************************************************************************/
242 static int Control( access_t *p_access, int i_query, va_list args )
243 {
244     access_sys_t *p_sys = p_access->p_sys;
245     vlc_bool_t   *pb_bool;
246     int          *pi_int;
247     int64_t      *pi_64;
248
249     switch( i_query )
250     {
251         /* */
252         case ACCESS_CAN_SEEK:
253         case ACCESS_CAN_FASTSEEK:
254         case ACCESS_CAN_PAUSE:
255         case ACCESS_CAN_CONTROL_PACE:
256             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
257             *pb_bool = VLC_FALSE;
258             break;
259         /* */
260         case ACCESS_GET_MTU:
261             pi_int = (int*)va_arg( args, int * );
262             *pi_int = p_sys->i_mtu;
263             break;
264
265         case ACCESS_GET_PTS_DELAY:
266             pi_64 = (int64_t*)va_arg( args, int64_t * );
267             *pi_64 = var_GetInteger( p_access, "udp-caching" ) * 1000;
268             break;
269
270         /* */
271         case ACCESS_SET_PAUSE_STATE:
272         case ACCESS_GET_TITLE_INFO:
273         case ACCESS_SET_TITLE:
274         case ACCESS_SET_SEEKPOINT:
275         case ACCESS_SET_PRIVATE_ID_STATE:
276             return VLC_EGENERIC;
277
278         default:
279             msg_Warn( p_access, "unimplemented query in control" );
280             return VLC_EGENERIC;
281
282     }
283     return VLC_SUCCESS;
284 }
285
286 /*****************************************************************************
287  * BlockUDP:
288  *****************************************************************************/
289 static block_t *BlockUDP( access_t *p_access )
290 {
291     access_sys_t *p_sys = p_access->p_sys;
292     block_t      *p_block;
293
294     /* Read data */
295     p_block = block_New( p_access, p_sys->i_mtu );
296     p_block->i_buffer = net_Read( p_access, p_sys->fd, NULL,
297                                   p_block->p_buffer, p_sys->i_mtu,
298                                   VLC_FALSE );
299     if( p_block->i_buffer <= 0 )
300     {
301         block_Release( p_block );
302         return NULL;
303     }
304
305     if( p_block->i_buffer >= p_sys->i_mtu && p_sys->b_auto_mtu &&
306         p_sys->i_mtu < 32767 )
307     {
308         /* Increase by 100% */
309         p_sys->i_mtu *= 2;
310         msg_Dbg( p_access, "increasing MTU to %d", p_sys->i_mtu );
311     }
312
313     return p_block;
314 }
315
316 /*****************************************************************************
317  * BlockParseRTP/BlockRTP:
318  *****************************************************************************/
319 static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
320 {
321     int     i_rtp_version;
322     int     i_CSRC_count;
323     int     i_payload_type;
324     int     i_skip = 0;
325
326     if( p_block->i_buffer < RTP_HEADER_LEN )
327         goto trash;
328
329     /* Parse the header and make some verifications.
330      * See RFC 1889 & RFC 2250. */
331     i_rtp_version  = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
332     i_CSRC_count   = ( p_block->p_buffer[0] & 0x0F );
333     i_payload_type = ( p_block->p_buffer[1] & 0x7F );
334
335     if ( i_rtp_version != 2 )
336         msg_Dbg( p_access, "RTP version is %u, should be 2", i_rtp_version );
337
338     if( i_payload_type == 14 )
339         i_skip = 4;
340     else if( i_payload_type !=  33 && i_payload_type != 32 )
341         msg_Dbg( p_access, "unsupported RTP payload type (%u)", i_payload_type );
342
343     i_skip += RTP_HEADER_LEN + 4*i_CSRC_count;
344
345     /* A CSRC extension field is 32 bits in size (4 bytes) */
346     if( i_skip >= p_block->i_buffer )
347         goto trash;
348
349     /* Return the packet without the RTP header. */
350     p_block->i_buffer -= i_skip;
351     p_block->p_buffer += i_skip;
352
353     return p_block;
354
355 trash:
356     msg_Warn( p_access, "received a too short packet for RTP" );
357     block_Release( p_block );
358     return NULL;
359 }
360
361 static block_t *BlockRTP( access_t *p_access )
362 {
363     block_t *p_block = BlockUDP( p_access );
364
365     if ( p_block != NULL )
366         return BlockParseRTP( p_access, p_block );
367     else
368         return NULL;
369 }
370
371 /*****************************************************************************
372  * BlockChoose: decide between RTP and UDP
373  *****************************************************************************/
374 static block_t *BlockChoose( access_t *p_access )
375 {
376     block_t *p_block;
377     int     i_rtp_version;
378     int     i_CSRC_count;
379     int     i_payload_type;
380
381     if( ( p_block = BlockUDP( p_access ) ) == NULL )
382         return NULL;
383
384     if( p_block->p_buffer[0] == 0x47 )
385     {
386         msg_Dbg( p_access, "detected TS over raw UDP" );
387         p_access->pf_block = BlockUDP;
388         return p_block;
389     }
390
391     if( p_block->i_buffer < RTP_HEADER_LEN )
392         return p_block;
393
394     /* Parse the header and make some verifications.
395      * See RFC 1889 & RFC 2250. */
396
397     i_rtp_version  = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
398     i_CSRC_count   = ( p_block->p_buffer[0] & 0x0F );
399     i_payload_type = ( p_block->p_buffer[1] & 0x7F );
400
401     if( i_rtp_version != 2 )
402     {
403         msg_Dbg( p_access, "no supported RTP header detected" );
404         p_access->pf_block = BlockUDP;
405         return p_block;
406     }
407
408     switch( i_payload_type )
409     {
410         case 33:
411             msg_Dbg( p_access, "detected TS over RTP" );
412             p_access->psz_demux = strdup( "ts" );
413             break;
414
415         case 14:
416             msg_Dbg( p_access, "detected MPEG audio over RTP" );
417             p_access->psz_demux = strdup( "mpga" );
418             break;
419
420         case 32:
421             msg_Dbg( p_access, "detected MPEG video over RTP" );
422             p_access->psz_demux = strdup( "mpgv" );
423             break;
424
425         default:
426             msg_Dbg( p_access, "no RTP header detected" );
427             p_access->pf_block = BlockUDP;
428             return p_block;
429     }
430
431     p_access->pf_block = BlockRTP;
432
433     return BlockParseRTP( p_access, p_block );
434 }