]> git.sesse.net Git - vlc/blob - modules/access_output/udp.c
- Support for customizing the checksum coverage
[vlc] / modules / access_output / udp.c
1 /*****************************************************************************
2  * udp.c
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Eric Petit <titer@videolan.org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <vlc/vlc.h>
29
30 #include <stdlib.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <assert.h>
37
38 #include <vlc_sout.h>
39 #include <vlc_block.h>
40
41 #ifdef HAVE_UNISTD_H
42 #   include <unistd.h>
43 #endif
44
45 #ifdef WIN32
46 #   include <winsock2.h>
47 #   include <ws2tcpip.h>
48 #else
49 #   include <sys/socket.h>
50 #endif
51
52 #include <vlc_network.h>
53
54 #if defined (HAVE_NETINET_UDPLITE_H)
55 # include <netinet/udplite.h>
56 #elif defined (__linux__)
57 # define UDPLITE_SEND_CSCOV     10
58 # define UDPLITE_RECV_CSCOV     11
59 #endif
60
61 #ifndef IPPROTO_UDPLITE
62 # define IPPROTO_UDPLITE 136 /* from IANA */
63 #endif
64 #ifndef SOL_UDPLITE
65 # define SOL_UDPLITE IPPROTO_UDPLITE
66 #endif
67
68 #define MAX_EMPTY_BLOCKS 200
69
70 #if defined(WIN32) || defined(UNDER_CE)
71 # define WINSOCK_STRERROR_SIZE 20
72 static const char *winsock_strerror( char *buf )
73 {
74     snprintf( buf, WINSOCK_STRERROR_SIZE, "Winsock error %d",
75               WSAGetLastError( ) );
76     buf[WINSOCK_STRERROR_SIZE - 1] = '\0';
77     return buf;
78 }
79 #endif
80
81 /*****************************************************************************
82  * Module descriptor
83  *****************************************************************************/
84 static int  Open ( vlc_object_t * );
85 static void Close( vlc_object_t * );
86
87 #define SOUT_CFG_PREFIX "sout-udp-"
88
89 #define CACHING_TEXT N_("Caching value (ms)")
90 #define CACHING_LONGTEXT N_( \
91     "Default caching value for outbound UDP streams. This " \
92     "value should be set in milliseconds." )
93
94 #define GROUP_TEXT N_("Group packets")
95 #define GROUP_LONGTEXT N_("Packets can be sent one by one at the right time " \
96                           "or by groups. You can choose the number " \
97                           "of packets that will be sent at a time. It " \
98                           "helps reducing the scheduling load on " \
99                           "heavily-loaded systems." )
100 #define RAW_TEXT N_("Raw write")
101 #define RAW_LONGTEXT N_("Packets will be sent " \
102                        "directly, without trying to fill the MTU (ie, " \
103                        "without trying to make the biggest possible packets " \
104                        "in order to improve streaming)." )
105 #define AUTO_MCAST_TEXT N_("Automatic multicast streaming")
106 #define AUTO_MCAST_LONGTEXT N_("Allocates an outbound multicast address " \
107                                "automatically.")
108 #define UDPLITE_TEXT N_("UDP-Lite")
109 #define UDPLITE_LONGTEXT N_("Use UDP-Lite/IP instead of normal UDP/IP")
110 #define CSCOV_TEXT N_("Checksum coverage")
111 #define CSCOV_LONGTEXT N_("Payload bytes covered by layer-4 checksum")
112
113 vlc_module_begin();
114     set_description( _("UDP stream output") );
115     set_shortname( "UDP" );
116     set_category( CAT_SOUT );
117     set_subcategory( SUBCAT_SOUT_ACO );
118     add_integer( SOUT_CFG_PREFIX "caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
119     add_integer( SOUT_CFG_PREFIX "group", 1, NULL, GROUP_TEXT, GROUP_LONGTEXT,
120                                  VLC_TRUE );
121     add_suppressed_integer( SOUT_CFG_PREFIX "late" );
122     add_bool( SOUT_CFG_PREFIX "raw",  0, NULL, RAW_TEXT, RAW_LONGTEXT,
123                                  VLC_TRUE );
124     add_bool( SOUT_CFG_PREFIX "auto-mcast", 0, NULL, AUTO_MCAST_TEXT,
125               AUTO_MCAST_LONGTEXT, VLC_TRUE );
126     add_bool( SOUT_CFG_PREFIX "udplite", 0, NULL, UDPLITE_TEXT, UDPLITE_LONGTEXT, VLC_TRUE );
127     add_integer( SOUT_CFG_PREFIX "cscov", 12, NULL, CSCOV_TEXT, CSCOV_LONGTEXT, VLC_TRUE );
128
129     set_capability( "sout access", 100 );
130     add_shortcut( "udp" );
131     add_shortcut( "rtp" ); // Will work only with ts muxer
132     set_callbacks( Open, Close );
133 vlc_module_end();
134
135 /*****************************************************************************
136  * Exported prototypes
137  *****************************************************************************/
138
139 static const char *ppsz_sout_options[] = {
140     "auto-mcast",
141     "caching",
142     "group",
143     "raw",
144     "lite",
145     "cscov",
146     NULL
147 };
148
149 /* Options handled by the libvlc network core */
150 static const char *ppsz_core_options[] = {
151     "dscp",
152     "ttl",
153     "miface",
154     "miface-addr",
155     NULL
156 };
157
158 static int  Write   ( sout_access_out_t *, block_t * );
159 static int  WriteRaw( sout_access_out_t *, block_t * );
160 static int  Seek    ( sout_access_out_t *, off_t  );
161
162 static void ThreadWrite( vlc_object_t * );
163 static block_t *NewUDPPacket( sout_access_out_t *, mtime_t );
164 static const char *MakeRandMulticast (int family, char *buf, size_t buflen);
165
166 typedef struct sout_access_thread_t
167 {
168     VLC_COMMON_MEMBERS
169
170     sout_instance_t *p_sout;
171
172     block_fifo_t *p_fifo;
173
174     int         i_handle;
175
176     int64_t     i_caching;
177     int         i_group;
178
179     block_fifo_t *p_empty_blocks;
180
181     uint32_t sent_pkts;
182     uint32_t sent_bytes;
183     size_t   rtcp_size;
184     int      rtcp_handle;
185     uint8_t  rtcp_data[28 + 8 + (2 * 257)];
186
187 } sout_access_thread_t;
188
189 struct sout_access_out_sys_t
190 {
191     int                 i_mtu;
192
193     vlc_bool_t          b_rtpts;  // 1 if add rtp/ts header
194     vlc_bool_t          b_mtu_warning;
195     uint16_t            i_sequence_number;
196     uint32_t            i_ssrc;
197
198     block_t             *p_buffer;
199
200     sout_access_thread_t *p_thread;
201
202 };
203
204 #define DEFAULT_PORT 1234
205 #define RTP_HEADER_LENGTH 12
206
207 static int OpenRTCP (sout_access_out_t *obj, int proto);
208 static void SendRTCP (sout_access_thread_t *obj, uint32_t timestamp);
209 static void CloseRTCP (sout_access_thread_t *obj);
210
211 /*****************************************************************************
212  * Open: open the file
213  *****************************************************************************/
214 static int Open( vlc_object_t *p_this )
215 {
216     sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
217     sout_access_out_sys_t   *p_sys;
218
219     char                *psz_dst_addr = NULL;
220     int                 i_dst_port, proto = IPPROTO_UDP;
221     const char          *protoname = "UDP";
222
223     int                 i_handle;
224
225     vlc_value_t         val;
226
227     config_ChainParse( p_access, SOUT_CFG_PREFIX,
228                        ppsz_sout_options, p_access->p_cfg );
229     config_ChainParse( p_access, "",
230                        ppsz_core_options, p_access->p_cfg );
231
232     if (var_Create (p_access, "dst-port", VLC_VAR_INTEGER)
233      || var_Create (p_access, "src-port", VLC_VAR_INTEGER)
234      || var_Create (p_access, "dst-addr", VLC_VAR_STRING)
235      || var_Create (p_access, "src-addr", VLC_VAR_STRING))
236     {
237         return VLC_ENOMEM;
238     }
239
240     if( !( p_sys = calloc ( 1, sizeof( sout_access_out_sys_t ) ) ) )
241     {
242         msg_Err( p_access, "not enough memory" );
243         return VLC_ENOMEM;
244     }
245     p_access->p_sys = p_sys;
246
247     if( p_access->psz_access != NULL )
248     {
249         if (strcmp (p_access->psz_access, "rtp") == 0)
250             p_sys->b_rtpts = VLC_TRUE;
251     }
252
253     if (var_GetBool (p_access, SOUT_CFG_PREFIX"lite"))
254     {
255         protoname = "UDP-Lite";
256         proto = IPPROTO_UDPLITE;
257     }
258
259     i_dst_port = DEFAULT_PORT;
260     if (var_GetBool (p_access, SOUT_CFG_PREFIX"auto-mcast"))
261     {
262         char buf[INET6_ADDRSTRLEN];
263         if (MakeRandMulticast (AF_INET, buf, sizeof (buf)) != NULL)
264             psz_dst_addr = strdup (buf);
265     }
266     else
267     {
268         char *psz_parser = psz_dst_addr = strdup( p_access->psz_path );
269
270         if (psz_parser[0] == '[')
271             psz_parser = strchr (psz_parser, ']');
272
273         psz_parser = strchr (psz_parser, ':');
274         if (psz_parser != NULL)
275         {
276             *psz_parser++ = '\0';
277             i_dst_port = atoi (psz_parser);
278         }
279     }
280
281     p_sys->p_thread =
282         vlc_object_create( p_access, sizeof( sout_access_thread_t ) );
283     if( !p_sys->p_thread )
284     {
285         msg_Err( p_access, "out of memory" );
286         free (p_sys);
287         free (psz_dst_addr);
288         return VLC_ENOMEM;
289     }
290
291     vlc_object_attach( p_sys->p_thread, p_access );
292     p_sys->p_thread->p_sout = p_access->p_sout;
293     p_sys->p_thread->b_die  = 0;
294     p_sys->p_thread->b_error= 0;
295     p_sys->p_thread->p_fifo = block_FifoNew( p_access );
296     p_sys->p_thread->p_empty_blocks = block_FifoNew( p_access );
297
298     i_handle = net_ConnectDgram( p_this, psz_dst_addr, i_dst_port, -1, proto );
299     free (psz_dst_addr);
300
301     if( i_handle == -1 )
302     {
303          msg_Err( p_access, "failed to create %s socket", protoname );
304          vlc_object_destroy (p_sys->p_thread);
305          free (p_sys);
306          return VLC_EGENERIC;
307     }
308     else
309     {
310         char addr[NI_MAXNUMERICHOST];
311         int port;
312
313         if (net_GetSockAddress (i_handle, addr, &port) == 0)
314         {
315             msg_Dbg (p_access, "source: %s port %d", addr, port);
316             var_SetString (p_access, "src-addr", addr);
317             var_SetInteger (p_access, "src-port", port);
318         }
319
320         if (net_GetPeerAddress (i_handle, addr, &port) == 0)
321         {
322             msg_Dbg (p_access, "destination: %s port %d", addr, port);
323             var_SetString (p_access, "dst-addr", addr);
324             var_SetInteger (p_access, "dst-port", port);
325         }
326     }
327     p_sys->p_thread->i_handle = i_handle;
328     shutdown( i_handle, SHUT_RD );
329
330     int cscov = var_GetInteger (p_access, SOUT_CFG_PREFIX"cscov");
331     if (cscov)
332     {
333         switch (proto)
334         {
335 #ifdef UDPLITE_SEND_CSCOV
336             case IPPROTO_UDPLITE:
337                 cscov += 8;
338                 setsockopt (i_handle, SOL_UDPLITE, UDPLITE_SEND_CSCOV,
339                             &(int){ cscov }, sizeof (cscov));
340                 break;
341 #endif
342 #ifdef DCCP_SOCKOPT_RECV_CSCOV
343             /* FIXME: ^^is this the right name ? */
344             /* FIXME: is this inherited by accept() ? */
345             case IPPROTO_DCCP:
346                 cscov = ((cscov + 3) >> 2) + 1;
347                 if (cscov > 15)
348                     break; /* out of DCCP cscov range */
349                 setsockopt (i_handle, SOL_DCCP, DCCP_SOCKOPT_RECV_CSCOV,
350                             &(int){ cscov }, sizeof (cscov));
351                 break;
352 #endif
353         }
354     }
355
356     var_Get( p_access, SOUT_CFG_PREFIX "caching", &val );
357     p_sys->p_thread->i_caching = (int64_t)val.i_int * 1000;
358
359     var_Get( p_access, SOUT_CFG_PREFIX "group", &val );
360     p_sys->p_thread->i_group = val.i_int;
361
362     p_sys->i_mtu = var_CreateGetInteger( p_this, "mtu" );
363
364     srand( (uint32_t)mdate());
365     p_sys->p_buffer          = NULL;
366     p_sys->i_sequence_number = rand()&0xffff;
367     p_sys->i_ssrc            = rand()&0xffffffff;
368
369     if (p_sys->b_rtpts && OpenRTCP (p_access, proto))
370     {
371         msg_Err (p_access, "cannot initialize RTCP sender");
372         net_Close (i_handle);
373         vlc_object_destroy (p_sys->p_thread);
374         free (p_sys);
375         return VLC_EGENERIC;
376     }
377
378     if( vlc_thread_create( p_sys->p_thread, "sout write thread", ThreadWrite,
379                            VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
380     {
381         msg_Err( p_access->p_sout, "cannot spawn sout access thread" );
382         net_Close (i_handle);
383         vlc_object_destroy( p_sys->p_thread );
384         free (p_sys);
385         return VLC_EGENERIC;
386     }
387
388     var_Get( p_access, SOUT_CFG_PREFIX "raw", &val );
389     if( val.b_bool )  p_access->pf_write = WriteRaw;
390     else p_access->pf_write = Write;
391
392     p_access->pf_seek = Seek;
393
394     /* update p_sout->i_out_pace_nocontrol */
395     p_access->p_sout->i_out_pace_nocontrol++;
396
397     return VLC_SUCCESS;
398 }
399
400 /*****************************************************************************
401  * Close: close the target
402  *****************************************************************************/
403 static void Close( vlc_object_t * p_this )
404 {
405     sout_access_out_t     *p_access = (sout_access_out_t*)p_this;
406     sout_access_out_sys_t *p_sys = p_access->p_sys;
407     int i;
408
409     p_sys->p_thread->b_die = 1;
410     for( i = 0; i < 10; i++ )
411     {
412         block_t *p_dummy = block_New( p_access, p_sys->i_mtu );
413         p_dummy->i_dts = 0;
414         p_dummy->i_pts = 0;
415         p_dummy->i_length = 0;
416         memset( p_dummy->p_buffer, 0, p_dummy->i_buffer );
417         block_FifoPut( p_sys->p_thread->p_fifo, p_dummy );
418     }
419     vlc_thread_join( p_sys->p_thread );
420
421     block_FifoRelease( p_sys->p_thread->p_fifo );
422     block_FifoRelease( p_sys->p_thread->p_empty_blocks );
423
424     if( p_sys->p_buffer ) block_Release( p_sys->p_buffer );
425
426     net_Close( p_sys->p_thread->i_handle );
427     CloseRTCP (p_sys->p_thread);
428
429     vlc_object_detach( p_sys->p_thread );
430     vlc_object_destroy( p_sys->p_thread );
431     /* update p_sout->i_out_pace_nocontrol */
432     p_access->p_sout->i_out_pace_nocontrol--;
433
434     msg_Dbg( p_access, "UDP access output closed" );
435     free( p_sys );
436 }
437
438 /*****************************************************************************
439  * Write: standard write on a file descriptor.
440  *****************************************************************************/
441 static int Write( sout_access_out_t *p_access, block_t *p_buffer )
442 {
443     sout_access_out_sys_t *p_sys = p_access->p_sys;
444     int i_len = 0;
445
446     while( p_buffer )
447     {
448         block_t *p_next;
449         int i_packets = 0;
450
451         if( !p_sys->b_mtu_warning && p_buffer->i_buffer > p_sys->i_mtu )
452         {
453             msg_Warn( p_access, "packet size > MTU, you should probably "
454                       "increase the MTU" );
455             p_sys->b_mtu_warning = VLC_TRUE;
456         }
457
458         /* Check if there is enough space in the buffer */
459         if( p_sys->p_buffer &&
460             p_sys->p_buffer->i_buffer + p_buffer->i_buffer > p_sys->i_mtu )
461         {
462             if( p_sys->p_buffer->i_dts + p_sys->p_thread->i_caching < mdate() )
463             {
464                 msg_Dbg( p_access, "late packet for UDP input (" I64Fd ")",
465                          mdate() - p_sys->p_buffer->i_dts
466                           - p_sys->p_thread->i_caching );
467             }
468             block_FifoPut( p_sys->p_thread->p_fifo, p_sys->p_buffer );
469             p_sys->p_buffer = NULL;
470         }
471
472         i_len += p_buffer->i_buffer;
473         while( p_buffer->i_buffer )
474         {
475             int i_payload_size = p_sys->i_mtu;
476             if( p_sys->b_rtpts )
477                 i_payload_size -= RTP_HEADER_LENGTH;
478
479             int i_write = __MIN( p_buffer->i_buffer, i_payload_size );
480
481             i_packets++;
482
483             if( !p_sys->p_buffer )
484             {
485                 p_sys->p_buffer = NewUDPPacket( p_access, p_buffer->i_dts );
486                 if( !p_sys->p_buffer ) break;
487             }
488
489             memcpy( p_sys->p_buffer->p_buffer + p_sys->p_buffer->i_buffer,
490                     p_buffer->p_buffer, i_write );
491
492             p_sys->p_buffer->i_buffer += i_write;
493             p_buffer->p_buffer += i_write;
494             p_buffer->i_buffer -= i_write;
495             if ( p_buffer->i_flags & BLOCK_FLAG_CLOCK )
496             {
497                 if ( p_sys->p_buffer->i_flags & BLOCK_FLAG_CLOCK )
498                     msg_Warn( p_access, "putting two PCRs at once" );
499                 p_sys->p_buffer->i_flags |= BLOCK_FLAG_CLOCK;
500             }
501
502             if( p_sys->p_buffer->i_buffer == p_sys->i_mtu || i_packets > 1 )
503             {
504                 /* Flush */
505                 if( p_sys->p_buffer->i_dts + p_sys->p_thread->i_caching
506                       < mdate() )
507                 {
508                     msg_Dbg( p_access, "late packet for udp input (" I64Fd ")",
509                              mdate() - p_sys->p_buffer->i_dts
510                               - p_sys->p_thread->i_caching );
511                 }
512                 block_FifoPut( p_sys->p_thread->p_fifo, p_sys->p_buffer );
513                 p_sys->p_buffer = NULL;
514             }
515         }
516
517         p_next = p_buffer->p_next;
518         block_Release( p_buffer );
519         p_buffer = p_next;
520     }
521
522     return( p_sys->p_thread->b_error ? -1 : i_len );
523 }
524
525 /*****************************************************************************
526  * WriteRaw: write p_buffer without trying to fill mtu
527  *****************************************************************************/
528 static int WriteRaw( sout_access_out_t *p_access, block_t *p_buffer )
529 {
530     sout_access_out_sys_t   *p_sys = p_access->p_sys;
531     block_t *p_buf;
532     int i_len;
533
534     while ( p_sys->p_thread->p_empty_blocks->i_depth >= MAX_EMPTY_BLOCKS )
535     {
536         p_buf = block_FifoGet(p_sys->p_thread->p_empty_blocks);
537         block_Release( p_buf );
538     }
539
540     i_len = p_buffer->i_buffer;
541     block_FifoPut( p_sys->p_thread->p_fifo, p_buffer );
542
543     return( p_sys->p_thread->b_error ? -1 : i_len );
544 }
545
546 /*****************************************************************************
547  * Seek: seek to a specific location in a file
548  *****************************************************************************/
549 static int Seek( sout_access_out_t *p_access, off_t i_pos )
550 {
551     msg_Err( p_access, "UDP sout access cannot seek" );
552     return -1;
553 }
554
555 /*****************************************************************************
556  * NewUDPPacket: allocate a new UDP packet of size p_sys->i_mtu
557  *****************************************************************************/
558 static block_t *NewUDPPacket( sout_access_out_t *p_access, mtime_t i_dts)
559 {
560     sout_access_out_sys_t *p_sys = p_access->p_sys;
561     block_t *p_buffer;
562
563     while ( p_sys->p_thread->p_empty_blocks->i_depth > MAX_EMPTY_BLOCKS )
564     {
565         p_buffer = block_FifoGet( p_sys->p_thread->p_empty_blocks );
566         block_Release( p_buffer );
567     }
568
569     if( p_sys->p_thread->p_empty_blocks->i_depth == 0 )
570     {
571         p_buffer = block_New( p_access->p_sout, p_sys->i_mtu );
572     }
573     else
574     {
575         p_buffer = block_FifoGet(p_sys->p_thread->p_empty_blocks );
576         p_buffer->i_flags = 0;
577         p_buffer = block_Realloc( p_buffer, 0, p_sys->i_mtu );
578     }
579
580     p_buffer->i_dts = i_dts;
581     p_buffer->i_buffer = 0;
582
583     if( p_sys->b_rtpts )
584     {
585         mtime_t i_timestamp = p_buffer->i_dts * 9 / 100;
586
587         /* add rtp/ts header */
588         p_buffer->p_buffer[0] = 0x80;
589         p_buffer->p_buffer[1] = 0x21; // mpeg2-ts
590
591         SetWBE( p_buffer->p_buffer + 2, p_sys->i_sequence_number );
592         p_sys->i_sequence_number++;
593         SetDWBE( p_buffer->p_buffer + 4, i_timestamp );
594         SetDWBE( p_buffer->p_buffer + 8, p_sys->i_ssrc );
595
596         p_buffer->i_buffer = RTP_HEADER_LENGTH;
597     }
598
599     return p_buffer;
600 }
601
602 /*****************************************************************************
603  * ThreadWrite: Write a packet on the network at the good time.
604  *****************************************************************************/
605 static void ThreadWrite( vlc_object_t *p_this )
606 {
607     sout_access_thread_t *p_thread = (sout_access_thread_t*)p_this;
608     mtime_t              i_date_last = -1;
609     mtime_t              i_to_send = p_thread->i_group;
610     int                  i_dropped_packets = 0;
611 #if defined(WIN32) || defined(UNDER_CE)
612     char strerror_buf[WINSOCK_STRERROR_SIZE];
613 # define strerror( x ) winsock_strerror( strerror_buf )
614 #endif
615     size_t rtcp_counter = 0;
616
617     while( !p_thread->b_die )
618     {
619         block_t *p_pk;
620         mtime_t       i_date, i_sent;
621 #if 0
622         if( (i++ % 1000)==0 ) {
623           int i = 0;
624           int j = 0;
625           block_t *p_tmp = p_thread->p_empty_blocks->p_first;
626           while( p_tmp ) { p_tmp = p_tmp->p_next; i++;}
627           p_tmp = p_thread->p_fifo->p_first;
628           while( p_tmp ) { p_tmp = p_tmp->p_next; j++;}
629           msg_Dbg( p_thread, "fifo depth: %d/%d, empty blocks: %d/%d",
630                    p_thread->p_fifo->i_depth, j,p_thread->p_empty_blocks->i_depth,i );
631         }
632 #endif
633         p_pk = block_FifoGet( p_thread->p_fifo );
634
635         i_date = p_thread->i_caching + p_pk->i_dts;
636         if( i_date_last > 0 )
637         {
638             if( i_date - i_date_last > 2000000 )
639             {
640                 if( !i_dropped_packets )
641                     msg_Dbg( p_thread, "mmh, hole ("I64Fd" > 2s) -> drop",
642                              i_date - i_date_last );
643
644                 block_FifoPut( p_thread->p_empty_blocks, p_pk );
645
646                 i_date_last = i_date;
647                 i_dropped_packets++;
648                 continue;
649             }
650             else if( i_date - i_date_last < -1000 )
651             {
652                 if( !i_dropped_packets )
653                     msg_Dbg( p_thread, "mmh, packets in the past ("I64Fd")",
654                              i_date_last - i_date );
655             }
656         }
657
658         i_to_send--;
659         if( !i_to_send || (p_pk->i_flags & BLOCK_FLAG_CLOCK) )
660         {
661             mwait( i_date );
662             i_to_send = p_thread->i_group;
663         }
664         ssize_t val = send( p_thread->i_handle, p_pk->p_buffer,
665                             p_pk->i_buffer, 0 );
666         if (val == -1)
667         {
668             msg_Warn( p_thread, "send error: %s", strerror(errno) );
669         }
670         else
671         {
672             p_thread->sent_pkts++;
673             p_thread->sent_bytes += val;
674             rtcp_counter += val;
675         }
676
677         if( i_dropped_packets )
678         {
679             msg_Dbg( p_thread, "dropped %i packets", i_dropped_packets );
680             i_dropped_packets = 0;
681         }
682
683 #if 1
684         i_sent = mdate();
685         if ( i_sent > i_date + 20000 )
686         {
687             msg_Dbg( p_thread, "packet has been sent too late (" I64Fd ")",
688                      i_sent - i_date );
689         }
690 #endif
691
692         if (p_thread->rtcp_handle != -1)
693         {
694             /* FIXME: this is a very incorrect simplistic RTCP timer */
695             if ((rtcp_counter / 80) >= p_thread->rtcp_size)
696             {
697                 SendRTCP (p_thread, GetDWBE (p_pk->p_buffer + 4));
698                 rtcp_counter = 0;
699             }
700         }
701
702         block_FifoPut( p_thread->p_empty_blocks, p_pk );
703
704         i_date_last = i_date;
705     }
706 }
707
708
709 static const char *MakeRandMulticast (int family, char *buf, size_t buflen)
710 {
711     uint32_t rand = (getpid() & 0xffff)
712                   | (uint32_t)(((mdate () >> 10) & 0xffff) << 16);
713
714     switch (family)
715     {
716 #ifdef AF_INET6
717         case AF_INET6:
718         {
719             struct in6_addr addr;
720             memcpy (&addr, "\xff\x38\x00\x00" "\x00\x00\x00\x00"
721                            "\x00\x00\x00\x00", 12);
722             rand |= 0x80000000;
723             memcpy (addr.s6_addr + 12, &(uint32_t){ htonl (rand) }, 4);
724             return inet_ntop (family, &addr, buf, buflen);
725         }
726 #endif
727
728         case AF_INET:
729         {
730             struct in_addr addr;
731             addr.s_addr = htonl ((rand & 0xffffff) | 0xe8000000);
732             return inet_ntop (family, &addr, buf, buflen);
733         }
734     }
735 #ifdef EAFNOSUPPORT
736     errno = EAFNOSUPPORT;
737 #endif
738     return NULL;
739 }
740
741
742 /*
743  * NOTE on RTCP implementation:
744  * - there is a single sender (us), no conferencing here! => n = sender = 1,
745  * - as such we need not bother to include Receiver Reports,
746  * - in unicast case, there is a single receiver => members = 1 + 1 = 2,
747  *   and obviously n > 25% of members,
748  * - in multicast case, we do not want to maintain the number of receivers
749  *   and we assume it is big (i.e. than 3) because that's what broadcasting is
750  *   all about,
751  * - it is assumed we_sent = true (could be wrong), since we are THE sender,
752  * - we always send SR + SDES, while running,
753  * - FIXME: we do not implement separate rate limiting for SDES,
754  * - we do not implement any profile-specific extensions for the time being.
755  */
756 static int OpenRTCP (sout_access_out_t *obj, int proto)
757 {
758     sout_access_out_sys_t *p_sys = obj->p_sys;
759     uint8_t *ptr;
760     int fd;
761
762     char src[NI_MAXNUMERICHOST], dst[NI_MAXNUMERICHOST];
763     int sport, dport;
764
765     fd = obj->p_sys->p_thread->i_handle;
766     if (net_GetSockAddress (fd, src, &sport)
767      || net_GetPeerAddress (fd, dst, &dport))
768         return VLC_EGENERIC;
769
770     sport++;
771     dport++;
772     fd = net_OpenDgram (obj, src, sport, dst, dport, AF_UNSPEC, proto);
773     if (fd == -1)
774         return VLC_EGENERIC;
775
776     obj->p_sys->p_thread->rtcp_handle = fd;
777
778     ptr = (uint8_t *)strchr (src, '%');
779     if (ptr != NULL)
780         *ptr = '\0'; /* remove scope ID frop IPv6 addresses */
781
782     ptr = obj->p_sys->p_thread->rtcp_data;
783
784     /* Sender report */
785     ptr[0] = 2 << 6; /* V = 2, P = RC = 0 */
786     ptr[1] = 200; /* payload type: Sender Report */
787     SetWBE (ptr + 2, 6); /* length = 6 (7 double words) */
788     SetDWBE (ptr + 4, p_sys->i_ssrc);
789     ptr += 28;
790     /* timestamps and counter are handled later */
791
792     /* Source description */
793     uint8_t *sdes = ptr;
794     ptr[0] = (2 << 6) | 1; /* V = 2, P = 0, SC = 1 */
795     ptr[1] = 202; /* payload type: Source Description */
796     uint8_t *lenptr = ptr + 2;
797     SetDWBE (ptr + 4, p_sys->i_ssrc);
798     ptr += 8;
799
800     ptr[0] = 1; /* CNAME - mandatory */
801     assert (NI_MAXNUMERICHOST <= 256);
802     ptr[1] = strlen (src);
803     memcpy (ptr + 2, src, ptr[1]);
804     ptr += ptr[1] + 2;
805
806     static const char tool[] = PACKAGE_STRING;
807     ptr[0] = 6; /* TOOL */
808     ptr[1] = (sizeof (tool) > 256) ? 255 : (sizeof (tool) - 1);
809     memcpy (ptr + 2, tool, ptr[1]);
810     ptr += ptr[1] + 2;
811
812     while ((ptr - sdes) & 3) /* 32-bits padding */
813         *ptr++ = 0;
814     SetWBE (lenptr, ptr - sdes);
815
816     obj->p_sys->p_thread->rtcp_size = ptr - obj->p_sys->p_thread->rtcp_data;
817     return VLC_SUCCESS;
818 }
819
820 static void CloseRTCP (sout_access_thread_t *obj)
821 {
822     uint8_t *ptr = obj->rtcp_data;
823     /* Bye */
824     ptr[0] = (2 << 6) | 1; /* V = 2, P = 0, SC = 1 */
825     ptr[1] = 203; /* payload type: Bye */
826     SetWBE (ptr + 2, 1);
827     /* SSRC is already there :) */
828
829     /* We are THE sender, so we are more important than anybody else, so
830      * we can afford not to check bandwidth constraints here. */
831     send (obj->rtcp_handle, obj->rtcp_data, 8, 0);
832
833     if (obj->rtcp_handle != -1)
834         net_Close (obj->rtcp_handle);
835 }
836
837 static void SendRTCP (sout_access_thread_t *obj, uint32_t timestamp)
838 {
839     uint8_t *ptr = obj->rtcp_data;
840     SetQWBE (ptr + 8, NTPtime64 ());
841     SetDWBE (ptr + 16, timestamp);
842     SetDWBE (ptr + 20, obj->sent_pkts);
843     SetDWBE (ptr + 24, obj->sent_bytes);
844
845     send (obj->rtcp_handle, ptr, obj->rtcp_size, 0);
846 }