1 /*****************************************************************************
2  * rist.c: RIST (Reliable Internet Stream Transport) input module
3  *****************************************************************************
4  * Copyright (C) 2018, DVEO, the Broadcast Division of Computer Modules, Inc.
5  * Copyright (C) 2018-2020, SipRadius LLC
6  *
7  * Authors: Sergio Ammirata <sergio@ammirata.net>
8  *          Daniele Lacamera <root@danielinux.net>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24 
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 
29 #include <vlc_common.h>
30 #include <vlc_interrupt.h>
31 #include <vlc_plugin.h>
32 #include <vlc_access.h>
33 #include <vlc_threads.h>
34 #include <vlc_network.h>
35 #include <vlc_block.h>
36 #include <vlc_url.h>
37 #ifdef HAVE_POLL
38 #include <poll.h>
39 #endif
40 
41 #include "rist.h"
42 
43 /* The default latency is 1000 ms */
44 #define RIST_DEFAULT_LATENCY 1000
45 /* The default nack retry interval */
46 #define RIST_DEFAULT_RETRY_INTERVAL 132
47 /* The default packet re-ordering buffer */
48 #define RIST_DEFAULT_REORDER_BUFFER 70
49 /* The default max packet size */
50 #define RIST_MAX_PACKET_SIZE 1472
51 /* The default timeout is 5 ms */
52 #define RIST_DEFAULT_POLL_TIMEOUT 5
53 /* The max retry count for nacks */
54 #define RIST_MAX_RETRIES 10
55 /* The rate at which we process and send nack requests */
56 #define NACK_INTERVAL 5 /*ms*/
57 /* Calculate and print stats once per second */
58 #define STATS_INTERVAL 1000 /*ms*/
59 
60 static const int nack_type[] = {
61     0, 1,
62 };
63 
64 static const char *const nack_type_names[] = {
65     N_("Range"), N_("Bitmask"),
66 };
67 
68 enum NACK_TYPE {
69     NACK_FMT_RANGE = 0,
70     NACK_FMT_BITMASK
71 };
72 
73 struct stream_sys_t
74 {
75     struct rist_flow *flow;
76     char             sender_name[MAX_CNAME];
77     enum NACK_TYPE   nack_type;
78     uint64_t         last_data_rx;
79     uint64_t         last_nack_tx;
80     vlc_thread_t     thread;
81     int              i_max_packet_size;
82     int              i_poll_timeout;
83     int              i_poll_timeout_current;
84     bool             b_ismulticast;
85     bool             b_sendnacks;
86     bool             b_sendblindnacks;
87     bool             b_disablenacks;
88     bool             b_flag_discontinuity;
89     block_fifo_t     *p_fifo;
90     vlc_mutex_t      lock;
91     uint64_t         last_message;
92     uint64_t         last_reset;
93     /* stat variables */
94     uint32_t         i_poll_timeout_zero_count;
95     uint32_t         i_poll_timeout_nonzero_count;
96     uint64_t         i_last_stat;
97     float            vbr_ratio;
98     uint16_t         vbr_ratio_count;
99     uint32_t         i_lost_packets;
100     uint32_t         i_nack_packets;
101     uint32_t         i_recovered_packets;
102     uint32_t         i_reordered_packets;
103     uint32_t         i_total_packets;
104 };
105 
Control(stream_t * p_access,int i_query,va_list args)106 static int Control(stream_t *p_access, int i_query, va_list args)
107 {
108     switch( i_query )
109     {
110         case STREAM_CAN_SEEK:
111         case STREAM_CAN_FASTSEEK:
112         case STREAM_CAN_PAUSE:
113         case STREAM_CAN_CONTROL_PACE:
114             *va_arg( args, bool * ) = false;
115             break;
116 
117         case STREAM_GET_PTS_DELAY:
118             *va_arg( args, int64_t * ) = RIST_TICK_FROM_MS(
119                    var_InheritInteger(p_access, "network-caching") );
120             break;
121 
122         default:
123             return VLC_EGENERIC;
124     }
125 
126     return VLC_SUCCESS;
127 }
128 
rist_init_rx(void)129 static struct rist_flow *rist_init_rx(void)
130 {
131     struct rist_flow *flow = calloc(1, sizeof(struct rist_flow));
132     if (!flow)
133         return NULL;
134 
135     flow->reset = 1;
136     flow->buffer = calloc(RIST_QUEUE_SIZE, sizeof(struct rtp_pkt));
137 
138     if ( unlikely( flow->buffer == NULL ) )
139     {
140         free(flow);
141         return NULL;
142     }
143     flow->fd_in = -1;
144     flow->fd_nack = -1;
145     flow->fd_rtcp_m = -1;
146 
147     return flow;
148 }
149 
rist_WriteTo_i11e_Locked(vlc_mutex_t lock,int fd,const void * buf,size_t len,const struct sockaddr * peer,socklen_t slen)150 static void rist_WriteTo_i11e_Locked(vlc_mutex_t lock, int fd, const void *buf, size_t len,
151     const struct sockaddr *peer, socklen_t slen)
152 {
153     vlc_mutex_lock( &lock );
154     rist_WriteTo_i11e(fd, buf, len, peer, slen);
155     vlc_mutex_unlock( &lock );
156 }
157 
rist_udp_receiver(stream_t * p_access,vlc_url_t * parsed_url,bool b_ismulticast)158 static struct rist_flow *rist_udp_receiver(stream_t *p_access, vlc_url_t *parsed_url, bool b_ismulticast)
159 {
160     stream_sys_t *p_sys = p_access->p_sys;
161     msg_Info( p_access, "Opening Rist Flow Receiver at %s:%d and %s:%d",
162              parsed_url->psz_host, parsed_url->i_port,
163              parsed_url->psz_host, parsed_url->i_port+1);
164 
165     p_sys->flow = rist_init_rx();
166     if (!p_sys->flow)
167         return NULL;
168 
169     p_sys->flow->fd_in = net_OpenDgram(p_access, parsed_url->psz_host, parsed_url->i_port, NULL,
170                 0, IPPROTO_UDP);
171     if (p_sys->flow->fd_in < 0)
172     {
173         msg_Err( p_access, "cannot open input socket" );
174         goto fail;
175     }
176 
177     if (b_ismulticast)
178     {
179         p_sys->flow->fd_rtcp_m = net_OpenDgram(p_access, parsed_url->psz_host, parsed_url->i_port + 1,
180             NULL, 0, IPPROTO_UDP);
181         if (p_sys->flow->fd_rtcp_m < 0)
182         {
183             msg_Err( p_access, "cannot open multicast nack socket" );
184             goto fail;
185         }
186         p_sys->flow->fd_nack = net_ConnectDgram(p_access, parsed_url->psz_host,
187             parsed_url->i_port + 1, -1, IPPROTO_UDP );
188     }
189     else
190     {
191         p_sys->flow->fd_nack = net_OpenDgram(p_access, parsed_url->psz_host, parsed_url->i_port + 1,
192             NULL, 0, IPPROTO_UDP);
193     }
194     if (p_sys->flow->fd_nack < 0)
195     {
196         msg_Err( p_access, "cannot open nack socket" );
197         goto fail;
198     }
199 
200     populate_cname(p_sys->flow->fd_nack, p_sys->flow->cname);
201     msg_Info(p_access, "our cname is %s", p_sys->flow->cname);
202 
203     return  p_sys->flow;
204 
205 fail:
206     if (p_sys->flow->fd_in != -1)
207         vlc_close(p_sys->flow->fd_in);
208     if (p_sys->flow->fd_nack != -1)
209         vlc_close(p_sys->flow->fd_nack);
210     if (p_sys->flow->fd_rtcp_m != -1)
211         vlc_close(p_sys->flow->fd_rtcp_m);
212     free(p_sys->flow->buffer);
213     free(p_sys->flow);
214     return NULL;
215 }
216 
is_index_in_range(struct rist_flow * flow,uint16_t idx)217 static int is_index_in_range(struct rist_flow *flow, uint16_t idx)
218 {
219     if (flow->ri <= flow->wi) {
220         return ((idx > flow->ri) && (idx <= flow->wi));
221     } else {
222         return ((idx > flow->ri) || (idx <= flow->wi));
223     }
224 }
225 
send_rtcp_feedback(stream_t * p_access,struct rist_flow * flow)226 static void send_rtcp_feedback(stream_t *p_access, struct rist_flow *flow)
227 {
228     stream_sys_t *p_sys = p_access->p_sys;
229     int namelen = strlen(flow->cname) + 1;
230 
231     /* we need to make sure it is a multiple of 4, pad if necessary */
232     if ((namelen - 2) & 0x3)
233         namelen = ((((namelen - 2) >> 2) + 1) << 2) + 2;
234 
235     int rtcp_feedback_size = RTCP_EMPTY_RR_SIZE + RIST_RTCP_SDES_SIZE + namelen;
236     uint8_t *buf = malloc(rtcp_feedback_size);
237     if ( unlikely( buf == NULL ) )
238         return;
239 
240     /* Populate RR */
241     uint8_t *rr = buf;
242     rist_rtp_set_hdr(rr);
243     rist_rtcp_rr_set_pt(rr);
244     rist_rtcp_set_length(rr, 1);
245     rist_rtcp_fb_set_int_ssrc_pkt_sender(rr, 0);
246 
247     /* Populate SDES */
248     uint8_t *p_sdes = (buf + RTCP_EMPTY_RR_SIZE);
249     rist_rtp_set_hdr(p_sdes);
250     rist_rtp_set_cc(p_sdes, 1); /* Actually it is source count in this case */
251     rist_rtcp_sdes_set_pt(p_sdes);
252     rist_rtcp_set_length(p_sdes, (namelen >> 2) + 2);
253     rist_rtcp_sdes_set_cname(p_sdes, 1);
254     rist_rtcp_sdes_set_name_length(p_sdes, strlen(flow->cname));
255     uint8_t *p_sdes_name = (buf + RTCP_EMPTY_RR_SIZE + RIST_RTCP_SDES_SIZE);
256     strlcpy((char *)p_sdes_name, flow->cname, namelen);
257 
258     /* Write to Socket */
259     rist_WriteTo_i11e_Locked(p_sys->lock, flow->fd_nack, buf, rtcp_feedback_size,
260         (struct sockaddr *)&flow->peer_sockaddr, flow->peer_socklen);
261     free(buf);
262     buf = NULL;
263 }
264 
send_bbnack(stream_t * p_access,int fd_nack,block_t * pkt_nacks,uint16_t nack_count)265 static void send_bbnack(stream_t *p_access, int fd_nack, block_t *pkt_nacks, uint16_t nack_count)
266 {
267     stream_sys_t *p_sys = p_access->p_sys;
268     struct rist_flow *flow = p_sys->flow;
269     int len = 0;
270 
271     int bbnack_bufsize = RIST_RTCP_FB_HEADER_SIZE +
272         RIST_RTCP_FB_FCI_GENERIC_NACK_SIZE * nack_count;
273     uint8_t *buf = malloc(bbnack_bufsize);
274     if ( unlikely( buf == NULL ) )
275         return;
276 
277     /* Populate NACKS */
278     uint8_t *nack = buf;
279     rist_rtp_set_hdr(nack);
280     rist_rtcp_fb_set_fmt(nack, NACK_FMT_BITMASK);
281     rist_rtcp_set_pt(nack, RIST_RTCP_PT_RTPFB);
282     rist_rtcp_set_length(nack, 2 + nack_count);
283     /*uint8_t name[4] = "RIST";*/
284     /*rist_rtcp_fb_set_ssrc_media_src(nack, name);*/
285     len += RIST_RTCP_FB_HEADER_SIZE;
286     /* TODO : group together */
287     uint16_t nacks[MAX_NACKS];
288     memcpy(nacks, pkt_nacks->p_buffer, pkt_nacks->i_buffer);
289     for (int i = 0; i < nack_count; i++) {
290         uint8_t *nack_record = buf + len + RIST_RTCP_FB_FCI_GENERIC_NACK_SIZE*i;
291         rist_rtcp_fb_nack_set_packet_id(nack_record, nacks[i]);
292         rist_rtcp_fb_nack_set_bitmask_lost(nack_record, 0);
293     }
294     len += RIST_RTCP_FB_FCI_GENERIC_NACK_SIZE * nack_count;
295 
296     /* Write to Socket */
297     if (p_sys->b_sendnacks && p_sys->b_disablenacks == false)
298         rist_WriteTo_i11e_Locked(p_sys->lock, fd_nack, buf, len,
299             (struct sockaddr *)&flow->peer_sockaddr, flow->peer_socklen);
300     free(buf);
301     buf = NULL;
302 }
303 
send_rbnack(stream_t * p_access,int fd_nack,block_t * pkt_nacks,uint16_t nack_count)304 static void send_rbnack(stream_t *p_access, int fd_nack, block_t *pkt_nacks, uint16_t nack_count)
305 {
306     stream_sys_t *p_sys = p_access->p_sys;
307     struct rist_flow *flow = p_sys->flow;
308     int len = 0;
309 
310     int rbnack_bufsize = RIST_RTCP_FB_HEADER_SIZE +
311         RIST_RTCP_FB_FCI_GENERIC_NACK_SIZE * nack_count;
312     uint8_t *buf = malloc(rbnack_bufsize);
313     if ( unlikely( buf == NULL ) )
314         return;
315 
316     /* Populate NACKS */
317     uint8_t *nack = buf;
318     rist_rtp_set_hdr(nack);
319     rist_rtcp_fb_set_fmt(nack, NACK_FMT_RANGE);
320     rist_rtcp_set_pt(nack, RTCP_PT_RTPFR);
321     rist_rtcp_set_length(nack, 2 + nack_count);
322     uint8_t name[4] = "RIST";
323     rist_rtcp_fb_set_ssrc_media_src(nack, name);
324     len += RIST_RTCP_FB_HEADER_SIZE;
325     /* TODO : group together */
326     uint16_t nacks[MAX_NACKS];
327     memcpy(nacks, pkt_nacks->p_buffer, pkt_nacks->i_buffer);
328     for (int i = 0; i < nack_count; i++)
329     {
330         uint8_t *nack_record = buf + len + RIST_RTCP_FB_FCI_GENERIC_NACK_SIZE*i;
331         rtcp_fb_nack_set_range_start(nack_record, nacks[i]);
332         rtcp_fb_nack_set_range_extra(nack_record, 0);
333     }
334     len += RIST_RTCP_FB_FCI_GENERIC_NACK_SIZE * nack_count;
335 
336     /* Write to Socket */
337     if (p_sys->b_sendnacks && p_sys->b_disablenacks == false)
338         rist_WriteTo_i11e_Locked(p_sys->lock, fd_nack, buf, len,
339             (struct sockaddr *)&flow->peer_sockaddr, flow->peer_socklen);
340     free(buf);
341     buf = NULL;
342 }
343 
send_nacks(stream_t * p_access,struct rist_flow * flow)344 static void send_nacks(stream_t *p_access, struct rist_flow *flow)
345 {
346     stream_sys_t *p_sys = p_access->p_sys;
347     struct rtp_pkt *pkt;
348     uint16_t idx;
349     uint64_t last_ts = 0;
350     uint16_t null_count = 0;
351     int nacks_len = 0;
352     uint16_t nacks[MAX_NACKS];
353 
354     idx = flow->ri;
355     while(idx++ != flow->wi)
356     {
357         pkt = &(flow->buffer[idx]);
358         if (pkt->buffer == NULL)
359         {
360             if (nacks_len + 1 >= MAX_NACKS)
361             {
362                 break;
363             }
364             else
365             {
366                 null_count++;
367                 /* TODO: after adding average spacing calculation, change this formula
368                    to extrapolated_ts = last_ts + null_count * avg_delta_ts; */
369                 uint64_t extrapolated_ts = last_ts;
370                 /* Find out the age and add it only if necessary */
371                 int retry_count = flow->nacks_retries[idx];
372                 uint64_t age = flow->hi_timestamp - extrapolated_ts;
373                 uint64_t expiration;
374                 if (retry_count == 0){
375                     expiration = flow->reorder_buffer;
376                 } else {
377                     expiration = (uint64_t)flow->nacks_retries[idx] * (uint64_t)flow->retry_interval;
378                 }
379                 if (age > expiration && retry_count <= flow->max_retries)
380                 {
381                     flow->nacks_retries[idx]++;
382                     nacks[nacks_len++] = idx;
383                     msg_Dbg(p_access, "Sending NACK for seq %d, age %"PRId64" ms, retry %u, " \
384                         "expiration %"PRId64" ms", idx, ts_get_from_rtp(age)/1000,
385                         flow->nacks_retries[idx], ts_get_from_rtp(expiration)/1000);
386                 }
387             }
388         }
389         else
390         {
391             last_ts = pkt->rtp_ts;
392             null_count = 0;
393         }
394     }
395     if (nacks_len > 0)
396     {
397         p_sys->i_nack_packets += nacks_len;
398         block_t *pkt_nacks = block_Alloc(nacks_len * 2);
399         if (pkt_nacks)
400         {
401             memcpy(pkt_nacks->p_buffer, nacks, nacks_len * 2);
402             pkt_nacks->i_buffer = nacks_len * 2;
403             block_FifoPut( p_sys->p_fifo, pkt_nacks );
404         }
405     }
406 }
407 
sockaddr_cmp(struct sockaddr * x,struct sockaddr * y)408 static int sockaddr_cmp(struct sockaddr *x, struct sockaddr *y)
409 {
410 #define CMP(a, b) if (a != b) return a < b ? -1 : 1
411 
412     CMP(x->sa_family, y->sa_family);
413 
414     if (x->sa_family == AF_INET)
415     {
416         struct sockaddr_in *xin = (void*)x, *yin = (void*)y;
417         CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr));
418         CMP(ntohs(xin->sin_port), ntohs(yin->sin_port));
419     }
420     else if (x->sa_family == AF_INET6)
421     {
422         struct sockaddr_in6 *xin6 = (void*)x, *yin6 = (void*)y;
423         int r = memcmp(xin6->sin6_addr.s6_addr, yin6->sin6_addr.s6_addr,
424             sizeof(xin6->sin6_addr.s6_addr));
425         if (r != 0)
426             return r;
427         CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port));
428         CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo);
429         CMP(xin6->sin6_scope_id, yin6->sin6_scope_id);
430     }
431 
432 #undef CMP
433     return 0;
434 }
435 
print_sockaddr_info_change(stream_t * p_access,struct sockaddr * x,struct sockaddr * y)436 static void print_sockaddr_info_change(stream_t *p_access, struct sockaddr *x, struct sockaddr *y)
437 {
438     if (x->sa_family == AF_INET)
439     {
440         struct sockaddr_in *xin = (void*)x, *yin = (void*)y;
441         msg_Info(p_access, "Peer IP:Port change detected: old IP:Port %s:%d, new IP:Port %s:%d",
442             inet_ntoa(xin->sin_addr), ntohs(xin->sin_port), inet_ntoa(yin->sin_addr),
443             ntohs(yin->sin_port));
444     }
445     else if (x->sa_family == AF_INET6)
446     {
447         struct sockaddr_in6 *xin6 = (void*)x, *yin6 = (void*)y;
448         char oldstr[INET6_ADDRSTRLEN];
449         char newstr[INET6_ADDRSTRLEN];
450         inet_ntop(xin6->sin6_family, &xin6->sin6_addr, oldstr, sizeof(struct in6_addr));
451         inet_ntop(yin6->sin6_family, &yin6->sin6_addr, newstr, sizeof(struct in6_addr));
452         msg_Info(p_access, "Peer IP:Port change detected: old IP:Port %s:%d, new IP:Port %s:%d",
453             oldstr, ntohs(xin6->sin6_port), newstr, ntohs(yin6->sin6_port));
454     }
455 }
456 
print_sockaddr_info(stream_t * p_access,struct sockaddr * x)457 static void print_sockaddr_info(stream_t *p_access, struct sockaddr *x)
458 {
459     if (x->sa_family == AF_INET)
460     {
461         struct sockaddr_in *xin = (void*)x;
462         msg_Info(p_access, "Peer IP:Port %s:%d", inet_ntoa(xin->sin_addr), ntohs(xin->sin_port));
463     }
464     else if (x->sa_family == AF_INET6)
465     {
466         struct sockaddr_in6 *xin6 = (void*)x;
467         char str[INET6_ADDRSTRLEN];
468         inet_ntop(xin6->sin6_family, &xin6->sin6_addr, str, sizeof(struct in6_addr));
469         msg_Info(p_access, "Peer IP:Port %s:%d", str, ntohs(xin6->sin6_port));
470     }
471 }
472 
rtcp_input(stream_t * p_access,struct rist_flow * flow,uint8_t * buf_in,size_t len,struct sockaddr * peer,socklen_t slen)473 static void rtcp_input(stream_t *p_access, struct rist_flow *flow, uint8_t *buf_in, size_t len,
474     struct sockaddr *peer, socklen_t slen)
475 {
476     stream_sys_t *p_sys = p_access->p_sys;
477     uint8_t  ptype;
478     uint16_t processed_bytes = 0;
479     uint16_t records;
480     char new_sender_name[MAX_CNAME];
481     uint8_t *buf;
482 
483     while (processed_bytes < len) {
484         buf = buf_in + processed_bytes;
485         /* safety checks */
486         uint16_t bytes_left = len - processed_bytes + 1;
487         if ( bytes_left < 4 )
488         {
489             /* we must have at least 4 bytes */
490             msg_Err(p_access, "Rist rtcp packet must have at least 4 bytes, we have %d",
491                 bytes_left);
492             return;
493         }
494         else if (!rist_rtp_check_hdr(buf))
495         {
496             /* check for a valid rtp header */
497             msg_Err(p_access, "Malformed rtcp packet starting with %02x, ignoring.", buf[0]);
498             return;
499         }
500 
501         ptype =  rist_rtcp_get_pt(buf);
502         records = rist_rtcp_get_length(buf);
503         uint16_t bytes = (uint16_t)(4 * (1 + records));
504         if (bytes > bytes_left)
505         {
506             /* check for a sane number of bytes */
507             msg_Err(p_access, "Malformed rtcp packet, wrong len %d, expecting %u bytes in the " \
508                 "packet, got a buffer of %u bytes.", rist_rtcp_get_length(buf), bytes, bytes_left);
509             return;
510         }
511 
512         switch(ptype) {
513             case RTCP_PT_RTPFR:
514             case RIST_RTCP_PT_RTPFB:
515                 break;
516 
517             case RIST_RTCP_PT_RR:
518                 break;
519 
520             case RIST_RTCP_PT_SDES:
521                 {
522                     if (p_sys->b_sendnacks == false)
523                         p_sys->b_sendnacks = true;
524                     if (p_sys->b_ismulticast)
525                         return;
526                     /* Check for changes in source IP address or port */
527                     int8_t name_length = rist_rtcp_sdes_get_name_length(buf);
528                     if (name_length > bytes_left || name_length <= 0 ||
529                         (size_t)name_length > sizeof(new_sender_name))
530                     {
531                         /* check for a sane number of bytes */
532                         msg_Err(p_access, "Malformed SDES packet, wrong cname len %d, got a " \
533                             "buffer of %u bytes.", name_length, bytes_left);
534                         return;
535                     }
536                     bool ip_port_changed = false;
537                     if (sockaddr_cmp((struct sockaddr *)&flow->peer_sockaddr, peer) != 0)
538                     {
539                         ip_port_changed = true;
540                         if(flow->peer_socklen > 0)
541                             print_sockaddr_info_change(p_access,
542                                 (struct sockaddr *)&flow->peer_sockaddr, peer);
543                         else
544                             print_sockaddr_info(p_access, peer);
545                         vlc_mutex_lock( &p_sys->lock );
546                         memcpy(&flow->peer_sockaddr, peer, sizeof(struct sockaddr_storage));
547                         flow->peer_socklen = slen;
548                         vlc_mutex_unlock( &p_sys->lock );
549                     }
550 
551                     /* Check for changes in cname */
552                     bool peer_name_changed = false;
553                     memset(new_sender_name, 0, MAX_CNAME);
554                     memcpy(new_sender_name, buf + RIST_RTCP_SDES_SIZE, name_length);
555                     if (memcmp(new_sender_name, p_sys->sender_name, name_length) != 0)
556                     {
557                         peer_name_changed = true;
558                         if (strcmp(p_sys->sender_name, "") == 0)
559                             msg_Info(p_access, "Peer Name: %s", new_sender_name);
560                         else
561                             msg_Info(p_access, "Peer Name change detected: old Name: %s, new " \
562                                 "Name: %s", p_sys->sender_name, new_sender_name);
563                         memset(p_sys->sender_name, 0, MAX_CNAME);
564                         memcpy(p_sys->sender_name, buf + RIST_RTCP_SDES_SIZE, name_length);
565                     }
566 
567                     /* Reset the buffer as the source must have been restarted */
568                     if (peer_name_changed || ip_port_changed)
569                     {
570                         /* reset the buffer */
571                         flow->reset = 1;
572                     }
573                 }
574                 break;
575 
576             case RIST_RTCP_PT_SR:
577                 if (p_sys->b_sendnacks == false)
578                     p_sys->b_sendnacks = true;
579                 if (p_sys->b_ismulticast)
580                         return;
581                 break;
582 
583             default:
584                 msg_Err(p_access, "   Unrecognized RTCP packet with PTYPE=%02x!!", ptype);
585         }
586         processed_bytes += (4 * (1 + records));
587     }
588 }
589 
rist_input(stream_t * p_access,struct rist_flow * flow,uint8_t * buf,size_t len)590 static bool rist_input(stream_t *p_access, struct rist_flow *flow, uint8_t *buf, size_t len)
591 {
592     stream_sys_t *p_sys = p_access->p_sys;
593 
594     /* safety checks */
595     if ( len < RIST_RTP_HEADER_SIZE )
596     {
597         /* check if packet size >= rtp header size */
598         msg_Err(p_access, "Rist rtp packet must have at least 12 bytes, we have %zu", len);
599         return false;
600     }
601     else if (!rist_rtp_check_hdr(buf))
602     {
603         /* check for a valid rtp header */
604         msg_Err(p_access, "Malformed rtp packet header starting with %02x, ignoring.", buf[0]);
605         return false;
606     }
607 
608     uint16_t idx = rist_rtp_get_seqnum(buf);
609     uint32_t pkt_ts = rist_rtp_get_timestamp(buf);
610     bool retrasnmitted = false;
611     bool success = true;
612 
613     if (flow->reset == 1)
614     {
615         msg_Info(p_access, "Traffic detected after buffer reset");
616         /* First packet in the queue */
617         flow->hi_timestamp = pkt_ts;
618         msg_Info(p_access, "ts@%u", flow->hi_timestamp);
619         flow->wi = idx;
620         flow->ri = idx;
621         flow->reset = 0;
622         p_sys->b_flag_discontinuity = true;
623     }
624 
625     /* Check to see if this is a retransmission or a regular packet */
626     if (buf[11] & (1 << 0))
627     {
628         msg_Dbg(p_access, "Packet %d RECOVERED, Window: [%d:%d-->%d]", idx, flow->ri, flow->wi,
629             flow->wi-flow->ri);
630         p_sys->i_recovered_packets++;
631         retrasnmitted = true;
632     }
633     else if (flow->wi != flow->ri)
634     {
635         /* Reset counter to 0 on incoming holes */
636         /* Regular packets only as retransmits are expected to come in out of order */
637         uint16_t idxnext = (uint16_t)(flow->wi + 1);
638         if (idx != idxnext)
639         {
640             if (idx > idxnext) {
641                 msg_Dbg(p_access, "Gap, got %d, expected %d, %d packet gap, Window: [%d:%d-->%d]",
642                     idx, idxnext, idx - idxnext, flow->ri, flow->wi, (uint16_t)(flow->wi-flow->ri));
643             } else {
644                 p_sys->i_reordered_packets++;
645                 msg_Dbg(p_access, "Out of order, got %d, expected %d, Window: [%d:%d-->%d]", idx,
646                     idxnext, flow->ri, flow->wi, (uint16_t)(flow->wi-flow->ri));
647             }
648             uint16_t zero_counter = (uint16_t)(flow->wi + 1);
649             while(zero_counter++ != idx) {
650                 flow->nacks_retries[zero_counter] = 0;
651             }
652             /*msg_Dbg(p_access, "Gap, reseting %d packets as zero nacks %d to %d",
653                 idx - flow->wi - 1, (uint16_t)(flow->wi + 1), idx);*/
654         }
655     }
656 
657     /* Always replace the existing one with the new one */
658     struct rtp_pkt *pkt;
659     pkt = &(flow->buffer[idx]);
660     if (pkt->buffer && pkt->buffer->i_buffer > 0)
661     {
662         block_Release(pkt->buffer);
663         pkt->buffer = NULL;
664     }
665     pkt->buffer = block_Alloc(len);
666     if (!pkt->buffer)
667         return false;
668 
669     pkt->buffer->i_buffer = len;
670     memcpy(pkt->buffer->p_buffer, buf, len);
671     pkt->rtp_ts = pkt_ts;
672     p_sys->last_data_rx = mdate();
673     /* Reset the try counter regardless of wether it was a retransmit or not */
674     flow->nacks_retries[idx] = 0;
675 
676     if (retrasnmitted)
677         return success;
678 
679     p_sys->i_total_packets++;
680     /* Perform discontinuity checks and udpdate counters */
681     if (!is_index_in_range(flow, idx) && pkt_ts >= flow->hi_timestamp)
682     {
683         if ((pkt_ts - flow->hi_timestamp) > flow->hi_timestamp/10)
684         {
685             msg_Info(p_access, "Forward stream discontinuity idx@%d/%d/%d ts@%u/%u", flow->ri, idx,
686                 flow->wi, pkt_ts, flow->hi_timestamp);
687             flow->reset = 1;
688             success = false;
689         }
690         else
691         {
692             flow->wi = idx;
693             flow->hi_timestamp = pkt_ts;
694         }
695     }
696     else if (!is_index_in_range(flow, idx))
697     {
698         /* incoming timestamp just jumped back in time or index is outside of scope */
699         msg_Info(p_access, "Backwards stream discontinuity idx@%d/%d/%d ts@%u/%u", flow->ri, idx,
700             flow->wi, pkt_ts, flow->hi_timestamp);
701         flow->reset = 1;
702         success = false;
703     }
704 
705     return success;
706 }
707 
rist_dequeue(stream_t * p_access,struct rist_flow * flow)708 static block_t *rist_dequeue(stream_t *p_access, struct rist_flow *flow)
709 {
710     stream_sys_t *p_sys = p_access->p_sys;
711     block_t *pktout = NULL;
712     struct rtp_pkt *pkt;
713     uint16_t idx;
714     if (flow->ri == flow->wi || flow->reset > 0)
715         return NULL;
716 
717     idx = flow->ri;
718     bool found_data = false;
719     uint16_t loss_amount = 0;
720     while(idx++ != flow->wi) {
721 
722         pkt = &(flow->buffer[idx]);
723         if (!pkt->buffer)
724         {
725             /*msg_Info(p_access, "Possible packet loss on index #%d", idx);*/
726             loss_amount++;
727             /* We move ahead until we find a timestamp but we do not move the cursor.
728              * None of them are guaranteed packet loss because we do not really
729              * know their timestamps. They might still arrive on the next loop.
730              * We can confirm the loss only if we get a valid packet in the loop below. */
731             continue;
732         }
733 
734         /*printf("IDX=%d, flow->hi_timestamp: %u, (ts + flow->rtp_latency): %u\n", idx,
735             flow->hi_timestamp, (ts - 100 * flow->qdelay));*/
736         if (flow->hi_timestamp > (uint32_t)(pkt->rtp_ts + flow->rtp_latency))
737         {
738             /* Populate output packet now but remove rtp header from source */
739             int newSize = pkt->buffer->i_buffer - RIST_RTP_HEADER_SIZE;
740             pktout = block_Alloc(newSize);
741             if (pktout)
742             {
743                 pktout->i_buffer = newSize;
744                 memcpy(pktout->p_buffer, pkt->buffer->p_buffer + RIST_RTP_HEADER_SIZE, newSize);
745                 /* free the buffer and increase the read index */
746                 flow->ri = idx;
747                 /* TODO: calculate average duration using buffer average (bring from sender) */
748                 found_data = true;
749             }
750             block_Release(pkt->buffer);
751             pkt->buffer = NULL;
752             break;
753         }
754 
755     }
756 
757     if (loss_amount > 0 && found_data == true)
758     {
759         /* Packet loss confirmed, we found valid data after the holes */
760         msg_Dbg(p_access, "Packet NOT RECOVERED, %d packet(s), Window: [%d:%d]", loss_amount,
761             flow->ri, flow->wi);
762         p_sys->i_lost_packets += loss_amount;
763         p_sys->b_flag_discontinuity = true;
764     }
765 
766     return pktout;
767 }
768 
rist_thread(void * data)769 static void *rist_thread(void *data)
770 {
771     stream_t *p_access = data;
772     stream_sys_t *p_sys = p_access->p_sys;
773 
774     /* Process nacks every 5ms */
775     /* We only ask for the relevant ones */
776     for (;;) {
777         block_t *pkt_nacks = block_FifoGet(p_sys->p_fifo);
778 
779         int canc = vlc_savecancel();
780 
781         /* there are two bytes per nack */
782         uint16_t nack_count = (uint16_t)pkt_nacks->i_buffer/2;
783         switch(p_sys->nack_type) {
784             case NACK_FMT_BITMASK:
785                 send_bbnack(p_access, p_sys->flow->fd_nack, pkt_nacks, nack_count);
786                 break;
787 
788             default:
789                 send_rbnack(p_access, p_sys->flow->fd_nack, pkt_nacks, nack_count);
790         }
791 
792         if (nack_count > 1)
793             msg_Dbg(p_access, "Sent %u NACKs !!!", nack_count);
794         block_Release(pkt_nacks);
795 
796         vlc_restorecancel (canc);
797     }
798 
799     return NULL;
800 }
801 
BlockRIST(stream_t * p_access,bool * restrict eof)802 static block_t *BlockRIST(stream_t *p_access, bool *restrict eof)
803 {
804     stream_sys_t *p_sys = p_access->p_sys;
805     uint64_t now;
806     *eof = false;
807     block_t *pktout = NULL;
808     struct pollfd pfd[3];
809     int ret;
810     ssize_t r;
811     struct sockaddr_storage peer;
812     socklen_t slen = sizeof(struct sockaddr_storage);
813     struct rist_flow *flow = p_sys->flow;
814 
815     if (vlc_killed())
816     {
817         *eof = true;
818         return NULL;
819     }
820 
821     int poll_sockets = 2;
822     pfd[0].fd = flow->fd_in;
823     pfd[0].events = POLLIN;
824     pfd[1].fd = flow->fd_nack;
825     pfd[1].events = POLLIN;
826     if (p_sys->b_ismulticast)
827     {
828         pfd[2].fd = flow->fd_rtcp_m;
829         pfd[2].events = POLLIN;
830         poll_sockets++;
831     }
832 
833     /* The protocol uses a fifo buffer with a fixed time delay.
834      * That buffer needs to be emptied at a rate that is determined by the rtp timestamps of the
835      * packets. If I waited indefinitely for data coming in, the rate and delay of output packets
836      * would be wrong. I am calling the rist_dequeue function every time a data packet comes in
837      * and also every time we get a poll timeout. The configurable poll timeout is for controling
838      * the maximum jitter of output data coming out of the buffer. The default 5ms timeout covers
839      * most cases. */
840 
841     ret = vlc_poll_i11e(pfd, poll_sockets, p_sys->i_poll_timeout_current);
842     if (unlikely(ret < 0))
843         return NULL;
844     else if (ret == 0)
845     {
846         /* Poll timeout, check the queue for the next packet that needs to be delivered */
847         pktout = rist_dequeue(p_access, flow);
848         /* if there is data, we need to come back faster to finish emptying it */
849         if (pktout) {
850             p_sys->i_poll_timeout_current = 0;
851             p_sys->i_poll_timeout_zero_count++;
852         } else {
853             p_sys->i_poll_timeout_current = p_sys->i_poll_timeout;
854             p_sys->i_poll_timeout_nonzero_count++;
855         }
856     }
857     else
858     {
859 
860         uint8_t *buf = malloc(p_sys->i_max_packet_size);
861         if ( unlikely( buf == NULL ) )
862             return NULL;
863 
864         /* Process rctp incoming data */
865         if (pfd[1].revents & POLLIN)
866         {
867             r = rist_ReadFrom_i11e(flow->fd_nack, buf, p_sys->i_max_packet_size,
868                 (struct sockaddr *)&peer, &slen);
869             if (unlikely(r == -1)) {
870                 msg_Err(p_access, "socket %d error: %s\n", flow->fd_nack, gai_strerror(errno));
871             }
872             else {
873                 if (p_sys->b_ismulticast == false)
874                     rtcp_input(p_access, flow, buf, r, (struct sockaddr *)&peer, slen);
875             }
876         }
877         if (p_sys->b_ismulticast && pfd[2].revents & POLLIN)
878         {
879             r = rist_ReadFrom_i11e(flow->fd_rtcp_m, buf, p_sys->i_max_packet_size,
880                 (struct sockaddr *)&peer, &slen);
881             if (unlikely(r == -1)) {
882                 msg_Err(p_access, "mcast socket %d error: %s\n",flow->fd_rtcp_m, gai_strerror(errno));
883             }
884             else {
885                 rtcp_input(p_access, flow, buf, r, (struct sockaddr *)&peer, slen);
886             }
887         }
888 
889         /* Process regular incoming data */
890         if (pfd[0].revents & POLLIN)
891         {
892             r = rist_Read_i11e(flow->fd_in, buf, p_sys->i_max_packet_size);
893             if (unlikely(r == -1)) {
894                 msg_Err(p_access, "socket %d error: %s\n", flow->fd_in, gai_strerror(errno));
895             }
896             else
897             {
898                 /* rist_input will process and queue the pkt */
899                 if (rist_input(p_access, flow, buf, r))
900                 {
901                     /* Check the queue for the next packet that needs to be delivered */
902                     pktout = rist_dequeue(p_access, flow);
903                     if (pktout) {
904                         p_sys->i_poll_timeout_current = 0;
905                         p_sys->i_poll_timeout_zero_count++;
906                     } else {
907                         p_sys->i_poll_timeout_current = p_sys->i_poll_timeout;
908                         p_sys->i_poll_timeout_nonzero_count++;
909                     }
910                 }
911             }
912         }
913 
914         free(buf);
915         buf = NULL;
916     }
917 
918     now = mdate();
919 
920     /* Process stats and print them out */
921     /* We need to measure some items every 70ms */
922     uint64_t interval = (now - flow->feedback_time);
923     if ( interval > RIST_TICK_FROM_MS(RTCP_INTERVAL) )
924     {
925         if (p_sys->i_poll_timeout_nonzero_count > 0)
926         {
927             float ratio = (float)p_sys->i_poll_timeout_zero_count
928                 / (float)p_sys->i_poll_timeout_nonzero_count;
929             if (ratio <= 1)
930                 p_sys->vbr_ratio += 1 - ratio;
931             else
932                 p_sys->vbr_ratio += ratio - 1;
933             p_sys->vbr_ratio_count++;
934             /*msg_Dbg(p_access, "zero poll %u, non-zero poll %u, ratio %.2f",
935                 p_sys->i_poll_timeout_zero_count, p_sys->i_poll_timeout_nonzero_count, ratio);*/
936             p_sys->i_poll_timeout_zero_count = 0;
937             p_sys->i_poll_timeout_nonzero_count =  0;
938         }
939     }
940     /* We print out the stats once per second */
941     interval = (now - p_sys->i_last_stat);
942     if ( interval >  RIST_TICK_FROM_MS(STATS_INTERVAL) )
943     {
944         if ( p_sys->i_lost_packets > 0)
945             msg_Err(p_access, "We have %d lost packets", p_sys->i_lost_packets);
946         float ratio = 1;
947         if (p_sys->vbr_ratio_count > 0)
948             ratio = p_sys->vbr_ratio / (float)p_sys->vbr_ratio_count;
949         float quality = 100;
950         if (p_sys->i_total_packets > 0)
951             quality -= (float)100*(float)(p_sys->i_lost_packets + p_sys->i_recovered_packets +
952                 p_sys->i_reordered_packets)/(float)p_sys->i_total_packets;
953         if (quality != 100)
954             msg_Info(p_access, "STATS: Total %u, Recovered %u/%u, Reordered %u, Lost %u, VBR " \
955                 "Score %.2f, Link Quality %.2f%%", p_sys->i_total_packets,
956                 p_sys->i_recovered_packets, p_sys->i_nack_packets, p_sys->i_reordered_packets,
957                 p_sys->i_lost_packets, ratio, quality);
958         p_sys->i_last_stat = now;
959         p_sys->vbr_ratio = 0;
960         p_sys->vbr_ratio_count = 0;
961         p_sys->i_lost_packets = 0;
962         p_sys->i_nack_packets = 0;
963         p_sys->i_recovered_packets = 0;
964         p_sys->i_reordered_packets = 0;
965         p_sys->i_total_packets = 0;
966     }
967 
968     /* Send rtcp feedback every RTCP_INTERVAL */
969     interval = (now - flow->feedback_time);
970     if ( interval > RIST_TICK_FROM_MS(RTCP_INTERVAL) )
971     {
972         /* msg_Dbg(p_access, "Calling RTCP Feedback %lu<%d ms using timer", interval,
973         RIST_TICK_FROM_MS(RTCP_INTERVAL)); */
974         send_rtcp_feedback(p_access, flow);
975         flow->feedback_time = now;
976     }
977 
978     /* Send nacks every NACK_INTERVAL (only the ones that have matured, if any) */
979     interval = (now - p_sys->last_nack_tx);
980     if ( interval > RIST_TICK_FROM_MS(NACK_INTERVAL) )
981     {
982         send_nacks(p_access, p_sys->flow);
983         p_sys->last_nack_tx = now;
984     }
985 
986     /* Safety check for when the input stream stalls */
987     if ( p_sys->last_data_rx > 0 && now > p_sys->last_data_rx &&
988         (uint64_t)(now - p_sys->last_data_rx) >  (uint64_t)RIST_TICK_FROM_MS(flow->latency) &&
989         (uint64_t)(now - p_sys->last_reset) > (uint64_t)RIST_TICK_FROM_MS(flow->latency) )
990     {
991         msg_Err(p_access, "No data received for %"PRId64" ms, resetting buffers",
992             (int64_t)(now - p_sys->last_data_rx)/1000);
993         p_sys->last_reset = now;
994         flow->reset = 1;
995     }
996 
997     if (pktout)
998     {
999         if (p_sys->b_flag_discontinuity) {
1000             pktout->i_flags |= BLOCK_FLAG_DISCONTINUITY;
1001             p_sys->b_flag_discontinuity = false;
1002         }
1003         return pktout;
1004     }
1005     else
1006         return NULL;
1007 }
1008 
Clean(stream_t * p_access)1009 static void Clean( stream_t *p_access )
1010 {
1011     stream_sys_t *p_sys = p_access->p_sys;
1012 
1013     if( likely(p_sys->p_fifo != NULL) )
1014         block_FifoRelease( p_sys->p_fifo );
1015 
1016     if (p_sys->flow)
1017     {
1018         if (p_sys->flow->fd_in >= 0)
1019             net_Close (p_sys->flow->fd_in);
1020         if (p_sys->flow->fd_nack >= 0)
1021             net_Close (p_sys->flow->fd_nack);
1022         if (p_sys->flow->fd_rtcp_m >= 0)
1023             net_Close (p_sys->flow->fd_rtcp_m);
1024         for (int i=0; i<RIST_QUEUE_SIZE; i++) {
1025             struct rtp_pkt *pkt = &(p_sys->flow->buffer[i]);
1026             if (pkt->buffer && pkt->buffer->i_buffer > 0) {
1027                 block_Release(pkt->buffer);
1028                 pkt->buffer = NULL;
1029             }
1030         }
1031         free(p_sys->flow->buffer);
1032         free(p_sys->flow);
1033     }
1034 }
1035 
Close(vlc_object_t * p_this)1036 static void Close(vlc_object_t *p_this)
1037 {
1038     stream_t     *p_access = (stream_t*)p_this;
1039     stream_sys_t *p_sys = p_access->p_sys;
1040 
1041     vlc_cancel(p_sys->thread);
1042     vlc_join(p_sys->thread, NULL);
1043 
1044     Clean( p_access );
1045 }
1046 
Open(vlc_object_t * p_this)1047 static int Open(vlc_object_t *p_this)
1048 {
1049     stream_t     *p_access = (stream_t*)p_this;
1050     stream_sys_t *p_sys = NULL;
1051     vlc_url_t     parsed_url = { 0 };
1052 
1053     p_sys = vlc_obj_calloc( p_this, 1, sizeof( *p_sys ) );
1054     if( unlikely( p_sys == NULL ) )
1055         return VLC_ENOMEM;
1056 
1057     p_access->p_sys = p_sys;
1058 
1059     vlc_mutex_init( &p_sys->lock );
1060 
1061     if ( vlc_UrlParse( &parsed_url, p_access->psz_url ) == -1 )
1062     {
1063         msg_Err( p_access, "Failed to parse input URL (%s)",
1064             p_access->psz_url );
1065         goto failed;
1066     }
1067 
1068     /* Initialize rist flow */
1069     p_sys->b_ismulticast = is_multicast_address(parsed_url.psz_host);
1070     p_sys->flow = rist_udp_receiver(p_access, &parsed_url, p_sys->b_ismulticast);
1071     vlc_UrlClean( &parsed_url );
1072     if (!p_sys->flow)
1073     {
1074         msg_Err( p_access, "Failed to open rist flow (%s)",
1075             p_access->psz_url );
1076         goto failed;
1077     }
1078 
1079     p_sys->b_flag_discontinuity = false;
1080     p_sys->b_disablenacks = var_InheritBool( p_access, "disable-nacks" );
1081     p_sys->b_sendblindnacks = var_InheritBool( p_access, "mcast-blind-nacks" );
1082     if (p_sys->b_sendblindnacks && p_sys->b_disablenacks == false)
1083         p_sys->b_sendnacks = true;
1084     else
1085         p_sys->b_sendnacks = false;
1086     p_sys->nack_type = var_InheritInteger( p_access, "nack-type" );
1087     p_sys->i_max_packet_size = var_InheritInteger( p_access, "packet-size" );
1088     p_sys->i_poll_timeout = var_InheritInteger( p_access, "maximum-jitter" );
1089     p_sys->flow->retry_interval = var_InheritInteger( p_access, "retry-interval" );
1090     p_sys->flow->max_retries = var_InheritInteger( p_access, "max-retries" );
1091     p_sys->flow->latency = var_InheritInteger( p_access, "latency" );
1092     if (p_sys->b_disablenacks)
1093         p_sys->flow->reorder_buffer = p_sys->flow->latency;
1094     else
1095         p_sys->flow->reorder_buffer = var_InheritInteger( p_access, "reorder-buffer" );
1096     msg_Info(p_access, "Setting queue latency to %d ms", p_sys->flow->latency);
1097 
1098     /* Convert to rtp times */
1099     p_sys->flow->rtp_latency = rtp_get_ts(RIST_TICK_FROM_MS(p_sys->flow->latency));
1100     p_sys->flow->retry_interval = rtp_get_ts(RIST_TICK_FROM_MS(p_sys->flow->retry_interval));
1101     p_sys->flow->reorder_buffer = rtp_get_ts(RIST_TICK_FROM_MS(p_sys->flow->reorder_buffer));
1102 
1103     p_sys->p_fifo = block_FifoNew();
1104     if( unlikely(p_sys->p_fifo == NULL) )
1105         goto failed;
1106 
1107     /* This extra thread is for sending feedback/nack packets even when no data comes in */
1108     if (vlc_clone(&p_sys->thread, rist_thread, p_access, VLC_THREAD_PRIORITY_INPUT))
1109     {
1110         msg_Err(p_access, "Failed to create worker thread.");
1111         goto failed;
1112     }
1113 
1114     p_access->pf_block = BlockRIST;
1115     p_access->pf_control = Control;
1116 
1117     return VLC_SUCCESS;
1118 
1119 failed:
1120     Clean( p_access );
1121     return VLC_EGENERIC;
1122 }
1123 
1124 /* Module descriptor */
1125 vlc_module_begin ()
1126 
1127     set_shortname( N_("RIST") )
1128     set_description( N_("RIST input") )
1129     set_category( CAT_INPUT )
1130     set_subcategory( SUBCAT_INPUT_ACCESS )
1131 
1132     add_integer( "packet-size", RIST_MAX_PACKET_SIZE,
1133         N_("RIST maximum packet size (bytes)"), NULL, true )
1134     add_integer( "maximum-jitter", RIST_DEFAULT_POLL_TIMEOUT,
1135         N_("RIST demux/decode maximum jitter (default is 5ms)"),
1136         N_("This controls the maximum jitter that will be passed to the demux/decode chain. "
1137             "The lower the value, the more CPU cycles the algorithm will consume"), true )
1138     add_integer( "latency", RIST_DEFAULT_LATENCY, N_("RIST latency (ms)"), NULL, true )
1139     add_integer( "retry-interval", RIST_DEFAULT_RETRY_INTERVAL, N_("RIST nack retry interval (ms)"),
1140         NULL, true )
1141     add_integer( "reorder-buffer", RIST_DEFAULT_REORDER_BUFFER, N_("RIST reorder buffer (ms)"),
1142         NULL, true )
1143     add_integer( "max-retries", RIST_MAX_RETRIES, N_("RIST maximum retry count"), NULL, true )
1144     add_integer( "nack-type", NACK_FMT_RANGE,
1145             N_("RIST nack type, 0 = range, 1 = bitmask. Default is range"), NULL, true )
1146         change_integer_list( nack_type, nack_type_names )
1147     add_bool( "disable-nacks", false, N_("Disable NACK output packets"),
1148         N_("Use this to disable packet recovery"), true )
1149     add_bool( "mcast-blind-nacks", false, N_("Do not check for a valid rtcp message from the encoder"),
1150         N_("Send nack messages even when we have not confirmed that the encoder is on our local " \
1151         "network."), true )
1152 
1153     set_capability( "access", 0 )
1154     add_shortcut( "rist", "tr06" )
1155 
1156     set_callbacks( Open, Close )
1157 
1158 vlc_module_end ()
1159