TSSRT Support
This commit is contained in:
parent
974380ab30
commit
19199cbff8
17 changed files with 1471 additions and 15 deletions
58
src/output/mist_out_srt.cpp
Normal file
58
src/output/mist_out_srt.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include OUTPUTTYPE
|
||||
#include <mist/config.h>
|
||||
#include <mist/defines.h>
|
||||
#include <mist/socket.h>
|
||||
#include <mist/socket_srt.h>
|
||||
#include <mist/util.h>
|
||||
|
||||
int spawnForked(Socket::SRTConnection &S){
|
||||
int fds[2];
|
||||
pipe(fds);
|
||||
Socket::Connection Sconn(fds[0], fds[1]);
|
||||
|
||||
mistOut tmp(Sconn, S.getSocket());
|
||||
return tmp.run();
|
||||
}
|
||||
|
||||
void handleUSR1(int signum, siginfo_t *sigInfo, void *ignore){
|
||||
HIGH_MSG("USR1 received - triggering rolling restart");
|
||||
Util::Config::is_restarting = true;
|
||||
Util::logExitReason("signal USR1");
|
||||
Util::Config::is_active = false;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
DTSC::trackValidMask = TRACK_VALID_EXT_HUMAN;
|
||||
Util::redirectLogsIfNeeded();
|
||||
Util::Config conf(argv[0]);
|
||||
mistOut::init(&conf);
|
||||
if (conf.parseArgs(argc, argv)){
|
||||
if (conf.getBool("json")){
|
||||
mistOut::capa["version"] = PACKAGE_VERSION;
|
||||
std::cout << mistOut::capa.toString() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
conf.activate();
|
||||
if (mistOut::listenMode()){
|
||||
{
|
||||
struct sigaction new_action;
|
||||
new_action.sa_sigaction = handleUSR1;
|
||||
sigemptyset(&new_action.sa_mask);
|
||||
new_action.sa_flags = 0;
|
||||
sigaction(SIGUSR1, &new_action, NULL);
|
||||
}
|
||||
mistOut::listener(conf, spawnForked);
|
||||
if (conf.is_restarting && Socket::checkTrueSocket(0)){
|
||||
INFO_MSG("Reloading input while re-using server socket");
|
||||
execvp(argv[0], argv);
|
||||
FAIL_MSG("Error reloading: %s", strerror(errno));
|
||||
}
|
||||
}else{
|
||||
Socket::Connection S(fileno(stdout), fileno(stdin));
|
||||
mistOut tmp(S, -1);
|
||||
return tmp.run();
|
||||
}
|
||||
}
|
||||
INFO_MSG("Exit reason: %s", Util::exitReason);
|
||||
return 0;
|
||||
}
|
112
src/output/output_tssrt.cpp
Normal file
112
src/output/output_tssrt.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include "mist/socket_srt.h"
|
||||
#include "output_tssrt.h"
|
||||
#include <mist/defines.h>
|
||||
#include <mist/http_parser.h>
|
||||
#include <mist/url.h>
|
||||
|
||||
namespace Mist{
|
||||
OutTSSRT::OutTSSRT(Socket::Connection &conn, SRTSOCKET _srtSock) : TSOutput(conn){
|
||||
// NOTE: conn is useless for SRT, as it uses a different socket type.
|
||||
sendRepeatingHeaders = 500; // PAT/PMT every 500ms (DVB spec)
|
||||
streamName = config->getString("streamname");
|
||||
pushOut = false;
|
||||
std::string tracks;
|
||||
// Push output configuration
|
||||
if (config->getString("target").size()){
|
||||
HTTP::URL target(config->getString("target"));
|
||||
if (target.protocol != "srt"){
|
||||
FAIL_MSG("Target %s must begin with srt://, aborting", target.getUrl().c_str());
|
||||
onFail("Invalid srt target: doesn't start with srt://", true);
|
||||
return;
|
||||
}
|
||||
if (!target.getPort()){
|
||||
FAIL_MSG("Target %s must contain a port, aborting", target.getUrl().c_str());
|
||||
onFail("Invalid srt target: missing port", true);
|
||||
return;
|
||||
}
|
||||
pushOut = true;
|
||||
if (targetParams.count("tracks")){tracks = targetParams["tracks"];}
|
||||
size_t connectCnt = 0;
|
||||
do{
|
||||
srtConn.connect(target.host, target.getPort(), "output");
|
||||
if (!srtConn){Util::sleep(1000);}
|
||||
++connectCnt;
|
||||
}while (!srtConn && connectCnt < 10);
|
||||
wantRequest = false;
|
||||
parseData = true;
|
||||
}else{
|
||||
// Pull output configuration, In this case we have an srt connection in the second constructor parameter.
|
||||
srtConn = Socket::SRTConnection(_srtSock);
|
||||
parseData = true;
|
||||
wantRequest = false;
|
||||
|
||||
// Handle override / append of streamname options
|
||||
std::string sName = srtConn.getStreamName();
|
||||
if (sName != ""){
|
||||
streamName = sName;
|
||||
HIGH_MSG("Requesting stream %s", streamName.c_str());
|
||||
}
|
||||
}
|
||||
initialize();
|
||||
}
|
||||
|
||||
OutTSSRT::~OutTSSRT(){}
|
||||
|
||||
void OutTSSRT::init(Util::Config *cfg){
|
||||
Output::init(cfg);
|
||||
capa["name"] = "TSSRT";
|
||||
capa["friendly"] = "TS over SRT";
|
||||
capa["desc"] = "Real time streaming of TS data over SRT";
|
||||
capa["deps"] = "";
|
||||
capa["required"]["streamname"]["name"] = "Stream";
|
||||
capa["required"]["streamname"]["help"] = "What streamname to serve. For multiple streams, add "
|
||||
"this protocol multiple times using different ports, "
|
||||
"or use the streamid option on the srt connection";
|
||||
capa["required"]["streamname"]["type"] = "str";
|
||||
capa["required"]["streamname"]["option"] = "--stream";
|
||||
capa["required"]["streamname"]["short"] = "s";
|
||||
capa["codecs"][0u][0u].append("HEVC");
|
||||
capa["codecs"][0u][0u].append("H264");
|
||||
capa["codecs"][0u][0u].append("MPEG2");
|
||||
capa["codecs"][0u][1u].append("AAC");
|
||||
capa["codecs"][0u][1u].append("MP3");
|
||||
capa["codecs"][0u][1u].append("AC3");
|
||||
capa["codecs"][0u][1u].append("MP2");
|
||||
cfg->addConnectorOptions(8889, capa);
|
||||
config = cfg;
|
||||
capa["push_urls"].append("srt://*");
|
||||
|
||||
JSON::Value opt;
|
||||
opt["arg"] = "string";
|
||||
opt["default"] = "";
|
||||
opt["arg_num"] = 1;
|
||||
opt["help"] = "Target srt:// URL to push out towards.";
|
||||
cfg->addOption("target", opt);
|
||||
}
|
||||
|
||||
// Buffer internally in the class, and send once we have over 1000 bytes of data.
|
||||
void OutTSSRT::sendTS(const char *tsData, size_t len){
|
||||
if (packetBuffer.size() >= 1000){
|
||||
srtConn.SendNow(packetBuffer);
|
||||
if (!srtConn){
|
||||
// Allow for proper disconnect
|
||||
parseData = false;
|
||||
}
|
||||
packetBuffer.clear();
|
||||
}
|
||||
packetBuffer.append(tsData, len);
|
||||
}
|
||||
|
||||
bool OutTSSRT::setAlternateConnectionStats(Comms::Statistics &statComm){
|
||||
statComm.setUp(srtConn.dataUp());
|
||||
statComm.setDown(srtConn.dataDown());
|
||||
statComm.setTime(Util::bootSecs() - srtConn.connTime());
|
||||
return true;
|
||||
}
|
||||
|
||||
void OutTSSRT::handleLossyStats(Comms::Statistics &statComm){
|
||||
statComm.setPacketCount(srtConn.packetCount());
|
||||
statComm.setPacketLostCount(srtConn.packetLostCount());
|
||||
statComm.setPacketRetransmitCount(srtConn.packetRetransmitCount());
|
||||
}
|
||||
}// namespace Mist
|
33
src/output/output_tssrt.h
Normal file
33
src/output/output_tssrt.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "output_ts_base.h"
|
||||
#include <mist/ts_stream.h>
|
||||
|
||||
#include <mist/socket_srt.h>
|
||||
|
||||
namespace Mist{
|
||||
class OutTSSRT : public TSOutput{
|
||||
public:
|
||||
OutTSSRT(Socket::Connection &conn, SRTSOCKET _srtSock);
|
||||
~OutTSSRT();
|
||||
|
||||
static bool listenMode(){return !(config->getString("target").size());}
|
||||
|
||||
static void init(Util::Config *cfg);
|
||||
void sendTS(const char *tsData, size_t len = 188);
|
||||
bool isReadyForPlay(){return true;}
|
||||
|
||||
protected:
|
||||
// Stats handling
|
||||
virtual bool setAlternateConnectionStats(Comms::Statistics &statComm);
|
||||
virtual void handleLossyStats(Comms::Statistics &statComm);
|
||||
|
||||
private:
|
||||
bool pushOut;
|
||||
std::string packetBuffer;
|
||||
Socket::UDPConnection pushSock;
|
||||
TS::Stream tsIn;
|
||||
|
||||
Socket::SRTConnection srtConn;
|
||||
};
|
||||
}// namespace Mist
|
||||
|
||||
typedef Mist::OutTSSRT mistOut;
|
Loading…
Add table
Add a link
Reference in a new issue