SRT improvements:

- Made SRT support optional
- Make build options visible in cmake-gui
- Improved generic connection stats for outputs
- Added streamid handling configuration for MistInTSSRT
- Push input support over SRT
- Fixed support for SRT settings in push outputs
- Fix parsing of SRT-passed stream names
- Fixed hostnames in MistOutTSSRT, fixed PUSH_REWRITE trigger payload
- Opus support in TS-SRT
- Fixed SRT socket stats, fixed SRT socket address logic, improved SRT socket rolling restart support
- Fixed SRT push deny
This commit is contained in:
Thulinma 2020-08-28 00:42:38 +02:00
parent 19199cbff8
commit 0bd5d742f6
19 changed files with 686 additions and 347 deletions

View file

@ -1,6 +1,8 @@
#include "defines.h"
#include "lib/http_parser.h"
#include "socket_srt.h"
#include "json.h"
#include "timing.h"
#include <cstdlib>
#include <sstream>
@ -69,13 +71,20 @@ namespace Socket{
return interpretSRTMode(params.count("mode") ? params.at("mode") : "default", u.host, "");
}
SRTConnection::SRTConnection(){initializeEmpty();}
SRTConnection::SRTConnection(){
initializeEmpty();
lastGood = Util::bootMS();
}
SRTConnection::SRTConnection(const std::string &_host, int _port, const std::string &_direction,
const std::map<std::string, std::string> &_params){
connect(_host, _port, _direction, _params);
}
SRTConnection::SRTConnection(SRTSOCKET alreadyConnected){
sock = alreadyConnected;
}
std::string SRTConnection::getStreamName(){
int sNameLen = 512;
char sName[sNameLen];
@ -84,29 +93,89 @@ namespace Socket{
return "";
}
/// Updates the downbuffer internal variable.
/// Returns true if new data was received, false otherwise.
std::string SRTConnection::RecvNow(){
char recvbuf[5000];
std::string SRTConnection::getBinHost(){
char tmpBuffer[17] = "\000\000\000\000\000\000\000\000\000\000\377\377\000\000\000\000";
switch (remoteaddr.sin6_family){
case AF_INET:
memcpy(tmpBuffer + 12, &(reinterpret_cast<const sockaddr_in *>(&remoteaddr)->sin_addr.s_addr), 4);
break;
case AF_INET6: memcpy(tmpBuffer, &(remoteaddr.sin6_addr.s6_addr), 16); break;
default: return ""; break;
}
return std::string(tmpBuffer, 16);
}
size_t SRTConnection::RecvNow(){
bool blockState = blocking;
setBlocking(true);
if (!blockState){setBlocking(true);}
SRT_MSGCTRL mc = srt_msgctrl_default;
int32_t receivedBytes = srt_recvmsg2(sock, recvbuf, 5000, &mc);
if (prev_pktseq != 0 && (mc.pktseq - prev_pktseq > 1)){WARN_MSG("Packet lost");}
//if (prev_pktseq != 0 && (mc.pktseq - prev_pktseq > 1)){WARN_MSG("Packet lost");}
prev_pktseq = mc.pktseq;
setBlocking(blockState);
if (!blockState){setBlocking(blockState);}
if (receivedBytes == -1){
int err = srt_getlasterror(0);
if (err == SRT_ECONNLOST){
close();
return 0;
}
if (err == SRT_ENOCONN){
if (Util::bootMS() > lastGood + 5000){
ERROR_MSG("SRT connection timed out - closing");
close();
}
return 0;
}
ERROR_MSG("Unable to receive data over socket: %s", srt_getlasterror_str());
if (srt_getsockstate(sock) != SRTS_CONNECTED){close();}
return "";
return 0;
}
if (receivedBytes == 0){
close();
}else{
lastGood = Util::bootMS();
}
srt_bstats(sock, &performanceMonitor, false);
return std::string(recvbuf, receivedBytes);
return receivedBytes;
}
///Attempts a read, obeying the current blocking setting.
///May result in socket being disconnected when connection was lost during read.
///Returns amount of bytes actually read
size_t SRTConnection::Recv(){
SRT_MSGCTRL mc = srt_msgctrl_default;
int32_t receivedBytes = srt_recvmsg2(sock, recvbuf, 5000, &mc);
prev_pktseq = mc.pktseq;
if (receivedBytes == -1){
int err = srt_getlasterror(0);
if (err == SRT_EASYNCRCV){return 0;}
if (err == SRT_ECONNLOST){
close();
return 0;
}
if (err == SRT_ENOCONN){
if (Util::bootMS() > lastGood + 5000){
ERROR_MSG("SRT connection timed out - closing");
close();
}
return 0;
}
ERROR_MSG("Unable to receive data over socket: %s", srt_getlasterror_str());
if (srt_getsockstate(sock) != SRTS_CONNECTED){close();}
return 0;
}
if (receivedBytes == 0){
close();
}else{
lastGood = Util::bootMS();
}
srt_bstats(sock, &performanceMonitor, false);
return receivedBytes;
}
void SRTConnection::connect(const std::string &_host, int _port, const std::string &_direction,
@ -143,6 +212,7 @@ namespace Socket{
HIGH_MSG("Going to connect sock %d", sock);
if (srt_connect(sock, psa, sizeof sa) == SRT_ERROR){
srt_close(sock);
sock = -1;
ERROR_MSG("Can't connect SRT Socket");
return;
}
@ -153,6 +223,7 @@ namespace Socket{
return;
}
INFO_MSG("Caller SRT socket %" PRId32 " success targetting %s:%u", sock, _host.c_str(), _port);
lastGood = Util::bootMS();
return;
}
if (modeName == "listener"){
@ -163,14 +234,17 @@ namespace Socket{
if (srt_bind(sock, psa, sizeof sa) == SRT_ERROR){
srt_close(sock);
ERROR_MSG("Can't connect SRT Socket");
sock = -1;
ERROR_MSG("Can't connect SRT Socket: %s", srt_getlasterror_str());
return;
}
if (srt_listen(sock, 1) == SRT_ERROR){
srt_close(sock);
sock = -1;
ERROR_MSG("Can not listen on Socket");
}
INFO_MSG("Listener SRT socket sucess @ %s:%u", _host.c_str(), _port);
lastGood = Util::bootMS();
return;
}
if (modeName == "rendezvous"){
@ -182,6 +256,7 @@ namespace Socket{
if (srt_bind(sock, psa, sizeof sa) == SRT_ERROR){
srt_close(sock);
sock = -1;
ERROR_MSG("Can't connect SRT Socket");
return;
}
@ -191,6 +266,7 @@ namespace Socket{
if (srt_connect(sock, psb, sizeof sb) == SRT_ERROR){
srt_close(sock);
sock = -1;
ERROR_MSG("Can't connect SRT Socket");
return;
}
@ -200,6 +276,7 @@ namespace Socket{
return;
}
INFO_MSG("Rendezvous SRT socket sucess @ %s:%u", _host.c_str(), _port);
lastGood = Util::bootMS();
return;
}
ERROR_MSG("Invalid mode parameter. Use 'client' or 'server'");
@ -220,8 +297,23 @@ namespace Socket{
int res = srt_sendmsg2(sock, data, len, NULL);
if (res == SRT_ERROR){
int err = srt_getlasterror(0);
//Do not report normal connection lost errors
if (err == SRT_ECONNLOST){
close();
return;
}
if (err == SRT_ENOCONN){
if (Util::bootMS() > lastGood + 5000){
ERROR_MSG("SRT connection timed out - closing");
close();
}
return;
}
ERROR_MSG("Unable to send data over socket %" PRId32 ": %s", sock, srt_getlasterror_str());
if (srt_getsockstate(sock) != SRTS_CONNECTED){close();}
}else{
lastGood = Util::bootMS();
}
srt_bstats(sock, &performanceMonitor, false);
}
@ -236,16 +328,16 @@ namespace Socket{
uint64_t SRTConnection::dataDown(){return performanceMonitor.byteRecvTotal;}
uint64_t SRTConnection::packetCount(){
return (direction == "input" ? performanceMonitor.pktRecvTotal : performanceMonitor.pktSentTotal);
return (direction == "output" ? performanceMonitor.pktSentTotal : performanceMonitor.pktRecvTotal);
}
uint64_t SRTConnection::packetLostCount(){
return (direction == "input" ? performanceMonitor.pktRcvLossTotal : performanceMonitor.pktSndLossTotal);
return (direction == "output" ? performanceMonitor.pktSndLossTotal : performanceMonitor.pktRcvLossTotal);
}
uint64_t SRTConnection::packetRetransmitCount(){
//\todo This should be updated with pktRcvRetransTotal on the retrieving end once srt has implemented this.
return (direction == "input" ? 0 : performanceMonitor.pktRetransTotal);
return (direction == "output" ? performanceMonitor.pktRetransTotal : 0);
}
void SRTConnection::initializeEmpty(){
@ -259,10 +351,8 @@ namespace Socket{
void SRTConnection::setBlocking(bool _blocking){
if (_blocking == blocking){return;}
// If we have an error setting the new blocking state, the state is unchanged so we return early.
if (srt_setsockopt(sock, 0, (direction == "output" ? SRTO_SNDSYN : SRTO_RCVSYN), &_blocking,
sizeof _blocking) == -1){
return;
}
if (srt_setsockopt(sock, 0, SRTO_SNDSYN, &_blocking, sizeof _blocking) == -1){return;}
if (srt_setsockopt(sock, 0, SRTO_RCVSYN, &_blocking, sizeof _blocking) == -1){return;}
blocking = _blocking;
}
@ -289,7 +379,7 @@ namespace Socket{
if (adapter == "" && modeName == "listener"){adapter = _host;}
tsbpdMode = ((params.count("tsbpd") && isFalseString(params.at("tsbpd"))) ? false : true);
tsbpdMode = (params.count("tsbpd") && JSON::Value(params.at("tsbpd")).asBool());
outgoing_port = (params.count("port") ? strtol(params.at("port").c_str(), 0, 0) : 0);
@ -332,14 +422,11 @@ namespace Socket{
int SRTConnection::postConfigureSocket(){
bool no = false;
if (srt_setsockopt(sock, 0, (direction == "output" ? SRTO_SNDSYN : SRTO_RCVSYN), &no, sizeof no) == -1){
return -1;
}
if (srt_setsockopt(sock, 0, SRTO_SNDSYN, &no, sizeof no) == -1){return -1;}
if (srt_setsockopt(sock, 0, SRTO_RCVSYN, &no, sizeof no) == -1){return -1;}
if (timeout){
if (srt_setsockopt(sock, 0, (direction == "output" ? SRTO_SNDTIMEO : SRTO_RCVTIMEO), &timeout,
sizeof timeout) == -1){
return -1;
}
if (srt_setsockopt(sock, 0, SRTO_SNDTIMEO, &timeout, sizeof timeout) == -1){return -1;}
if (srt_setsockopt(sock, 0, SRTO_RCVTIMEO, &timeout, sizeof timeout) == -1){return -1;}
}
std::string errMsg = configureSocketLoop(SRT::SockOpt::POST);
if (errMsg.size()){
@ -455,15 +542,7 @@ namespace Socket{
}
}break;
case SRT::SockOpt::BOOL:{
bool tmp;
if (isFalseString(v)){
tmp = true;
}else if (isTrueString(v)){
tmp = true;
}else{
return false;
}
val.b = tmp;
val.b = JSON::Value(v).asBool();
val.value = &val.b;
val.size = sizeof val.b;
}break;