Commit 70e98618 authored by Sergio Ammirata's avatar Sergio Ammirata
Browse files

Add libRIST based access and access_output modules.

These support the new RIST main profile as well as the RIST simple profile.
parent d886ad29
Pipeline #83119 passed with stage
in 80 minutes and 21 seconds
......@@ -4286,6 +4286,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 RIST plugin
dnl
PKG_ENABLE_MODULES_VLC([RIST], [rist access_output_rist], [librist], [RIST input/output plugin (default auto)])
EXTEND_HELP_STRING([Visualisations and Video filter plugins:])
dnl
dnl goom visualization plugin
......
......@@ -445,3 +445,12 @@ libaccess_srt_plugin_la_LIBADD = $(SRT_LIBS)
libaccess_srt_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(accessdir)'
access_LTLIBRARIES += $(LTLIBaccess_srt)
EXTRA_LTLIBRARIES += libaccess_srt_plugin.la
### RIST ###
librist_plugin_la_SOURCES = access/rist.c access/rist.h
librist_plugin_la_CFLAGS = $(AM_CFLAGS) $(RIST_CFLAGS)
librist_plugin_la_LIBADD = $(RIST_LIBS) $(SOCKET_LIBS) $(LIBPTHREAD)
librist_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(accessdir)'
access_LTLIBRARIES += $(LTLIBrist)
EXTRA_LTLIBRARIES += librist_plugin.la
/*****************************************************************************
* rist.c: RIST (Reliable Internet Stream Transport) input module
*****************************************************************************
* Copyright (C) 2021, SipRadius LLC
*
* Authors: Sergio Ammirata <sergio@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>
#define RIST_CFG_PREFIX "rist-"
#include "rist.h"
#define NACK_FMT_RANGE 0
#define NACK_FMT_BITMASK 1
static const int nack_type_values[] = {
NACK_FMT_RANGE, NACK_FMT_BITMASK,
};
static const char *const nack_type_names[] = {
N_("Range"), N_("Bitmask"),
};
typedef struct
{
struct rist_ctx *receiver_ctx;
int gre_filter_src_port;
int gre_filter_dst_port;
uint32_t cumulative_loss;
uint32_t flow_id;
bool playback_initialize;
bool eof;
int pts_delay;
int recovery_buffer_us;
int i_max_packet_size;
int i_maximum_jitter;
bool b_sendnacks;
bool b_disablenacks;
rist_log_t rist_log_callback_arg;
} stream_sys_t;
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;
if (stats_receiver_flow->lost > 0 || stats_receiver_flow->missing > 0)
{
msg_Info(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
);
}
else
{
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;
block_t *pktout = NULL;
const struct rist_data_block *rist_buffer = NULL;
int ret = rist_receiver_data_read(p_sys->receiver_ctx, &rist_buffer, p_sys->i_maximum_jitter);
if (ret && rist_buffer->payload) {
if (ret > 50 && ret % 10 == 0)
msg_Warn(p_access, "Falling behind reading rist buffer by %d packets", ret);
pktout = block_Alloc(rist_buffer->payload_len);
if (pktout)
{
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 = VLC_TICK_FROM_NS(nanoseconds);
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;
}
if (rist_buffer->flags == RIST_DATA_FLAGS_FLOW_BUFFER_START) {
pktout->i_flags = BLOCK_FLAG_DISCONTINUITY;
}
rist_receiver_data_block_free((struct rist_data_block **const) &rist_buffer);
}
else {
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;
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;
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->i_maximum_jitter = var_InheritInteger(p_access, RIST_CFG_PREFIX "maximum-jitter");
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_network_caching = var_InheritInteger(p_access, "network-caching");
int i_recovery_length = var_InheritInteger(p_access, RIST_CFG_PREFIX RIST_CFG_LATENCY);
if (i_recovery_length == 0) {
// Auto-configure the recovery buffer
p_sys->pts_delay = i_network_caching / 2;
i_recovery_length = i_network_caching / 2;
} 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;
p_sys->rist_log_callback_arg.p_access = (vlc_object_t *)p_access;
if (rist_logging_set(&logging_settings, i_verbose_level, log_cb, (void *)&p_sys->rist_log_callback_arg, 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;
}
int nack_type = var_InheritInteger( p_access, RIST_CFG_PREFIX "nack-type" );
if (rist_receiver_nack_type_set(p_sys->receiver_ctx, nack_type)) {
msg_Err(p_access, "Could not set nack type");
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;
}
p_sys->i_max_packet_size = rist_get_max_packet_size((vlc_object_t *)p_access);
if( !rist_add_peers((vlc_object_t *)p_access, p_sys->receiver_ctx, p_access->psz_url, 0, RIST_DEFAULT_VIRT_DST_PORT, i_recovery_length) )
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 "maximum-jitter", 5,
N_("RIST demux/decode maximum jitter (default is 5ms)"),
N_("This controls the maximum jitter that will be passed to the demux/decode chain. "
"The lower the value, the more CPU cycles the module will consume"), true )
add_integer( RIST_CFG_PREFIX "nack-type", NACK_FMT_RANGE,
N_("RIST nack type, 0 = range, 1 = bitmask. Default is range"), NULL, true )
change_integer_list( nack_type_values, nack_type_names )
add_bool( RIST_CFG_PREFIX RIST_CFG_DISABLE_NACKS, false, RIST_DISABLE_NACKS_TEXT,
RIST_DISABLE_NACKS_LONGTEXT, true )
add_bool( RIST_CFG_PREFIX "mcast-blind-nacks", false, "Do not check for a valid rtcp message from the encoder",
"Send nack messages even when we have not confirmed that the encoder is on our local " \
"network.", true )
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_integer( RIST_CFG_PREFIX RIST_CFG_MAX_PACKET_SIZE, RIST_MAX_PACKET_SIZE,
RIST_PACKET_SIZE_TEXT, NULL, true )
add_string( RIST_CFG_PREFIX RIST_CFG_URL2, NULL, RIST_URL2_TEXT, NULL, true )
add_string( RIST_CFG_PREFIX RIST_CFG_URL3, NULL, RIST_URL3_TEXT, NULL, true )
add_string( RIST_CFG_PREFIX RIST_CFG_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_CFG_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_CFG_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_CFG_LATENCY, 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 )
add_string( RIST_CFG_PREFIX RIST_URL_PARAM_SRP_USERNAME, "",
RIST_SRP_USERNAME_TEXT, NULL, true )
add_password( RIST_CFG_PREFIX RIST_URL_PARAM_SRP_PASSWORD, "",
RIST_SRP_PASSWORD_TEXT, NULL )
set_capability( "access", 10 )
add_shortcut( "librist", "rist", "tr06" )
set_callbacks( Open, Close )
vlc_module_end ()
/*****************************************************************************
* rist.h: RIST (Reliable Internet Stream Transport) helper
*****************************************************************************
* Copyright (C) 2021, SipRadius LLC
*
* Authors: Sergio Ammirata <sergio@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_CFG_MAX_PACKET_SIZE "packet-size"
#define RIST_CFG_URL2 "peer-url2"
#define RIST_CFG_URL3 "peer-url3"
#define RIST_CFG_URL4 "peer-url4"
#define RIST_CFG_RETRY_INTERVAL "retry-interval"
#define RIST_CFG_MAX_RETRIES "max-retries"
#define RIST_CFG_LATENCY "latency"
#define RIST_CFG_DISABLE_NACKS "disable-nacks"
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 minimum retry interval (ms)")
#define RIST_REORDER_BUFFER_TEXT N_("RIST reorder buffer size (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" )
#define RIST_PACKET_SIZE_TEXT N_("RIST maximum packet size (bytes)")
#define RIST_DISABLE_NACKS_TEXT N_("Disable NACK packet processing")
#define RIST_DISABLE_NACKS_LONGTEXT N_("Use this to disable packet recovery")
#define RIST_SRP_USERNAME_TEXT N_("Username used for stream authentication")
#define RIST_SRP_PASSWORD_TEXT N_("Password used for stream authentication")
/* 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
// This will restrict the use of the library to the configured maximum packet size
#define RIST_MAX_PACKET_SIZE (10000)
#define RIST_MAX_LOG_BUFFER 512
typedef struct
{
vlc_object_t *p_access;
uint32_t i_log_counter;
char log_buffer[RIST_MAX_LOG_BUFFER];
} rist_log_t;
static inline int log_cb(void *arg, enum rist_log_level log_level, const char *msg)
{
rist_log_t *rist_log_callback_arg = (rist_log_t *)arg;
vlc_object_t *p_access = rist_log_callback_arg->p_access;
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;
int repeat_message = strncmp(msg1, rist_log_callback_arg->log_buffer, RIST_MAX_LOG_BUFFER);
if (repeat_message == 0)
rist_log_callback_arg->i_log_counter++;
if (rist_log_callback_arg->i_log_counter == 0)
{
strncpy(rist_log_callback_arg->log_buffer, msg1, RIST_MAX_LOG_BUFFER - 1);
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);
}
else if (repeat_message != 0)
{
msg_Info(p_access, "[RIST-%s]: Last message repeated %d times", rist_log_label[label_index], rist_log_callback_arg->i_log_counter);
rist_log_callback_arg->i_log_counter = 0;
}
return 0;
}
static inline int rist_get_max_packet_size(vlc_object_t *p_this)
{
int i_max_packet_size = var_InheritInteger( p_this, RIST_CFG_PREFIX RIST_CFG_MAX_PACKET_SIZE );
if (i_max_packet_size > RIST_MAX_PACKET_SIZE)
{
msg_Err(p_this, "The maximum packet size configured is bigger than what the library allows %d > %d, using %d instead",
i_max_packet_size, RIST_MAX_PACKET_SIZE, RIST_MAX_PACKET_SIZE);
i_max_packet_size = RIST_MAX_PACKET_SIZE;
}
return i_max_packet_size;
}
static inline bool rist_add_peers(vlc_object_t *p_this, struct rist_ctx *ctx, char *psz_url, int i_multipeer_mode, int virt_dst_port, int i_recovery_length)
{
char *addr[RIST_PEER_COUNT];
int i_rist_reorder_buffer = var_InheritInteger( p_this, RIST_CFG_PREFIX RIST_URL_PARAM_REORDER_BUFFER );
int i_rist_retry_interval = var_InheritInteger( p_this, RIST_CFG_PREFIX RIST_CFG_RETRY_INTERVAL );
int i_rist_max_retries = var_InheritInteger( p_this, RIST_CFG_PREFIX RIST_CFG_MAX_RETRIES );
int i_rist_max_bitrate = var_InheritInteger(p_this, RIST_CFG_PREFIX RIST_URL_PARAM_BANDWIDTH);
char *psz_stream_name = NULL;
psz_stream_name = var_InheritString( p_this, RIST_CFG_PREFIX RIST_URL_PARAM_CNAME );
char *psz_shared_secret = NULL;
psz_shared_secret = var_InheritString( p_this, RIST_CFG_PREFIX RIST_URL_PARAM_SECRET );
int i_key_size = var_InheritInteger(p_this, RIST_CFG_PREFIX RIST_URL_PARAM_AES_TYPE);
char *psz_srp_username = NULL;
psz_srp_username = var_InheritString( p_this, RIST_CFG_PREFIX RIST_URL_PARAM_SRP_USERNAME );
char *psz_srp_password = NULL;
psz_srp_password = var_InheritString( p_this, RIST_CFG_PREFIX RIST_URL_PARAM_SRP_PASSWORD );
int recovery_mode = RIST_RECOVERY_MODE_TIME;
bool b_disablenacks = var_InheritBool( p_this, RIST_CFG_PREFIX RIST_CFG_DISABLE_NACKS );
if (b_disablenacks)
recovery_mode = RIST_RECOVERY_MODE_DISABLED;
msg_Info( p_this, "Setting retry buffer to %d ms", i_recovery_length );
addr[0] = strdup(psz_url);
addr[1] = var_InheritString( p_this, RIST_CFG_PREFIX RIST_CFG_URL2 );
addr[2] = var_InheritString( p_this, RIST_CFG_PREFIX RIST_CFG_URL3 );
addr[3] = var_InheritString( p_this, RIST_CFG_PREFIX RIST_CFG_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')