Qt: do not show open options in both normal and advanced UI
[vlc.git] / modules / access_output / udp.c
blobd996d749279694007e17d2158912c6ed7ec60c0e
1 /*****************************************************************************
2 * udp.c
3 *****************************************************************************
4 * Copyright (C) 2001-2007 the VideoLAN team
5 * $Id$
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Eric Petit <titer@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include <sys/types.h>
36 #include <assert.h>
38 #include <vlc_sout.h>
39 #include <vlc_block.h>
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
45 #ifdef WIN32
46 # include <winsock2.h>
47 # include <ws2tcpip.h>
48 #else
49 # include <sys/socket.h>
50 #endif
52 #include <vlc_network.h>
54 #define MAX_EMPTY_BLOCKS 200
56 /*****************************************************************************
57 * Module descriptor
58 *****************************************************************************/
59 static int Open ( vlc_object_t * );
60 static void Close( vlc_object_t * );
62 #define SOUT_CFG_PREFIX "sout-udp-"
64 #define CACHING_TEXT N_("Caching value (ms)")
65 #define CACHING_LONGTEXT N_( \
66 "Default caching value for outbound UDP streams. This " \
67 "value should be set in milliseconds." )
69 #define GROUP_TEXT N_("Group packets")
70 #define GROUP_LONGTEXT N_("Packets can be sent one by one at the right time " \
71 "or by groups. You can choose the number " \
72 "of packets that will be sent at a time. It " \
73 "helps reducing the scheduling load on " \
74 "heavily-loaded systems." )
76 vlc_module_begin ()
77 set_description( N_("UDP stream output") )
78 set_shortname( "UDP" )
79 set_category( CAT_SOUT )
80 set_subcategory( SUBCAT_SOUT_ACO )
81 add_integer( SOUT_CFG_PREFIX "caching", DEFAULT_PTS_DELAY / 1000, CACHING_TEXT, CACHING_LONGTEXT, true )
82 add_integer( SOUT_CFG_PREFIX "group", 1, GROUP_TEXT, GROUP_LONGTEXT,
83 true )
85 set_capability( "sout access", 0 )
86 add_shortcut( "udp" )
87 set_callbacks( Open, Close )
88 vlc_module_end ()
90 /*****************************************************************************
91 * Exported prototypes
92 *****************************************************************************/
94 static const char *const ppsz_sout_options[] = {
95 "caching",
96 "group",
97 NULL
100 /* Options handled by the libvlc network core */
101 static const char *const ppsz_core_options[] = {
102 "dscp",
103 "ttl",
104 "miface",
105 NULL
108 static ssize_t Write ( sout_access_out_t *, block_t * );
109 static int Seek ( sout_access_out_t *, off_t );
110 static int Control( sout_access_out_t *, int, va_list );
112 static void* ThreadWrite( void * );
113 static block_t *NewUDPPacket( sout_access_out_t *, mtime_t );
115 struct sout_access_out_sys_t
117 mtime_t i_caching;
118 int i_handle;
119 bool b_mtu_warning;
120 size_t i_mtu;
122 block_fifo_t *p_fifo;
123 block_fifo_t *p_empty_blocks;
124 block_t *p_buffer;
126 vlc_thread_t thread;
129 #define DEFAULT_PORT 1234
131 /*****************************************************************************
132 * Open: open the file
133 *****************************************************************************/
134 static int Open( vlc_object_t *p_this )
136 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
137 sout_access_out_sys_t *p_sys;
139 char *psz_dst_addr = NULL;
140 int i_dst_port;
142 int i_handle;
144 config_ChainParse( p_access, SOUT_CFG_PREFIX,
145 ppsz_sout_options, p_access->p_cfg );
146 config_ChainParse( p_access, "",
147 ppsz_core_options, p_access->p_cfg );
149 if (var_Create (p_access, "dst-port", VLC_VAR_INTEGER)
150 || var_Create (p_access, "src-port", VLC_VAR_INTEGER)
151 || var_Create (p_access, "dst-addr", VLC_VAR_STRING)
152 || var_Create (p_access, "src-addr", VLC_VAR_STRING))
154 return VLC_ENOMEM;
157 if( !( p_sys = malloc ( sizeof( *p_sys ) ) ) )
158 return VLC_ENOMEM;
159 p_access->p_sys = p_sys;
161 i_dst_port = DEFAULT_PORT;
162 char *psz_parser = psz_dst_addr = strdup( p_access->psz_path );
163 if( !psz_dst_addr )
165 free( p_sys );
166 return VLC_ENOMEM;
169 if (psz_parser[0] == '[')
170 psz_parser = strchr (psz_parser, ']');
172 psz_parser = strchr (psz_parser ? psz_parser : psz_dst_addr, ':');
173 if (psz_parser != NULL)
175 *psz_parser++ = '\0';
176 i_dst_port = atoi (psz_parser);
179 i_handle = net_ConnectDgram( p_this, psz_dst_addr, i_dst_port, -1,
180 IPPROTO_UDP );
181 free (psz_dst_addr);
183 if( i_handle == -1 )
185 msg_Err( p_access, "failed to create raw UDP socket" );
186 free (p_sys);
187 return VLC_EGENERIC;
189 else
191 char addr[NI_MAXNUMERICHOST];
192 int port;
194 if (net_GetSockAddress (i_handle, addr, &port) == 0)
196 msg_Dbg (p_access, "source: %s port %d", addr, port);
197 var_SetString (p_access, "src-addr", addr);
198 var_SetInteger (p_access, "src-port", port);
201 if (net_GetPeerAddress (i_handle, addr, &port) == 0)
203 msg_Dbg (p_access, "destination: %s port %d", addr, port);
204 var_SetString (p_access, "dst-addr", addr);
205 var_SetInteger (p_access, "dst-port", port);
208 shutdown( i_handle, SHUT_RD );
210 p_sys->i_caching = UINT64_C(1000)
211 * var_GetInteger( p_access, SOUT_CFG_PREFIX "caching");
212 p_sys->i_handle = i_handle;
213 p_sys->i_mtu = var_CreateGetInteger( p_this, "mtu" );
214 p_sys->b_mtu_warning = false;
215 p_sys->p_fifo = block_FifoNew();
216 p_sys->p_empty_blocks = block_FifoNew();
217 p_sys->p_buffer = NULL;
219 if( vlc_clone( &p_sys->thread, ThreadWrite, p_access,
220 VLC_THREAD_PRIORITY_HIGHEST ) )
222 msg_Err( p_access, "cannot spawn sout access thread" );
223 block_FifoRelease( p_sys->p_fifo );
224 block_FifoRelease( p_sys->p_empty_blocks );
225 net_Close (i_handle);
226 free (p_sys);
227 return VLC_EGENERIC;
230 p_access->pf_write = Write;
231 p_access->pf_seek = Seek;
232 p_access->pf_control = Control;
234 return VLC_SUCCESS;
237 /*****************************************************************************
238 * Close: close the target
239 *****************************************************************************/
240 static void Close( vlc_object_t * p_this )
242 sout_access_out_t *p_access = (sout_access_out_t*)p_this;
243 sout_access_out_sys_t *p_sys = p_access->p_sys;
245 vlc_cancel( p_sys->thread );
246 vlc_join( p_sys->thread, NULL );
247 block_FifoRelease( p_sys->p_fifo );
248 block_FifoRelease( p_sys->p_empty_blocks );
250 if( p_sys->p_buffer ) block_Release( p_sys->p_buffer );
252 net_Close( p_sys->i_handle );
253 free( p_sys );
256 static int Control( sout_access_out_t *p_access, int i_query, va_list args )
258 (void)p_access;
260 switch( i_query )
262 case ACCESS_OUT_CONTROLS_PACE:
263 *va_arg( args, bool * ) = false;
264 break;
266 default:
267 return VLC_EGENERIC;
269 return VLC_SUCCESS;
272 /*****************************************************************************
273 * Write: standard write on a file descriptor.
274 *****************************************************************************/
275 static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
277 sout_access_out_sys_t *p_sys = p_access->p_sys;
278 int i_len = 0;
280 while( p_buffer )
282 block_t *p_next;
283 int i_packets = 0;
284 mtime_t now = mdate();
286 if( !p_sys->b_mtu_warning && p_buffer->i_buffer > p_sys->i_mtu )
288 msg_Warn( p_access, "packet size > MTU, you should probably "
289 "increase the MTU" );
290 p_sys->b_mtu_warning = true;
293 /* Check if there is enough space in the buffer */
294 if( p_sys->p_buffer &&
295 p_sys->p_buffer->i_buffer + p_buffer->i_buffer > p_sys->i_mtu )
297 if( p_sys->p_buffer->i_dts + p_sys->i_caching < now )
299 msg_Dbg( p_access, "late packet for UDP input (%"PRId64 ")",
300 now - p_sys->p_buffer->i_dts
301 - p_sys->i_caching );
303 block_FifoPut( p_sys->p_fifo, p_sys->p_buffer );
304 p_sys->p_buffer = NULL;
307 i_len += p_buffer->i_buffer;
308 while( p_buffer->i_buffer )
310 size_t i_payload_size = p_sys->i_mtu;
311 size_t i_write = __MIN( p_buffer->i_buffer, i_payload_size );
313 i_packets++;
315 if( !p_sys->p_buffer )
317 p_sys->p_buffer = NewUDPPacket( p_access, p_buffer->i_dts );
318 if( !p_sys->p_buffer ) break;
321 memcpy( p_sys->p_buffer->p_buffer + p_sys->p_buffer->i_buffer,
322 p_buffer->p_buffer, i_write );
324 p_sys->p_buffer->i_buffer += i_write;
325 p_buffer->p_buffer += i_write;
326 p_buffer->i_buffer -= i_write;
327 if ( p_buffer->i_flags & BLOCK_FLAG_CLOCK )
329 if ( p_sys->p_buffer->i_flags & BLOCK_FLAG_CLOCK )
330 msg_Warn( p_access, "putting two PCRs at once" );
331 p_sys->p_buffer->i_flags |= BLOCK_FLAG_CLOCK;
334 if( p_sys->p_buffer->i_buffer == p_sys->i_mtu || i_packets > 1 )
336 /* Flush */
337 if( p_sys->p_buffer->i_dts + p_sys->i_caching < now )
339 msg_Dbg( p_access, "late packet for udp input (%"PRId64 ")",
340 mdate() - p_sys->p_buffer->i_dts
341 - p_sys->i_caching );
343 block_FifoPut( p_sys->p_fifo, p_sys->p_buffer );
344 p_sys->p_buffer = NULL;
348 p_next = p_buffer->p_next;
349 block_Release( p_buffer );
350 p_buffer = p_next;
353 return i_len;
356 /*****************************************************************************
357 * Seek: seek to a specific location in a file
358 *****************************************************************************/
359 static int Seek( sout_access_out_t *p_access, off_t i_pos )
361 (void) i_pos;
362 msg_Err( p_access, "UDP sout access cannot seek" );
363 return -1;
366 /*****************************************************************************
367 * NewUDPPacket: allocate a new UDP packet of size p_sys->i_mtu
368 *****************************************************************************/
369 static block_t *NewUDPPacket( sout_access_out_t *p_access, mtime_t i_dts)
371 sout_access_out_sys_t *p_sys = p_access->p_sys;
372 block_t *p_buffer;
374 while ( block_FifoCount( p_sys->p_empty_blocks ) > MAX_EMPTY_BLOCKS )
376 p_buffer = block_FifoGet( p_sys->p_empty_blocks );
377 block_Release( p_buffer );
380 if( block_FifoCount( p_sys->p_empty_blocks ) == 0 )
382 p_buffer = block_Alloc( p_sys->i_mtu );
384 else
386 p_buffer = block_FifoGet(p_sys->p_empty_blocks );
387 p_buffer->i_flags = 0;
388 p_buffer = block_Realloc( p_buffer, 0, p_sys->i_mtu );
391 p_buffer->i_dts = i_dts;
392 p_buffer->i_buffer = 0;
394 return p_buffer;
397 /*****************************************************************************
398 * ThreadWrite: Write a packet on the network at the good time.
399 *****************************************************************************/
400 static void* ThreadWrite( void *data )
402 sout_access_out_t *p_access = data;
403 sout_access_out_sys_t *p_sys = p_access->p_sys;
404 mtime_t i_date_last = -1;
405 const unsigned i_group = var_GetInteger( p_access,
406 SOUT_CFG_PREFIX "group" );
407 mtime_t i_to_send = i_group;
408 unsigned i_dropped_packets = 0;
410 for (;;)
412 block_t *p_pk = block_FifoGet( p_sys->p_fifo );
413 mtime_t i_date, i_sent;
415 i_date = p_sys->i_caching + p_pk->i_dts;
416 if( i_date_last > 0 )
418 if( i_date - i_date_last > 2000000 )
420 if( !i_dropped_packets )
421 msg_Dbg( p_access, "mmh, hole (%"PRId64" > 2s) -> drop",
422 i_date - i_date_last );
424 block_FifoPut( p_sys->p_empty_blocks, p_pk );
426 i_date_last = i_date;
427 i_dropped_packets++;
428 continue;
430 else if( i_date - i_date_last < -1000 )
432 if( !i_dropped_packets )
433 msg_Dbg( p_access, "mmh, packets in the past (%"PRId64")",
434 i_date_last - i_date );
438 block_cleanup_push( p_pk );
439 i_to_send--;
440 if( !i_to_send || (p_pk->i_flags & BLOCK_FLAG_CLOCK) )
442 mwait( i_date );
443 i_to_send = i_group;
445 if ( send( p_sys->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 ) == -1 )
446 msg_Warn( p_access, "send error: %m" );
447 vlc_cleanup_pop();
449 if( i_dropped_packets )
451 msg_Dbg( p_access, "dropped %i packets", i_dropped_packets );
452 i_dropped_packets = 0;
455 #if 1
456 i_sent = mdate();
457 if ( i_sent > i_date + 20000 )
459 msg_Dbg( p_access, "packet has been sent too late (%"PRId64 ")",
460 i_sent - i_date );
462 #endif
464 block_FifoPut( p_sys->p_empty_blocks, p_pk );
466 i_date_last = i_date;
468 return NULL;