Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (4)
......@@ -4273,6 +4273,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
......
1c45f87bb0f0ea5a7acb529a796c546190cb5b461297930f2fad214fe0a84c76771158564d9e0ac92e8882e5e008b406655940b3babb5d198e68816cbba4bc68 librist-v0.2.4.tar.gz
# librist
LIBRIST_VERSION := v0.2.4
LIBRIST_URL := http://code.videolan.org/rist/librist/-/archive/$(LIBRIST_VERSION)/librist-$(LIBRIST_VERSION).tar.gz
ifdef BUILD_NETWORK
PKGS += librist
endif
ifeq ($(call need_pkg,"librist >= 0.2"),)
PKGS_FOUND += librist
endif
LIBRIST_CONF = -Dbuilt_tools=false -Dtest=false
$(TARBALLS)/librist-$(LIBRIST_VERSION).tar.gz:
$(call download_pkg,$(LIBRIST_URL),librist)
.sum-librist: librist-$(LIBRIST_VERSION).tar.gz
librist: librist-$(LIBRIST_VERSION).tar.gz .sum-librist
$(UNPACK)
$(MOVE)
.librist: librist crossfile.meson
cd $< && rm -rf ./build
cd $< && $(HOSTVARS_MESON) $(MESON) $(LIBRIST_CONF) build
cd $< && cd build && ninja install
touch $@
......@@ -18,4 +18,4 @@ e9785f3d620a204b7d20222888917dc065c2036cae28667065bf7862dfa1b25235095a12fd04efdb
d24849b93de58b20f518c071687e7bfa653a96600382f36c4cf7fc1047656458f75f093b911b786b18b6931b2453cb60868ecbe07cc7d2984e5981a874b34942 help2man-1.47.6.tar.xz
8d23dde18525dccaa648ca01df40151e7f00cec4846bd611c8970dbcfc1fb57a453facfe4d41462e7c3c8bb548d44b961a04e4fc3073ab6b65063e53f42bf6fd nasm-2.14.tar.gz
1650bf9e3eddeb0b0fbb415c2b8e0a7c094421e991fa8139fd77fae0f6ee7ee980b7cf5e98d883c3a884f99abcb06fa26e3980af3a3a5bb6dd655124755782c2 ninja-1.8.2.tar.gz
172b4de8c7474d709f172431b89bf2b2b1c2c38bc842039cccf6be075a45bd3509a1dab8512bc5b2ee025d65d8050d2f717dd15c1f9be17fca3b2e7da0d3e889 meson-0.55.1.tar.gz
3b6cc5cae31d756b251ecde3483d3710bceff50cfd03ef6cf6f939d9e599998e61fcb03a2ee09d6a6f9bfa2198f43e7f20447359de3bff1055febcf03e82e514 meson-0.56.2.tar.gz
......@@ -57,7 +57,7 @@ GETTEXT_URL=$(GNU)/gettext/gettext-$(GETTEXT_VERSION).tar.gz
HELP2MAN_VERSION=1.47.6
HELP2MAN_URL=$(GNU)/help2man/help2man-$(HELP2MAN_VERSION).tar.xz
MESON_VERSION=0.55.1
MESON_VERSION=0.56.2
MESON_URL=https://github.com/mesonbuild/meson/releases/download/$(MESON_VERSION)/meson-$(MESON_VERSION).tar.gz
NINJA_VERSION=1.8.2
......
......@@ -449,8 +449,8 @@ EXTRA_LTLIBRARIES += libaccess_srt_plugin.la
### RIST ###
librist_plugin_la_SOURCES = access/rist.c access/rist.h
librist_plugin_la_CFLAGS = $(AM_CFLAGS) $(BITSTREAM_CFLAGS)
librist_plugin_la_LIBADD = $(SOCKET_LIBS)
if HAVE_BITSTREAM
access_LTLIBRARIES += librist_plugin.la
endif
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
This diff is collapsed.
/*****************************************************************************
* rist.h: RIST (Reliable Internet Stream Transport) helper
*****************************************************************************
* Copyright (C) 2018, DVEO, the Broadcast Division of Computer Modules, Inc.
* Copyright (C) 2018, SipRadius LLC
* Copyright (C) 2020, SipRadius LLC
*
* Authors: Sergio Ammirata <sergio@ammirata.net>
* Daniele Lacamera <root@danielinux.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
......@@ -22,346 +20,223 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <stdint.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <errno.h>
#include <assert.h>
#ifndef RIST_VLC_COMMON_H
#define RIST_VLC_COMMON_H 1
/*****************************************************************************
* Public API
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
/* RIST */
/* RTP header format (RFC 3550) */
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#define RIST_QUEUE_SIZE 65536
#define RTP_PKT_SIZE (1472)
#define RTCP_INTERVAL 75 /*ms*/
#define SEVENTY_YEARS_OFFSET (2208988800ULL)
#define MAX_NACKS 32
#define MAX_CNAME 128
#define RTCP_EMPTY_RR_SIZE 8
#define RTCP_PT_RTPFR 204
struct rtp_pkt {
uint32_t rtp_ts;
struct block_t *buffer;
#include <vlc_common.h>
#include <librist/librist.h>
/* RIST max fifo count (private RIST_DATAOUT_QUEUE_BUFFERS in librist) */
#define RIST_MAX_QUEUE_BUFFERS (1024)
/* 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"
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_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"),
};
/* RIST NACK header format */
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SNBase low bits | Length recovery |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|E| PT recovery | Mask |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TS recovery |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|N|D|type |index| Offset | NA |SNBase ext bits|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct rist_flow {
uint8_t reset;
struct rtp_pkt *buffer;
uint32_t qsize;
uint32_t last_out;
uint32_t ssrc;
char cname[MAX_CNAME];
struct sockaddr_storage peer_sockaddr;
socklen_t peer_socklen;
uint16_t ri, wi;
int fd_in;
int fd_out;
int fd_rtcp;
int fd_rtcp_m;
int fd_nack;
uint8_t nacks_retries[RIST_QUEUE_SIZE];
uint32_t hi_timestamp;
uint64_t feedback_time;
uint32_t latency;
uint32_t rtp_latency;
uint32_t retry_interval;
uint32_t reorder_buffer;
uint8_t max_retries;
uint32_t packets_count;
uint32_t bytes_count;
/* 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"),
};
static inline uint16_t rtcp_fb_nack_get_range_start(const uint8_t *p_rtcp_fb_nack)
{
return (p_rtcp_fb_nack[0] << 8) | p_rtcp_fb_nack[1];
}
/* Max number of peers */
// This will restrict the use of the library to the configured maximum packet size
#define RIST_MAX_PACKET_SIZE (10000)
static inline uint16_t rtcp_fb_nack_get_range_extra(const uint8_t *p_rtcp_fb_nack)
{
return (p_rtcp_fb_nack[2] << 8) | p_rtcp_fb_nack[3];
}
#define RIST_MAX_LOG_BUFFER 512
static inline void rtcp_fb_nack_set_range_start(uint8_t *p_rtcp_fb_nack,
uint16_t start)
{
p_rtcp_fb_nack[0] = (start >> 8) & 0xff;
p_rtcp_fb_nack[1] = start & 0xff;
}
static inline void rtcp_fb_nack_set_range_extra(uint8_t *p_rtcp_fb_nack,
uint16_t extra)
static inline int log_cb(void *arg, enum rist_log_level log_level, const char *msg)
{
p_rtcp_fb_nack[2] = (extra >> 8) & 0xff;
p_rtcp_fb_nack[3] = extra & 0xff;
vlc_object_t *p_access = (vlc_object_t *)arg;
int label_index = 0;
if (log_level > 8)
label_index = 8;
else if (log_level > 0)
label_index = log_level;
if (log_level == RIST_LOG_ERROR)
msg_Err(p_access, "[RIST-%s]: %.*s", rist_log_label[label_index], (int)strlen(msg) - 1, msg);
else if (log_level == RIST_LOG_WARN)
msg_Warn(p_access, "[RIST-%s]: %.*s", rist_log_label[label_index], (int)strlen(msg) - 1, msg);
else if (log_level == RIST_LOG_INFO)
//libRIST follows Syslog log priorities and assigns INFO a low prio, VLC gives Info the highest
//so make it warn (debug would be too verbose)
msg_Warn(p_access, "[RIST-%s]: %.*s", rist_log_label[label_index], (int)strlen(msg) - 1, msg);
else if (log_level > RIST_LOG_DEBUG)
msg_Dbg(p_access, "[RIST-%s]: %.*s", rist_log_label[label_index], (int)strlen(msg) - 1, msg);
return 0;
}
static inline void populate_cname(int fd, char *identifier)
static inline int rist_get_max_packet_size(vlc_object_t *p_this)
{
/* Set the CNAME Identifier as host@ip:port and fallback to hostname if needed */
char hostname[MAX_CNAME];
struct sockaddr_storage peer_sockaddr;
int name_length = 0;
socklen_t peer_socklen = 0;
int ret_hostname = gethostname(hostname, MAX_CNAME);
if (ret_hostname == -1)
snprintf(hostname, MAX_CNAME, "UnknownHost");
int ret_sockname = getsockname(fd, (struct sockaddr *)&peer_sockaddr, &peer_socklen);
if (ret_sockname == 0)
{
struct sockaddr *peer = (struct sockaddr *)&peer_sockaddr;
if (peer->sa_family == AF_INET) {
struct sockaddr_in *xin = (void*)peer;
name_length = snprintf(identifier, MAX_CNAME, "%s@%s:%u", hostname,
inet_ntoa(xin->sin_addr), ntohs(xin->sin_port));
if (name_length >= MAX_CNAME)
identifier[MAX_CNAME-1] = 0;
} else if (peer->sa_family == AF_INET6) {
struct sockaddr_in6 *xin6 = (void*)peer;
char str[INET6_ADDRSTRLEN];
inet_ntop(xin6->sin6_family, &xin6->sin6_addr, str, sizeof(struct in6_addr));
name_length = snprintf(identifier, MAX_CNAME, "%s@%s:%u", hostname,
str, ntohs(xin6->sin6_port));
if (name_length >= MAX_CNAME)
identifier[MAX_CNAME-1] = 0;
}
}
if (name_length == 0)
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)
{
name_length = snprintf(identifier, MAX_CNAME, "%s", hostname);
if (name_length >= MAX_CNAME)
identifier[MAX_CNAME-1] = 0;
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 uint32_t rtp_get_ts( vlc_tick_t i_pts )
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)
{
unsigned i_clock_rate = 90000;
/* This is an overflow-proof way of doing:
* return i_pts * (int64_t)i_clock_rate / CLOCK_FREQ;
*
* NOTE: this plays nice with offsets because the (equivalent)
* calculations are linear. */
lldiv_t q = lldiv(i_pts, CLOCK_FREQ);
return q.quot * (int64_t)i_clock_rate
+ q.rem * (int64_t)i_clock_rate / CLOCK_FREQ;
}
static inline vlc_tick_t ts_get_from_rtp( uint32_t i_rtp_ts )
{
unsigned i_clock_rate = 90000;
return (vlc_tick_t)i_rtp_ts * (vlc_tick_t)(CLOCK_FREQ/i_clock_rate);
}
static inline ssize_t rist_ReadFrom_i11e(int fd, void *buf, size_t len, struct sockaddr *peer,
socklen_t *slen)
{
ssize_t ret = -1;
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);
if (peer == NULL)
ret = vlc_recv_i11e(fd, buf, len, 0);
else
ret = vlc_recvfrom_i11e(fd, buf, len, 0, peer, slen);
char *psz_stream_name = NULL;
psz_stream_name = var_InheritString( p_this, RIST_CFG_PREFIX RIST_URL_PARAM_CNAME );
if (ret == -1)
{
switch (errno)
{
case EAGAIN:
case EINTR:
if (vlc_killed())
return ret;
/* retry one time */
if (peer == NULL)
ret = vlc_recv_i11e(fd, buf, len, 0);
else
ret = vlc_recvfrom_i11e(fd, buf, len, 0, peer, slen);
default:
break;
}
}
return ret;
}
char *psz_shared_secret = NULL;
psz_shared_secret = var_InheritString( p_this, RIST_CFG_PREFIX RIST_URL_PARAM_SECRET );
static inline ssize_t rist_Read_i11e(int fd, void *buf, size_t len)
{
return rist_ReadFrom_i11e(fd, buf, len, NULL, NULL);
}
int i_key_size = var_InheritInteger(p_this, RIST_CFG_PREFIX RIST_URL_PARAM_AES_TYPE);
static inline ssize_t rist_ReadFrom(int fd, void *buf, size_t len, struct sockaddr *peer,
socklen_t *slen)
{
ssize_t ret = -1;
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 );
if (peer == NULL)
ret = recv(fd, buf, len, 0);
else
ret = recvfrom(fd, buf, len, 0, peer, slen);
int recovery_mode = RIST_RECOVERY_MODE_TIME;
if (ret == -1)
{
switch (errno)
{
case EAGAIN:
case EINTR:
/* retry one time */
if (peer == NULL)
ret = recv(fd, buf, len, 0);
else
ret = recvfrom(fd, buf, len, 0, peer, slen);
default:
break;
}
}
return ret;
}
msg_Info( p_this, "Setting retry buffer to %d ms", i_recovery_length );
static inline ssize_t rist_Read(int fd, void *buf, size_t len)
{
return rist_ReadFrom(fd, buf, len, NULL, NULL);
}
char *addr[] = {
strdup(psz_url),
var_InheritString( p_this, RIST_CFG_PREFIX RIST_CFG_URL2 ),
var_InheritString( p_this, RIST_CFG_PREFIX RIST_CFG_URL3 ),
var_InheritString( p_this, RIST_CFG_PREFIX RIST_CFG_URL4 )
};
static inline ssize_t rist_WriteTo_i11e(int fd, const void *buf, size_t len,
const struct sockaddr *peer, socklen_t slen)
{
#ifdef _WIN32
# define ENOBUFS WSAENOBUFS
# define EAGAIN WSAEWOULDBLOCK
# define EWOULDBLOCK WSAEWOULDBLOCK
#endif
ssize_t r = -1;
if (slen == 0)
r = vlc_send_i11e( fd, buf, len, 0 );
else
r = vlc_sendto_i11e( fd, buf, len, 0, peer, slen );
if( r == -1
&& net_errno != EAGAIN && net_errno != EWOULDBLOCK
&& net_errno != ENOBUFS && net_errno != ENOMEM )
{
int type;
if (!getsockopt( fd, SOL_SOCKET, SO_TYPE,
&type, &(socklen_t){ sizeof(type) }))
{
if( type == SOCK_DGRAM )
{
/* ICMP soft error: ignore and retry */
if (slen == 0)
r = vlc_send_i11e( fd, buf, len, 0 );
else
r = vlc_sendto_i11e( fd, buf, len, 0, peer, slen );
}
bool b_peer_alive = false;
for (size_t i = 0; i < ARRAY_SIZE(addr); i++) {
if (addr[i] == NULL) {
continue;
}
else if (addr[i][0] == '\0') {
free(addr[i]);
continue;
}
}
return r;
}
static inline ssize_t rist_Write_i11e(int fd, const void *buf, size_t len)
{
return rist_WriteTo_i11e(fd, buf, len, NULL, 0);
}
struct rist_peer_config app_peer_config = {
.version = RIST_PEER_CONFIG_VERSION,
.virt_dst_port = virt_dst_port,
.recovery_mode = recovery_mode,
.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)10*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') {
strlcpy(app_peer_config.secret, psz_shared_secret, sizeof(app_peer_config.secret));
}
static inline ssize_t rist_WriteTo(int fd, const void *buf, size_t len, const struct sockaddr *peer,
socklen_t slen)
{
#ifdef _WIN32
# define ENOBUFS WSAENOBUFS
# define EAGAIN WSAEWOULDBLOCK
# define EWOULDBLOCK WSAEWOULDBLOCK
#endif
ssize_t r = -1;
if (slen == 0)
r = send( fd, buf, len, 0 );
else
r = sendto( fd, buf, len, 0, peer, slen );
if( r == -1
&& net_errno != EAGAIN && net_errno != EWOULDBLOCK
&& net_errno != ENOBUFS && net_errno != ENOMEM )
{
int type;
if (!getsockopt( fd, SOL_SOCKET, SO_TYPE,
&type, &(socklen_t){ sizeof(type) }))
if ( psz_stream_name != NULL && psz_stream_name[0] != '\0') {
strlcpy(app_peer_config.cname, psz_stream_name, sizeof(app_peer_config.cname));
}
// URL overrides (also cleans up the URL)
struct rist_peer_config *peer_config = &app_peer_config;
if (rist_parse_address2(addr[i], &peer_config))
{
if( type == SOCK_DGRAM )
{
/* ICMP soft error: ignore and retry */
if (slen == 0)
r = send( fd, buf, len, 0 );
else
r = sendto( fd, buf, len, 0, peer, slen );
}
msg_Err( p_this, "Could not parse peer options for sender #%d\n", (int)(i + 1));
free(addr[i]);
continue;
}
struct rist_peer *peer;
if (rist_peer_create(ctx, &peer, peer_config)) {
msg_Err( p_this, "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]);
}
return r;
}
static inline ssize_t rist_Write(int fd, const void *buf, size_t len)
{
return rist_WriteTo(fd, buf, len, NULL, 0);
}
free(psz_shared_secret);
free(psz_stream_name);
free(psz_srp_username);
free(psz_srp_password);
static bool is_multicast_address(char *psz_dst_server)
{
int ret;
int ismulticast = 0;
struct addrinfo hint = {
.ai_socktype = SOCK_DGRAM,
.ai_protocol = IPPROTO_UDP,
.ai_flags = AI_NUMERICSERV | AI_IDN | AI_PASSIVE,
}, *res;
ret = vlc_getaddrinfo(psz_dst_server, 0, &hint, &res);
if (ret) {
return 0;
} else if(res->ai_family == AF_INET) {
unsigned long addr = ntohl(inet_addr(psz_dst_server));
ismulticast = IN_MULTICAST(addr);
} else if (res->ai_family == AF_INET6) {
if (strlen(psz_dst_server) >= 5 && (strncmp("[ff00", psz_dst_server, 5) == 0 ||
strncmp("[FF00", psz_dst_server, 5) == 0))
ismulticast = 1;
}
return b_peer_alive;
freeaddrinfo(res);
}
#endif
return ismulticast;
}
\ No newline at end of file
......@@ -41,9 +41,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_LIBADD = $(SOCKET_LIBS)
if HAVE_BITSTREAM
access_out_LTLIBRARIES += libaccess_output_rist_plugin.la
endif
libaccess_output_rist_plugin_la_SOURCES = access_output/rist.c
libaccess_output_rist_plugin_la_CFLAGS = $(AM_CFLAGS) $(RIST_CFLAGS)
libaccess_output_rist_plugin_la_LIBADD = $(RIST_LIBS) $(SOCKET_LIBS) $(LIBPTHREAD)
libaccess_output_rist_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(access_outdir)'
access_out_LTLIBRARIES += $(LTLIBaccess_output_rist)
EXTRA_LTLIBRARIES += libaccess_output_rist_plugin.la
/*****************************************************************************
* * rist.c: RIST (Reliable Internet Stream Transport) output module
* 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) 2021, SipRadius LLC
*
* Authors: Sergio Ammirata <sergio@ammirata.net>
* Daniele Lacamera <root@danielinux.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
......@@ -28,568 +26,75 @@
#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_queue.h>
#include <vlc_threads.h>
#include <vlc_rand.h>
#ifdef HAVE_POLL_H
#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>
#define RIST_CFG_PREFIX "sout-rist-"
#include "../access/rist.h"
/* Uncomment the following to introduce induced packet loss for TESTING purposes only */
/*#define TEST_PACKET_LOSS*/
/* 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 MPEG_II_TRANSPORT_STREAM (0x21)
#define RIST_DEFAULT_PORT 1968
#define SOUT_CFG_PREFIX "sout-rist-"
static const char *const ppsz_sout_options[] = {
"packet-size",
"caching",
"buffer-size",
"ssrc",
"stream-name",
RIST_CFG_MAX_PACKET_SIZE,
RIST_URL_PARAM_VIRT_SRC_PORT,
RIST_URL_PARAM_VIRT_DST_PORT,
RIST_CFG_LATENCY,
"multipeer-mode",
RIST_CFG_URL2,
RIST_CFG_URL3,
RIST_CFG_URL4,
RIST_URL_PARAM_BANDWIDTH,
RIST_CFG_RETRY_INTERVAL,
RIST_URL_PARAM_REORDER_BUFFER,
RIST_CFG_MAX_RETRIES,
RIST_URL_PARAM_VERBOSE_LEVEL,
RIST_URL_PARAM_CNAME,
RIST_URL_PARAM_PROFILE,
RIST_URL_PARAM_SECRET,
RIST_URL_PARAM_AES_TYPE,
RIST_URL_PARAM_SRP_USERNAME,
RIST_URL_PARAM_SRP_PASSWORD,
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;
bool dead;
vlc_queue_t queue;
/* stats variables */
uint64_t i_last_stat;
uint32_t i_retransmit_packets;
uint32_t i_total_packets;
struct rist_ctx *sender_ctx;
int gre_src_port;
int gre_dst_port;
uint32_t i_recovery_buffer;
size_t i_max_packet_size;
struct rist_logging_settings logging_settings;
} 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 )
static int cb_stats(void *arg, const struct rist_stats *stats_container)
{
sout_access_out_t *p_access = data;
sout_access_out_t *p_access = (sout_access_out_t*)arg;
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;
block_t *out;
while ((out = vlc_queue_DequeueKillable(&p_sys->queue,
&p_sys->dead)) != NULL)
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_Dbg(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->i_recovery_buffer)
{
ssize_t len = 0;
uint16_t seq = 0;
uint32_t pkt_ts = 0;
vlc_tick_wait (out->i_dts + i_caching);
len = out->i_buffer;
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++;
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->i_recovery_buffer);
}
return NULL;
}
static void SendtoFIFO( sout_access_out_t *p_access, block_t *buffer )
{
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);
vlc_queue_Enqueue(&p_sys->queue, block_Duplicate(buffer));
rist_stats_free(stats_container);
return 0;
}
static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
......@@ -597,56 +102,24 @@ 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;
struct rist_data_block rist_buffer = { 0 };
rist_buffer.virt_src_port = p_sys->gre_src_port;
rist_buffer.virt_dst_port = p_sys->gre_dst_port;
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 )
{
SendtoFIFO(p_access, p_sys->p_pktbuffer);
p_sys->p_pktbuffer->i_buffer = RTP_HEADER_SIZE;
}
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 == RTP_HEADER_SIZE )
{
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;
size_t i_write = __MIN( p_buffer->i_buffer, p_sys->i_max_packet_size );
rist_buffer.payload = p_buffer->p_buffer;
rist_buffer.payload_len = p_buffer->i_buffer;
rist_sender_data_write(p_sys->sender_ctx, &rist_buffer);
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 )
{
SendtoFIFO(p_access, p_sys->p_pktbuffer);
p_sys->p_pktbuffer->i_buffer = RTP_HEADER_SIZE;
}
}
p_next = p_buffer->p_next;
......@@ -654,10 +127,6 @@ static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
p_buffer = p_next;
}
if ( i_len <= 0 ) {
block_ChainRelease( p_buffer );
}
return i_len;
}
......@@ -681,49 +150,13 @@ 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 ( 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);
}
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_queue_Kill(&p_sys->queue, &p_sys->dead);
vlc_join(p_sys->ristthread, NULL);
vlc_join(p_sys->senderthread, NULL);
Clean( p_access );
rist_destroy(p_sys->sender_ctx);
p_sys->sender_ctx = NULL;
}
static int Open( vlc_object_t *p_this )
......@@ -737,78 +170,65 @@ static int Open( vlc_object_t *p_this )
|| var_Create ( p_access, "src-addr", VLC_VAR_STRING ) )
{
msg_Err( p_access, "Valid network information is required." );
return VLC_ENOMEM;
return VLC_EGENERIC;
}
config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
config_ChainParse( p_access, RIST_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;
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 )
return VLC_ENOMEM;
p_access->p_sys = p_sys;
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 );
p_sys->gre_src_port = var_InheritInteger(p_access, RIST_CFG_PREFIX RIST_URL_PARAM_VIRT_SRC_PORT);
p_sys->gre_dst_port = var_InheritInteger(p_access, RIST_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_EGENERIC;
}
vlc_mutex_init( &p_sys->lock );
vlc_mutex_init( &p_sys->fd_lock );
p_sys->i_max_packet_size = rist_get_max_packet_size((vlc_object_t *)p_access);
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)
goto failed;
int i_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);
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);
//disable global logging: see comment in access/rist.c
struct rist_logging_settings rist_global_logging_settings = LOGGING_SETTINGS_INITIALIZER;
if (rist_logging_set_global(&rist_global_logging_settings) != 0) {
msg_Err(p_access,"Could not set logging\n");
return VLC_EGENERIC;
}
/* 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->dead = false;
vlc_queue_Init(&p_sys->queue, offsetof (block_t, p_next));
p_sys->p_pktbuffer = block_Alloc( p_sys->i_packet_size );
if( unlikely(p_sys->p_pktbuffer == NULL) )
goto failed;
p_sys->p_pktbuffer->i_buffer = RTP_HEADER_SIZE;
struct rist_logging_settings *logging_settings = &p_sys->logging_settings;
logging_settings->log_socket = -1;
logging_settings->log_stream = NULL;
logging_settings->log_level = i_verbose_level;
logging_settings->log_cb = log_cb;
logging_settings->log_cb_arg = p_access;
p_access->p_sys = p_sys;
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");
return VLC_EGENERIC;
}
if( vlc_clone(&p_sys->senderthread, ThreadSend, p_access, VLC_THREAD_PRIORITY_HIGHEST ) )
{
msg_Err(p_access, "Failed to create sender thread.");
// 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;
}
if (vlc_clone(&p_sys->ristthread, rist_thread, p_access, VLC_THREAD_PRIORITY_INPUT))
{
msg_Err(p_access, "Failed to create worker thread.");
vlc_queue_Kill(&p_sys->queue, &p_sys->dead);
vlc_join(p_sys->senderthread, NULL);
int i_multipeer_mode = var_InheritInteger(p_access, RIST_CFG_PREFIX "multipeer-mode");
int i_recovery_length = var_InheritInteger(p_access, RIST_CFG_PREFIX RIST_CFG_LATENCY);
p_sys->i_recovery_buffer = i_recovery_length;
if ( !rist_add_peers((vlc_object_t *)p_access, p_sys->sender_ctx, p_access->psz_path, i_multipeer_mode, p_sys->gre_dst_port + 1, i_recovery_length) )
goto failed;
if (rist_start(p_sys->sender_ctx) == -1) {
msg_Err( p_access, "Could not start rist sender\n");
goto failed;
}
......@@ -818,31 +238,32 @@ static int Open( vlc_object_t *p_this )
return VLC_SUCCESS;
failed:
Clean( p_access );
rist_destroy(p_sys->sender_ctx);
p_sys->sender_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" )
#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 NAME_TEXT N_("Stream name")
#define NAME_LONGTEXT N_( \
"This Stream name will be sent to the receiver using the rist RTCP channel" )
#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()
......@@ -852,19 +273,49 @@ vlc_module_begin()
set_category( CAT_SOUT )
set_subcategory( SUBCAT_SOUT_ACO )
add_integer( SOUT_CFG_PREFIX "packet-size", RIST_TARGET_PACKET_SIZE,
N_("RIST target packet size (bytes)"), NULL )
add_integer( SOUT_CFG_PREFIX "caching", DEFAULT_CACHING_DELAY,
CACHING_TEXT, CACHING_LONGTEXT )
add_integer( SOUT_CFG_PREFIX "buffer-size", DEFAULT_BUFFER_SIZE,
add_integer( RIST_CFG_PREFIX RIST_CFG_MAX_PACKET_SIZE, RIST_DEFAULT_TARGET_PAYLOAD_SIZE,
N_("RIST target payload size (bytes)"), NULL )
add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_VIRT_SRC_PORT, RIST_DEFAULT_VIRT_SRC_PORT,
SRC_PORT_TEXT, SRC_PORT_LONGTEXT )
add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_VIRT_DST_PORT, RIST_DEFAULT_VIRT_DST_PORT,
DST_PORT_TEXT, DST_PORT_LONGTEXT )
add_integer( RIST_CFG_PREFIX "multipeer-mode", RIST_DEFAULT_MULTIPEER_MODE,
RIST_MULTIPEER_MODE_TEXT, RIST_MULTIPEER_MODE_LONGTEXT )
change_integer_list( multipeer_mode_type, multipeer_mode_type_names )
add_string( RIST_CFG_PREFIX RIST_CFG_URL2, NULL, RIST_URL2_TEXT, NULL )
add_string( RIST_CFG_PREFIX RIST_CFG_URL3, NULL, RIST_URL3_TEXT, NULL )
add_string( RIST_CFG_PREFIX RIST_CFG_URL4, NULL, RIST_URL4_TEXT, NULL )
add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_BANDWIDTH, RIST_DEFAULT_RECOVERY_MAXBITRATE,
RIST_MAX_BITRATE_TEXT, RIST_MAX_BITRATE_LONGTEXT )
add_integer( RIST_CFG_PREFIX RIST_CFG_RETRY_INTERVAL, RIST_DEFAULT_RECOVERY_RTT_MIN,
RIST_RETRY_INTERVAL_TEXT, NULL )
add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_REORDER_BUFFER, RIST_DEFAULT_RECOVERY_REORDER_BUFFER,
RIST_REORDER_BUFFER_TEXT, NULL )
add_integer( RIST_CFG_PREFIX RIST_CFG_MAX_RETRIES, RIST_DEFAULT_MAX_RETRIES,
RIST_MAX_RETRIES_TEXT, NULL )
add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_VERBOSE_LEVEL, RIST_DEFAULT_VERBOSE_LEVEL,
RIST_VERBOSE_LEVEL_TEXT, RIST_VERBOSE_LEVEL_LONGTEXT )
change_integer_list( verbose_level_type, verbose_level_type_names )
add_integer( RIST_CFG_PREFIX RIST_CFG_LATENCY, RIST_DEFAULT_RECOVERY_LENGHT_MIN,
BUFFER_TEXT, BUFFER_LONGTEXT )
add_integer( SOUT_CFG_PREFIX "ssrc", 0,
SSRC_TEXT, SSRC_LONGTEXT )
add_string( SOUT_CFG_PREFIX "stream-name", NULL, NAME_TEXT, NAME_LONGTEXT )
set_capability( "sout access", 0 )
add_shortcut( "rist", "tr06" )
add_string( RIST_CFG_PREFIX RIST_URL_PARAM_CNAME, NULL, RIST_CNAME_TEXT,
RIST_CNAME_LONGTEXT )
add_integer( RIST_CFG_PREFIX RIST_URL_PARAM_PROFILE, RIST_DEFAULT_PROFILE,
RIST_PROFILE_TEXT, RIST_PROFILE_LONGTEXT )
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 )
change_integer_list( rist_encryption_type, rist_encryption_type_names )
add_string( RIST_CFG_PREFIX RIST_URL_PARAM_SRP_USERNAME, "",
RIST_SRP_USERNAME_TEXT, NULL )
add_password( RIST_CFG_PREFIX RIST_URL_PARAM_SRP_PASSWORD, "",
RIST_SRP_PASSWORD_TEXT, NULL )
set_capability( "sout access", 10 )
add_shortcut( "librist", "rist", "tr06" )
set_callbacks( Open, Close )
vlc_module_end ()