[vlc-devel] New attempt at librist plugins

Romain Vimont rom1v at videolabs.io
Wed Jun 10 17:22:06 CEST 2020


Hi,

You posted this message as a reply to an existing thread (probably
because you clicked on "reply" in your mail editor).

Please post a new mail to vlc-devel at videolan.org directly.

Regards

On Wed, Jun 10, 2020 at 11:13:48AM -0400, Sergio M. Ammirata, Ph.D. wrote:
> Here is a new version of the patch for inclusion of librist
> based plugins.
> 
> The library has been cleanup up significantly since the
> last time these were submitted.
> 
> Besides the attached patch, the source code can be reviewed
> here:
> 
> Library: https://code.videolan.org/rist/librist
> 
> VLC tree with the librist commit:  
> https://code.videolan.org/rist/vlc/-/commits/librist-dev
> 
> Regards,
> Sergio Ammirata

> From 34a580c2b65819980df05f168ad93bb2888fe414 Mon Sep 17 00:00:00 2001
> From: Sergio Ammirata <sergio at ammirata.net>
> Date: Wed, 10 Jun 2020 11:01:56 -0400
> Subject: [PATCH 1/1] Add libRIST based access and access_output modules. These
>  support the new RIST main profile as well as the RIST simple profile.
> 
> ---
>  configure.ac                      |   5 +
>  modules/access/Makefile.am        |  18 +-
>  modules/access/librist.c          | 446 ++++++++++++++++++++++++++++
>  modules/access/librist.h          |  95 ++++++
>  modules/access_output/Makefile.am |  16 +-
>  modules/access_output/librist.c   | 473 ++++++++++++++++++++++++++++++
>  6 files changed, 1043 insertions(+), 10 deletions(-)
>  create mode 100644 modules/access/librist.c
>  create mode 100644 modules/access/librist.h
>  create mode 100644 modules/access_output/librist.c
> 
> diff --git a/configure.ac b/configure.ac
> index 399d0695be..12151d2288 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -4246,6 +4246,11 @@ dnl  SRT plugin
>  dnl
>  PKG_ENABLE_MODULES_VLC([SRT], [access_srt access_output_srt], [srt >= 1.3.0], [SRT input/output plugin], [auto], [], [], [-DENABLE_SRT])
>  
> +dnl
> +dnl  libRIST plugin
> +dnl
> +PKG_ENABLE_MODULES_VLC([LIBRIST], [], [librist], [RIST input/output plugin (default auto)])
> +
>  EXTEND_HELP_STRING([Visualisations and Video filter plugins:])
>  dnl
>  dnl  goom visualization plugin
> diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
> index 9cd3098fc2..c91a796bfd 100644
> --- a/modules/access/Makefile.am
> +++ b/modules/access/Makefile.am
> @@ -446,11 +446,19 @@ libaccess_srt_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(accessdir)'
>  access_LTLIBRARIES += $(LTLIBaccess_srt)
>  EXTRA_LTLIBRARIES += libaccess_srt_plugin.la
>  
> -### RIST ###
> +### RIST SIMPLE PROFILE ###
>  
> -librist_plugin_la_SOURCES = access/rist.c access/rist.h
> -librist_plugin_la_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS)
> -librist_plugin_la_LIBADD = $(SOCKET_LIBS)
> +libristsimple_plugin_la_SOURCES = access/rist.c access/rist.h
> +libristsimple_plugin_la_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS)
> +libristsimple_plugin_la_LIBADD = $(SOCKET_LIBS)
>  if HAVE_BITSTREAM
> -access_LTLIBRARIES += librist_plugin.la
> +access_LTLIBRARIES += libristsimple_plugin.la
>  endif
> +
> +### libRIST ###
> +
> +librist_plugin_la_SOURCES = access/librist.c
> +librist_plugin_la_CFLAGS = $(AM_CFLAGS)
> +librist_plugin_la_LIBADD = $(LIBRIST_LIBS) $(SOCKET_LIBS) $(LIBPTHREAD)
> +librist_plugin_la_LDFLAGS = $(AM_LDFLAGS)
> +access_LTLIBRARIES += librist_plugin.la
> diff --git a/modules/access/librist.c b/modules/access/librist.c
> new file mode 100644
> index 0000000000..a2e2f85033
> --- /dev/null
> +++ b/modules/access/librist.c
> @@ -0,0 +1,446 @@
> +/*****************************************************************************
> + * rist.c: RIST (Reliable Internet Stream Transport) input module
> + *****************************************************************************
> + * Copyright (C) 2020, SipRadius LLC
> + *
> + * Authors: Sergio Ammirata <sergio at ammirata.net>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by
> + * the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> + *****************************************************************************/
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <vlc_common.h>
> +#include <vlc_interrupt.h>
> +#include <vlc_plugin.h>
> +#include <vlc_access.h>
> +#include <vlc_block.h>
> +
> +#include "librist.h"
> +
> +#define RIST_CFG_PREFIX "rist-"
> +
> +typedef struct
> +{
> +    struct       rist_ctx *receiver_ctx;
> +    int          gre_filter_src_port;
> +    int          gre_filter_dst_port;
> +    block_fifo_t *p_fifo;
> +    uint32_t     cumulative_loss;
> +    uint32_t     flow_id;
> +    bool         playback_initialize;
> +    bool         eof;
> +    int          pts_delay;
> +    int          recovery_buffer_us;
> +} stream_sys_t;
> +
> +static int log_cb(void *arg, enum rist_log_level log_level, const char *msg)
> +{
> +    stream_t *p_access = (stream_t*)arg;
> +    int label_index = 0;
> +    if (log_level > 8)
> +        label_index = 8;
> +    else if (log_level > 0)
> +        label_index = log_level;
> +    // remove the last \n
> +    char *msg1 = (void *)msg;
> +    msg1[strlen(msg1) - 1] = 0;
> +    if (log_level == 3)
> +        msg_Err(p_access, "[RIST-%s]: %s", rist_log_label[label_index], msg1);
> +    else if (log_level == 4)
> +        msg_Warn(p_access, "[RIST-%s]: %s", rist_log_label[label_index], msg1);
> +    else if (log_level == 6)
> +        msg_Info(p_access, "[RIST-%s]: %s", rist_log_label[label_index], msg1);
> +    else if (log_level > 6)
> +        msg_Dbg(p_access, "[RIST-%s]: %s", rist_log_label[label_index], msg1);
> +
> +    return 0;
> +}
> +
> +static int cb_stats(void *arg, const struct rist_stats *stats_container)
> +{
> +    stream_t *p_access = (stream_t*)arg;
> +    stream_sys_t *p_sys = p_access->p_sys;
> +
> +    msg_Dbg(p_access, "[RIST-STATS]: %s", stats_container->stats_json);
> +
> +    const struct rist_stats_receiver_flow *stats_receiver_flow = &stats_container->stats.receiver_flow;
> +    p_sys->cumulative_loss += stats_receiver_flow->lost;
> +    msg_Warn(p_access, "[RIST-STATS]: received %"PRIu64", missing %"PRIu32", reordered %"PRIu32", recovered %"PRIu32", lost %"PRIu32", Q %.2f, max jitter (us) %"PRIu64", rtt %"PRIu32"ms, cumulative loss %"PRIu32"", 
> +        stats_receiver_flow->received,
> +        stats_receiver_flow->missing,
> +        stats_receiver_flow->reordered,
> +        stats_receiver_flow->recovered,
> +        stats_receiver_flow->lost,
> +        stats_receiver_flow->quality,
> +        stats_receiver_flow->max_inter_packet_spacing,
> +        stats_receiver_flow->rtt,
> +        p_sys->cumulative_loss
> +        );
> +
> +    if ((int)stats_receiver_flow->max_inter_packet_spacing > p_sys->recovery_buffer_us)
> +    {
> +        msg_Err(p_access, "The IP network jitter exceeded your recovery buffer size, %d > %d ms, you should increase the recovery buffer size or fix your source/network jitter",
> +            (int)stats_receiver_flow->max_inter_packet_spacing / 1000, p_sys->recovery_buffer_us / 1000);
> +    }
> +
> +    if ((int)stats_receiver_flow->rtt > (p_sys->recovery_buffer_us / 1000))
> +    {
> +        msg_Err(p_access, "The RTT between us and the sender is higher than the configured recovery buffer size, %"PRIu32" > %d ms, you should increase the recovery buffer size",
> +            stats_receiver_flow->rtt, p_sys->recovery_buffer_us / 1000);
> +    }
> +
> +    /* Trigger the appropriate response when there is no more data */
> +    if (p_sys->flow_id == stats_receiver_flow->flow_id) {
> +        /* status of 1 is no data for one buffer length */
> +        /* status of 2 is no data for 60 seconds, i.e. session timeout */
> +        if (stats_receiver_flow->status == 1) {
> +            p_sys->playback_initialize = true;
> +        } else if(stats_receiver_flow->status == 2) {
> +            p_sys->eof = true;
> +        }
> +    }
> +
> +    rist_stats_free((void *)stats_container);
> +    return 0;
> +}
> +
> +static int Control(stream_t *p_access, int i_query, va_list args)
> +{
> +    stream_sys_t *p_sys = p_access->p_sys;
> +    switch( i_query )
> +    {
> +        case STREAM_CAN_SEEK:
> +        case STREAM_CAN_FASTSEEK:
> +        case STREAM_CAN_PAUSE:
> +        case STREAM_CAN_CONTROL_PACE:
> +            *va_arg( args, bool * ) = false;
> +            break;
> +
> +        case STREAM_GET_PTS_DELAY:
> +            *va_arg( args, int64_t * ) = INT64_C(1000)
> +                   * (int64_t)p_sys->pts_delay;
> +            break;
> +
> +        default:
> +            return VLC_EGENERIC;
> +    }
> +
> +    return VLC_SUCCESS;
> +}
> +
> +static block_t *BlockRIST(stream_t *p_access, bool *restrict eof)
> +{
> +    stream_sys_t *p_sys = p_access->p_sys;
> +    *eof = false;
> +
> +    if (vlc_killed())
> +    {
> +        *eof = true;
> +        return NULL;
> +    }
> +
> +    block_t *pktout = NULL;
> +    const struct rist_data_block *rist_buffer;
> +    int ret = rist_receiver_data_read(p_sys->receiver_ctx, &rist_buffer, 5);
> +    if (ret && ret % 100 == 0)
> +        msg_Warn(p_access, "Falling behind reading rist buffer by %d packets", ret);
> +    if (rist_buffer && rist_buffer->payload) {
> +        pktout = block_Alloc(rist_buffer->payload_len);
> +        if (pktout && rist_buffer && rist_buffer->payload)
> +        {
> +            memcpy(pktout->p_buffer, rist_buffer->payload, rist_buffer->payload_len);
> +            pktout->i_buffer = rist_buffer->payload_len;
> +            // Convert ntp64 to vlc_ticks
> +            uint64_t ts_ntp = rist_buffer->ts_ntp;
> +            uint64_t nanoseconds = (uint64_t)(ts_ntp >> 32);
> +            nanoseconds *= 1000000000;
> +            nanoseconds += ts_ntp & 0x000000ffffffff;
> +            pktout->i_dts = pktout->i_pts = nanoseconds / INT64_C(1000);
> +            if (p_sys->flow_id != rist_buffer->flow_id || rist_buffer->flags == RIST_DATA_FLAGS_DISCONTINUITY)
> +                pktout->i_flags = BLOCK_FLAG_DISCONTINUITY;
> +            if (p_sys->flow_id != rist_buffer->flow_id)
> +            {
> +                msg_Info(p_access, "New flow detected with id %"PRIu32"", rist_buffer->flow_id);
> +                p_sys->flow_id = rist_buffer->flow_id;
> +            }
> +        }
> +        else {
> +            msg_Err(p_access, "cb_recv OOM!");
> +            return NULL;
> +        }
> +    }
> +
> +    if (p_sys->eof)
> +    {
> +        p_sys->eof = false;
> +        *eof = true;
> +    }
> +    return pktout;
> +}
> +
> +static int Clean(struct stream_t *p_access)
> +{
> +    stream_sys_t *p_sys = p_access->p_sys;
> +
> +    if( likely(p_sys->p_fifo != NULL) )
> +        block_FifoRelease( p_sys->p_fifo );
> +
> +   return rist_destroy(p_sys->receiver_ctx);
> +}
> +
> +static void Close(vlc_object_t *p_this)
> +{
> +    stream_t *p_access = (stream_t*)p_this;
> +
> +    if (Clean(p_access))
> +        msg_Err(p_access, "Error while closing the RIST module");
> +}
> +
> +static int Open(vlc_object_t *p_this)
> +{
> +    stream_t     *p_access = (stream_t*)p_this;
> +    stream_sys_t *p_sys = NULL;
> +    char *addr[RIST_PEER_COUNT];
> +
> +    p_sys = vlc_obj_calloc( p_this, 1, sizeof( *p_sys ) );
> +    if( unlikely( p_sys == NULL ) )
> +        return VLC_ENOMEM;
> +
> +    p_access->p_sys = p_sys;
> +
> +    p_sys->gre_filter_src_port = var_InheritInteger(p_access, RIST_CFG_PREFIX RIST_URL_PARAM_VIRT_SRC_PORT);
> +    p_sys->gre_filter_dst_port = var_InheritInteger(p_access, RIST_CFG_PREFIX RIST_URL_PARAM_VIRT_DST_PORT);
> +    if (p_sys->gre_filter_dst_port % 2 != 0) {
> +        msg_Err(p_access, "Virtual destination port must be an even number.");
> +        return VLC_ENOMEM;
> +    }
> +
> +    int i_recovery_length = var_InheritInteger( p_access, RIST_CFG_PREFIX RIST_URL_PARAM_BUFFER_SIZE );
> +    int i_rist_reorder_buffer = var_InheritInteger( p_access, RIST_CFG_PREFIX RIST_URL_PARAM_REORDER_BUFFER );
> +    int i_rist_retry_interval = var_InheritInteger( p_access, RIST_CFG_PREFIX RIST_PARAM_RETRY_INTERVAL );
> +    int i_rist_max_retries = var_InheritInteger( p_access, RIST_CFG_PREFIX RIST_PARAM_MAX_RETRIES );
> +    int i_rist_max_bitrate = var_InheritInteger(p_access, RIST_CFG_PREFIX RIST_URL_PARAM_BANDWIDTH);
> +
> +    int i_network_caching = var_InheritInteger(p_access, "network-caching");
> +    if (i_recovery_length == 0) {
> +        // Auto-configure the recovery buffer
> +        if (i_network_caching < 400 || i_network_caching > 600) {
> +            p_sys->pts_delay = i_network_caching / 2;
> +            i_recovery_length = i_network_caching / 2;
> +        } else {
> +            // This is the sweet-spot (400 to 600 ms total latency) for internet streams
> +            // We use a fixed i_recovery_length of 300 (6 x rtt of 50ms)
> +            // and we assign whatever is left to the pts_delay buffer
> +            p_sys->pts_delay = i_network_caching - 300;
> +            i_recovery_length = 300;
> +        }
> +    } else  {
> +        if (i_network_caching > i_recovery_length) {
> +            p_sys->pts_delay = i_network_caching - i_recovery_length;
> +        } else {
> +            msg_Err(p_access, "The rist buffer size configured is bigger than the total network cache size %d > %d, using %d instead",
> +                i_recovery_length, i_network_caching, i_network_caching / 2);
> +                i_recovery_length = i_network_caching / 2;
> +                p_sys->pts_delay = i_network_caching / 2;
> +        }
> +    }
> +
> +    p_sys->recovery_buffer_us = i_recovery_length * 1000;
> +
> +    // We do not want to increase delay on playback
> +    var_Create( vlc_object_instance(p_access), "clock-jitter", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
> +    var_SetInteger( vlc_object_instance(p_access), "clock-jitter", 0 );
> +    msg_Info(p_access, "Starting with a recovery buffer of %d and a total Network-caching of %d ms", 
> +        i_recovery_length,
> +        p_sys->pts_delay + i_recovery_length);
> +
> +    int rist_profile = var_InheritInteger(p_access, RIST_CFG_PREFIX RIST_URL_PARAM_PROFILE);
> +    int i_verbose_level = var_InheritInteger( p_access, RIST_CFG_PREFIX RIST_URL_PARAM_VERBOSE_LEVEL );
> +    static struct rist_logging_settings *logging_settings;
> +
> +    if (rist_logging_set(&logging_settings, i_verbose_level, log_cb, (void *)p_access, NULL, stderr) != 0) {
> +        msg_Err(p_access,"Could not set logging\n");
> +        goto failed;
> +    }
> +
> +    if (rist_receiver_create(&p_sys->receiver_ctx, rist_profile, logging_settings) != 0) {
> +        msg_Err(p_access, "Could not create rist receiver context");
> +        goto failed;
> +    }
> +
> +    // Enable stats data
> +    if (rist_stats_callback_set(p_sys->receiver_ctx, 1000, cb_stats, (void *)p_access) == -1) {
> +        msg_Err(p_access, "Could not enable stats callback");
> +        goto failed;
> +    }
> +
> +    char *psz_stream_name = NULL;
> +    psz_stream_name = var_InheritString( p_access, RIST_CFG_PREFIX RIST_URL_PARAM_CNAME );
> +    char *psz_shared_secret = NULL;
> +    psz_shared_secret = var_InheritString( p_access, RIST_CFG_PREFIX RIST_URL_PARAM_SECRET );
> +    int i_keysize = var_InheritInteger( p_access, RIST_CFG_PREFIX RIST_URL_PARAM_AES_TYPE );
> +
> +    addr[0] = strdup(p_access->psz_url);
> +    addr[1] = var_InheritString( p_access, RIST_CFG_PREFIX RIST_PARAM_URL2 );
> +    addr[2] = var_InheritString( p_access, RIST_CFG_PREFIX RIST_PARAM_URL3 );
> +    addr[3] = var_InheritString( p_access, RIST_CFG_PREFIX RIST_PARAM_URL4 );
> +    bool b_peer_alive = false;
> +
> +    for (size_t i = 0; i < RIST_PEER_COUNT; i++) {
> +        if (addr[i] == NULL) {
> +            continue;
> +        }
> +        else if (addr[i][0] == '\0') {
> +            free(addr[i]);
> +            continue;
> +        }
> +
> +        const struct rist_peer_config app_peer_config = {
> +            .version = RIST_PEER_CONFIG_VERSION,
> +            .virt_dst_port = RIST_DEFAULT_VIRT_DST_PORT,
> +            .recovery_mode = RIST_RECOVERY_MODE_TIME,
> +            .recovery_maxbitrate = (uint32_t)i_rist_max_bitrate,
> +            .recovery_maxbitrate_return = 0,
> +            .recovery_length_min = (uint32_t)i_recovery_length,
> +            .recovery_length_max = (uint32_t)i_recovery_length,
> +            .recovery_reorder_buffer = (uint32_t)i_rist_reorder_buffer,
> +            .recovery_rtt_min = (uint32_t)i_rist_retry_interval,
> +            .recovery_rtt_max = (uint32_t)i_rist_retry_interval,
> +            .weight = 0,
> +            .congestion_control_mode = RIST_CONGESTION_CONTROL_MODE_NORMAL,
> +            .min_retries = 6,
> +            .max_retries = (uint32_t)i_rist_max_retries,
> +            .key_size = i_keysize
> +        };
> +
> +        if (psz_shared_secret != NULL && psz_shared_secret[0] != '\0') {
> +            strncpy((void *)&app_peer_config.secret[0], psz_shared_secret, RIST_MAX_STRING_SHORT);
> +        }
> +
> +        if ( psz_stream_name != NULL && psz_stream_name[0] != '\0') {
> +            strncpy((void *)&app_peer_config.cname[0], psz_stream_name, RIST_MAX_STRING_SHORT);
> +        }
> +
> +        // URL overrides (also cleans up the URL)
> +        const struct rist_peer_config *peer_config = &app_peer_config;
> +        if (rist_parse_address(addr[i], &peer_config))
> +        {
> +            msg_Err(p_access, "Could not parse peer options for sender #%d\n", (int)(i + 1));
> +            free(addr[i]);
> +            continue;
> +        }
> +
> +        struct rist_peer *peer;
> +        if (rist_peer_create(p_sys->receiver_ctx, &peer, peer_config)) {
> +            msg_Err(p_access, "Could not init rist receiver #%i at %s", (int)(i + 1), addr[i]);
> +            free(addr[i]);
> +            continue;
> +        }
> +        else {
> +            b_peer_alive = true;
> +        }
> +        free(addr[i]);
> +    }
> +
> +    if (psz_shared_secret != NULL && psz_shared_secret[0] != '\0')
> +        free(psz_shared_secret);
> +
> +    if (psz_stream_name != NULL && psz_stream_name[0] != '\0')
> +        free(psz_stream_name);
> +
> +    if (!b_peer_alive)
> +        goto failed;
> +
> +    p_sys->p_fifo = block_FifoNew();
> +    if( unlikely(p_sys->p_fifo == NULL) )
> +        goto failed;
> +
> +    /* Start the rist protocol thread */
> +    if (rist_start(p_sys->receiver_ctx)) {
> +        msg_Err(p_access, "Could not start rist receiver");
> +        goto failed;
> +    }
> +
> +    p_access->pf_block = BlockRIST;
> +    p_access->pf_control = Control;
> +
> +    return VLC_SUCCESS;
> +
> +failed:
> +    Clean(p_access);
> +    msg_Err(p_access, "Failed to open rist module");
> +    return VLC_EGENERIC;
> +}
> +
> +#define SRC_PORT_TEXT N_("Virtual Source Port Filter")
> +#define SRC_PORT_LONGTEXT N_( \
> +    "Source port to be used inside the reduced-mode of the main profile to " \
> +    "filter incoming data. Use zero to allow all." )
> +
> +#define DST_PORT_TEXT N_("Virtual Destination Port Filter")
> +#define DST_PORT_LONGTEXT N_( \
> +    "Destination port to be used inside the reduced-mode of the main profile "\
> +    "to filter incoming data. Use zero to allow all." )
> +
> +/* Module descriptor */
> +vlc_module_begin ()
> +
> +    set_shortname( N_("RIST") )
> +    set_description( N_("RIST input") )
> +    set_category( CAT_INPUT )
> +    set_subcategory( SUBCAT_INPUT_ACCESS )
> +
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_VIRT_SRC_PORT, 0,
> +            SRC_PORT_TEXT, SRC_PORT_LONGTEXT, true )
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_VIRT_DST_PORT, 0,
> +            DST_PORT_TEXT, DST_PORT_LONGTEXT, true )
> +    add_string( RIST_CFG_PREFIX RIST_PARAM_URL2, NULL, RIST_URL2_TEXT, NULL, true )
> +    add_string( RIST_CFG_PREFIX RIST_PARAM_URL3, NULL, RIST_URL3_TEXT, NULL, true )
> +    add_string( RIST_CFG_PREFIX RIST_PARAM_URL4, NULL, RIST_URL4_TEXT, NULL, true )
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_BANDWIDTH, RIST_DEFAULT_RECOVERY_MAXBITRATE,
> +            RIST_MAX_BITRATE_TEXT, RIST_MAX_BITRATE_LONGTEXT, true )
> +    add_integer( RIST_CFG_PREFIX RIST_PARAM_RETRY_INTERVAL, RIST_DEFAULT_RECOVERY_RTT_MIN, 
> +        RIST_RETRY_INTERVAL_TEXT, NULL, true )
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_REORDER_BUFFER, RIST_DEFAULT_RECOVERY_REORDER_BUFFER, 
> +        RIST_REORDER_BUFFER_TEXT, NULL, true )
> +    add_integer( RIST_CFG_PREFIX RIST_PARAM_MAX_RETRIES, RIST_DEFAULT_MAX_RETRIES, 
> +        RIST_MAX_RETRIES_TEXT, NULL, true )
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_VERBOSE_LEVEL, RIST_DEFAULT_VERBOSE_LEVEL,
> +            RIST_VERBOSE_LEVEL_TEXT, RIST_VERBOSE_LEVEL_LONGTEXT, true )
> +        change_integer_list( verbose_level_type, verbose_level_type_names )
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_BUFFER_SIZE, 0,
> +            BUFFER_TEXT, BUFFER_LONGTEXT, true )
> +    add_string( RIST_CFG_PREFIX RIST_URL_PARAM_CNAME, NULL, RIST_CNAME_TEXT, 
> +            RIST_CNAME_LONGTEXT, true )
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_PROFILE, RIST_DEFAULT_PROFILE,
> +            RIST_PROFILE_TEXT, RIST_PROFILE_LONGTEXT, true )
> +    add_password( RIST_CFG_PREFIX RIST_URL_PARAM_SECRET, "",
> +            RIST_SHARED_SECRET_TEXT, NULL )
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_AES_TYPE, 0,
> +            RIST_ENCRYPTION_TYPE_TEXT, NULL, true )
> +        change_integer_list( rist_encryption_type, rist_encryption_type_names )
> +    add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_TIMING_MODE, RIST_DEFAULT_TIMING_MODE,
> +            RIST_TIMING_MODE_TEXT, NULL, true )
> +        change_integer_list( rist_timing_mode_type, rist_timing_mode_names )
> +
> +    set_capability( "access", 10 )
> +    add_shortcut( "librist", "rist", "tr06" )
> +
> +    set_callbacks( Open, Close )
> +
> +vlc_module_end ()
> diff --git a/modules/access/librist.h b/modules/access/librist.h
> new file mode 100644
> index 0000000000..61a89f9d19
> --- /dev/null
> +++ b/modules/access/librist.h
> @@ -0,0 +1,95 @@
> +/*****************************************************************************
> + * rist.h: RIST (Reliable Internet Stream Transport) helper
> + *****************************************************************************
> + * Copyright (C) 2020, SipRadius LLC
> + *
> + * Authors: Sergio Ammirata <sergio at ammirata.net>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by
> + * the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> + *****************************************************************************/
> +
> +#ifndef RIST_VLC_COMMON_H
> +#define RIST_VLC_COMMON_H 1
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <vlc_common.h>
> +#include <librist/librist.h>
> +
> +/* RIST parameter names */
> +#define RIST_PARAM_URL2              "peer-url2"
> +#define RIST_PARAM_URL3              "peer-url3"
> +#define RIST_PARAM_URL4              "peer-url4"
> +#define RIST_PARAM_RETRY_INTERVAL    "retry-interval"
> +#define RIST_PARAM_MAX_RETRIES       "max-retries"
> +
> +static const char *rist_log_label[9] = {"DISABLED", "", "", "ERROR", "WARN", "", "INFO", "DEBUG", "SIMULATE"};
> +
> +/* RIST parameter descriptions */
> +#define RIST_URL2_TEXT N_("Second peer URL")
> +#define RIST_URL3_TEXT N_("Third peer URL")
> +#define RIST_URL4_TEXT N_("Fourth peer URL")
> +#define RIST_MAX_BITRATE_TEXT N_("Max bitrate in Kbps")
> +#define RIST_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 RIST_RETRY_INTERVAL_TEXT N_("RIST nack retry interval (ms)")
> +#define RIST_REORDER_BUFFER_TEXT N_("RIST reorder buffer (ms)")
> +#define RIST_MAX_RETRIES_TEXT N_("RIST maximum retry count")
> +#define BUFFER_TEXT N_("RIST retry-buffer queue size (ms)")
> +#define BUFFER_LONGTEXT N_( \
> +    "This must match the buffer size (latency) configured on the other side. If you " \
> +    "are not sure, leave it blank and it will use 1000ms" )
> +#define RIST_SHARED_SECRET_TEXT N_("Shared Secret")
> +#define RIST_SHARED_SECRET_LONGTEXT N_( \
> +    "This shared secret is a passphare shared between sender and receiver. The AES key " \
> +    "is derived from it" )
> +#define RIST_CNAME_TEXT N_("Peer cname")
> +#define RIST_CNAME_LONGTEXT N_( \
> +    "This name will be sent using the rist RTCP channel and uniquely identifies us" )
> +/* Profile selection */
> +#define RIST_PROFILE_TEXT N_("Rist Profile")
> +#define RIST_PROFILE_LONGTEXT N_( "Select the rist profile to use" )
> +static const int rist_profile[] = { 0, 1, 2 };
> +static const char *const rist_profile_names[] = {
> +    N_("Simple Profile"), N_("Main Profile"), N_("Advanced Profile"),
> +};
> +/* Encryption type */
> +#define RIST_ENCRYPTION_TYPE_TEXT N_("Encryption type")
> +#define RIST_DEFAULT_ENCRYPTION_TPE 128
> +static const int rist_encryption_type[] = { 0, 128, 256, };
> +static const char *const rist_encryption_type_names[] = {
> +    N_("Disabled"), N_("AES 128 bits"), N_("AES 256 bits"),
> +};
> +/* Timing Mode */
> +#define RIST_TIMING_MODE_TEXT N_("Timing mode")
> +static const int rist_timing_mode_type[] = { 0, 1, 2, };
> +static const char *const rist_timing_mode_names[] = {
> +    N_("Use Source Time"), N_("Use Arrival Time"), N_("Use RTC"),
> +};
> +/* Verbose level */
> +#define RIST_VERBOSE_LEVEL_TEXT N_("Verbose level")
> +#define RIST_VERBOSE_LEVEL_LONGTEXT N_("This controls how much log data the library will output over stderr")
> +static const int verbose_level_type[] = { RIST_LOG_DISABLE, RIST_LOG_ERROR, RIST_LOG_WARN, RIST_LOG_INFO, RIST_LOG_DEBUG, RIST_LOG_SIMULATE };
> +static const char *const verbose_level_type_names[] = {
> +    N_("Quiet"), N_("Errors"), N_("Warnings"), N_("Info"), N_("Debug"), N_("Simulate-Loss"),
> +};
> +
> +/* Max number of peers */
> +#define RIST_PEER_COUNT 4
> +
> +#endif
> diff --git a/modules/access_output/Makefile.am b/modules/access_output/Makefile.am
> index f6f78c0b73..3c37441822 100644
> --- a/modules/access_output/Makefile.am
> +++ b/modules/access_output/Makefile.am
> @@ -35,10 +35,16 @@ libaccess_output_srt_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(access_outdir)'
>  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_LIBADD = $(SOCKET_LIBS)
> +### RIST SIMPLE PROFILE ###
> +libaccess_output_ristsimple_plugin_la_SOURCES = access_output/rist.c access/rist.h
> +libaccess_output_ristsimple_plugin_la_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS)
> +libaccess_output_ristsimple_plugin_la_LIBADD = $(SOCKET_LIBS)
>  if HAVE_BITSTREAM
> -access_out_LTLIBRARIES += libaccess_output_rist_plugin.la
> +access_out_LTLIBRARIES += libaccess_output_ristsimple_plugin.la
>  endif
> +
> +### libRIST ###
> +libaccess_output_rist_plugin_la_SOURCES = access_output/librist.c
> +libaccess_output_rist_plugin_la_CFLAGS = $(AM_CFLAGS)
> +libaccess_output_rist_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(LIBRIST_LIBS) $(SOCKET_LIBS) $(LIBPTHREAD)
> +access_out_LTLIBRARIES += libaccess_output_rist_plugin.la
> diff --git a/modules/access_output/librist.c b/modules/access_output/librist.c
> new file mode 100644
> index 0000000000..46ba0cc7d8
> --- /dev/null
> +++ b/modules/access_output/librist.c
> @@ -0,0 +1,473 @@
> +/*****************************************************************************
> + *  * rist.c: RIST (Reliable Internet Stream Transport) output module
> + *****************************************************************************
> + * Copyright (C) 2020, SipRadius LLC
> + *
> + * Authors: Sergio Ammirata <sergio at ammirata.net>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by
> + * the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> + *****************************************************************************/
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <vlc_common.h>
> +#include <vlc_interrupt.h>
> +#include <vlc_plugin.h>
> +#include <vlc_sout.h>
> +#include <vlc_block.h>
> +#include <vlc_rand.h>
> +#include <sys/time.h>
> +
> +#include "../access/librist.h"
> +
> +#define SOUT_CFG_PREFIX "sout-rist-"
> +
> +static const char *const ppsz_sout_options[] = {
> +    "payload-size",
> +    RIST_URL_PARAM_VIRT_SRC_PORT,
> +    RIST_URL_PARAM_VIRT_DST_PORT,
> +    "multipeer-mode",
> +    RIST_PARAM_URL2,
> +    RIST_PARAM_URL3,
> +    RIST_PARAM_URL4,
> +    RIST_URL_PARAM_BANDWIDTH,
> +    RIST_PARAM_RETRY_INTERVAL,
> +    RIST_URL_PARAM_REORDER_BUFFER,
> +    RIST_PARAM_MAX_RETRIES,
> +    RIST_URL_PARAM_VERBOSE_LEVEL,
> +    RIST_URL_PARAM_BUFFER_SIZE,
> +    RIST_URL_PARAM_CNAME,
> +    RIST_URL_PARAM_PROFILE,
> +    RIST_URL_PARAM_SECRET,
> +    RIST_URL_PARAM_AES_TYPE,
> +    NULL
> +};
> +
> +typedef struct
> +{
> +    struct rist_ctx    *sender_ctx;
> +    block_t            *p_pktbuffer;
> +    int                gre_src_port;
> +    int                gre_dst_port;
> +    bool               b_mtu_warning;
> +    size_t             i_packet_size;
> +    uint32_t           recovery_buffer;
> +} sout_access_out_sys_t;
> +
> +static int log_cb(void *arg, enum rist_log_level log_level, const char *msg)
> +{
> +    sout_access_out_t *p_access = (sout_access_out_t*)arg;
> +    int label_index = 0;
> +    if (log_level > 8)
> +        label_index = 8;
> +    else if (log_level > 0)
> +        label_index = log_level;
> +    // remove the last \n
> +    char *msg1 = (void *)msg;
> +    msg1[strlen(msg1) - 1] = 0;
> +    if (log_level == 3)
> +        msg_Err(p_access, "[RIST-%s]: %s", rist_log_label[label_index], msg1);
> +    else if (log_level == 4)
> +        msg_Warn(p_access, "[RIST-%s]: %s", rist_log_label[label_index], msg1);
> +    else if (log_level == 6)
> +        msg_Info(p_access, "[RIST-%s]: %s", rist_log_label[label_index], msg1);
> +    else if (log_level > 6)
> +        msg_Dbg(p_access, "[RIST-%s]: %s", rist_log_label[label_index], msg1);
> +
> +    return 0;
> +}
> +
> +static int cb_stats(void *arg, const struct rist_stats *stats_container)
> +{
> +    sout_access_out_t *p_access = (sout_access_out_t*)arg;
> +    sout_access_out_sys_t *p_sys = p_access->p_sys;
> +
> +    msg_Dbg(p_access, "[RIST-STATS]: %s", stats_container->stats_json);
> +
> +    const struct rist_stats_sender_peer *stats_sender_peer = &stats_container->stats.sender_peer;
> +    msg_Warn(p_access, "[RIST-STATS]: name %s, id %"PRIu32", bitrate %zu, sent %"PRIu64", received %"PRIu64", retransmitted %"PRIu64", Q %.2f, rtt %"PRIu32"ms",
> +        stats_sender_peer->cname,
> +        stats_sender_peer->peer_id,
> +        stats_sender_peer->bandwidth,
> +        stats_sender_peer->sent,
> +        stats_sender_peer->received,
> +        stats_sender_peer->retransmitted,
> +        stats_sender_peer->quality,
> +        stats_sender_peer->rtt
> +    );
> +
> +    if (stats_sender_peer->rtt > p_sys->recovery_buffer)
> +    {
> +        msg_Err(p_access, "The RTT between us and the receiver is higher than the configured recovery buffer size, %"PRIu32" > %"PRIu32" ms, you should increase the recovery buffer size",
> +            stats_sender_peer->rtt, p_sys->recovery_buffer);
> +    }
> +
> +    rist_stats_free((void *)stats_container);
> +    return 0;
> +}
> +
> +static uint64_t i_dts_to_ntp64( uint64_t i_dts )
> +{
> +    lldiv_t d = lldiv (i_dts, CLOCK_FREQ);
> +    struct timespec ts = { d.quot, INT64_C(1000) * 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 )
> +{
> +    sout_access_out_sys_t *p_sys = p_access->p_sys;
> +    int i_len = 0;
> +
> +    while( p_buffer )
> +    {
> +        block_t *p_next;
> +        int i_block_split = 0;
> +
> +        if( !p_sys->b_mtu_warning && p_buffer->i_buffer > p_sys->i_packet_size )
> +        {
> +            msg_Warn( p_access, "Buffer data size (%zu) > configured packet size (%zu), you " \
> +                "should probably increase the configured packet size", p_buffer->i_buffer, 
> +                p_sys->i_packet_size );
> +            p_sys->b_mtu_warning = true;
> +        }
> +
> +        /* Temp buffer is already too large, flush */
> +        if( p_sys->p_pktbuffer->i_buffer + p_buffer->i_buffer > p_sys->i_packet_size )
> +        {
> +            struct rist_data_block rist_buffer;
> +            rist_buffer.payload = p_sys->p_pktbuffer->p_buffer;
> +            rist_buffer.payload_len = p_sys->p_pktbuffer->i_buffer;
> +            rist_buffer.virt_src_port = p_sys->gre_src_port;
> +            // Delegate the virt_dst_port to the lib so that it matches the appropriate peer
> +            rist_buffer.virt_dst_port = 0;
> +            rist_buffer.ts_ntp = i_dts_to_ntp64(p_sys->p_pktbuffer->i_dts);
> +            rist_sender_data_write(p_sys->sender_ctx, &rist_buffer);
> +            p_sys->p_pktbuffer->i_buffer = 0;
> +        }
> +
> +        i_len += p_buffer->i_buffer;
> +
> +        while( p_buffer->i_buffer )
> +        {
> +
> +            size_t i_write = __MIN( p_buffer->i_buffer, p_sys->i_packet_size );
> +
> +            i_block_split++;
> +
> +            if( p_sys->p_pktbuffer->i_buffer == 0 )
> +            {
> +                p_sys->p_pktbuffer->i_dts = p_buffer->i_dts;
> +            }
> +
> +            memcpy( p_sys->p_pktbuffer->p_buffer + p_sys->p_pktbuffer->i_buffer,
> +                    p_buffer->p_buffer, i_write );
> +
> +            p_sys->p_pktbuffer->i_buffer += i_write;
> +            p_buffer->p_buffer += i_write;
> +            p_buffer->i_buffer -= i_write;
> +
> +            /*  Flush if we reached the target size for the case of block size < target packet size.
> +             *  Also flush when we are in block_split > 1 for the case when the block_size is
> +             *  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 )
> +            {
> +                struct rist_data_block rist_buffer;
> +                rist_buffer.payload = p_sys->p_pktbuffer->p_buffer;
> +                rist_buffer.payload_len = p_sys->p_pktbuffer->i_buffer;
> +                rist_buffer.virt_src_port = p_sys->gre_src_port;
> +                // Delegate the virt_dst_port to the lib so that it matches the appropriate peer
> +                rist_buffer.virt_dst_port = 0;
> +                rist_buffer.ts_ntp = i_dts_to_ntp64(p_sys->p_pktbuffer->i_dts);
> +                rist_sender_data_write(p_sys->sender_ctx, &rist_buffer);
> +                p_sys->p_pktbuffer->i_buffer = 0;
> +            }
> +
> +        }
> +
> +        p_next = p_buffer->p_next;
> +        block_Release( p_buffer );
> +        p_buffer = p_next;
> +
> +    }
> +
> +    if ( i_len <= 0 ) {
> +        block_ChainRelease( p_buffer );
> +    }
> +    return i_len;
> +}
> +
> +static int Control( sout_access_out_t *p_access, int i_query, va_list args )
> +{
> +    VLC_UNUSED( p_access );
> +
> +    int i_ret = VLC_SUCCESS;
> +
> +    switch( i_query )
> +    {
> +        case ACCESS_OUT_CONTROLS_PACE:
> +            *va_arg( args, bool * ) = false;
> +            break;
> +
> +        default:
> +            i_ret = VLC_EGENERIC;
> +            break;
> +    }
> +
> +    return i_ret;
> +}
> +
> +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;
> +
> +    if (p_sys->p_pktbuffer)
> +        block_Release(p_sys->p_pktbuffer);
> +
> +    rist_destroy(p_sys->sender_ctx);
> +    p_sys->sender_ctx = NULL;
> +}
> +
> +static int Open( vlc_object_t *p_this )
> +{
> +    sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
> +    sout_access_out_sys_t   *p_sys = NULL;
> +    char *addr[RIST_PEER_COUNT];
> +    static struct rist_logging_settings *logging_settings;
> +
> +    if (var_Create ( p_access, "dst-port", VLC_VAR_INTEGER )
> +     || var_Create ( p_access, "src-port", VLC_VAR_INTEGER )
> +     || var_Create ( p_access, "dst-addr", VLC_VAR_STRING )
> +     || var_Create ( p_access, "src-addr", VLC_VAR_STRING ) )
> +    {
> +        msg_Err( p_access, "Valid network information is required." );
> +        return VLC_ENOMEM;
> +    }
> +
> +    config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
> +
> +    p_sys = vlc_obj_calloc( p_this, 1, sizeof( *p_sys ) );
> +    if( unlikely( p_sys == NULL ) )
> +        return VLC_ENOMEM;
> +
> +    p_sys->gre_src_port = var_InheritInteger(p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_VIRT_SRC_PORT);
> +    p_sys->gre_dst_port = var_InheritInteger(p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_VIRT_DST_PORT);
> +    if (p_sys->gre_dst_port % 2 != 0) {
> +        msg_Err( p_access, "Virtual destination port must be an even number." );
> +        return VLC_ENOMEM;
> +    }
> +
> +    p_sys->i_packet_size = var_InheritInteger(p_access, SOUT_CFG_PREFIX "payload-size" );
> +    p_sys->p_pktbuffer = block_Alloc( p_sys->i_packet_size );
> +    if( unlikely(p_sys->p_pktbuffer == NULL) )
> +        goto failed;
> +
> +    int i_rist_profile = var_InheritInteger(p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_PROFILE);
> +    int i_verbose_level = var_InheritInteger(p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_VERBOSE_LEVEL);
> +
> +    if (rist_logging_set(&logging_settings, i_verbose_level, log_cb, (void *)p_access, NULL, stderr) != 0) {
> +        msg_Err(p_access,"Could not set logging\n");
> +        goto failed;
> +    }
> +
> +    if (rist_sender_create(&p_sys->sender_ctx, i_rist_profile, 0, logging_settings) != 0) {
> +        msg_Err( p_access, "Could not create rist sender context\n");
> +        goto failed;
> +    }
> +
> +    // Enable stats data
> +    if (rist_stats_callback_set(p_sys->sender_ctx, 1000, cb_stats, (void *)p_access) == -1) {
> +        msg_Err(p_access, "Could not enable stats callback");
> +        goto failed;
> +    }
> +
> +    char *psz_stream_name = NULL;
> +    psz_stream_name = var_InheritString( p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_CNAME );
> +
> +    char *psz_shared_secret = NULL;
> +    psz_shared_secret = var_InheritString( p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_SECRET );
> +
> +    int i_recovery_length = var_InheritInteger( p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_BUFFER_SIZE );
> +    int i_rist_reorder_buffer = var_InheritInteger( p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_REORDER_BUFFER );
> +    int i_rist_retry_interval = var_InheritInteger( p_access, SOUT_CFG_PREFIX RIST_PARAM_RETRY_INTERVAL );
> +    int i_rist_max_retries = var_InheritInteger( p_access, SOUT_CFG_PREFIX RIST_PARAM_MAX_RETRIES );
> +    int i_rist_max_bitrate = var_InheritInteger(p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_BANDWIDTH);
> +    int i_multipeer_mode = var_InheritInteger(p_access, SOUT_CFG_PREFIX "multipeer-mode");
> +    int i_key_size = var_InheritInteger(p_access, SOUT_CFG_PREFIX RIST_URL_PARAM_AES_TYPE);
> +
> +    msg_Info( p_access, "Setting retry buffer to %d ms", i_recovery_length );
> +
> +    addr[0] = strdup(p_access->psz_path);
> +    addr[1] = var_InheritString( p_access, SOUT_CFG_PREFIX RIST_PARAM_URL2 );
> +    addr[2] = var_InheritString( p_access, SOUT_CFG_PREFIX RIST_PARAM_URL3 );
> +    addr[3] = var_InheritString( p_access, SOUT_CFG_PREFIX RIST_PARAM_URL4 );
> +    bool b_peer_alive = false;
> +    for (size_t i = 0; i < RIST_PEER_COUNT; i++) {
> +        if (addr[i] == NULL) {
> +            continue;
> +        }
> +        else if (addr[i][0] == '\0') {
> +            free(addr[i]);
> +            continue;
> +        }
> +
> +        struct rist_peer_config app_peer_config = {
> +            .version = RIST_PEER_CONFIG_VERSION,
> +            .virt_dst_port = p_sys->gre_dst_port + 1,
> +            .recovery_mode = RIST_RECOVERY_MODE_TIME,
> +            .recovery_maxbitrate = (uint32_t)i_rist_max_bitrate,
> +            .recovery_maxbitrate_return = 0,
> +            .recovery_length_min = (uint32_t)i_recovery_length,
> +            .recovery_length_max = (uint32_t)i_recovery_length,
> +            .recovery_reorder_buffer = (uint32_t)i_rist_reorder_buffer,
> +            .recovery_rtt_min = (uint32_t)i_rist_retry_interval,
> +            .recovery_rtt_max = (uint32_t)i_rist_retry_interval,
> +            .weight = (uint32_t)i_multipeer_mode,
> +            .congestion_control_mode = RIST_CONGESTION_CONTROL_MODE_NORMAL,
> +            .min_retries = 6,
> +            .max_retries = (uint32_t)i_rist_max_retries,
> +            .key_size = i_key_size
> +        };
> +        
> +        if (psz_shared_secret != NULL && psz_shared_secret[0] != '\0') {
> +            strncpy((void *)&app_peer_config.secret[0], psz_shared_secret, RIST_MAX_STRING_SHORT);
> +        }
> +
> +        if ( psz_stream_name != NULL && psz_stream_name[0] != '\0') {
> +            strncpy((void *)&app_peer_config.cname[0], psz_stream_name, RIST_MAX_STRING_SHORT);
> +        }
> +
> +        // URL overrides (also cleans up the URL)
> +        const struct rist_peer_config *peer_config = &app_peer_config;
> +        if (rist_parse_address(addr[i], &peer_config))
> +        {
> +            msg_Err( p_access, "Could not parse peer options for sender #%d\n", (int)(i + 1));
> +            free(addr[i]);
> +            continue;
> +        }
> +
> +        p_sys->recovery_buffer = peer_config->recovery_length_max;
> +
> +        struct rist_peer *peer;
> +        if (rist_peer_create(p_sys->sender_ctx, &peer, peer_config)) {
> +            msg_Err( p_access, "Could not init rist sender #%i at %s",(int)(i + 1), addr[i] );
> +            free(addr[i]);
> +            continue;
> +        }
> +        else {
> +            b_peer_alive = true;
> +        }
> +        free(addr[i]);
> +    }
> +
> +    if (!b_peer_alive)
> +        goto failed;
> +
> +    if (rist_start(p_sys->sender_ctx) == -1) {
> +        msg_Err( p_access, "Could not start rist sender\n");
> +        goto failed;
> +    }
> +
> +    p_access->p_sys = p_sys;
> +    p_access->pf_write = Write;
> +    p_access->pf_control = Control;
> +
> +    return VLC_SUCCESS;
> +
> +failed:
> +    rist_destroy(p_sys->sender_ctx);
> +    p_sys->sender_ctx = NULL;
> +    return VLC_EGENERIC;
> +}
> +
> +#define SRC_PORT_TEXT N_("Virtual 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_("Virtual Destination Port")
> +#define DST_PORT_LONGTEXT N_( \
> +    "Destination port to be used inside the reduced-mode of the main profile" )
> +
> +/* The default target payload size */
> +#define RIST_DEFAULT_TARGET_PAYLOAD_SIZE 1316
> +
> +/* Multipeer mode */
> +#define RIST_DEFAULT_MULTIPEER_MODE 0
> +#define RIST_MULTIPEER_MODE_TEXT N_("Multipeer mode")
> +#define RIST_MULTIPEER_MODE_LONGTEXT N_( \
> +    "This allows you to select between duplicate or load balanced modes when " \
> +    "sending data to multiple peers (several network paths)" )
> +static const int multipeer_mode_type[] = { 0, 5, };
> +static const char *const multipeer_mode_type_names[] = {
> +    N_("Duplicate"), N_("Load balanced"),
> +};
> +
> +/* Module descriptor */
> +vlc_module_begin()
> +
> +    set_shortname( N_("RIST") )
> +    set_description( N_("RIST stream output") )
> +    set_category( CAT_SOUT )
> +    set_subcategory( SUBCAT_SOUT_ACO )
> +
> +    add_integer( SOUT_CFG_PREFIX "payload-size", RIST_DEFAULT_TARGET_PAYLOAD_SIZE,
> +            N_("RIST target payload size (bytes)"), NULL, true )
> +    add_integer( SOUT_CFG_PREFIX RIST_URL_PARAM_VIRT_SRC_PORT, RIST_DEFAULT_VIRT_SRC_PORT,
> +            SRC_PORT_TEXT, SRC_PORT_LONGTEXT, true )
> +    add_integer( SOUT_CFG_PREFIX RIST_URL_PARAM_VIRT_DST_PORT, RIST_DEFAULT_VIRT_DST_PORT,
> +            DST_PORT_TEXT, DST_PORT_LONGTEXT, true )
> +    add_integer( SOUT_CFG_PREFIX "multipeer-mode", RIST_DEFAULT_MULTIPEER_MODE,
> +            RIST_MULTIPEER_MODE_TEXT, RIST_MULTIPEER_MODE_LONGTEXT, true )
> +        change_integer_list( multipeer_mode_type, multipeer_mode_type_names )
> +    add_string( SOUT_CFG_PREFIX RIST_PARAM_URL2, NULL, RIST_URL2_TEXT, NULL, true )
> +    add_string( SOUT_CFG_PREFIX RIST_PARAM_URL3, NULL, RIST_URL3_TEXT, NULL, true )
> +    add_string( SOUT_CFG_PREFIX RIST_PARAM_URL4, NULL, RIST_URL4_TEXT, NULL, true )
> +    add_integer( SOUT_CFG_PREFIX RIST_URL_PARAM_BANDWIDTH, RIST_DEFAULT_RECOVERY_MAXBITRATE,
> +            RIST_MAX_BITRATE_TEXT, RIST_MAX_BITRATE_LONGTEXT, true )
> +    add_integer( SOUT_CFG_PREFIX RIST_PARAM_RETRY_INTERVAL, RIST_DEFAULT_RECOVERY_RTT_MIN, 
> +        RIST_RETRY_INTERVAL_TEXT, NULL, true )
> +    add_integer( SOUT_CFG_PREFIX RIST_URL_PARAM_REORDER_BUFFER, RIST_DEFAULT_RECOVERY_REORDER_BUFFER, 
> +        RIST_REORDER_BUFFER_TEXT, NULL, true )
> +    add_integer( SOUT_CFG_PREFIX RIST_PARAM_MAX_RETRIES, RIST_DEFAULT_MAX_RETRIES, 
> +        RIST_MAX_RETRIES_TEXT, NULL, true )
> +    add_integer( SOUT_CFG_PREFIX RIST_URL_PARAM_VERBOSE_LEVEL, RIST_DEFAULT_VERBOSE_LEVEL,
> +            RIST_VERBOSE_LEVEL_TEXT, RIST_VERBOSE_LEVEL_LONGTEXT, true )
> +        change_integer_list( verbose_level_type, verbose_level_type_names )
> +    add_integer( SOUT_CFG_PREFIX RIST_URL_PARAM_BUFFER_SIZE, RIST_DEFAULT_RECOVERY_LENGHT_MIN,
> +            BUFFER_TEXT, BUFFER_LONGTEXT, true )
> +    add_string( SOUT_CFG_PREFIX RIST_URL_PARAM_CNAME, NULL, RIST_CNAME_TEXT, 
> +            RIST_CNAME_LONGTEXT, true )
> +    add_integer( SOUT_CFG_PREFIX RIST_URL_PARAM_PROFILE, RIST_DEFAULT_PROFILE,
> +            RIST_PROFILE_TEXT, RIST_PROFILE_LONGTEXT, true )
> +    add_password( SOUT_CFG_PREFIX RIST_URL_PARAM_SECRET, "",
> +            RIST_SHARED_SECRET_TEXT, NULL )
> +    add_integer( SOUT_CFG_PREFIX RIST_URL_PARAM_AES_TYPE, 0,
> +            RIST_ENCRYPTION_TYPE_TEXT, NULL, true )
> +        change_integer_list( rist_encryption_type, rist_encryption_type_names )
> +
> +    set_capability( "sout access", 10 )
> +    add_shortcut( "librist", "rist", "tr06" )
> +
> +    set_callbacks( Open, Close )
> +
> +vlc_module_end ()
> -- 
> 2.17.1
> 

> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel




More information about the vlc-devel mailing list