TSSRT Support
This commit is contained in:
parent
974380ab30
commit
19199cbff8
17 changed files with 1471 additions and 15 deletions
|
@ -5,8 +5,8 @@
|
|||
#include "encode.h"
|
||||
#include "procs.h"
|
||||
#include "timing.h"
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Comms{
|
||||
Comms::Comms(){
|
||||
|
@ -166,6 +166,9 @@ namespace Comms{
|
|||
dataAccX.addField("stream", RAX_STRING, 100);
|
||||
dataAccX.addField("connector", RAX_STRING, 20);
|
||||
dataAccX.addField("crc", RAX_32UINT);
|
||||
dataAccX.addField("pktcount", RAX_64UINT);
|
||||
dataAccX.addField("pktloss", RAX_64UINT);
|
||||
dataAccX.addField("pktretrans", RAX_64UINT);
|
||||
}
|
||||
|
||||
void Statistics::nullFields(){
|
||||
|
@ -180,6 +183,9 @@ namespace Comms{
|
|||
setTime(0);
|
||||
setNow(0);
|
||||
setSync(0);
|
||||
setPacketCount(0);
|
||||
setPacketLostCount(0);
|
||||
setPacketRetransmitCount(0);
|
||||
}
|
||||
|
||||
void Statistics::fieldAccess(){
|
||||
|
@ -194,6 +200,9 @@ namespace Comms{
|
|||
stream = dataAccX.getFieldAccX("stream");
|
||||
connector = dataAccX.getFieldAccX("connector");
|
||||
crc = dataAccX.getFieldAccX("crc");
|
||||
pktcount = dataAccX.getFieldAccX("pktcount");
|
||||
pktloss = dataAccX.getFieldAccX("pktloss");
|
||||
pktretrans = dataAccX.getFieldAccX("pktretrans");
|
||||
}
|
||||
|
||||
uint8_t Statistics::getSync() const{return sync.uint(index);}
|
||||
|
@ -246,9 +255,7 @@ namespace Comms{
|
|||
up.set(_up, idx);
|
||||
}
|
||||
|
||||
std::string Statistics::getHost() const{
|
||||
return std::string(host.ptr(index), 16);
|
||||
}
|
||||
std::string Statistics::getHost() const{return std::string(host.ptr(index), 16);}
|
||||
std::string Statistics::getHost(size_t idx) const{
|
||||
if (!master){return std::string((size_t)16, (char)'\000');}
|
||||
return std::string(host.ptr(idx), 16);
|
||||
|
@ -285,6 +292,36 @@ namespace Comms{
|
|||
crc.set(_crc, idx);
|
||||
}
|
||||
|
||||
uint64_t Statistics::getPacketCount() const{return pktcount.uint(index);}
|
||||
uint64_t Statistics::getPacketCount(size_t idx) const{
|
||||
return (master ? pktcount.uint(idx) : 0);
|
||||
}
|
||||
void Statistics::setPacketCount(uint64_t _count){pktcount.set(_count, index);}
|
||||
void Statistics::setPacketCount(uint64_t _count, size_t idx){
|
||||
if (!master){return;}
|
||||
pktcount.set(_count, idx);
|
||||
}
|
||||
|
||||
uint64_t Statistics::getPacketLostCount() const{return pktloss.uint(index);}
|
||||
uint64_t Statistics::getPacketLostCount(size_t idx) const{
|
||||
return (master ? pktloss.uint(idx) : 0);
|
||||
}
|
||||
void Statistics::setPacketLostCount(uint64_t _lost){pktloss.set(_lost, index);}
|
||||
void Statistics::setPacketLostCount(uint64_t _lost, size_t idx){
|
||||
if (!master){return;}
|
||||
pktloss.set(_lost, idx);
|
||||
}
|
||||
|
||||
uint64_t Statistics::getPacketRetransmitCount() const{return pktretrans.uint(index);}
|
||||
uint64_t Statistics::getPacketRetransmitCount(size_t idx) const{
|
||||
return (master ? pktretrans.uint(idx) : 0);
|
||||
}
|
||||
void Statistics::setPacketRetransmitCount(uint64_t _retrans){pktretrans.set(_retrans, index);}
|
||||
void Statistics::setPacketRetransmitCount(uint64_t _retrans, size_t idx){
|
||||
if (!master){return;}
|
||||
pktretrans.set(_retrans, idx);
|
||||
}
|
||||
|
||||
std::string Statistics::getSessId() const{return getSessId(index);}
|
||||
|
||||
std::string Statistics::getSessId(size_t idx) const{
|
||||
|
|
18
lib/comms.h
18
lib/comms.h
|
@ -124,6 +124,21 @@ namespace Comms{
|
|||
void setCRC(uint32_t _crc);
|
||||
void setCRC(uint32_t _crc, size_t idx);
|
||||
|
||||
uint64_t getPacketCount() const;
|
||||
uint64_t getPacketCount(size_t idx) const;
|
||||
void setPacketCount(uint64_t _count);
|
||||
void setPacketCount(uint64_t _count, size_t idx);
|
||||
|
||||
uint64_t getPacketLostCount() const;
|
||||
uint64_t getPacketLostCount(size_t idx) const;
|
||||
void setPacketLostCount(uint64_t _lost);
|
||||
void setPacketLostCount(uint64_t _lost, size_t idx);
|
||||
|
||||
uint64_t getPacketRetransmitCount() const;
|
||||
uint64_t getPacketRetransmitCount(size_t idx) const;
|
||||
void setPacketRetransmitCount(uint64_t _retransmit);
|
||||
void setPacketRetransmitCount(uint64_t _retransmit, size_t idx);
|
||||
|
||||
std::string getSessId() const;
|
||||
std::string getSessId(size_t index) const;
|
||||
|
||||
|
@ -138,6 +153,9 @@ namespace Comms{
|
|||
Util::FieldAccX stream;
|
||||
Util::FieldAccX connector;
|
||||
Util::FieldAccX crc;
|
||||
Util::FieldAccX pktcount;
|
||||
Util::FieldAccX pktloss;
|
||||
Util::FieldAccX pktretrans;
|
||||
};
|
||||
|
||||
class Users : public Comms{
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "defines.h"
|
||||
#include "lib/socket_srt.h"
|
||||
#include "stream.h"
|
||||
#include "timing.h"
|
||||
#include "tinythread.h"
|
||||
|
@ -30,17 +31,18 @@
|
|||
#include <iostream>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h> // for va_list
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h> // for va_list
|
||||
|
||||
bool Util::Config::is_active = false;
|
||||
bool Util::Config::is_restarting = false;
|
||||
static Socket::Server *serv_sock_pointer = 0;
|
||||
static Socket::SRTServer *serv_srt_sock_pointer = 0; ///< Holds a pointer to SRT Server, if it is connected
|
||||
uint32_t Util::printDebugLevel = DEBUG;
|
||||
std::string Util::streamName;
|
||||
char Util::exitReason[256] = {0};
|
||||
char Util::exitReason[256] ={0};
|
||||
|
||||
void Util::logExitReason(const char *format, ...){
|
||||
if (exitReason[0]){return;}
|
||||
|
@ -53,6 +55,13 @@ void Util::logExitReason(const char *format, ...){
|
|||
std::string Util::listenInterface;
|
||||
uint32_t Util::listenPort = 0;
|
||||
|
||||
// Sets pointer to the SRT Server, for proper cleanup later.
|
||||
//
|
||||
// Currently used for TSSRT Input only, as this doesn't use the config library to setup a listener
|
||||
void Util::Config::registerSRTSockPtr(Socket::SRTServer *ptr){
|
||||
serv_srt_sock_pointer = ptr;
|
||||
}
|
||||
|
||||
Util::Config::Config(){
|
||||
// global options here
|
||||
vals["debug"]["long"] = "debug";
|
||||
|
@ -202,7 +211,9 @@ bool Util::Config::parseArgs(int &argc, char **&argv){
|
|||
#endif
|
||||
#ifdef STAT_CUTOFF
|
||||
if (STAT_CUTOFF != 600){
|
||||
std::cout << "- Setting: Stats cutoff point " << STAT_CUTOFF << " seconds. Statistics and session cache are only kept for this long, as opposed to the default of 600 seconds." << std::endl;
|
||||
std::cout << "- Setting: Stats cutoff point "
|
||||
<< STAT_CUTOFF << " seconds. Statistics and session cache are only kept for this long, as opposed to the default of 600 seconds."
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
#ifndef SSL
|
||||
|
@ -320,6 +331,23 @@ struct callbackData{
|
|||
int (*cb)(Socket::Connection &);
|
||||
};
|
||||
|
||||
// As above, but using an SRT Connection
|
||||
struct callbackSRTData{
|
||||
Socket::SRTConnection *sock;
|
||||
int (*cb)(Socket::SRTConnection &);
|
||||
};
|
||||
|
||||
// Callback for SRT-serving threads
|
||||
static void callThreadCallbackSRT(void *cDataArg){
|
||||
INSANE_MSG("Thread for %p started", cDataArg);
|
||||
callbackSRTData *cData = (callbackSRTData *)cDataArg;
|
||||
cData->cb(*(cData->sock));
|
||||
cData->sock->close();
|
||||
delete cData->sock;
|
||||
delete cData;
|
||||
INSANE_MSG("Thread for %p ended", cDataArg);
|
||||
}
|
||||
|
||||
static void callThreadCallback(void *cDataArg){
|
||||
INSANE_MSG("Thread for %p started", cDataArg);
|
||||
callbackData *cData = (callbackData *)cDataArg;
|
||||
|
@ -402,6 +430,53 @@ int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){
|
|||
return r;
|
||||
}
|
||||
|
||||
// This is a THREADED server!! Fork does not work as the SRT library itself already starts up a
|
||||
// thread, and forking after thread creation messes up all control flow internal to the library.
|
||||
int Util::Config::serveSRTSocket(int (*callback)(Socket::SRTConnection &S)){
|
||||
Socket::SRTServer server_socket;
|
||||
if (vals.isMember("port") && vals.isMember("interface")){
|
||||
server_socket = Socket::SRTServer(getInteger("port"), getString("interface"), false, "output");
|
||||
}
|
||||
if (!server_socket.connected()){
|
||||
DEVEL_MSG("Failure to open socket");
|
||||
return 1;
|
||||
}
|
||||
serv_srt_sock_pointer = &server_socket;
|
||||
activate();
|
||||
if (server_socket.getSocket()){
|
||||
int oldSock = server_socket.getSocket();
|
||||
if (!dup2(oldSock, 0)){
|
||||
server_socket = Socket::SRTServer(0);
|
||||
close(oldSock);
|
||||
}
|
||||
}
|
||||
int r = SRTServer(server_socket, callback);
|
||||
serv_srt_sock_pointer = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int Util::Config::SRTServer(Socket::SRTServer &server_socket, int (*callback)(Socket::SRTConnection &)){
|
||||
Util::Procs::socketList.insert(server_socket.getSocket());
|
||||
while (is_active && server_socket.connected()){
|
||||
Socket::SRTConnection S = server_socket.accept(false, "output");
|
||||
if (S.connected()){// check if the new connection is valid
|
||||
callbackSRTData *cData = new callbackSRTData;
|
||||
cData->sock = new Socket::SRTConnection(S);
|
||||
cData->cb = callback;
|
||||
// spawn a new thread for this connection
|
||||
tthread::thread T(callThreadCallbackSRT, (void *)cData);
|
||||
// detach it, no need to keep track of it anymore
|
||||
T.detach();
|
||||
HIGH_MSG("Spawned new thread for socket %i", S.getSocket());
|
||||
}else{
|
||||
Util::sleep(10); // sleep 10ms
|
||||
}
|
||||
}
|
||||
Util::Procs::socketList.erase(server_socket.getSocket());
|
||||
if (!is_restarting){server_socket.close();}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection &S)){
|
||||
Socket::Server server_socket;
|
||||
if (Socket::checkTrueSocket(0)){
|
||||
|
@ -466,6 +541,8 @@ void Util::Config::signal_handler(int signum, siginfo_t *sigInfo, void *ignore){
|
|||
case SIGHUP:
|
||||
case SIGTERM:
|
||||
if (serv_sock_pointer){serv_sock_pointer->close();}
|
||||
// Close the srt server as well, if set
|
||||
if (serv_srt_sock_pointer){serv_srt_sock_pointer->close();}
|
||||
#if DEBUG >= DLVL_DEVEL
|
||||
static int ctr = 0;
|
||||
if (!is_active && ++ctr > 4){BACKTRACE;}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#endif
|
||||
|
||||
#include "json.h"
|
||||
#include "socket_srt.h"
|
||||
#include <signal.h>
|
||||
#include <string>
|
||||
|
||||
|
@ -16,7 +17,7 @@ namespace Util{
|
|||
extern uint32_t printDebugLevel;
|
||||
extern std::string streamName; ///< Used by debug messages to identify the stream name
|
||||
extern char exitReason[256];
|
||||
void logExitReason(const char * format, ...);
|
||||
void logExitReason(const char *format, ...);
|
||||
|
||||
/// Deals with parsing configuration from commandline options.
|
||||
class Config{
|
||||
|
@ -41,6 +42,7 @@ namespace Util{
|
|||
int64_t getInteger(std::string optname);
|
||||
bool getBool(std::string optname);
|
||||
void activate();
|
||||
void registerSRTSockPtr(Socket::SRTServer *ptr);
|
||||
int threadServer(Socket::Server &server_socket, int (*callback)(Socket::Connection &S));
|
||||
int forkServer(Socket::Server &server_socket, int (*callback)(Socket::Connection &S));
|
||||
int serveThreadedSocket(int (*callback)(Socket::Connection &S));
|
||||
|
@ -49,6 +51,9 @@ namespace Util{
|
|||
void addOptionsFromCapabilities(const JSON::Value &capabilities);
|
||||
void addBasicConnectorOptions(JSON::Value &capabilities);
|
||||
void addConnectorOptions(int port, JSON::Value &capabilities);
|
||||
|
||||
int serveSRTSocket(int (*callback)(Socket::SRTConnection &S));
|
||||
int SRTServer(Socket::SRTServer &server_socket, int (*callback)(Socket::SRTConnection &S));
|
||||
};
|
||||
|
||||
/// The interface address the current serveSocket function is listening on
|
||||
|
|
548
lib/socket_srt.cpp
Normal file
548
lib/socket_srt.cpp
Normal file
|
@ -0,0 +1,548 @@
|
|||
#include "defines.h"
|
||||
#include "lib/http_parser.h"
|
||||
#include "socket_srt.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
#define INVALID_SRT_SOCKET -1
|
||||
|
||||
namespace Socket{
|
||||
namespace SRT{
|
||||
bool isInited = false;
|
||||
|
||||
// Both Init and Cleanup functions are called implicitly if not done ourselves.
|
||||
// SRT documentation states explicitly that this is unreliable behaviour
|
||||
bool libraryInit(){
|
||||
if (!isInited){
|
||||
int res = srt_startup();
|
||||
if (res == -1){ERROR_MSG("Unable to initialize SRT Library!");}
|
||||
isInited = (res != -1);
|
||||
}
|
||||
return isInited;
|
||||
}
|
||||
|
||||
bool libraryCleanup(){
|
||||
if (isInited){
|
||||
srt_cleanup();
|
||||
isInited = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}// namespace SRT
|
||||
|
||||
template <typename T> std::string asString(const T &val){
|
||||
std::stringstream x;
|
||||
x << val;
|
||||
return x.str();
|
||||
}
|
||||
|
||||
sockaddr_in createInetAddr(const std::string &_host, int _port){
|
||||
sockaddr_in res;
|
||||
memset(&res, 9, sizeof res);
|
||||
res.sin_family = AF_INET;
|
||||
res.sin_port = htons(_port);
|
||||
|
||||
if (_host != ""){
|
||||
if (inet_pton(AF_INET, _host.c_str(), &res.sin_addr) == 1){return res;}
|
||||
hostent *he = gethostbyname(_host.c_str());
|
||||
if (!he || he->h_addrtype != AF_INET){ERROR_MSG("Host not found %s", _host.c_str());}
|
||||
res.sin_addr = *(in_addr *)he->h_addr_list[0];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string interpretSRTMode(const std::string &_mode, const std::string &_host, const std::string &_adapter){
|
||||
if (_mode == "client" || _mode == "caller"){return "caller";}
|
||||
if (_mode == "server" || _mode == "listener"){return "listener";}
|
||||
if (_mode == "rendezvouz"){return "rendezvous";}
|
||||
if (_mode != "default"){return "";}
|
||||
if (_host == ""){return "listener";}
|
||||
if (_adapter != ""){return "rendezvous";}
|
||||
return "caller";
|
||||
}
|
||||
|
||||
std::string interpretSRTMode(const HTTP::URL &u){
|
||||
paramList params;
|
||||
HTTP::parseVars(u.args, params);
|
||||
return interpretSRTMode(params.count("mode") ? params.at("mode") : "default", u.host, "");
|
||||
}
|
||||
|
||||
SRTConnection::SRTConnection(){initializeEmpty();}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::string SRTConnection::getStreamName(){
|
||||
int sNameLen = 512;
|
||||
char sName[sNameLen];
|
||||
int optRes = srt_getsockflag(sock, SRTO_STREAMID, (void *)sName, &sNameLen);
|
||||
if (optRes != -1 && sNameLen){return sName;}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// Updates the downbuffer internal variable.
|
||||
/// Returns true if new data was received, false otherwise.
|
||||
std::string SRTConnection::RecvNow(){
|
||||
char recvbuf[5000];
|
||||
|
||||
bool blockState = blocking;
|
||||
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");}
|
||||
prev_pktseq = mc.pktseq;
|
||||
|
||||
setBlocking(blockState);
|
||||
if (receivedBytes == -1){
|
||||
ERROR_MSG("Unable to receive data over socket: %s", srt_getlasterror_str());
|
||||
if (srt_getsockstate(sock) != SRTS_CONNECTED){close();}
|
||||
return "";
|
||||
}
|
||||
|
||||
srt_bstats(sock, &performanceMonitor, false);
|
||||
return std::string(recvbuf, receivedBytes);
|
||||
}
|
||||
|
||||
void SRTConnection::connect(const std::string &_host, int _port, const std::string &_direction,
|
||||
const std::map<std::string, std::string> &_params){
|
||||
initializeEmpty();
|
||||
|
||||
direction = _direction;
|
||||
|
||||
handleConnectionParameters(_host, _params);
|
||||
|
||||
HIGH_MSG("Opening SRT connection %s in %s mode on %s:%d", modeName.c_str(), direction.c_str(),
|
||||
_host.c_str(), _port);
|
||||
|
||||
sock = srt_create_socket();
|
||||
if (sock == SRT_ERROR){
|
||||
ERROR_MSG("Error creating an SRT socket");
|
||||
return;
|
||||
}
|
||||
if (modeName == "rendezvous"){
|
||||
bool v = true;
|
||||
srt_setsockopt(sock, 0, SRTO_RENDEZVOUS, &v, sizeof v);
|
||||
}
|
||||
if (preConfigureSocket() == SRT_ERROR){
|
||||
ERROR_MSG("Error configuring SRT socket");
|
||||
return;
|
||||
}
|
||||
|
||||
if (modeName == "caller"){
|
||||
if (outgoing_port){setupAdapter("", outgoing_port);}
|
||||
|
||||
sockaddr_in sa = createInetAddr(_host, _port);
|
||||
sockaddr *psa = (sockaddr *)&sa;
|
||||
|
||||
HIGH_MSG("Going to connect sock %d", sock);
|
||||
if (srt_connect(sock, psa, sizeof sa) == SRT_ERROR){
|
||||
srt_close(sock);
|
||||
ERROR_MSG("Can't connect SRT Socket");
|
||||
return;
|
||||
}
|
||||
HIGH_MSG("Connected sock %d", sock);
|
||||
|
||||
if (postConfigureSocket() == SRT_ERROR){
|
||||
ERROR_MSG("Error during postconfigure socket");
|
||||
return;
|
||||
}
|
||||
INFO_MSG("Caller SRT socket %" PRId32 " success targetting %s:%u", sock, _host.c_str(), _port);
|
||||
return;
|
||||
}
|
||||
if (modeName == "listener"){
|
||||
HIGH_MSG("Going to bind a server on %s:%u", _host.c_str(), _port);
|
||||
|
||||
sockaddr_in sa = createInetAddr(_host, _port);
|
||||
sockaddr *psa = (sockaddr *)&sa;
|
||||
|
||||
if (srt_bind(sock, psa, sizeof sa) == SRT_ERROR){
|
||||
srt_close(sock);
|
||||
ERROR_MSG("Can't connect SRT Socket");
|
||||
return;
|
||||
}
|
||||
if (srt_listen(sock, 1) == SRT_ERROR){
|
||||
srt_close(sock);
|
||||
ERROR_MSG("Can not listen on Socket");
|
||||
}
|
||||
INFO_MSG("Listener SRT socket sucess @ %s:%u", _host.c_str(), _port);
|
||||
return;
|
||||
}
|
||||
if (modeName == "rendezvous"){
|
||||
int outport = (outgoing_port ? outgoing_port : _port);
|
||||
HIGH_MSG("Going to bind a server on %s:%u", _host.c_str(), _port);
|
||||
|
||||
sockaddr_in sa = createInetAddr(_host, outport);
|
||||
sockaddr *psa = (sockaddr *)&sa;
|
||||
|
||||
if (srt_bind(sock, psa, sizeof sa) == SRT_ERROR){
|
||||
srt_close(sock);
|
||||
ERROR_MSG("Can't connect SRT Socket");
|
||||
return;
|
||||
}
|
||||
|
||||
sockaddr_in sb = createInetAddr(_host, outport);
|
||||
sockaddr *psb = (sockaddr *)&sb;
|
||||
|
||||
if (srt_connect(sock, psb, sizeof sb) == SRT_ERROR){
|
||||
srt_close(sock);
|
||||
ERROR_MSG("Can't connect SRT Socket");
|
||||
return;
|
||||
}
|
||||
|
||||
if (postConfigureSocket() == SRT_ERROR){
|
||||
ERROR_MSG("Error during postconfigure socket");
|
||||
return;
|
||||
}
|
||||
INFO_MSG("Rendezvous SRT socket sucess @ %s:%u", _host.c_str(), _port);
|
||||
return;
|
||||
}
|
||||
ERROR_MSG("Invalid mode parameter. Use 'client' or 'server'");
|
||||
}
|
||||
|
||||
void SRTConnection::setupAdapter(const std::string &_host, int _port){
|
||||
sockaddr_in localsa = createInetAddr(_host, _port);
|
||||
sockaddr *psa = (sockaddr *)&localsa;
|
||||
if (srt_bind(sock, psa, sizeof localsa) == SRT_ERROR){
|
||||
ERROR_MSG("Unable to bind socket to %s:%u", _host.c_str(), _port);
|
||||
}
|
||||
}
|
||||
|
||||
void SRTConnection::SendNow(const std::string &data){SendNow(data.data(), data.size());}
|
||||
|
||||
void SRTConnection::SendNow(const char *data, size_t len){
|
||||
srt_clearlasterror();
|
||||
int res = srt_sendmsg2(sock, data, len, NULL);
|
||||
|
||||
if (res == SRT_ERROR){
|
||||
ERROR_MSG("Unable to send data over socket %" PRId32 ": %s", sock, srt_getlasterror_str());
|
||||
if (srt_getsockstate(sock) != SRTS_CONNECTED){close();}
|
||||
}
|
||||
srt_bstats(sock, &performanceMonitor, false);
|
||||
}
|
||||
|
||||
unsigned int SRTConnection::connTime(){
|
||||
srt_bstats(sock, &performanceMonitor, false);
|
||||
return performanceMonitor.msTimeStamp / 1000;
|
||||
}
|
||||
|
||||
uint64_t SRTConnection::dataUp(){return performanceMonitor.byteSentTotal;}
|
||||
|
||||
uint64_t SRTConnection::dataDown(){return performanceMonitor.byteRecvTotal;}
|
||||
|
||||
uint64_t SRTConnection::packetCount(){
|
||||
return (direction == "input" ? performanceMonitor.pktRecvTotal : performanceMonitor.pktSentTotal);
|
||||
}
|
||||
|
||||
uint64_t SRTConnection::packetLostCount(){
|
||||
return (direction == "input" ? performanceMonitor.pktRcvLossTotal : performanceMonitor.pktSndLossTotal);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void SRTConnection::initializeEmpty(){
|
||||
prev_pktseq = 0;
|
||||
sock = SRT_INVALID_SOCK;
|
||||
outgoing_port = 0;
|
||||
chunkTransmitSize = 1316;
|
||||
blocking = false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
blocking = _blocking;
|
||||
}
|
||||
|
||||
bool SRTConnection::isBlocking(){return blocking;}
|
||||
|
||||
void SRTConnection::handleConnectionParameters(const std::string &_host,
|
||||
const std::map<std::string, std::string> &_params){
|
||||
params = _params;
|
||||
DONTEVEN_MSG("SRT Received parameters: ");
|
||||
for (std::map<std::string, std::string>::const_iterator it = params.begin(); it != params.end(); it++){
|
||||
DONTEVEN_MSG(" %s: %s", it->first.c_str(), it->second.c_str());
|
||||
}
|
||||
|
||||
adapter = (params.count("adapter") ? params.at("adapter") : "");
|
||||
|
||||
modeName = interpretSRTMode((params.count("mode") ? params.at("mode") : "default"), _host, adapter);
|
||||
if (modeName == ""){
|
||||
ERROR_MSG("Invalid SRT mode encountered");
|
||||
return;
|
||||
}
|
||||
|
||||
// Using strtol because the original code uses base 0 -> automatic detection of octal and hexadecimal systems.
|
||||
timeout = (params.count("timeout") ? strtol(params.at("timeout").c_str(), 0, 0) : 0);
|
||||
|
||||
if (adapter == "" && modeName == "listener"){adapter = _host;}
|
||||
|
||||
tsbpdMode = ((params.count("tsbpd") && isFalseString(params.at("tsbpd"))) ? false : true);
|
||||
|
||||
outgoing_port = (params.count("port") ? strtol(params.at("port").c_str(), 0, 0) : 0);
|
||||
|
||||
if ((!params.count("transtype") || params.at("transtype") != "file") && chunkTransmitSize > SRT_LIVE_DEF_PLSIZE){
|
||||
if (chunkTransmitSize > SRT_LIVE_MAX_PLSIZE){
|
||||
ERROR_MSG("Chunk size in live mode exceeds 1456 bytes!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
params["payloadsize"] = asString(chunkTransmitSize);
|
||||
}
|
||||
|
||||
int SRTConnection::preConfigureSocket(){
|
||||
bool no = false;
|
||||
if (!tsbpdMode){
|
||||
if (srt_setsockopt(sock, 0, SRTO_TSBPDMODE, &no, sizeof no) == -1){return -1;}
|
||||
}
|
||||
if (srt_setsockopt(sock, 0, SRTO_RCVSYN, &no, sizeof no) == -1){return -1;}
|
||||
|
||||
if (params.count("linger")){
|
||||
linger lin;
|
||||
lin.l_linger = atoi(params.at("linger").c_str());
|
||||
lin.l_onoff = lin.l_linger > 0 ? 1 : 0;
|
||||
srt_setsockopt(sock, 0, SRTO_LINGER, &lin, sizeof(linger));
|
||||
}
|
||||
|
||||
std::string errMsg = configureSocketLoop(SRT::SockOpt::PRE);
|
||||
if (errMsg.size()){
|
||||
WARN_MSG("Failed to set the following options: %s", errMsg.c_str());
|
||||
return SRT_ERROR;
|
||||
}
|
||||
|
||||
if (direction == "output"){
|
||||
int v = 1;
|
||||
if (srt_setsockopt(sock, 0, SRTO_SENDER, &v, sizeof v) == SRT_ERROR){return SRT_ERROR;}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SRTConnection::postConfigureSocket(){
|
||||
bool no = false;
|
||||
if (srt_setsockopt(sock, 0, (direction == "output" ? SRTO_SNDSYN : 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;
|
||||
}
|
||||
}
|
||||
std::string errMsg = configureSocketLoop(SRT::SockOpt::POST);
|
||||
if (errMsg.size()){
|
||||
WARN_MSG("Failed to set the following options: %s", errMsg.c_str());
|
||||
return SRT_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string SRTConnection::configureSocketLoop(SRT::SockOpt::Binding _binding){
|
||||
std::string errMsg;
|
||||
|
||||
std::vector<SocketOption> allSrtOptions = srtOptions();
|
||||
for (std::vector<SocketOption>::iterator it = allSrtOptions.begin(); it != allSrtOptions.end(); it++){
|
||||
if (it->binding == _binding && params.count(it->name)){
|
||||
std::string value = params.at(it->name);
|
||||
if (!it->apply(sock, value)){errMsg += it->name + " ";}
|
||||
}
|
||||
}
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
void SRTConnection::close(){
|
||||
if (sock != -1){
|
||||
srt_close(sock);
|
||||
sock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
SRTServer::SRTServer(){}
|
||||
|
||||
SRTServer::SRTServer(int fromSock){conn = SRTConnection(fromSock);}
|
||||
|
||||
SRTServer::SRTServer(int port, std::string hostname, bool nonblock, const std::string &_direction){
|
||||
// We always create a server as listening
|
||||
std::map<std::string, std::string> listenMode;
|
||||
listenMode["mode"] = "listener";
|
||||
if (hostname == ""){hostname = "0.0.0.0";}
|
||||
conn.connect(hostname, port, _direction, listenMode);
|
||||
conn.setBlocking(true);
|
||||
if (!conn){
|
||||
ERROR_MSG("Unable to create socket");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SRTConnection SRTServer::accept(bool nonblock, const std::string &direction){
|
||||
if (!conn){return SRTConnection();}
|
||||
struct sockaddr_in6 tmpaddr;
|
||||
int len = sizeof(tmpaddr);
|
||||
|
||||
SRTConnection r(srt_accept(conn.getSocket(), (sockaddr *)&tmpaddr, &len));
|
||||
if (!r){
|
||||
if (conn.getSocket() != -1 && srt_getlasterror(0) != SRT_EASYNCRCV){
|
||||
FAIL_MSG("Error during accept: %s. Closing server socket %d.", srt_getlasterror_str(), conn.getSocket());
|
||||
close();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
r.direction = direction;
|
||||
r.postConfigureSocket();
|
||||
r.setBlocking(!nonblock);
|
||||
static char addrconv[INET6_ADDRSTRLEN];
|
||||
|
||||
r.remoteaddr = tmpaddr;
|
||||
if (tmpaddr.sin6_family == AF_INET6){
|
||||
r.remotehost = inet_ntop(AF_INET6, &(tmpaddr.sin6_addr), addrconv, INET6_ADDRSTRLEN);
|
||||
HIGH_MSG("IPv6 addr [%s]", r.remotehost.c_str());
|
||||
}
|
||||
if (tmpaddr.sin6_family == AF_INET){
|
||||
r.remotehost = inet_ntop(AF_INET, &(((sockaddr_in *)&tmpaddr)->sin_addr), addrconv, INET6_ADDRSTRLEN);
|
||||
HIGH_MSG("IPv4 addr [%s]", r.remotehost.c_str());
|
||||
}
|
||||
INFO_MSG("Accepted a socket coming from %s", r.remotehost.c_str());
|
||||
return r;
|
||||
}
|
||||
|
||||
void SRTServer::setBlocking(bool blocking){conn.setBlocking(blocking);}
|
||||
|
||||
bool SRTServer::isBlocking(){return (conn ? conn.isBlocking() : false);}
|
||||
|
||||
void SRTServer::close(){conn.close();}
|
||||
|
||||
bool SRTServer::connected() const{return conn.connected();}
|
||||
|
||||
int SRTServer::getSocket(){return conn.getSocket();}
|
||||
|
||||
inline int SocketOption::setSo(int socket, int proto, int sym, const void *data, size_t size, bool isSrtOpt){
|
||||
if (isSrtOpt){return srt_setsockopt(socket, 0, SRT_SOCKOPT(sym), data, (int)size);}
|
||||
return ::setsockopt(socket, proto, sym, (const char *)data, (int)size);
|
||||
}
|
||||
|
||||
bool SocketOption::extract(const std::string &v, OptionValue &val, SRT::SockOpt::Type asType){
|
||||
switch (asType){
|
||||
case SRT::SockOpt::STRING:
|
||||
val.s = v;
|
||||
val.value = val.s.data();
|
||||
val.size = val.s.size();
|
||||
break;
|
||||
case SRT::SockOpt::INT:
|
||||
case SRT::SockOpt::INT64:{
|
||||
int64_t tmp = strtol(v.c_str(), 0, 0);
|
||||
if (tmp == 0 && (!v.size() || v[0] != '0')){return false;}
|
||||
if (asType == SRT::SockOpt::INT){
|
||||
val.i = tmp;
|
||||
val.value = &val.i;
|
||||
val.size = sizeof(val.i);
|
||||
}else{
|
||||
val.l = tmp;
|
||||
val.value = &val.l;
|
||||
val.size = sizeof(val.l);
|
||||
}
|
||||
}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.value = &val.b;
|
||||
val.size = sizeof val.b;
|
||||
}break;
|
||||
case SRT::SockOpt::ENUM:{
|
||||
// Search value in the map. If found, set to o.
|
||||
SockOptVals::const_iterator p = valmap.find(v);
|
||||
if (p != valmap.end()){
|
||||
val.i = p->second;
|
||||
val.value = &val.i;
|
||||
val.size = sizeof val.i;
|
||||
return true;
|
||||
}
|
||||
// Fallback: try interpreting it as integer.
|
||||
return extract(v, val, SRT::SockOpt::INT);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SocketOption::apply(int socket, const std::string &value, bool isSrtOpt){
|
||||
OptionValue o;
|
||||
int result = -1;
|
||||
if (extract(value, o, type)){
|
||||
result = setSo(socket, protocol, symbol, o.value, o.size, isSrtOpt);
|
||||
}
|
||||
return result != -1;
|
||||
}
|
||||
|
||||
const std::map<std::string, int> enummap_transtype;
|
||||
|
||||
std::vector<SocketOption> srtOptions(){
|
||||
|
||||
static std::map<std::string, int> enummap_transtype;
|
||||
if (!enummap_transtype.size()){
|
||||
enummap_transtype["live"] = SRTT_LIVE;
|
||||
enummap_transtype["file"] = SRTT_FILE;
|
||||
}
|
||||
|
||||
static std::vector<SocketOption> res;
|
||||
if (res.size()){return res;}
|
||||
res.push_back(SocketOption("transtype", 0, SRTO_TRANSTYPE, SRT::SockOpt::PRE,
|
||||
SRT::SockOpt::ENUM, enummap_transtype));
|
||||
res.push_back(SocketOption("maxbw", 0, SRTO_MAXBW, SRT::SockOpt::PRE, SRT::SockOpt::INT64));
|
||||
res.push_back(SocketOption("pbkeylen", 0, SRTO_PBKEYLEN, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("passphrase", 0, SRTO_PASSPHRASE, SRT::SockOpt::PRE, SRT::SockOpt::STRING));
|
||||
|
||||
res.push_back(SocketOption("mss", 0, SRTO_MSS, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("fc", 0, SRTO_FC, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("sndbuf", 0, SRTO_SNDBUF, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("rcvbuf", 0, SRTO_RCVBUF, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
// linger option is handled outside of the common loop, therefore commented out.
|
||||
// res.push_back(SocketOption( "linger", 0, SRTO_LINGER, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("ipttl", 0, SRTO_IPTTL, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("iptos", 0, SRTO_IPTOS, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("inputbw", 0, SRTO_INPUTBW, SRT::SockOpt::POST, SRT::SockOpt::INT64));
|
||||
res.push_back(SocketOption("oheadbw", 0, SRTO_OHEADBW, SRT::SockOpt::POST, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("latency", 0, SRTO_LATENCY, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("tsbpdmode", 0, SRTO_TSBPDMODE, SRT::SockOpt::PRE, SRT::SockOpt::BOOL));
|
||||
res.push_back(SocketOption("tlpktdrop", 0, SRTO_TLPKTDROP, SRT::SockOpt::PRE, SRT::SockOpt::BOOL));
|
||||
res.push_back(SocketOption("snddropdelay", 0, SRTO_SNDDROPDELAY, SRT::SockOpt::POST, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("nakreport", 0, SRTO_NAKREPORT, SRT::SockOpt::PRE, SRT::SockOpt::BOOL));
|
||||
res.push_back(SocketOption("conntimeo", 0, SRTO_CONNTIMEO, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("lossmaxttl", 0, SRTO_LOSSMAXTTL, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("rcvlatency", 0, SRTO_RCVLATENCY, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("peerlatency", 0, SRTO_PEERLATENCY, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("minversion", 0, SRTO_MINVERSION, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("streamid", 0, SRTO_STREAMID, SRT::SockOpt::PRE, SRT::SockOpt::STRING));
|
||||
res.push_back(SocketOption("congestion", 0, SRTO_CONGESTION, SRT::SockOpt::PRE, SRT::SockOpt::STRING));
|
||||
res.push_back(SocketOption("messageapi", 0, SRTO_MESSAGEAPI, SRT::SockOpt::PRE, SRT::SockOpt::BOOL));
|
||||
// res.push_back(SocketOption("payloadsize", 0, SRTO_PAYLOADSIZE, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("kmrefreshrate", 0, SRTO_KMREFRESHRATE, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("kmpreannounce", 0, SRTO_KMPREANNOUNCE, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("enforcedencryption", 0, SRTO_ENFORCEDENCRYPTION, SRT::SockOpt::PRE,
|
||||
SRT::SockOpt::BOOL));
|
||||
res.push_back(SocketOption("peeridletimeo", 0, SRTO_PEERIDLETIMEO, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
res.push_back(SocketOption("packetfilter", 0, SRTO_PACKETFILTER, SRT::SockOpt::PRE, SRT::SockOpt::STRING));
|
||||
// res.push_back(SocketOption( "groupconnect", 0, SRTO_GROUPCONNECT, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
// res.push_back(SocketOption( "groupstabtimeo", 0, SRTO_GROUPSTABTIMEO, SRT::SockOpt::PRE, SRT::SockOpt::INT));
|
||||
return res;
|
||||
}
|
||||
}// namespace Socket
|
154
lib/socket_srt.h
Normal file
154
lib/socket_srt.h
Normal file
|
@ -0,0 +1,154 @@
|
|||
#pragma once
|
||||
|
||||
#include "socket.h"
|
||||
#include "url.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <srt/srt.h>
|
||||
|
||||
typedef std::map<std::string, int> SockOptVals;
|
||||
typedef std::map<std::string, std::string> paramList;
|
||||
|
||||
namespace Socket{
|
||||
std::string interpretSRTMode(const HTTP::URL &u);
|
||||
|
||||
inline bool isFalseString(const std::string &_val){
|
||||
return _val == "0" || _val == "no" || _val == "off" || _val == "false";
|
||||
}
|
||||
|
||||
inline bool isTrueString(const std::string &_val){
|
||||
return _val == "1" || _val == "yes" || _val == "on" || _val == "true";
|
||||
}
|
||||
|
||||
sockaddr_in createInetAddr(const std::string &_host, int _port);
|
||||
|
||||
namespace SRT{
|
||||
extern bool isInited;
|
||||
bool libraryInit();
|
||||
bool libraryCleanup();
|
||||
|
||||
// By absence of class enum (c++11), moved enums to a separate namespace
|
||||
namespace SockOpt{
|
||||
enum Type{STRING = 0, INT, INT64, BOOL, ENUM};
|
||||
enum Binding{PRE = 0, POST};
|
||||
}// namespace SockOpt
|
||||
}// namespace SRT
|
||||
|
||||
class SRTConnection{
|
||||
public:
|
||||
SRTConnection();
|
||||
SRTConnection(SRTSOCKET alreadyConnected){sock = alreadyConnected;}
|
||||
SRTConnection(const std::string &_host, int _port, const std::string &_direction = "input",
|
||||
const paramList &_params = paramList());
|
||||
|
||||
void connect(const std::string &_host, int _port, const std::string &_direction = "input",
|
||||
const paramList &_params = paramList());
|
||||
void close();
|
||||
bool connected() const{return sock != -1;}
|
||||
operator bool() const{return connected();}
|
||||
|
||||
void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false).
|
||||
bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false).
|
||||
|
||||
std::string RecvNow();
|
||||
void SendNow(const std::string &data);
|
||||
void SendNow(const char *data, size_t len);
|
||||
|
||||
SRTSOCKET getSocket(){return sock;}
|
||||
|
||||
int postConfigureSocket();
|
||||
|
||||
std::string getStreamName();
|
||||
|
||||
unsigned int connTime();
|
||||
uint64_t dataUp();
|
||||
uint64_t dataDown();
|
||||
uint64_t packetCount();
|
||||
uint64_t packetLostCount();
|
||||
uint64_t packetRetransmitCount();
|
||||
|
||||
std::string direction;
|
||||
|
||||
struct sockaddr_in6 remoteaddr;
|
||||
std::string remotehost;
|
||||
|
||||
private:
|
||||
SRTSOCKET sock;
|
||||
CBytePerfMon performanceMonitor;
|
||||
|
||||
std::string host;
|
||||
int outgoing_port;
|
||||
int32_t prev_pktseq;
|
||||
|
||||
uint32_t chunkTransmitSize;
|
||||
|
||||
// From paramaeter parsing
|
||||
std::string adapter;
|
||||
std::string modeName;
|
||||
int timeout;
|
||||
bool tsbpdMode;
|
||||
paramList params;
|
||||
|
||||
void initializeEmpty();
|
||||
void handleConnectionParameters(const std::string &_host, const paramList &_params);
|
||||
int preConfigureSocket();
|
||||
std::string configureSocketLoop(SRT::SockOpt::Binding _binding);
|
||||
void setupAdapter(const std::string &_host, int _port);
|
||||
|
||||
bool blocking;
|
||||
};
|
||||
|
||||
/// This class is for easily setting up listening socket, either TCP or Unix.
|
||||
class SRTServer{
|
||||
public:
|
||||
SRTServer();
|
||||
SRTServer(int existingSock);
|
||||
SRTServer(int port, std::string hostname, bool nonblock = false, const std::string &_direction = "input");
|
||||
SRTConnection accept(bool nonblock = false, const std::string &direction = "input");
|
||||
void setBlocking(bool blocking);
|
||||
bool connected() const;
|
||||
bool isBlocking();
|
||||
void close();
|
||||
int getSocket();
|
||||
|
||||
private:
|
||||
SRTConnection conn;
|
||||
std::string direction;
|
||||
};
|
||||
|
||||
struct OptionValue{
|
||||
std::string s;
|
||||
int i;
|
||||
int64_t l;
|
||||
bool b;
|
||||
|
||||
const void *value;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
class SocketOption{
|
||||
public:
|
||||
//{"enforcedencryption", 0, SRTO_ENFORCEDENCRYPTION, SRT::SockOpt::PRE, SRT::SockOpt::BOOL, nullptr},
|
||||
SocketOption(const std::string &_name, int _protocol, int _symbol, SRT::SockOpt::Binding _binding,
|
||||
SRT::SockOpt::Type _type, const SockOptVals &_values = SockOptVals())
|
||||
: name(_name), protocol(_protocol), symbol(_symbol), binding(_binding), type(_type),
|
||||
valmap(_values){};
|
||||
|
||||
std::string name;
|
||||
int protocol;
|
||||
int symbol;
|
||||
SRT::SockOpt::Binding binding;
|
||||
SRT::SockOpt::Type type;
|
||||
SockOptVals valmap;
|
||||
|
||||
bool apply(int socket, const std::string &value, bool isSrtOpt = true);
|
||||
|
||||
static int setSo(int socket, int protocol, int symbol, const void *data, size_t size, bool isSrtOpt = true);
|
||||
|
||||
bool extract(const std::string &v, OptionValue &val, SRT::SockOpt::Type asType);
|
||||
};
|
||||
|
||||
std::vector<SocketOption> srtOptions();
|
||||
}// namespace Socket
|
|
@ -1015,7 +1015,8 @@ namespace TS{
|
|||
((adtsInfo[it->first].getFrequencyIndex() & 0x0E) >> 1);
|
||||
init[1] = ((adtsInfo[it->first].getFrequencyIndex() & 0x01) << 7) |
|
||||
((adtsInfo[it->first].getChannelConfig() & 0x0F) << 3);
|
||||
|
||||
// Wait with adding the track until we have init data
|
||||
if (init[0] == 0 && init[1] == 0){addNewTrack = false;}
|
||||
type = "audio";
|
||||
codec = "AAC";
|
||||
size = 16;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue