[vlc-devel] access_output: rist: refactor to use the librist library (we now support simple and main profiles)

Sergio M. Ammirata, Ph.D. sergio at ammirata.net
Sun Mar 22 16:30:09 CET 2020


>From a114dd5f9491d1ce9e1171d95e7fa2083ad16ec9 Mon Sep 17
00:00:00 2001
From: Sergio Ammirata <sergio at ammirata.net>
Date: Sun, 22 Mar 2020 11:26:08 -0400
Subject: [PATCH] access_output: rist: refactor to use the
librist library (we now support simple and main profiles)

---
 modules/access_output/Makefile.am |   5 +-
 modules/access_output/rist.c      | 815 ++++++----------
--------------
 2 files changed, 159 insertions(+), 661 deletions(-)

diff --git a/modules/access_output/Makefile.am
b/modules/access_output/Makefile.am
index f6f78c0b73..5e54eae8ff 100644
--- a/modules/access_output/Makefile.am
+++ b/modules/access_output/Makefile.am
@@ -36,9 +36,10 @@ access_out_LTLIBRARIES +=
$(LTLIBaccess_output_srt)
 EXTRA_LTLIBRARIES += libaccess_output_srt_plugin.la
 
 ### RIST ###
-libaccess_output_rist_plugin_la_SOURCES =
access_output/rist.c access/rist.h
-libaccess_output_rist_plugin_la_CFLAGS = $(AM_CFLAGS)
$(BITSTREAM_CFLAGS)
+libaccess_output_rist_plugin_la_SOURCES =
access_output/rist.c
+libaccess_output_rist_plugin_la_CFLAGS = $(AM_CFLAGS)
 libaccess_output_rist_plugin_la_LIBADD = $(SOCKET_LIBS)
+libaccess_output_rist_plugin_la_LDFLAGS = $(AM_LDFLAGS)
-lrist
 if HAVE_BITSTREAM
 access_out_LTLIBRARIES += libaccess_output_rist_plugin.la
 endif
diff --git a/modules/access_output/rist.c
b/modules/access_output/rist.c
index 3f2f3901bd..8d044df7f0 100644
--- a/modules/access_output/rist.c
+++ b/modules/access_output/rist.c
@@ -2,7 +2,7 @@
  *  * rist.c: RIST (Reliable Internet Stream Transport)
output module
 
***********************************************************
******************
  * Copyright (C) 2018, DVEO, the Broadcast Division of
Computer Modules, Inc.
- * Copyright (C) 2018, SipRadius LLC
+ * Copyright (C) 2018-2020, SipRadius LLC
  *
  * Authors: Sergio Ammirata <sergio at ammirata.net>
  *          Daniele Lacamera <root at danielinux.net>
@@ -28,571 +28,63 @@
 
 #include <vlc_common.h>
 #include <vlc_interrupt.h>
-#include <vlc_fs.h>
 #include <vlc_plugin.h>
 #include <vlc_sout.h>
 #include <vlc_block.h>
-#include <vlc_network.h>
-#include <vlc_threads.h>
 #include <vlc_rand.h>
-#ifdef HAVE_POLL
-#include <poll.h>
-#endif
 #include <sys/time.h>
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <bitstream/ietf/rtcp_rr.h>
-#include <bitstream/ietf/rtcp_sr.h>
-#include <bitstream/ietf/rtcp_fb.h>
-#include <bitstream/ietf/rtcp_sdes.h>
-#include <bitstream/ietf/rtp.h>
-
-#include "../access/rist.h"
-
-/* Uncomment the following to introduce induced packet
loss for TESTING purposes only */
-/*#define TEST_PACKET_LOSS*/
+#include <librist.h>
 
 /* The default target packet size */
-#define RIST_TARGET_PACKET_SIZE 1328
-/* The default caching delay for output data */
-#define DEFAULT_CACHING_DELAY 50
-/* The default buffer size in ms */
-#define DEFAULT_BUFFER_SIZE 0
-/* Calculate and print stats once per second */
-#define STATS_INTERVAL 1000 /*ms*/
+#define RIST_TARGET_PACKET_SIZE 1316
 
-#define MPEG_II_TRANSPORT_STREAM (0x21)
-#define RIST_DEFAULT_PORT 1968
+/* The default max bitrate in Kbps */
+#define DEFAULT_MAX_BITRATE 100000
+/* The default buffer size in ms */
+#define DEFAULT_BUFFER_SIZE 1000
+/* Default ports for main profile mode */
+#define RIST_DEFAULT_SRC_PORT 1971
+#define RIST_DEFAULT_DST_PORT 1968
+/* Default profile */
+#define RIST_DEFAULT_PROFILE RIST_PROFILE_MAIN
 
 #define SOUT_CFG_PREFIX "sout-rist-"
 
 static const char *const ppsz_sout_options[] = {
     "packet-size",
-    "caching",
     "buffer-size",
-    "ssrc",
     "stream-name",
+    "profile",
+    "gre-src-port",
+    "gre-dst-port",
+    "max-bitrate",
+    "encryption-type",
+    "shared-secret",
     NULL
 };
 
 typedef struct
 {
-    struct       rist_flow *flow;
-    uint16_t     rtp_counter;
-    char         receiver_name[MAX_CNAME];
-    uint64_t     last_rtcp_tx;
-    vlc_thread_t ristthread;
-    vlc_thread_t senderthread;
-    size_t       i_packet_size;
-    bool         b_mtu_warning;
-    bool         b_ismulticast;
-    vlc_mutex_t  lock;
-    vlc_mutex_t  fd_lock;
-    block_t      *p_pktbuffer;
-    uint64_t     i_ticks_caching;
-    uint32_t     ssrc;
-    block_fifo_t *p_fifo;
-    /* stats variables */
-    uint64_t     i_last_stat;
-    uint32_t     i_retransmit_packets;
-    uint32_t     i_total_packets;
+    struct rist_client *client_ctx;
+    block_t            *p_pktbuffer;
+    int                gre_src_port;
+    int                gre_dst_port;
+    int                rist_profile;
+    bool               b_mtu_warning;
+    size_t             i_packet_size;
 } sout_access_out_sys_t;
 
-static struct rist_flow *rist_init_tx()
-{
-    struct rist_flow *flow = calloc(1, sizeof(struct
rist_flow));
-    if (!flow)
-        return NULL;
-
-    flow->reset = 1;
-    flow->buffer = calloc(RIST_QUEUE_SIZE, sizeof(struct
rtp_pkt));
-    if ( unlikely( flow->buffer == NULL ) )
-    {
-        free(flow);
-        return NULL;
-    }
-    flow->fd_out = -1;
-    flow->fd_rtcp = -1;
-    flow->fd_rtcp_m = -1;
-
-    return flow;
-}
-
-static struct rist_flow
*rist_udp_transmitter(sout_access_out_t *p_access, char
*psz_dst_server, 
-    int i_dst_port, bool b_ismulticast)
-{
-    struct rist_flow *flow;
-    flow = rist_init_tx();
-    if (!flow)
-        return NULL;
-
-    flow->fd_out = net_ConnectDgram(p_access,
psz_dst_server, i_dst_port, -1, IPPROTO_UDP );
-    if (flow->fd_out < 0)
-    {
-        msg_Err( p_access, "cannot open output socket" );
-        goto fail;
-    }
-
-    if (b_ismulticast) {
-        flow->fd_rtcp_m = net_OpenDgram(p_access,
psz_dst_server, i_dst_port + 1,
-            NULL, 0, IPPROTO_UDP);
-        if (flow->fd_rtcp_m < 0)
-        {
-            msg_Err( p_access, "cannot open multicast nack
socket" );
-            goto fail;
-        }
-    }
-
-    flow->fd_rtcp = net_ConnectDgram(p_access,
psz_dst_server, i_dst_port + 1, -1, IPPROTO_UDP );
-    if (flow->fd_rtcp < 0)
-    {
-        msg_Err( p_access, "cannot open nack socket" );
-        goto fail;
-    }
-
-    char *psz_streamname = NULL;
-    psz_streamname = var_InheritString( p_access,
SOUT_CFG_PREFIX "stream-name" );
-    if ( psz_streamname != NULL && psz_streamname[0] !=
'\0')
-    {
-        int name_length = snprintf(flow->cname, MAX_CNAME,
"%s", psz_streamname);
-        if (name_length >= MAX_CNAME)
-            flow->cname[MAX_CNAME-1] = 0;
-        free( psz_streamname );
-    }
-    else
-        populate_cname(flow->fd_rtcp, flow->cname);
-
-    msg_Info(p_access, "our cname is %s", flow->cname);
-
-    return flow;
-
-fail:
-    if (flow->fd_out != -1)
-        vlc_close(flow->fd_out);
-    if (flow->fd_rtcp != -1)
-        vlc_close(flow->fd_rtcp);
-    if (flow->fd_rtcp_m != -1)
-        vlc_close(flow->fd_rtcp_m);
-    free(flow->buffer);
-    free(flow);
-    return NULL;
-}
-
-static void rist_retransmit(sout_access_out_t *p_access,
struct rist_flow *flow, uint16_t seq)
-{
-    sout_access_out_sys_t *p_sys = p_access->p_sys;
-    struct rtp_pkt *pkt = &(flow->buffer[seq]);
-    if (pkt->buffer == NULL)
-    {
-        msg_Err(p_access, "RIST recovery: missing
requested packet %d, buffer not yet full", seq);
-        return;
-    }
-
-    /* Mark SSID for retransmission (change the last bit
of the ssrc to 1) */
-    pkt->buffer->p_buffer[11] |= (1 << 0);
-#ifdef TEST_PACKET_LOSS
-#   warning COMPILED WITH SELF INFLICTED PACKET LOSS
-        if ((flow->packets_count % 14) == 0) {
-            return;
-        }
-#endif
-    uint32_t rtp_age = flow->hi_timestamp - pkt->rtp_ts;
-    uint64_t age = ts_get_from_rtp(rtp_age)/1000;
-    if (flow->rtp_latency > 0 && rtp_age > flow-
>rtp_latency)
-    {
-        msg_Err(p_access, "   Not Sending Nack #%d, too
old (age %"PRId64" ms), current seq is:" \
-            " [%d]. Perhaps you should increase the
buffer-size ...", seq, age, flow->wi);
-    }
-    else
-    {
-        msg_Dbg(p_access, "   Sending Nack #%d (age
%"PRId64" ms), current seq is: [%d]", 
-            seq, age, flow->wi);
-        p_sys->i_retransmit_packets++;
-        vlc_mutex_lock( &p_sys->fd_lock );
-        if (rist_Write(flow->fd_out, pkt->buffer-
>p_buffer, pkt->buffer->i_buffer) 
-                != (ssize_t)pkt->buffer->i_buffer) {
-            msg_Err(p_access, "Error sending retransmitted
packet after 2 tries ...");
-        }
-
-        vlc_mutex_unlock( &p_sys->fd_lock );
-    }
-}
-
-static void process_nack(sout_access_out_t *p_access,
uint8_t  ptype, uint16_t nrecords, 
-    struct rist_flow *flow, uint8_t *pkt)
-{
-    sout_access_out_sys_t *p_sys = p_access->p_sys;
-    int i,j;
-
-    /*msg_Info(p_access, "   Nack (BbRR), %d record(s),
Window: [%d:%d-->%d]", nrecords, 
-        flow->ri, flow->wi, flow->wi-flow->ri);*/
-
-    if (ptype == RTCP_PT_RTPFR)
-    {
-        uint8_t pi_ssrc[4];
-        rtcp_fb_get_ssrc_media_src(pkt, pi_ssrc);
-        if (memcmp(pi_ssrc, "RIST", 4) != 0)
-        {
-            msg_Info(p_access, "   Ignoring Nack with name
%s", pi_ssrc);
-            return; /* Ignore app-type not RIST */
-        }
-
-        for (i = 0; i < (nrecords-2); i++) {
-            uint16_t missing;
-            uint16_t additional;
-            uint8_t *rtp_nack_record = (pkt + 12 + i * 4);
-            missing =
rtcp_fb_nack_get_range_start(rtp_nack_record);
-            additional =
rtcp_fb_nack_get_range_extra(rtp_nack_record);
-            /*msg_Info(p_access, "   Nack (Range), %d,
current seq is: [%d]", missing, flow->wi);*/
-            vlc_mutex_lock( &p_sys->lock );
-            rist_retransmit(p_access, flow, missing);
-            for (j = 0; j < additional; j++) {
-                rist_retransmit(p_access, flow, missing +
j + 1);
-            }
-            vlc_mutex_unlock( &p_sys->lock );
-        }
-    }
-    else if (ptype == RTCP_PT_RTPFB)
-    {
-        for (i = 0; i < (nrecords-2); i++) {
-            uint16_t missing;
-            uint16_t bitmask;
-            uint8_t *rtp_nack_record = (pkt + 12 + i * 4);
-            missing =
rtcp_fb_nack_get_packet_id(rtp_nack_record);
-            bitmask =
rtcp_fb_nack_get_bitmask_lost(rtp_nack_record);
-            /*msg_Info(p_access, "  Nack (Bitmask), %d,
current seq is: [%d]", missing, flow->wi);*/
-            vlc_mutex_lock( &p_sys->lock );
-            rist_retransmit(p_access, flow, missing);
-            for (j = 0; j < 16; j++) {
-                if ((bitmask & (1 << j)) == (1 << j)) {
-                    rist_retransmit(p_access, flow,
missing + j + 1);
-                }
-            }
-            vlc_mutex_unlock( &p_sys->lock );
-        }
-    }
-    else
-    {
-        msg_Err(p_access, "   !!! Wrong feedback. Ptype is
%02x!=%02x, FMT: %02x", ptype, 
-            RTCP_PT_RTPFR, rtcp_fb_get_fmt(pkt));
-    }
-}
-
-static void rist_rtcp_recv(sout_access_out_t *p_access,
struct rist_flow *flow, uint8_t *pkt_raw, 
-    size_t len)
-{
-    sout_access_out_sys_t *p_sys = p_access->p_sys;
-    uint8_t *pkt = pkt_raw;
-    uint8_t  ptype;
-    uint16_t processed_bytes = 0;
-    uint16_t records;
-
-    while (processed_bytes < len) {
-        pkt = pkt_raw + processed_bytes;
-        /* safety checks */
-        uint16_t bytes_left = len - processed_bytes + 1;
-        if ( bytes_left < 4 )
-        {
-            /* we must have at least 4 bytes */
-            msg_Err(p_access, "Rist rtcp packet must have
at least 4 bytes, we have %d", 
-                bytes_left);
-            return; 
-        }
-        else if (!rtp_check_hdr(pkt))
-        {
-            /* check for a valid rtp header */
-            msg_Err(p_access, "Malformed feedback packet
starting with %02x, ignoring.", pkt[0]);
-            return;
-        }
-
-        ptype =  rtcp_get_pt(pkt);
-        records = rtcp_get_length(pkt);
-        uint16_t bytes = (uint16_t)(4 * (1 + records));
-        if (bytes > bytes_left)
-        {
-            /* check for a sane number of bytes */
-            msg_Err(p_access, "Malformed feedback packet,
wrong len %d, expecting %u bytes in the" \
-                " packet, got a buffer of %u bytes. ptype
= %d", rtcp_get_length(pkt), bytes, 
-                bytes_left, ptype);
-            return;
-        }
-
-        switch(ptype) {
-            case RTCP_PT_RTPFR:
-            case RTCP_PT_RTPFB:
-                process_nack(p_access, ptype, records,
flow, pkt);
-                break;
-
-            case RTCP_PT_RR:
-                /*
-                if (p_sys->b_ismulticast == false)
-                    process_rr(f, pkt, len);
-                */
-                break;
-
-            case RTCP_PT_SDES:
-                {
-                    if (p_sys->b_ismulticast == false)
-                    {
-                        int8_t name_length =
rtcp_sdes_get_name_length(pkt);
-                        if (name_length > bytes_left)
-                        {
-                            /* check for a sane number of
bytes */
-                            msg_Err(p_access, "Malformed
SDES packet, wrong cname len %u, got a " \
-                                "buffer of %u bytes.",
name_length, bytes_left);
-                            return;
-                        }
-                        if (memcmp(pkt + RTCP_SDES_SIZE,
p_sys->receiver_name, name_length) != 0)
-                        {
-                            memcpy(p_sys->receiver_name,
pkt + RTCP_SDES_SIZE, name_length);
-                            msg_Info(p_access, "Receiver
name: %s", p_sys->receiver_name);
-                        }
-                    }
-                }
-                break;
-
-            case RTCP_PT_SR:
-                break;
-
-            default:
-                msg_Err(p_access, "   Unrecognized RTCP
packet with PTYPE=%02x!!", ptype);
-        }
-        processed_bytes += bytes;
-    }
-}
-
-static void rist_rtcp_send(sout_access_out_t *p_access)
-{
-    sout_access_out_sys_t *p_sys = p_access->p_sys;
-    struct rist_flow *flow = p_sys->flow;
-    uint8_t rtcp_buf[RTCP_SR_SIZE + RTCP_SDES_SIZE +
MAX_CNAME] = { };
-    struct timeval tv;
-    int r;
-    uint64_t fractions;
-    uint16_t namelen = strlen(flow->cname) + 1;
-    gettimeofday(&tv, NULL);
-
-    /* Populate SR for sender report */
-    uint8_t *p_sr = rtcp_buf;
-    rtp_set_hdr(p_sr);
-    rtcp_sr_set_pt(p_sr);
-    rtcp_sr_set_length(p_sr, 6);
-    rtcp_fb_set_int_ssrc_pkt_sender(p_sr, p_sys->ssrc);
-    rtcp_sr_set_ntp_time_msw(p_sr, tv.tv_sec +
SEVENTY_YEARS_OFFSET);
-    fractions = (uint64_t)tv.tv_usec;
-    fractions <<= 32ULL;
-    fractions /= 1000000ULL;
-    rtcp_sr_set_ntp_time_lsw(p_sr, (uint32_t)fractions);
-    rtcp_sr_set_rtp_time(p_sr,
rtp_get_ts(vlc_tick_now()));
-    vlc_mutex_lock( &p_sys->lock );
-    rtcp_sr_set_packet_count(p_sr, flow->packets_count);
-    rtcp_sr_set_octet_count(p_sr, flow->bytes_count);
-    vlc_mutex_unlock( &p_sys->lock );
-
-    /* Populate SDES for sender description */
-    uint8_t *p_sdes = (rtcp_buf + RTCP_SR_SIZE);
-    /* we need to make sure it is a multiple of 4, pad if
necessary */
-    if ((namelen - 2) & 0x3)
-        namelen = ((((namelen - 2) >> 2) + 1) << 2) + 2;
-    rtp_set_hdr(p_sdes);
-    rtp_set_cc(p_sdes, 1); /* Actually it is source count
in this case */
-    rtcp_sdes_set_pt(p_sdes);
-    rtcp_set_length(p_sdes, (namelen >> 2) + 2);
-    rtcp_sdes_set_cname(p_sdes, 1);
-    rtcp_sdes_set_name_length(p_sdes, strlen(flow-
>cname));
-    p_sdes += RTCP_SDES_SIZE;
-    strlcpy((char *)p_sdes, flow->cname, namelen);
-
-    /* Send the rtcp message */
-    r = send(flow->fd_rtcp, rtcp_buf, RTCP_SR_SIZE +
RTCP_SDES_SIZE + namelen, 0);
-    (void)r;
-}
-
-static void *rist_thread(void *data)
-{
-    sout_access_out_t *p_access = data;
-    sout_access_out_sys_t *p_sys = p_access->p_sys;
-    uint64_t now;
-    uint8_t pkt[RTP_PKT_SIZE];
-    struct pollfd pfd[2];
-    int ret;
-    ssize_t r;
-
-    int poll_sockets = 1;
-    pfd[0].fd = p_sys->flow->fd_rtcp;
-    pfd[0].events = POLLIN;
-    if (p_sys->b_ismulticast)
-    {
-        pfd[1].fd = p_sys->flow->fd_rtcp_m;
-        pfd[1].events = POLLIN;
-        poll_sockets++;
-    }
-
-    for (;;) {
-        ret = poll(pfd, poll_sockets, RTCP_INTERVAL >> 1);
-        int canc = vlc_savecancel();
-        if (ret > 0)
-        {
-            if (pfd[0].revents & POLLIN)
-            {
-                r = rist_Read(p_sys->flow->fd_rtcp, pkt,
RTP_PKT_SIZE);
-                if (r == RTP_PKT_SIZE) {
-                    msg_Err(p_access, "Rist RTCP messsage
is too big (%zd bytes) and was probably " \
-                        "cut, please keep it under %d
bytes", r, RTP_PKT_SIZE);
-                }
-                if (unlikely(r == -1)) {
-                    msg_Err(p_access, "socket %d error:
%s\n", p_sys->flow->fd_rtcp, 
-                        gai_strerror(errno));
-                }
-                else {
-                    rist_rtcp_recv(p_access, p_sys->flow,
pkt, r);
-                }
-            }
-            if (p_sys->b_ismulticast && (pfd[1].revents &
POLLIN))
-            {
-                r = rist_Read(p_sys->flow->fd_rtcp_m, pkt,
RTP_PKT_SIZE);
-                if (r == RTP_PKT_SIZE) {
-                    msg_Err(p_access, "Rist RTCP messsage
is too big (%zd bytes) and was " \
-                        "probably cut, please keep it
under %d bytes", r, RTP_PKT_SIZE);
-                }
-                if (unlikely(r == -1)) {
-                    msg_Err(p_access, "mcast socket %d
error: %s\n", p_sys->flow->fd_rtcp_m,
-                        gai_strerror(errno));
-                }
-                else {
-                    rist_rtcp_recv(p_access, p_sys->flow,
pkt, r);
-                }
-            }
-        }
-
-        /* And, in any case: */
-        now = vlc_tick_now();
-        if ((now - p_sys->last_rtcp_tx) >
VLC_TICK_FROM_MS(RTCP_INTERVAL))
-        {
-            rist_rtcp_send(p_access);
-            p_sys->last_rtcp_tx = now;
-        }
-        vlc_restorecancel (canc);
-    }
-
-    return NULL;
-}
-
-/*********************************************************
*******************
- * RTP send
-
***********************************************************
*****************/
-static void* ThreadSend( void *data )
-{
-    sout_access_out_t *p_access = data;
-    sout_access_out_sys_t *p_sys = p_access->p_sys;
-    vlc_tick_t i_caching = p_sys->i_ticks_caching;
-    struct rist_flow *flow = p_sys->flow;
-
-    for (;;)
-    {
-        ssize_t len = 0;
-        uint16_t seq = 0;
-        uint32_t pkt_ts = 0;
-        block_t *out = block_FifoGet( p_sys->p_fifo );
-
-        block_cleanup_push( out );
-        vlc_tick_wait (out->i_dts + i_caching);
-        vlc_cleanup_pop();
-
-        len = out->i_buffer;
-        int canc = vlc_savecancel();
-
-        seq = rtp_get_seqnum(out->p_buffer);
-        pkt_ts = rtp_get_timestamp(out->p_buffer);
-
-        vlc_mutex_lock( &p_sys->fd_lock );
-#ifdef TEST_PACKET_LOSS
-#   warning COMPILED WITH SELF INFLICTED PACKET LOSS
-        if ((seq % 14) == 0) {
-            /*msg_Err(p_access, "Dropped packet with seq
number %d ...", seq);*/
-        }
-        else
-        {
-            if (rist_Write(flow->fd_out, out->p_buffer,
len) != len) {
-                msg_Err(p_access, "Error sending data
packet after 2 tries ...");
-            }
-        }
-#else
-        if (rist_Write(flow->fd_out, out->p_buffer, len)
!= len) {
-            msg_Err(p_access, "Error sending data packet
after 2 tries ...");
-        }
-#endif
-        vlc_mutex_unlock( &p_sys->fd_lock );
-
-        /* Insert Into Queue */
-        vlc_mutex_lock( &p_sys->lock );
-        /* Always replace the existing one with the new
one */
-        struct rtp_pkt *pkt;
-        pkt = &(flow->buffer[seq]);
-        if (pkt->buffer)
-        {
-            block_Release(pkt->buffer);
-            pkt->buffer = NULL;
-        }
-        pkt->rtp_ts = pkt_ts;
-        pkt->buffer = out;
-
-        if (flow->reset == 1)
-        {
-            msg_Info(p_access, "Traffic detected");
-            /* First packet in the queue */
-            flow->reset = 0;
-        }
-        flow->wi = seq;
-        flow->hi_timestamp = pkt_ts;
-        /* Stats for RTCP feedback packets */
-        flow->packets_count++;
-        flow->bytes_count += len;
-        flow->last_out = seq;
-        vlc_mutex_unlock( &p_sys->lock );
-
-        /* We print out the stats once per second */
-        uint64_t now = vlc_tick_now();
-        uint64_t interval = (now - p_sys->i_last_stat);
-        if ( interval > VLC_TICK_FROM_MS(STATS_INTERVAL) )
-        {
-            if (p_sys->i_retransmit_packets > 0)
-            {
-                float quality = 100;
-                if (p_sys->i_total_packets > 0)
-                    quality = (float)100 -
(float)100*(float)(p_sys->i_retransmit_packets)
-                        /(float)p_sys->i_total_packets;
-                msg_Info(p_access, "STATS: Total %u,
Retransmitted %u, Link Quality %.2f%%", 
-                    p_sys->i_total_packets, p_sys-
>i_retransmit_packets, quality);
-            }
-            p_sys->i_last_stat = now;
-            p_sys->i_retransmit_packets = 0;
-            p_sys->i_total_packets = 0;
-        }
-        p_sys->i_total_packets++;
-
-        vlc_restorecancel (canc);
-    }
-    return NULL;
-}
-
-static void SendtoFIFO( sout_access_out_t *p_access,
block_t *buffer )
+static uint64_t i_dts_to_ntp64( vlc_tick_t i_dts )
 {
-    sout_access_out_sys_t *p_sys = p_access->p_sys;
-    uint16_t seq = p_sys->rtp_counter++;
-
-    /* Set fresh rtp header data */
-    uint8_t *bufhdr = buffer->p_buffer;
-    rtp_set_hdr(bufhdr);
-    rtp_set_type(bufhdr, MPEG_II_TRANSPORT_STREAM);
-    rtp_set_seqnum(bufhdr, seq);
-    rtp_set_int_ssrc(bufhdr, p_sys->ssrc);
-    uint32_t pkt_ts = rtp_get_ts(buffer->i_dts);
-    rtp_set_timestamp(bufhdr, pkt_ts);
-
-    block_t *pkt = block_Duplicate(buffer);
-    block_FifoPut( p_sys->p_fifo, pkt );
+    lldiv_t d = lldiv (i_dts, CLOCK_FREQ);
+    struct timespec ts = { d.quot, NS_FROM_VLC_TICK( d.rem
) };
+    // Convert nanoseconds to 32-bits fraction (232
picosecond units)
+    uint64_t t = (uint64_t)(ts.tv_nsec) << 32;
+    t /= 1000000000;
+    // There is 70 years (incl. 17 leap ones) offset to
the Unix Epoch.
+    // No leap seconds during that period since they were
not invented yet.
+    t |= ((70LL * 365 + 17) * 24 * 60 * 60 + ts.tv_sec) <<
32;
+    return t; // nanoseconds (technically, 232.831
picosecond units)
 }
 
 static ssize_t Write( sout_access_out_t *p_access, block_t
*p_buffer )
@@ -616,8 +108,9 @@ static ssize_t Write( sout_access_out_t
*p_access, block_t *p_buffer )
         /* Temp buffer is already too large, flush */
         if( p_sys->p_pktbuffer->i_buffer + p_buffer-
>i_buffer > p_sys->i_packet_size )
         {
-            SendtoFIFO(p_access, p_sys->p_pktbuffer);
-            p_sys->p_pktbuffer->i_buffer =
RTP_HEADER_SIZE;
+            rist_client_write_timed(p_sys->client_ctx,
p_sys->p_pktbuffer->p_buffer, p_sys->p_pktbuffer->i_buffer,
+                                    p_sys->gre_src_port,
p_sys->gre_dst_port, i_dts_to_ntp64(p_sys->p_pktbuffer-
>i_dts));
+            p_sys->p_pktbuffer->i_buffer = 0;
         }
 
         i_len += p_buffer->i_buffer;
@@ -629,7 +122,7 @@ static ssize_t Write( sout_access_out_t
*p_access, block_t *p_buffer )
 
             i_block_split++;
 
-            if( p_sys->p_pktbuffer->i_buffer ==
RTP_HEADER_SIZE )
+            if( p_sys->p_pktbuffer->i_buffer == 0 )
             {
                 p_sys->p_pktbuffer->i_dts = p_buffer-
>i_dts;
             }
@@ -646,8 +139,9 @@ static ssize_t Write( sout_access_out_t
*p_access, block_t *p_buffer )
              *  larger than the packet-size because we
need to continue the inner loop */
             if( p_sys->p_pktbuffer->i_buffer == p_sys-
>i_packet_size || i_block_split > 1 )
             {
-                SendtoFIFO(p_access, p_sys->p_pktbuffer);
-                p_sys->p_pktbuffer->i_buffer =
RTP_HEADER_SIZE;
+                rist_client_write_timed(p_sys->client_ctx, 
p_sys->p_pktbuffer->p_buffer, p_sys->p_pktbuffer->i_buffer,
+                                        p_sys-
>gre_src_port, p_sys->gre_dst_port, i_dts_to_ntp64(p_sys-
>p_pktbuffer->i_dts));
+                p_sys->p_pktbuffer->i_buffer = 0;
             }
 
         }
@@ -684,54 +178,16 @@ static int Control( sout_access_out_t
*p_access, int i_query, va_list args )
     return i_ret;
 }
 
-static void Clean( sout_access_out_t *p_access )
-{
-    sout_access_out_sys_t *p_sys = p_access->p_sys;
-
-    if( likely(p_sys->p_fifo != NULL) )
-        block_FifoRelease( p_sys->p_fifo );
-
-    if ( p_sys->flow )
-    {
-        if (p_sys->flow->fd_out >= 0) {
-            net_Close (p_sys->flow->fd_out);
-        }
-        if (p_sys->flow->fd_rtcp >= 0) {
-            net_Close (p_sys->flow->fd_rtcp);
-        }
-        if (p_sys->flow->fd_rtcp_m >= 0) {
-            net_Close (p_sys->flow->fd_rtcp_m);
-        }
-        for (int i=0; i<RIST_QUEUE_SIZE; i++) {
-            struct rtp_pkt *pkt = &(p_sys->flow-
>buffer[i]);
-            if (pkt->buffer)
-            {
-                block_Release(pkt->buffer);
-                pkt->buffer = NULL;
-            }
-        }
-        free(p_sys->flow->buffer);
-        free(p_sys->flow);
-    }
-
-    vlc_mutex_destroy( &p_sys->lock );
-    vlc_mutex_destroy( &p_sys->fd_lock );
-    if (p_sys->p_pktbuffer)
-        block_Release(p_sys->p_pktbuffer);
-}
-
 static void Close( vlc_object_t * p_this )
 {
     sout_access_out_t     *p_access =
(sout_access_out_t*)p_this;
     sout_access_out_sys_t *p_sys = p_access->p_sys;
 
-    vlc_cancel(p_sys->ristthread);
-    vlc_cancel(p_sys->senderthread);
-
-    vlc_join(p_sys->ristthread, NULL);
-    vlc_join(p_sys->senderthread, NULL);
+    if (p_sys->p_pktbuffer)
+        block_Release(p_sys->p_pktbuffer);
 
-    Clean( p_access );
+    rist_client_destroy(p_sys->client_ctx);
+    p_sys->client_ctx = NULL;
 }
 
 static int Open( vlc_object_t *p_this )
@@ -754,105 +210,139 @@ static int Open( vlc_object_t
*p_this )
     if( unlikely( p_sys == NULL ) )
         return VLC_ENOMEM;
 
-    int i_dst_port = RIST_DEFAULT_PORT;
-    char *psz_dst_addr;
-    char *psz_parser = psz_dst_addr = strdup( p_access-
>psz_path );
-    if( !psz_dst_addr )
+    p_sys->gre_src_port = var_InheritInteger(p_access,
SOUT_CFG_PREFIX "gre-src-port");
+    p_sys->gre_dst_port = var_InheritInteger(p_access,
SOUT_CFG_PREFIX "gre-dst-port");
+    if (p_sys->gre_dst_port % 2 != 0) {
+        msg_Err( p_access, "GRE destination port must be
an even number." );
         return VLC_ENOMEM;
-
-    if ( psz_parser[0] == '[' )
-        psz_parser = strchr( psz_parser, ']' );
-
-    psz_parser = strchr( psz_parser ? psz_parser :
psz_dst_addr, ':' );
-    if ( psz_parser != NULL )
-    {
-        *psz_parser++ = '\0';
-        i_dst_port = atoi( psz_parser );
     }
 
-    vlc_mutex_init( &p_sys->lock );
-    vlc_mutex_init( &p_sys->fd_lock );
+    p_sys->i_packet_size = var_InheritInteger(p_access,
SOUT_CFG_PREFIX "packet-size" );
+    p_sys->p_pktbuffer = block_Alloc( p_sys->i_packet_size 
);
+    if( unlikely(p_sys->p_pktbuffer == NULL) )
+        goto failed;
 
-    msg_Info(p_access, "Connecting RIST output to %s:%d
and %s:%d", psz_dst_addr, i_dst_port, 
-        psz_dst_addr, i_dst_port+1);
-    p_sys->b_ismulticast =
is_multicast_address(psz_dst_addr);
-    struct rist_flow *flow =
rist_udp_transmitter(p_access, psz_dst_addr, i_dst_port,
-        p_sys->b_ismulticast);
-    free (psz_dst_addr);
-    if (!flow)
+    p_sys->rist_profile = var_InheritInteger(p_access,
SOUT_CFG_PREFIX "profile");
+    if (rist_client_create(&p_sys->client_ctx, p_sys-
>rist_profile) != 0) {
+        msg_Err( p_access, "Could not create rist client
context\n");
         goto failed;
+    }
 
-    p_sys->flow = flow;
-    flow->latency = var_InheritInteger(p_access,
SOUT_CFG_PREFIX "buffer-size");
-    flow->rtp_latency = rtp_get_ts(VLC_TICK_FROM_MS(flow-
>latency));
-    p_sys->ssrc = var_InheritInteger(p_access,
SOUT_CFG_PREFIX "ssrc");
-    if (p_sys->ssrc == 0) {
-        vlc_rand_bytes(&p_sys->ssrc, 4);
+    char *psz_streamname = NULL;
+    psz_streamname = var_InheritString( p_access,
SOUT_CFG_PREFIX "stream-name" );
+    if ( psz_streamname != NULL && psz_streamname[0] !=
'\0')
+    {
+        if (rist_client_set_cname(p_sys->client_ctx,
psz_streamname, strlen(psz_streamname)) != 0) {
+            msg_Err( p_access, "Could not set the
cname\n");
+            goto failed;
+        }
+        free( psz_streamname );
     }
-    /* Last bit of ssrc must be 0 for normal data and 1
for retries */
-    p_sys->ssrc &= ~(1 << 0);
 
-    msg_Info(p_access, "SSRC: 0x%08X", p_sys->ssrc);
-    p_sys->i_ticks_caching =
VLC_TICK_FROM_MS(var_InheritInteger( p_access, 
-        SOUT_CFG_PREFIX "caching"));
-    p_sys->i_packet_size = var_InheritInteger(p_access,
SOUT_CFG_PREFIX "packet-size" );
-    p_sys->p_fifo = block_FifoNew();
-    if( unlikely(p_sys->p_fifo == NULL) )
-        goto failed;
-    p_sys->p_pktbuffer = block_Alloc( p_sys->i_packet_size 
);
-    if( unlikely(p_sys->p_pktbuffer == NULL) )
+    uint64_t now;
+    struct timeval time;
+    gettimeofday(&time, NULL);
+    now = time.tv_sec * 1000000;
+    now += time.tv_usec;
+    uint32_t adv_flow_id = (uint32_t)(now >> 16);
+    // It must me an even number
+    adv_flow_id &= ~(1UL << 0);
+
+    if(rist_client_init(p_sys->client_ctx, adv_flow_id,
RIST_LOG_WARN, NULL, NULL, NULL) < 0) {
+        msg_Err( p_access, "Could not initialize rist
client\n");
         goto failed;
+    }
 
-    p_sys->p_pktbuffer->i_buffer = RTP_HEADER_SIZE;
-
-    p_access->p_sys = p_sys;
+    int i_encryption_type = var_InheritInteger(p_access,
SOUT_CFG_PREFIX "encryption-type");
+    char *psz_shared_secret = NULL;
+    psz_shared_secret = var_InheritString( p_access,
SOUT_CFG_PREFIX "stream-name" );
+    if (psz_shared_secret != NULL && psz_shared_secret[0]
!= '\0') {
+        if (i_encryption_type) {
+            int keysize =  i_encryption_type == 1 ? 128 :
256;
+            if (rist_client_encrypt_enable(p_sys-
>client_ctx, psz_shared_secret, keysize) == -1) {
+                msg_Err( p_access, "Could not enable
encryption\n");
+                free(psz_shared_secret);
+                goto failed;
+            }
+        }
+        free(psz_shared_secret);
+    }
 
-    if( vlc_clone(&p_sys->senderthread, ThreadSend,
p_access, VLC_THREAD_PRIORITY_HIGHEST ) )
-    {
-        msg_Err(p_access, "Failed to create sender
thread.");
+    const struct rist_peer_config peer_config = {
+        .address = p_access->psz_path,
+        .recovery_mode = RIST_RECOVERY_MODE_TIME,
+        .recovery_maxbitrate =
var_InheritInteger(p_access, SOUT_CFG_PREFIX "max-
bitrate"),
+        .recovery_maxbitrate_return = 0,
+        .recovery_length_min =
var_InheritInteger(p_access, SOUT_CFG_PREFIX "buffer-
size"),
+        .recovery_length_max =
var_InheritInteger(p_access, SOUT_CFG_PREFIX "buffer-
size"),
+        .recover_reorder_buffer = 70,
+        .recovery_rtt_min = 50,
+        .recovery_rtt_max = 500,
+        .weight = 5,
+        .bufferbloat_mode = RIST_BUFFER_BLOAT_MODE_NORMAL,
+        .bufferbloat_limit = 7,
+        .bufferbloat_hard_limit = 20
+    };
+
+    struct rist_peer *peer;
+    if (rist_client_add_peer(p_sys->client_ctx,
&peer_config, &peer) == -1) {
+        msg_Err( p_access, "Could not add peer connector
to client\n");
         goto failed;
     }
 
-    if (vlc_clone(&p_sys->ristthread, rist_thread,
p_access, VLC_THREAD_PRIORITY_INPUT))
-    {
-        msg_Err(p_access, "Failed to create worker
thread.");
-        vlc_cancel(p_sys->senderthread);
-        vlc_join(p_sys->senderthread, NULL);
+    if (rist_client_start(p_sys->client_ctx) == -1) {
+        msg_Err( p_access, "Could not start rist
client\n");
         goto failed;
     }
 
+    p_access->p_sys = p_sys;
     p_access->pf_write = Write;
     p_access->pf_control = Control;
 
     return VLC_SUCCESS;
 
 failed:
-    Clean( p_access );
+    rist_client_destroy(p_sys->client_ctx);
+    p_sys->client_ctx = NULL;
     return VLC_EGENERIC;
 }
 
-#define CACHING_TEXT N_("RIST data output caching size
(ms)")
-#define CACHING_LONGTEXT N_( \
-    "Having this cache will guarantee that the packets
going out are " \
-    "delivered at a spacing determined by the chain
timestamps thus ensuring " \
-    "a near jitter free output. Be aware that this setting
will also add to " \
-    "the overall latency of the stream." )
-
 #define BUFFER_TEXT N_("RIST retry-buffer queue size
(ms)")
 #define BUFFER_LONGTEXT N_( \
-    "This must match the buffer size (latency) configured
on the server side. If you " \
-    "are not sure, leave the default of 0 which will set
it the maximum " \
-    "value and will use about 100MB of RAM" )
+    "This must match the buffer size (latency) configured
on the receiver side. If you " \
+    "are not sure, leave it blank and it will use 1000ms"
)
 
-#define SSRC_TEXT N_("SSRC used in RTP output (default is
random, i.e. 0)")
-#define SSRC_LONGTEXT N_( \
-    "Use this setting to specify a known SSRC for the RTP
header. This is only useful " \
-    "if your receiver acts on it. When using VLC as
receiver, it is not." )
+#define MAX_BITRATE_TEXT N_("Max bitrate in Kbps")
+#define MAX_BITRATE_LONGTEXT N_( \
+    "Use this value to guarantee that data+retries bitrate
never exceeds your pipe size. " \
+    "Default value is 100000 Kbps (100 Mbps)" )
 
 #define NAME_TEXT N_("Stream name")
 #define NAME_LONGTEXT N_( \
     "This Stream name will be sent to the receiver using
the rist RTCP channel" )
 
+#define PROFILE_TEXT N_("Rist Profile")
+#define PROFILE_LONGTEXT N_( \
+    "Select the rist profile to use, 0 is simple, 1 is
main. Default is main (1)" )
+
+#define SRC_PORT_TEXT N_("GRE Source Port")
+#define SRC_PORT_LONGTEXT N_( \
+    "Source port to be used inside the reduced-mode of the
main profile" )
+
+#define DST_PORT_TEXT N_("GRE Destination Port")
+#define DST_PORT_LONGTEXT N_( \
+    "Destination port to be used inside the reduced-mode
of the main profile" )
+
+#define ENCRYPTION_TYPE_TEXT N_("Encryption Type")
+#define ENCRYPTION_TYPE_LONGTEXT N_( \
+    "Type of encryption to use: 0 = disabled, 1 = AES 128,
2 = AES 256, default is " \
+    "disabled" )
+
+#define SHARED_SECRET_TEXT N_("Shared Secret")
+#define SHARED_SECRET_LONGTEXT N_( \
+    "This shared secret is a passphare shared between
sender and receiver. The AES key " \
+    "is derived from it" )
+
 /* Module descriptor */
 vlc_module_begin()
 
@@ -863,13 +353,20 @@ vlc_module_begin()
 
     add_integer( SOUT_CFG_PREFIX "packet-size",
RIST_TARGET_PACKET_SIZE,
             N_("RIST target packet size (bytes)"), NULL,
true )
-    add_integer( SOUT_CFG_PREFIX "caching",
DEFAULT_CACHING_DELAY,
-            CACHING_TEXT, CACHING_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "buffer-size",
DEFAULT_BUFFER_SIZE,
             BUFFER_TEXT, BUFFER_LONGTEXT, true )
-    add_integer( SOUT_CFG_PREFIX "ssrc", 0,
-            SSRC_TEXT, SSRC_LONGTEXT, true )
+    add_integer( SOUT_CFG_PREFIX "max-bitrate",
DEFAULT_MAX_BITRATE,
+            MAX_BITRATE_TEXT, MAX_BITRATE_LONGTEXT, true )
+    add_integer( SOUT_CFG_PREFIX "profile",
RIST_DEFAULT_PROFILE,
+            PROFILE_TEXT, PROFILE_LONGTEXT, true )
+    add_integer( SOUT_CFG_PREFIX "gre-src-port",
RIST_DEFAULT_SRC_PORT,
+            SRC_PORT_TEXT, SRC_PORT_LONGTEXT, true )
+    add_integer( SOUT_CFG_PREFIX "gre-dst-port",
RIST_DEFAULT_DST_PORT,
+            DST_PORT_TEXT, DST_PORT_LONGTEXT, true )
+    add_integer( SOUT_CFG_PREFIX "encryption-type", 0,
+            ENCRYPTION_TYPE_TEXT,
ENCRYPTION_TYPE_LONGTEXT, true )
     add_string( SOUT_CFG_PREFIX "stream-name", NULL,
NAME_TEXT, NAME_LONGTEXT, true )
+    add_string( SOUT_CFG_PREFIX "shared-secret", NULL,
SHARED_SECRET_TEXT, SHARED_SECRET_LONGTEXT, true )
 
     set_capability( "sout access", 0 )
     add_shortcut( "rist", "tr06" )
-- 
2.17.1


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200322/044ae09d/attachment.html>


More information about the vlc-devel mailing list