Added machine readable exit reasons, INPUT_END trigger, OUTPUT_END trigger, and updated RECORDING_END trigger to include all of these.

This commit is contained in:
Marco 2022-12-22 13:41:10 +01:00 committed by Thulinma
parent a16d98b7b2
commit b0d4422d27
47 changed files with 493 additions and 256 deletions

View file

@ -42,19 +42,21 @@ bool Util::Config::is_restarting = false;
static Socket::Server *serv_sock_pointer = 0;
uint32_t Util::printDebugLevel = DEBUG;
__thread char Util::streamName[256] = {0};
__thread char Util::exitReason[256] ={0};
__thread char Util::exitReason[256] = {0};
__thread char* Util::mRExitReason = (char*)ER_UNKNOWN;
Util::binType Util::Config::binaryType = UNSET;
void Util::setStreamName(const std::string & sn){
strncpy(Util::streamName, sn.c_str(), 256);
}
void Util::logExitReason(const char *format, ...){
void Util::logExitReason(const char* shortString, const char *format, ...){
if (exitReason[0]){return;}
va_list args;
va_start(args, format);
vsnprintf(exitReason, 255, format, args);
va_end(args);
mRExitReason = (char*)shortString;
}
std::string Util::listenInterface;
@ -597,9 +599,9 @@ void Util::Config::signal_handler(int signum, siginfo_t *sigInfo, void *ignore){
case SI_TIMER:
case SI_ASYNCIO:
case SI_MESGQ:
logExitReason("signal %s (%d) from process %d", strsignal(signum), signum, sigInfo->si_pid);
logExitReason(ER_CLEAN_SIGNAL, "signal %s (%d) from process %d", strsignal(signum), signum, sigInfo->si_pid);
break;
default: logExitReason("signal %s (%d)", strsignal(signum), signum);
default: logExitReason(ER_CLEAN_SIGNAL, "signal %s (%d)", strsignal(signum), signum);
}
is_active = false;
default:

View file

@ -17,7 +17,16 @@ namespace Util{
extern __thread char streamName[256]; ///< Used by debug messages to identify the stream name
void setStreamName(const std::string & sn);
extern __thread char exitReason[256];
void logExitReason(const char *format, ...);
extern __thread char* mRExitReason;
void logExitReason(const char* shortString, const char *format, ...);
enum binType {
UNSET,
INPUT,
OUTPUT,
PROCESS,
CONTROLLER
};
/// Deals with parsing configuration from commandline options.
class Config{
@ -30,6 +39,7 @@ namespace Util{
// variables
static bool is_active; ///< Set to true by activate(), set to false by the signal handler.
static bool is_restarting; ///< Set to true when restarting, set to false on boot.
static binType binaryType;
// functions
Config();
Config(std::string cmd);

View file

@ -303,3 +303,27 @@ static inline void show_stackframe(){}
#define SESS_HTTP_AS_UNSPECIFIED 4
#define SESS_TKN_DEFAULT_MODE 15
#define ER_UNKNOWN "UNKNOWN"
#define ER_CLEAN_LIVE_BUFFER_REQ "CLEAN_LIVE_BUFFER_REQ"
#define ER_CLEAN_CONTROLLER_REQ "CLEAN_CONTROLLER_REQ"
#define ER_CLEAN_INTENDED_STOP "CLEAN_INTENDED_STOP"
#define ER_CLEAN_REMOTE_CLOSE "CLEAN_REMOTE_CLOSE"
#define ER_CLEAN_INACTIVE "CLEAN_INACTIVE"
#define ER_CLEAN_SIGNAL "CLEAN_SIGNAL"
#define ER_CLEAN_EOF "CLEAN_EOF"
#define ER_READ_START_FAILURE "READ_START_FAILURE"
#define ER_PROCESS_SPECIFIC "PROCESS_SPECIFIC"
#define ER_FORMAT_SPECIFIC "FORMAT_SPECIFIC"
#define ER_INTERNAL_ERROR "INTERNAL_ERROR"
#define ER_WRITE_FAILURE "WRITE_FAILURE"
#define ER_EXEC_FAILURE "EXEC_FAILURE"
#define ER_MEMORY "OUT_OF_MEMORY"
#define ER_SHM_LOST "SHM_LOST"
#define ER_UNSUPPORTED "UNSUPPORTED"
#define ER_SEGFAULT "SEGFAULT"
#define ER_TRIGGER "TRIGGER"
#define ER_SIGTRAP "SIGTRAP"
#define ER_SIGABRT "SIGABRT"
#define ER_SIGILL "SIGILL"
#define ER_SIGFPE "SIGFPE"
#define ER_SIGBUS "SIGBUS"

View file

@ -629,6 +629,7 @@ int main(int argc, char **argv){
}
Controller::conf = Util::Config(argv[0]);
Util::Config::binaryType = Util::CONTROLLER;
Controller::conf.activate();
if (getenv("ATHEIST")){return main_loop(argc, argv);}
uint64_t reTimer = 0;

View file

@ -115,6 +115,12 @@ namespace Controller{
trgs["STREAM_END"]["response"] = "ignored";
trgs["STREAM_END"]["response_action"] = "None.";
trgs["INPUT_ABORT"]["when"] = "Every time an Input process exits with an error";
trgs["INPUT_ABORT"]["stream_specific"] = true;
trgs["INPUT_ABORT"]["payload"] = "stream name (string)\nsource URI (string)\nbinary name (string)\npid (integer)\nmachine-readable reason for exit (string, enum)\nhuman-readable reason for exit (string)";
trgs["INPUT_ABORT"]["response"] = "ignored";
trgs["INPUT_ABORT"]["response_action"] = "None.";
trgs["RTMP_PUSH_REWRITE"]["when"] =
"On incoming RTMP pushes, allows rewriting the RTMP URL to/from custom formatting";
trgs["RTMP_PUSH_REWRITE"]["stream_specific"] = false;
@ -150,10 +156,21 @@ namespace Controller{
"(integer)\nseconds spent recording (integer)\nunix time recording started (integer)\nunix "
"time recording stopped (integer)\ntotal milliseconds of media data recorded "
"(integer)\nmillisecond timestamp of first media packet (integer)\nmillisecond timestamp "
"of last media packet (integer)\n";
"of last media packet (integer)\nmachine-readable reason for exit (string, enum)\nhuman-readable reason for exit (string)";
trgs["RECORDING_END"]["response"] = "ignored";
trgs["RECORDING_END"]["response_action"] = "None.";
trgs["OUTPUT_END"]["when"] = "When an output finishes";
trgs["OUTPUT_END"]["stream_specific"] = true;
trgs["OUTPUT_END"]["payload"] =
"stream name (string)\npush target (string)\nconnector / filetype (string)\nbytes recorded "
"(integer)\nseconds spent recording (integer)\nunix time output started (integer)\nunix "
"time output stopped (integer)\ntotal milliseconds of media data recorded "
"(integer)\nmillisecond timestamp of first media packet (integer)\nmillisecond timestamp "
"of last media packet (integer)\nmachine-readable reason for exit (string, enum)\nhuman-readable reason for exit (string)";
trgs["OUTPUT_END"]["response"] = "ignored";
trgs["OUTPUT_END"]["response_action"] = "None.";
trgs["CONN_OPEN"]["when"] = "After a new connection is accepted";
trgs["CONN_OPEN"]["stream_specific"] = true;
trgs["CONN_OPEN"]["payload"] = "stream name (string)\nconnection address (string)\nconnector "

View file

@ -93,6 +93,7 @@ namespace Mist{
Input::Input(Util::Config *cfg) : InOutBase(){
config = cfg;
standAlone = true;
Util::Config::binaryType = Util::INPUT;
JSON::Value option;
option["long"] = "json";
@ -399,8 +400,8 @@ namespace Mist{
}
if (!checkArguments()){
FAIL_MSG("Setup failed - exiting");
return 0;
Util::logExitReason(ER_UNKNOWN, "Setup failed - exiting");
return exitAndLogReason();
}
IPC::semaphore playerLock;
@ -476,8 +477,12 @@ namespace Mist{
streamStatus.master = false;
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INIT;}
}
int ret = 0;
if (preRun()){ret = run();}
int ret = 1;
if (preRun()){
ret = run();
}else{
return exitAndLogReason();
}
if (playerLock){
playerLock.unlink();
char pageName[NAME_BUFFER_SIZE];
@ -514,7 +519,9 @@ namespace Mist{
// Abandon all semaphores, ye who enter here.
playerLock.abandon();
pullLock.abandon();
if (!preRun()){return 0;}
if (!preRun()){
return exitAndLogReason();
}
return run();
}
Util::Procs::fork_complete();
@ -538,8 +545,9 @@ namespace Mist{
}
HIGH_MSG("Done waiting for child for stream %s", streamName.c_str());
// if the exit was clean, don't restart it
if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)){
INFO_MSG("Input for stream %s shut down cleanly", streamName.c_str());
int exitCode = WEXITSTATUS(status);
if (WIFEXITED(status) && (exitCode == 0 || exitCode == 1)){
HIGH_MSG("Input for stream %s shut down cleanly", streamName.c_str());
break;
}
if (playerLock){
@ -548,12 +556,49 @@ namespace Mist{
streamStatus.init(pageName, 2, false, false);
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INVALID;}
}
#if DEBUG >= DLVL_DEVEL
// Fire the INPUT_ABORT trigger if the child process ends with an abnormal exit code
// Prevents automatic restarts of the input for unrecoverable errors
if (WIFEXITED(status)){
char exitReason[256];
memcpy(exitReason, Util::exitReason, 256);
if (exitCode == 2){
WARN_MSG("Child process %u exited with exit code %i (major error occurred), cleaning up...", pid, exitCode);
Util::logExitReason(ER_UNKNOWN, "Child process %u exited with exit code %i (major error occurred)", pid, exitCode);
}else if (exitCode == 132){
WARN_MSG("Child process %u exited with exit code %i (SIGILL), cleaning up...", pid, exitCode);
Util::logExitReason(ER_SIGILL, "Child process %u exited with exit code %i (SIGILL)", pid, exitCode);
}else if (exitCode == 133){
WARN_MSG("Child process %u exited with exit code %i (SIGTRAP)", pid, exitCode);
Util::logExitReason(ER_SIGTRAP, "Child process %u exited with exit code %i (SIGTRAP)", pid, exitCode);
}else if (exitCode == 134){
WARN_MSG("Child process %u exited with exit code %i (SIGABRT)", pid, exitCode);
Util::logExitReason(ER_SIGABRT, "Child process %u exited with exit code %i (SIGABRT)", pid, exitCode);
}else if (exitCode == 136){
WARN_MSG("Child process %u exited with exit code %i (SIGFPE)", pid, exitCode);
Util::logExitReason(ER_SIGFPE, "Child process %u exited with exit code %i (SIGFPE)", pid, exitCode);
}else if (exitCode == 137){
WARN_MSG("Child process %u exited with exit code %i (used too much memory), cleaning up...", pid, exitCode);
Util::logExitReason(ER_MEMORY, "Child process %u exited with exit code %i (used too much memory)", pid, exitCode);
}else if (exitCode == 138){
WARN_MSG("Child process %u exited with exit code %i (SIGBUS)", pid, exitCode);
Util::logExitReason(ER_SIGBUS, "Child process %u exited with exit code %i (SIGBUS)", pid, exitCode);
}else if (exitCode == 139){
WARN_MSG("Child process %u exited with exit code %i (SEGFAULT)", pid, exitCode);
Util::logExitReason(ER_SEGFAULT, "Child process %u exited with exit code %i (SEGFAULT)", pid, exitCode);
}else{
WARN_MSG("Child process %u exited with an unhandled exit code %i, cleaning up...", pid, exitCode);
Util::logExitReason(ER_UNKNOWN, "Child process %u exited with an unhandled exit code %i", pid, exitCode);
}
doInputAbortTrigger(pid, Util::mRExitReason, Util::exitReason);
memcpy(Util::exitReason, exitReason, 256);
}
#if DEBUG >= DLVL_DEVEL
WARN_MSG(
"Input for stream %s uncleanly shut down! Aborting restart; this is a development build.",
streamName.c_str());
break;
#else
#else
if (config->is_active){
WARN_MSG("Input for stream %s uncleanly shut down! Cleaning and restarting...", streamName.c_str());
}else{
@ -609,8 +654,8 @@ namespace Mist{
if (needHeader()){
uint64_t timer = Util::getMicros();
if (!readHeader() || (!M && needsLock())){
FAIL_MSG("Reading header for '%s' failed.", config->getString("input").c_str());
return 0;
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed", config->getString("input").c_str());
return exitAndLogReason();
}
timer = Util::getMicros(timer);
INFO_MSG("Created header in %.3f ms (%zu tracks)", (double)timer/1000.0, M?M.trackCount():(size_t)0);
@ -639,7 +684,7 @@ namespace Mist{
INFO_MSG("Starting serve");
serve();
}
return 0;
return exitAndLogReason();
}
void Input::convert(){
@ -694,6 +739,40 @@ namespace Mist{
outMeta.toFile(fileName + ".dtsh");
}
// Fires the `INPUT_ABORT` trigger. Allows overrides to allow parent processes
// to fire the trigger for child processes which have already exited (EG segfaults)
void Input::doInputAbortTrigger(pid_t pid, char *mRExitReason, char *exitReason){
// Calculate variables required for the trigger
if (Util::Config::binaryType == Util::INPUT && Triggers::shouldTrigger("INPUT_ABORT", streamName)){
std::ostringstream pidString;
pidString << pid;
std::string payload = streamName + "\n" + config->getString("input") + "\n" \
+ "MistIn" + capa["name"].asString() + "\n" + pidString.str() + "\n" \
+ mRExitReason + "\n" + exitReason;
Triggers::doTrigger("INPUT_ABORT", payload, streamName);
}
}
// Logs the current exit reason and returns a 0 or 1 depending on whether
// this was a clean exit or not
bool Input::exitAndLogReason(){
int returnCode = 1;
// If no reason is set at all, return the default status
if (!Util::exitReason[0]){
INFO_MSG("Input closing without a set exit reason");
}else if(strncmp(Util::mRExitReason, "CLEAN", 5) == 0){
INFO_MSG("Input closing cleanly with reason: %s", Util::exitReason);
returnCode = 0;
}else{
WARN_MSG("Input closing unclean, reason: %s", Util::exitReason);
}
// If this is an unclean exit, fire the INPUT_ABORT trigger
if (returnCode){
doInputAbortTrigger(getpid(), Util::mRExitReason, Util::exitReason);
}
return returnCode;
}
/// Checks in the server configuration if this stream is set to always on or not.
/// Returns true if it is, or if the stream could not be found in the configuration.
/// If the compiled default debug level is < INFO, instead returns false if the stream is not found.
@ -748,7 +827,7 @@ namespace Mist{
if (Triggers::shouldTrigger("STREAM_READY", config->getString("streamname"))){
std::string payload = config->getString("streamname") + "\n" + capa["name"].asStringRef();
if (!Triggers::doTrigger("STREAM_READY", payload, config->getString("streamname"))){
Util::logExitReason("STREAM_READY trigger returned false");
Util::logExitReason(ER_TRIGGER, "STREAM_READY trigger returned false");
config->is_active = false;
}
}
@ -789,7 +868,6 @@ namespace Mist{
config->is_active = false;
}
finish();
INFO_MSG("Input closing clean, reason: %s", Util::exitReason);
userSelect.clear();
if (!isThread()){
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_OFF;}
@ -837,7 +915,7 @@ namespace Mist{
}
/*LTS-END*/
if (!ret && ((Util::bootSecs() - activityCounter) >= INPUT_TIMEOUT)){
Util::logExitReason("no activity for %u seconds", Util::bootSecs() - activityCounter);
Util::logExitReason(ER_CLEAN_INACTIVE, "no activity for %u seconds", Util::bootSecs() - activityCounter);
}
return ret;
}
@ -882,14 +960,13 @@ namespace Mist{
if (config->getBool("realtime")){
realtimeMainLoop();
finish();
INFO_MSG("Real-time input closing clean; reason: %s", Util::exitReason);
return;
}
meta.reInit(streamName, false);
if (!openStreamSource()){
FAIL_MSG("Unable to connect to source");
Util::logExitReason(ER_READ_START_FAILURE, "Unable to connect to source");
return;
}
parseStreamHeader();
@ -897,9 +974,9 @@ namespace Mist{
if (publishesTracks()){
std::set<size_t> validTracks = M.getMySourceTracks(getpid());
if (!validTracks.size()){
Util::logExitReason(ER_CLEAN_EOF, "No tracks found, cancelling pull");
userSelect.clear();
finish();
INFO_MSG("No tracks found, cancelling");
return;
}
}
@ -908,7 +985,6 @@ namespace Mist{
closeStreamSource();
userSelect.clear();
finish();
INFO_MSG("Input closing clean; reason: %s", Util::exitReason);
return;
}
@ -929,17 +1005,17 @@ namespace Mist{
}
while (thisPacket && config->is_active && userSelect[thisIdx]){
if (userSelect[thisIdx].getStatus() & COMM_STATUS_REQDISCONNECT){
Util::logExitReason("buffer requested shutdown");
Util::logExitReason(ER_CLEAN_LIVE_BUFFER_REQ, "buffer requested shutdown");
break;
}
if (isSingular() && !bufferActive()){
Util::logExitReason("Buffer shut down");
Util::logExitReason(ER_SHM_LOST, "Buffer shut down");
return;
}
bufferLivePacket(thisPacket);
getNext();
if (!thisPacket){
Util::logExitReason("no more data");
Util::logExitReason(ER_CLEAN_EOF, "no more data");
break;
}
if (thisPacket && !userSelect.count(thisIdx)){
@ -952,7 +1028,7 @@ namespace Mist{
if (statComm){
if (!statComm){
config->is_active = false;
Util::logExitReason("received shutdown request from controller");
Util::logExitReason(ER_CLEAN_CONTROLLER_REQ, "received shutdown request from controller");
return;
}
uint64_t now = Util::bootSecs();
@ -1080,7 +1156,7 @@ namespace Mist{
while (config->is_active){
getNext();
if (!thisPacket){
Util::logExitReason("no more data");
Util::logExitReason(ER_CLEAN_EOF, "no more data");
break;
}
idx = realTimeTrackMap.count(thisIdx) ? realTimeTrackMap[thisIdx] : INVALID_TRACK_ID;
@ -1088,7 +1164,7 @@ namespace Mist{
userSelect[idx].reload(streamName, idx, COMM_STATUS_ACTIVE | COMM_STATUS_SOURCE | COMM_STATUS_DONOTTRACK);
}
if (userSelect[idx].getStatus() & COMM_STATUS_REQDISCONNECT){
Util::logExitReason("buffer requested shutdown");
Util::logExitReason(ER_CLEAN_LIVE_BUFFER_REQ, "buffer requested shutdown");
break;
}
while (config->is_active && userSelect[idx] &&
@ -1114,7 +1190,7 @@ namespace Mist{
if (statComm){
if (statComm.getStatus() & COMM_STATUS_REQDISCONNECT){
config->is_active = false;
Util::logExitReason("received shutdown request from controller");
Util::logExitReason(ER_CLEAN_CONTROLLER_REQ, "received shutdown request from controller");
return;
}
uint64_t now = Util::bootSecs();

View file

@ -95,6 +95,8 @@ namespace Mist{
virtual void connStats(Comms::Connections & statComm);
virtual void parseHeader();
bool bufferFrame(size_t track, uint32_t keyNum);
void doInputAbortTrigger(pid_t pid, char *mRExitReason, char *exitReason);
bool exitAndLogReason();
uint64_t activityCounter;

View file

@ -80,12 +80,12 @@ namespace Mist{
bool inputAAC::checkArguments(){
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -94,7 +94,10 @@ namespace Mist{
bool inputAAC::preRun(){
inFile.open(config->getString("input"));
if (!inFile || inFile.isEOF()){return false;}
if (!inFile || inFile.isEOF()){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
struct stat statData;
lastModTime = 0;
@ -131,7 +134,7 @@ namespace Mist{
size_t bytesRead = 0;
if (!inFile || inFile.isEOF()){
INFO_MSG("Could not open input stream");
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
@ -140,15 +143,12 @@ namespace Mist{
// Read fixed + variable header
inFile.readSome(aacData, bytesRead, 6);
if (bytesRead < 6){
WARN_MSG("Not enough bytes left in buffer. Quitting...");
// Dump for debug purposes
INFO_MSG("Header contains bytes: %x %x %x %x %x %x", aacData[0]
, aacData[1], aacData[2], aacData[3], aacData[4], aacData[5]);
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Not enough bytes left in buffer", config->getString("input").c_str());
return false;
}
// Confirm syncword (= FFF)
if (aacData[0] != 0xFF || (aacData[1] & 0xF0) != 0xF0){
WARN_MSG("Invalid sync word at start of header");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Reading header for '%s' failed: Invalid sync word at start of header", config->getString("input").c_str());
return false;
}
// Calculate the starting position of the next frame
@ -172,7 +172,7 @@ namespace Mist{
// Create ADTS object of complete frame info
aac::adts adtsPack(aacFrame, frameSize);
if (!adtsPack){
WARN_MSG("Could not parse ADTS package!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Reading header for '%s' failed: Could not parse ADTS package", config->getString("input").c_str());
return false;
}
@ -231,7 +231,7 @@ namespace Mist{
size_t disregardAmount = 0;
if (!inFile || inFile.isEOF()){
INFO_MSG("Reached EOF");
Util::logExitReason(ER_CLEAN_EOF, "Reached EOF");
return;
}
@ -251,9 +251,10 @@ namespace Mist{
aacData[3] == 0x54 && aacData[4] == 0x41 && aacData[5] == 0x47){
inFile.readAll(aacData, bytesRead);
INFO_MSG("Throwing out %zu bytes of metadata...", bytesRead);
Util::logExitReason(ER_CLEAN_EOF, "Reached EOF");
return;
}
WARN_MSG("Invalid sync word at start of header");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Invalid sync word at start of header");
return;
}
// Calculate the starting position of the next frame
@ -278,21 +279,7 @@ namespace Mist{
// Create ADTS object of frame
aac::adts adtsPack(aacFrame, frameSize);
if (!adtsPack){
WARN_MSG("Could not parse ADTS package!");
WARN_MSG("Current frame info:");
WARN_MSG("Current frame pos: %zu", filePos);
WARN_MSG("Next frame pos: %zu", nextFramePos);
WARN_MSG("Frame size expected: %" PRIu64, frameSize);
WARN_MSG("Bytes read: %zu", bytesRead);
WARN_MSG("ADTS getAACProfile: %li", adtsPack.getAACProfile());
WARN_MSG("ADTS getFrequencyIndex: %li", adtsPack.getFrequencyIndex());
WARN_MSG("ADTS getFrequency: %li", adtsPack.getFrequency());
WARN_MSG("ADTS getChannelConfig: %li", adtsPack.getChannelConfig());
WARN_MSG("ADTS getChannelCount: %li", adtsPack.getChannelCount());
WARN_MSG("ADTS getHeaderSize: %li", adtsPack.getHeaderSize());
WARN_MSG("ADTS getPayloadSize: %li", adtsPack.getPayloadSize());
WARN_MSG("ADTS getCompleteSize: %li", adtsPack.getCompleteSize());
WARN_MSG("ADTS getSampleCount: %li", adtsPack.getSampleCount());
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not parse ADTS package");
return;
}
@ -313,8 +300,7 @@ namespace Mist{
if (trks.size()){
audioTrack = *(trks.begin());
}else{
Util::logExitReason("no audio track in header");
FAIL_MSG("No audio track in header - aborting");
Util::logExitReason(ER_FORMAT_SPECIFIC, "No audio track in header");
return;
}
}

View file

@ -43,17 +43,17 @@ namespace Mist{
bool inputAV::checkArguments(){
if (config->getString("input") == "-"){
std::cerr << "Input from stdin not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -79,7 +79,7 @@ namespace Mist{
if (ret != 0){
char errstr[300];
av_strerror(ret, errstr, 300);
FAIL_MSG("Could not open file: %s", errstr);
Util::logExitReason(ER_READ_START_FAILURE, "Could not open file: %s", errstr);
return false; // Couldn't open file
}
@ -88,7 +88,7 @@ namespace Mist{
if (ret < 0){
char errstr[300];
av_strerror(ret, errstr, 300);
FAIL_MSG("Could not find stream info: %s", errstr);
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not find stream info: %s", errstr);
return false;
}
return true;
@ -195,7 +195,7 @@ namespace Mist{
thisPacket.null();
preRun();
// failure :-(
FAIL_MSG("getNext failed");
Util::logExitReason(ER_UNKNOWN, "getNext failed");
}
void inputAV::seek(uint64_t seekTime, size_t idx){

View file

@ -489,7 +489,7 @@ namespace Mist{
}
if (hasPush){everHadPush = true;}
if (!hasPush && everHadPush && !resumeMode && config->is_active){
Util::logExitReason("source disconnected for non-resumable stream");
Util::logExitReason(ER_CLEAN_EOF, "source disconnected for non-resumable stream");
if (streamStatus){streamStatus.mapped[0] = STRMSTAT_SHUTDOWN;}
config->is_active = false;
userSelect.clear();

View file

@ -210,12 +210,12 @@ namespace Mist{
if (!needsLock()){return true;}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -223,7 +223,7 @@ namespace Mist{
// open File
F = fopen(config->getString("input").c_str(), "r+b");
if (!F){
HIGH_MSG("Could not open file %s", config->getString("input").c_str());
Util::logExitReason(ER_READ_START_FAILURE, "Could not open file %s", config->getString("input").c_str());
return false;
}
fseek(F, 0, SEEK_SET);
@ -236,17 +236,20 @@ namespace Mist{
}
bool inputDTSC::readHeader(){
if (!F){return false;}
if (!F){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
size_t moreHeader = 0;
do{
char hdr[8];
fseek(F, moreHeader, SEEK_SET);
if (fread(hdr, 8, 1, F) != 1){
FAIL_MSG("Could not read header @ bpos %zu", moreHeader);
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not read header @ bpos %zu", config->getString("input").c_str(), moreHeader);
return false;
}
if (memcmp(hdr, DTSC::Magic_Header, 4)){
FAIL_MSG("File does not have a DTSC header @ bpos %zu", moreHeader);
Util::logExitReason(ER_FORMAT_SPECIFIC, "Reading header for '%s' failed: File does not have a DTSC header @ bpos %zu", config->getString("input").c_str(), moreHeader);
return false;
}
size_t pktLen = Bit::btohl(hdr + 4);
@ -283,6 +286,7 @@ namespace Mist{
fseek(F, thisPos.bytePos, SEEK_SET);
if (feof(F)){
thisPacket.null();
Util::logExitReason(ER_CLEAN_EOF, "End of file reached");
return;
}
clearerr(F);
@ -290,9 +294,9 @@ namespace Mist{
lastreadpos = ftell(F);
if (fread(buffer, 4, 1, F) != 1){
if (feof(F)){
INFO_MSG("End of file reached while seeking @ %" PRIu64, lastreadpos);
Util::logExitReason(ER_CLEAN_EOF, "End of file reached while seeking @ %" PRIu64, lastreadpos);
}else{
ERROR_MSG("Could not seek to next @ %" PRIu64, lastreadpos);
Util::logExitReason(ER_UNKNOWN, "Could not seek to next @ %" PRIu64, lastreadpos);
}
thisPacket.null();
return;
@ -306,13 +310,13 @@ namespace Mist{
if (memcmp(buffer, DTSC::Magic_Packet, 4) == 0){version = 1;}
if (memcmp(buffer, DTSC::Magic_Packet2, 4) == 0){version = 2;}
if (version == 0){
ERROR_MSG("Invalid packet header @ %#" PRIx64 " - %.4s != %.4s @ %" PRIu64, lastreadpos,
Util::logExitReason(ER_FORMAT_SPECIFIC, "Invalid packet header @ %#" PRIx64 " - %.4s != %.4s @ %" PRIu64, lastreadpos,
buffer, DTSC::Magic_Packet2, lastreadpos);
thisPacket.null();
return;
}
if (fread(buffer + 4, 4, 1, F) != 1){
ERROR_MSG("Could not read packet size @ %" PRIu64, lastreadpos);
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not read packet size @ %" PRIu64, lastreadpos);
thisPacket.null();
return;
}
@ -321,7 +325,7 @@ namespace Mist{
pBuf.resize(8 + packSize);
memcpy((char *)pBuf.data(), buffer, 8);
if (fread((void *)(pBuf.data() + 8), packSize, 1, F) != 1){
ERROR_MSG("Could not read packet @ %" PRIu64, lastreadpos);
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not read packet @ %" PRIu64, lastreadpos);
thisPacket.null();
return;
}
@ -353,7 +357,7 @@ namespace Mist{
}
if (cmd == "error"){
thisPacket.getString("msg", cmd);
Util::logExitReason("%s", cmd.c_str());
Util::logExitReason(ER_FORMAT_SPECIFIC, "%s", cmd.c_str());
thisPacket.null();
return;
}

View file

@ -56,7 +56,7 @@ namespace Mist{
key = Encodings::Base64::decode(config->getString("key"));
if (key == ""){
if (config->getString("keyseed") == "" || config->getString("keyid") == ""){
std::cerr << "No key given, and no keyseed/keyid geven" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "No key given, and no keyseed/keyid given");
return false;
}
std::string tmpSeed = Encodings::Base64::decode(config->getString("keyseed"));
@ -66,29 +66,35 @@ namespace Mist{
}
if (config->getString("input") == "-"){
std::cerr << "Input from stdin not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
// open File
inFile = DTSC::File(config->getString("input"));
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
return true;
}
bool inputDTSC::readHeader(){
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
DTSC::File tmp(config->getString("input") + ".dtsh");
if (tmp){
myMeta = tmp.getMeta();
@ -96,7 +102,7 @@ namespace Mist{
return true;
}
if (inFile.getMeta().moreheader < 0 || inFile.getMeta().tracks.size() == 0){
DEBUG_MSG(DLVL_FAIL, "Missing external header file");
Util::logExitReason(ER_READ_START_FAILURE, "Missing external header file");
return false;
}
myMeta = DTSC::Meta(inFile.getMeta());

View file

@ -105,12 +105,12 @@ namespace Mist{
bool InputEBML::checkArguments(){
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -150,7 +150,10 @@ namespace Mist{
int fin = -1, fout = -1;
Util::Procs::StartPiped(args, &fin, &fout, 0);
if (fout == -1){return false;}
if (fout == -1){
Util::logExitReason(ER_PROCESS_SPECIFIC, "Unable to start mkv-exec process `%s`", args);
return false;
}
dup2(fout, 0);
inFile.open(0);
return true;
@ -161,7 +164,10 @@ namespace Mist{
}else{
// open File
inFile.open(config->getString("input"));
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
standAlone = inFile.isSeekable();
}
return true;
@ -261,7 +267,10 @@ namespace Mist{
}
bool InputEBML::readHeader(){
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
if (!meta || (needsLock() && isSingular())){
meta.reInit(isSingular() ? streamName : "");
}
@ -728,7 +737,7 @@ namespace Mist{
}
}
if (seekPos > readPos + readBuffer.size()){
Util::logExitReason("Input file seek abort");
Util::logExitReason(ER_READ_START_FAILURE, "Input file seek abort");
config->is_active = false;
readBufferOffset = 0;
return;

View file

@ -40,17 +40,17 @@ namespace Mist{
bool inputFLAC::checkArguments(){
if (config->getString("input") == "-"){
std::cerr << "Input from stdin not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -59,7 +59,10 @@ namespace Mist{
bool inputFLAC::preRun(){
inFile = fopen(config->getString("input").c_str(), "r");
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
return true;
}
@ -81,7 +84,7 @@ namespace Mist{
bool inputFLAC::readMagicPacket(){
char magic[4];
if (fread(magic, 4, 1, inFile) != 1){
FAIL_MSG("Could not read magic word - aborting!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not read magic word - aborting!");
return false;
}
@ -90,12 +93,15 @@ namespace Mist{
return true;
}
FAIL_MSG("Not a FLAC file - aborting!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Not a FLAC file - aborting!");
return false;
}
bool inputFLAC::readHeader(){
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
if (readExistingHeader()){
WARN_MSG("header exists, read old one");
@ -118,7 +124,7 @@ namespace Mist{
char metahead[4];
while (!feof(inFile) && !lastMeta){
if (fread(metahead, 4, 1, inFile) != 1){
FAIL_MSG("Could not read metadata block header - aborting!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not read metadata block header - aborting!");
return false;
}
@ -132,7 +138,7 @@ namespace Mist{
char metaTmp[bytes];
if (fread(metaTmp, bytes, 1, inFile) != 1){
FAIL_MSG("Could not read streaminfo metadata - aborting!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not read streaminfo metadata - aborting!");
return false;
}
@ -147,8 +153,8 @@ namespace Mist{
blockSize = (metaTmp[0] << 8 | metaTmp[1]);
if ((metaTmp[2] << 8 | metaTmp[3]) != blockSize){
FAIL_MSG("variable block size not supported!");
return 1;
Util::logExitReason(ER_FORMAT_SPECIFIC, "variable block size not supported!");
return false;
}
sampleRate = ((metaTmp[10] << 12) | (metaTmp[11] << 4) | ((metaTmp[12] & 0xf0) >> 4));
@ -174,11 +180,11 @@ namespace Mist{
}
if (!sampleRate){
FAIL_MSG("Could not get sample rate from file header");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not get sample rate from file header");
return false;
}
if (!channels){
FAIL_MSG("no channel information found!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "no channel information found!");
return false;
}

View file

@ -32,17 +32,17 @@ namespace Mist{
bool inputFLV::checkArguments(){
if (config->getString("input") == "-"){
std::cerr << "Input from stdin not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -52,7 +52,10 @@ namespace Mist{
bool inputFLV::preRun(){
// open File
inFile = fopen(config->getString("input").c_str(), "r");
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
struct stat statData;
lastModTime = 0;
if (stat(config->getString("input").c_str(), &statData) != -1){
@ -78,7 +81,10 @@ namespace Mist{
}
bool inputFLV::readHeader(){
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
meta.reInit(isSingular() ? streamName : "");
// Create header file from FLV data
Util::fseek(inFile, 13, SEEK_SET);
@ -128,13 +134,14 @@ namespace Mist{
}
}
if (feof(inFile)){
Util::logExitReason(ER_CLEAN_EOF, "Reached EOF");
thisPacket.null();
return;
}
if (FLV::Parse_Error){
FLV::Parse_Error = false;
tmpTag = FLV::Tag();
FAIL_MSG("FLV error @ %" PRIu64 ": %s", lastBytePos, FLV::Error_Str.c_str());
Util::logExitReason(ER_FORMAT_SPECIFIC, "FLV error @ %" PRIu64 ": %s", lastBytePos, FLV::Error_Str.c_str());
thisPacket.null();
return;
}

View file

@ -27,27 +27,27 @@ namespace Mist{
streamName = config->getString("streamname");
if (streamName.find_first_of("+ ") == std::string::npos){
FAIL_MSG("Folder input requires a + or space in the stream name.");
return 1;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Folder input requires a + or space in the stream name.");
return exitAndLogReason();
}
std::string folder = config->getString("input");
if (folder[folder.size() - 1] != '/'){
FAIL_MSG("Input path must end in a forward slash.");
return 1;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input path must end in a forward slash.");
return exitAndLogReason();
}
std::string folder_noslash = folder.substr(0, folder.size() - 1);
struct stat fileCheck;
if (stat(folder_noslash.c_str(), &fileCheck) != 0 || !S_ISDIR(fileCheck.st_mode)){
FAIL_MSG("Folder input requires a folder as input.");
return 1;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Folder input requires a folder as input.");
return exitAndLogReason();
}
std::string path = folder + streamName.substr(streamName.find_first_of("+ ") + 1);
if (stat(path.c_str(), &fileCheck) != 0 || S_ISDIR(fileCheck.st_mode)){
FAIL_MSG("File not found: %s", path.c_str());
return 1;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File not found: %s", path.c_str());
return exitAndLogReason();
}
Util::startInput(streamName, path, false);

View file

@ -66,7 +66,7 @@ namespace Mist{
bool InputH264::checkArguments(){
std::string input = config->getString("input");
if (input != "-" && input.substr(0, 10) != "h264-exec:"){
FAIL_MSG("Unsupported input type: %s", input.c_str());
Util::logExitReason(ER_FORMAT_SPECIFIC, "Unsupported input type: %s", input.c_str());
return false;
}
return true;

View file

@ -740,7 +740,10 @@ namespace Mist{
return false;
}
if (!initPlaylist(config->getString("input"), false)){return false;}
if (!initPlaylist(config->getString("input"), false)){
Util::logExitReason(ER_UNKNOWN, "Failed to load HLS playlist, aborting");
return false;
}
// If the playlist is of event type, init the amount of segments in the playlist
if (isLiveDVR){
@ -756,7 +759,7 @@ namespace Mist{
void inputHLS::parseStreamHeader(){
if (!initPlaylist(config->getString("input"))){
FAIL_MSG("Failed to load HLS playlist, aborting");
Util::logExitReason(ER_UNKNOWN, "Failed to load HLS playlist, aborting");
return;
}
meta.reInit(isSingular() ? streamName : "", false);
@ -1195,7 +1198,7 @@ namespace Mist{
tsStream.getPacket(tid, thisPacket);
}
if (!thisPacket){
FAIL_MSG("Could not getNext TS packet!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not getNext TS packet!");
return;
}
@ -1256,7 +1259,7 @@ namespace Mist{
// Nothing works!
// HLS input will now quit trying to prevent severe mental depression.
INFO_MSG("No packets can be read - exhausted all playlists");
Util::logExitReason(ER_CLEAN_EOF, "No packets can be read - exhausted all playlists");
thisPacket.null();
return;
}
@ -1481,14 +1484,14 @@ namespace Mist{
INFO_MSG("Downloading main playlist file from '%s'", uri.c_str());
HTTP::URIReader plsDL;
if (!plsDL.open(playlistRootPath) || !plsDL){
FAIL_MSG("Could not open main playlist, aborting");
Util::logExitReason(ER_READ_START_FAILURE, "Could not open main playlist, aborting");
return false;
}
char * dataPtr;
size_t dataLen;
plsDL.readAll(dataPtr, dataLen);
if (!dataLen){
FAIL_MSG("Could not download main playlist, aborting.");
Util::logExitReason(ER_READ_START_FAILURE, "Could not download main playlist, aborting.");
return false;
}
urlSource.str(std::string(dataPtr, dataLen));
@ -1503,7 +1506,7 @@ namespace Mist{
}
fileSource.open(playlistLocation.c_str());
if (!fileSource.good()){
FAIL_MSG("Could not open playlist (%s): %s", strerror(errno), playlistLocation.c_str());
Util::logExitReason(ER_READ_START_FAILURE, "Could not open playlist (%s): %s", strerror(errno), playlistLocation.c_str());
}
}

View file

@ -24,17 +24,17 @@ namespace Mist{
bool inputISMV::checkArguments(){
if (config->getString("input") == "-"){
std::cerr << "Input from stdin not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -43,11 +43,18 @@ namespace Mist{
bool inputISMV::preRun(){
inFile = fopen(config->getString("input").c_str(), "r");
return inFile; // True if not null
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
return true;
}
bool inputISMV::readHeader(){
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
meta.reInit(streamName);
// parse ismv header
fseek(inFile, 0, SEEK_SET);
@ -189,7 +196,10 @@ namespace Mist{
MP4::MOOF moof;
moof.read(inFile);
if (feof(inFile)){return false;}
if (feof(inFile)){
Util::logExitReason(ER_CLEAN_EOF, "Reached EOF");
return false;
}
MP4::TRAF trafBox = moof.getChild<MP4::TRAF>();
for (size_t j = 0; j < trafBox.getContentCount(); j++){
@ -205,7 +215,11 @@ namespace Mist{
}
MP4::skipBox(inFile);
return !feof(inFile);
if (feof(inFile)){
Util::logExitReason(ER_CLEAN_EOF, "Reached EOF");
return false;
}
return true;
}
void inputISMV::bufferFragmentData(size_t trackId, uint32_t keyNum){
@ -230,7 +244,7 @@ namespace Mist{
if (trafBox.getContent(j).isType("trun")){trunBox = (MP4::TRUN &)trafBox.getContent(j);}
if (trafBox.getContent(j).isType("tfhd")){
if (M.getID(trackId) != ((MP4::TFHD &)trafBox.getContent(j)).getTrackID()){
FAIL_MSG("Trackids do not match");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Trackids do not match");
return;
}
}

View file

@ -25,17 +25,17 @@ namespace Mist{
bool inputMP3::checkArguments(){
if (config->getString("input") == "-"){
std::cerr << "Input from stdin not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -45,12 +45,18 @@ namespace Mist{
bool inputMP3::preRun(){
// open File
inFile = fopen(config->getString("input").c_str(), "r");
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
return true;
}
bool inputMP3::readHeader(){
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
meta.reInit(isSingular() ? streamName : "");
size_t tNum = meta.addTrack();
meta.setID(tNum, tNum);
@ -93,7 +99,10 @@ namespace Mist{
static char packHeader[3000];
size_t filePos = ftell(inFile);
size_t read = fread(packHeader, 1, 3000, inFile);
if (!read){return;}
if (!read){
Util::logExitReason(ER_CLEAN_EOF, "Reached EOF");
return;
}
if (packHeader[0] != 0xFF || (packHeader[1] & 0xE0) != 0xE0){
// Find the first occurence of sync byte
char *i = (char *)memchr(packHeader, (char)0xFF, read);
@ -107,7 +116,7 @@ namespace Mist{
}
}
if (!offset){
FAIL_MSG("Sync byte not found from offset %zu", filePos);
Util::logExitReason(ER_FORMAT_SPECIFIC, "Sync byte not found from offset %zu", filePos);
return;
}
filePos += offset;

View file

@ -127,17 +127,17 @@ namespace Mist{
bool inputMP4::checkArguments(){
if (config->getString("input") == "-"){
std::cerr << "Input from stdin not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not yet supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output in player mode not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
streamName = config->getString("streamname");
@ -148,9 +148,12 @@ namespace Mist{
bool inputMP4::preRun(){
// open File
inFile.open(config->getString("input"));
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Could not open URL or contains no data");
return false;
}
if (!inFile.isSeekable()){
FAIL_MSG("MP4 input only supports seekable data sources, for now, and this source is not seekable: %s", config->getString("input").c_str());
Util::logExitReason(ER_READ_START_FAILURE, "MP4 input only supports seekable data sources, for now, and this source is not seekable: %s", config->getString("input").c_str());
return false;
}
return true;
@ -168,7 +171,7 @@ namespace Mist{
bool inputMP4::readHeader(){
if (!inFile){
Util::logExitReason("Could not open input file");
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
bool hasMoov = false;
@ -183,7 +186,7 @@ namespace Mist{
while (readBuffer.size() < 16 && inFile && keepRunning()){inFile.readSome(16, *this);}
//Failed? Abort.
if (readBuffer.size() < 16){
FAIL_MSG("Could not read box header from input!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not read box header from input!");
break;
}
//Box type is always on bytes 5-8 from the start of a box
@ -192,7 +195,7 @@ namespace Mist{
if (boxType == "moov"){
while (readBuffer.size() < boxSize && inFile && keepRunning()){inFile.readSome(boxSize-readBuffer.size(), *this);}
if (readBuffer.size() < boxSize){
FAIL_MSG("Could not read entire MOOV box into memory");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not read entire MOOV box into memory");
break;
}
MP4::Box moovBox(readBuffer, false);
@ -221,8 +224,11 @@ namespace Mist{
}
if (!hasMoov){
if (!inFile){Util::logExitReason("URIReader for source file was disconnected!");}
Util::logExitReason("No MOOV box found in source file; aborting!");
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: URIReader for source file was disconnected!", config->getString("input").c_str());
}else{
Util::logExitReason(ER_FORMAT_SPECIFIC, "Reading header for '%s' failed: No MOOV box found in source file; aborting!", config->getString("input").c_str());
}
return false;
}
@ -515,7 +521,7 @@ namespace Mist{
INFO_MSG("Buffer contains %" PRIu64 "-%" PRIu64 ", but we need %" PRIu64 "; seeking!", readPos, readPos + readBuffer.size(), curPart.bpos);
readBuffer.truncate(0);
if (!inFile.seek(curPart.bpos)){
FAIL_MSG("seek unsuccessful @bpos %" PRIu64 ": %s", curPart.bpos, strerror(errno));
Util::logExitReason(ER_FORMAT_SPECIFIC, "seek unsuccessful @bpos %" PRIu64 ": %s", curPart.bpos, strerror(errno));
thisPacket.null();
return;
}
@ -536,7 +542,7 @@ namespace Mist{
FAIL_MSG("Read unsuccessful at %" PRIu64 ", seeking to retry...", readPos+readBuffer.size());
readBuffer.truncate(0);
if (!inFile.seek(curPart.bpos)){
FAIL_MSG("seek unsuccessful @bpos %" PRIu64 ": %s", curPart.bpos, strerror(errno));
Util::logExitReason(ER_FORMAT_SPECIFIC, "seek unsuccessful @bpos %" PRIu64 ": %s", curPart.bpos, strerror(errno));
thisPacket.null();
return;
}
@ -545,7 +551,7 @@ namespace Mist{
inFile.readSome((curPart.bpos+curPart.size) - (readPos+readBuffer.size()), *this);
}
if (readPos+readBuffer.size() < curPart.bpos+curPart.size){
FAIL_MSG("Read retry unsuccessful at %" PRIu64 ", aborting", readPos+readBuffer.size());
Util::logExitReason(ER_FORMAT_SPECIFIC, "Read retry unsuccessful at %" PRIu64 ", aborting", readPos+readBuffer.size());
thisPacket.null();
return;
}

View file

@ -54,7 +54,10 @@ namespace Mist{
bool inputOGG::preRun(){
// open File
inFile = fopen(config->getString("input").c_str(), "r");
if (!inFile){return false;}
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
return true;
}
@ -142,7 +145,7 @@ namespace Mist{
size_t len = myPage.getSegmentLen(i);
theora::header tmpHead((char *)myPage.getSegment(i), len);
if (!tmpHead.isHeader()){// not copying the header anymore, should this check isHeader?
FAIL_MSG("Theora Header read failed!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Reading header for '%s' failed: Theora header read failed", config->getString("input").c_str());
return false;
}
switch (tmpHead.getHeaderType()){
@ -174,7 +177,7 @@ namespace Mist{
size_t len = myPage.getSegmentLen(i);
vorbis::header tmpHead((char *)myPage.getSegment(i), len);
if (!tmpHead.isHeader()){
FAIL_MSG("Header read failed!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Reading header for '%s' failed: Header read failed", config->getString("input").c_str());
return false;
}
switch (tmpHead.getHeaderType()){

View file

@ -22,17 +22,17 @@ namespace Mist{
bool inputPlaylist::checkArguments(){
if (config->getString("input") == "-"){
std::cerr << "Input from stdin not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
std::cerr << "Output to stdout not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
std::cerr << "File output not supported" << std::endl;
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -45,7 +45,7 @@ namespace Mist{
killSwitch.reload(streamName, (size_t)INVALID_TRACK_ID, (uint8_t)(COMM_STATUS_ACTIVE | COMM_STATUS_DONOTTRACK));
while (config->is_active){
if (killSwitch && killSwitch.getStatus() & COMM_STATUS_REQDISCONNECT){
Util::logExitReason("buffer requested shutdown");
Util::logExitReason(ER_CLEAN_LIVE_BUFFER_REQ, "buffer requested shutdown");
config->is_active = false;
break;
}
@ -55,7 +55,7 @@ namespace Mist{
wallTime = wTime->tm_hour * 60 + wTime->tm_min;
reloadPlaylist();
if (!playlist.size()){
Util::logExitReason("No entries in playlist");
Util::logExitReason(ER_FORMAT_SPECIFIC, "No entries in playlist");
return;
}
++playlistIndex;
@ -112,7 +112,7 @@ namespace Mist{
seenValidEntry = true;
while (Util::Procs::isRunning(spawn_pid) && config->is_active){
if (killSwitch && killSwitch.getStatus() & COMM_STATUS_REQDISCONNECT){
Util::logExitReason("buffer requested shutdown");
Util::logExitReason(ER_CLEAN_LIVE_BUFFER_REQ, "buffer requested shutdown");
config->is_active = false;
break;
}

View file

@ -122,12 +122,12 @@ namespace Mist{
bool InputRTSP::checkArguments(){
const std::string &inpt = config->getString("input");
if (inpt.substr(0, 7) != "rtsp://"){
FAIL_MSG("Unsupported RTSP URL: '%s'", inpt.c_str());
Util::logExitReason(ER_FORMAT_SPECIFIC, "Unsupported RTSP URL: '%s'", inpt.c_str());
return false;
}
const std::string &transport = config->getString("transport");
if (transport != "TCP" && transport != "UDP" && transport != "tcp" && transport != "udp"){
FAIL_MSG("Not a supported transport mode: %s", transport.c_str());
Util::logExitReason(ER_FORMAT_SPECIFIC, "Not a supported transport mode: %s", transport.c_str());
return false;
}
if (transport == "UDP" || transport == "udp"){TCPmode = false;}
@ -142,7 +142,11 @@ namespace Mist{
bool InputRTSP::openStreamSource(){
tcpCon.open(url.host, url.getPort(), false);
mainConn = &tcpCon;
return tcpCon;
if (!tcpCon){
Util::logExitReason(ER_READ_START_FAILURE, "Opening TCP socket `%s:%s` failed", url.host.c_str(), url.getPort());
return false;
}
return true;
}
void InputRTSP::parseStreamHeader(){
@ -152,7 +156,7 @@ namespace Mist{
extraHeaders["Accept"] = "application/sdp";
sendCommand("DESCRIBE", url.getUrl(), "", &extraHeaders);
if (!tcpCon || !seenSDP){
FAIL_MSG("Could not get stream description!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not get stream description!");
return;
}
if (sdpState.tracks.size()){
@ -178,7 +182,7 @@ namespace Mist{
atLeastOne = true;
continue;
}
FAIL_MSG("Could not setup track %s!", M.getTrackIdentifier(it->first).c_str());
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not setup track %s!", M.getTrackIdentifier(it->first).c_str());
tcpCon.close();
return;
}
@ -214,7 +218,7 @@ namespace Mist{
if (statComm){
if (statComm.getStatus() & COMM_STATUS_REQDISCONNECT){
config->is_active = false;
Util::logExitReason("received shutdown request from controller");
Util::logExitReason(ER_CLEAN_CONTROLLER_REQ, "received shutdown request from controller");
return;
}
uint64_t now = Util::bootSecs();
@ -229,7 +233,7 @@ namespace Mist{
}
}
if (!tcpCon){
Util::logExitReason("TCP connection closed");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "TCP connection closed");
}
}
@ -402,7 +406,7 @@ namespace Mist{
userSelect[idx].reload(streamName, idx, COMM_STATUS_ACTIVE | COMM_STATUS_SOURCE | COMM_STATUS_DONOTTRACK);
}
if (userSelect[idx].getStatus() & COMM_STATUS_REQDISCONNECT){
Util::logExitReason("buffer requested shutdown");
Util::logExitReason(ER_CLEAN_LIVE_BUFFER_REQ, "buffer requested shutdown");
tcpCon.close();
}
}

View file

@ -77,7 +77,7 @@ namespace Mist{
bool InputSDP::checkArguments(){
const std::string &inpt = config->getString("input");
if (inpt.substr(inpt.length() - 4) != ".sdp"){
FAIL_MSG("Expected a SDP file but received: '%s'", inpt.c_str());
Util::logExitReason(ER_FORMAT_SPECIFIC, "Expected a SDP file but received: '%s'", inpt.c_str());
return false;
}
return true;
@ -88,13 +88,17 @@ namespace Mist{
const std::string &inpt = config->getString("input");
reader.open(inpt);
// Will return false if it cant open file or it is EOF
return reader;
if (!reader){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", config->getString("input").c_str());
return false;
}
return true;
}
/// Gets and parses the SDP file
void InputSDP::parseStreamHeader(){
if (!reader){
FAIL_MSG("Connection lost with input. Could not get stream description!");
Util::logExitReason(ER_READ_START_FAILURE, "Connection lost with input. Could not get stream description!");
return;
}
@ -206,7 +210,7 @@ namespace Mist{
if (statComm){
if (statComm.getStatus() == COMM_STATUS_REQDISCONNECT){
config->is_active = false;
Util::logExitReason("received shutdown request from controller");
Util::logExitReason(ER_CLEAN_CONTROLLER_REQ, "received shutdown request from controller");
return;
}
uint64_t now = Util::bootSecs();
@ -312,7 +316,7 @@ namespace Mist{
userSelect[idx].reload(streamName, idx, COMM_STATUS_ACTIVE | COMM_STATUS_SOURCE | COMM_STATUS_DONOTTRACK);
}
if (userSelect[idx].getStatus() == COMM_STATUS_REQDISCONNECT){
Util::logExitReason("buffer requested shutdown");
Util::logExitReason(ER_CLEAN_LIVE_BUFFER_REQ, "buffer requested shutdown");
}
}

View file

@ -17,7 +17,7 @@ namespace Mist{
fileSource.close();
fileSource.open(config->getString("input").c_str());
if (!fileSource.is_open()){
FAIL_MSG("Could not open file %s: %s", config->getString("input").c_str(), strerror(errno));
Util::logExitReason(ER_READ_START_FAILURE, "Could not open file %s: %s", config->getString("input").c_str(), strerror(errno));
return false;
}
return true;
@ -25,7 +25,7 @@ namespace Mist{
bool InputSrt::checkArguments(){
if (config->getString("input") == "-"){
FAIL_MSG("Reading from standard input not yet supported");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input from stdin not yet supported");
return false;
}else{
preRun();
@ -33,12 +33,12 @@ namespace Mist{
if (!config->getString("streamname").size()){
if (config->getString("output") == "-"){
FAIL_MSG("Writing to standard output not yet supported");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Output to stdout not yet supported");
return false;
}
}else{
if (config->getString("output") != "-"){
FAIL_MSG("File output in player mode not supported");
Util::logExitReason(ER_FORMAT_SPECIFIC, "File output in player mode not supported");
return false;
}
}
@ -46,7 +46,10 @@ namespace Mist{
}
bool InputSrt::readHeader(){
if (!fileSource.good()){return false;}
if (!fileSource.good()){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
size_t idx = meta.addTrack();
meta.setID(idx, 1);
meta.setType(idx, "meta");

View file

@ -353,7 +353,11 @@ namespace Mist{
FILE * inFile = fopen(inCfg.c_str() + 9, "r");
reader.open(fileno(inFile));
standAlone = false;
return inFile;
if (!inFile){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", inCfg.c_str());
return false;
}
return true;
}
//Anything else, read through URIReader
HTTP::URL url = HTTP::localURIResolver().link(inCfg);
@ -361,7 +365,11 @@ namespace Mist{
if (url.protocol == "https-ts"){url.protocol = "https";}
reader.open(url);
standAlone = reader.isSeekable();
return reader;
if (!reader){
Util::logExitReason(ER_READ_START_FAILURE, "Opening input '%s' failed", inCfg.c_str());
return false;
}
return true;
}
void inputTS::dataCallback(const char *ptr, size_t size){
@ -387,7 +395,10 @@ namespace Mist{
/// for a specific track to metadata. After the entire stream has been read,
/// it writes the remaining metadata.
bool inputTS::readHeader(){
if (!reader){return false;}
if (!reader){
Util::logExitReason(ER_READ_START_FAILURE, "Reading header for '%s' failed: Could not open input stream", config->getString("input").c_str());
return false;
}
meta.reInit(isSingular() ? streamName : "");
TS::Packet packet; // to analyse and extract data
DTSC::Packet headerPack;
@ -471,7 +482,7 @@ namespace Mist{
}
if (!thisPacket){
INFO_MSG("Could not getNext TS packet!");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Could not getNext TS packet!");
return;
}
tsStream.initializeMetadata(meta);
@ -583,7 +594,7 @@ namespace Mist{
}
if (!reader){
config->is_active = false;
Util::logExitReason("end of streamed input");
Util::logExitReason(ER_CLEAN_EOF, "end of streamed input");
return;
}
}else{
@ -635,7 +646,7 @@ namespace Mist{
if (statComm){
if (statComm.getStatus() & COMM_STATUS_REQDISCONNECT){
config->is_active = false;
Util::logExitReason("received shutdown request from controller");
Util::logExitReason(ER_CLEAN_CONTROLLER_REQ, "received shutdown request from controller");
return;
}
uint64_t now = Util::bootSecs();
@ -654,7 +665,7 @@ namespace Mist{
if (hasStarted && !threadTimer.size()){
if (!isAlwaysOn()){
config->is_active = false;
Util::logExitReason("no active threads and we had input in the past");
Util::logExitReason(ER_CLEAN_INACTIVE, "no active threads and we had input in the past");
return;
}else{
liveStream.clear();
@ -686,7 +697,7 @@ namespace Mist{
if (Util::bootSecs() - noDataSince > 20){
if (!isAlwaysOn()){
config->is_active = false;
Util::logExitReason("no packets received for 20 seconds");
Util::logExitReason(ER_CLEAN_INACTIVE, "no packets received for 20 seconds");
return;
}else{
noDataSince = Util::bootSecs();

View file

@ -167,7 +167,7 @@ namespace Mist{
standAlone = false;
HTTP::URL u(source);
if (u.protocol != "rist"){
FAIL_MSG("Input protocol must begin with rist://");
Util::logExitReason(ER_FORMAT_SPECIFIC, "Input protocol must begin with rist://");
return false;
}
std::map<std::string, std::string> arguments;
@ -184,7 +184,7 @@ namespace Mist{
while (!hasRaw && config->is_active){
Util::sleep(50);
if (!bufferActive()){
Util::logExitReason("Buffer shut down");
Util::logExitReason(ER_SHM_LOST, "Buffer shut down");
return;
}
}
@ -198,7 +198,7 @@ namespace Mist{
}else{
Util::sleep(50);
if (!bufferActive()){
Util::logExitReason("Buffer shut down");
Util::logExitReason(ER_SHM_LOST, "Buffer shut down");
return;
}
}
@ -224,7 +224,7 @@ namespace Mist{
void inputTSRIST::onFail(const std::string & msg){
FAIL_MSG("%s", msg.c_str());
Util::logExitReason(msg.c_str());
Util::logExitReason(ER_FORMAT_SPECIFIC, msg.c_str());
}
bool inputTSRIST::openStreamSource(){

View file

@ -229,9 +229,9 @@ namespace Mist{
if (!thisPacket){
if (srtConn){
INFO_MSG("Could not getNext TS packet!");
Util::logExitReason("internal TS parser error");
Util::logExitReason(ER_FORMAT_SPECIFIC, "internal TS parser error");
}else{
Util::logExitReason("SRT connection close");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "SRT connection close");
}
return;
}

View file

@ -471,7 +471,7 @@ namespace Mist{
if (!livePage[packTrack].exists()){
WARN_MSG("Data page '%s' was deleted - forcing source shutdown to prevent unstable state", livePage[packTrack].name.c_str());
Util::logExitReason("data page was deleted, forcing shutdown to prevent unstable state");
Util::logExitReason(ER_SHM_LOST, "data page was deleted, forcing shutdown to prevent unstable state");
bufferFinalize(packTrack, livePage[packTrack]);
kill(getpid(), SIGINT);
return;

View file

@ -20,7 +20,7 @@ int spawnForked(Socket::Connection &S){
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::logExitReason(ER_CLEAN_SIGNAL, "signal USR1");
Util::Config::is_active = false;
}

View file

@ -113,6 +113,7 @@ namespace Mist{
firstData = true;
newUA = true;
lastPushUpdate = 0;
Util::Config::binaryType = Util::OUTPUT;
lastRecv = Util::bootSecs();
if (myConn){
@ -185,7 +186,7 @@ namespace Mist{
}else{
MEDIUM_MSG("onFail '%s': %s", streamName.c_str(), msg.c_str());
}
Util::logExitReason(msg.c_str());
Util::logExitReason(ER_UNKNOWN, msg.c_str());
isInitialized = false;
wantRequest = false;
parseData = false;
@ -1519,12 +1520,14 @@ namespace Mist{
if (!streamName.size()){
WARN_MSG("Recording unconnected %s output to file! Cancelled.", capa["name"].asString().c_str());
onFail("Unconnected recording output", true);
recEndTrigger();
return 2;
}
initialize();
if (!M.getValidTracks().size() || !userSelect.size() || !keepGoing()){
INFO_MSG("Stream not available - aborting");
onFail("Stream not available for recording", true);
recEndTrigger();
return 3;
}
initialSeek();
@ -1562,6 +1565,7 @@ namespace Mist{
}else{
if (!connectToFile(newTarget, targetParams.count("append"))){
onFail("Could not connect to the target for recording", true);
recEndTrigger();
return 3;
}
INFO_MSG("Recording %s to %s with %s format", streamName.c_str(),
@ -1752,7 +1756,7 @@ namespace Mist{
INFO_MSG("Switching to next push target filename: %s", newTarget.c_str());
if (!connectToFile(newTarget)){
FAIL_MSG("Failed to open file, aborting: %s", newTarget.c_str());
Util::logExitReason("failed to open file, aborting: %s", newTarget.c_str());
Util::logExitReason(ER_WRITE_FAILURE, "failed to open file, aborting: %s", newTarget.c_str());
onFinish();
break;
}
@ -1763,7 +1767,7 @@ namespace Mist{
}else{
if (!onFinish()){
INFO_MSG("Shutting down because planned stopping point reached");
Util::logExitReason("planned stopping point reached");
Util::logExitReason(ER_CLEAN_INTENDED_STOP, "planned stopping point reached");
break;
}
}
@ -1779,20 +1783,20 @@ namespace Mist{
}
/*LTS-END*/
if (!onFinish()){
Util::logExitReason("end of stream");
Util::logExitReason(ER_CLEAN_EOF, "end of stream");
break;
}
}
}
if (!meta){
Util::logExitReason("lost internal connection to stream data");
Util::logExitReason(ER_SHM_LOST, "lost internal connection to stream data");
break;
}
}
stats();
}
if (!config->is_active){Util::logExitReason("set inactive");}
if (!myConn){Util::logExitReason("connection closed");}
if (!config->is_active){Util::logExitReason(ER_UNKNOWN, "set inactive");}
if (!myConn){Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "connection closed");}
if (strncmp(Util::exitReason, "connection closed", 17) == 0){
MEDIUM_MSG("Client handler shutting down, exit reason: %s", Util::exitReason);
}else{
@ -1831,7 +1835,6 @@ namespace Mist{
}else{
FAIL_MSG("Lost connection to the playlist file `%s` during segmenting", playlistLocationString.c_str());
Util::logExitReason("Lost connection to the playlist file `%s` during segmenting", playlistLocationString.c_str());
return 1;
}
}
@ -1841,25 +1844,10 @@ namespace Mist{
streamName + "\n" + getConnectedHost() + "\n" + capa["name"].asStringRef() + "\n" + reqUrl;
Triggers::doTrigger("CONN_CLOSE", payload, streamName);
}
if (isRecordingToFile && config->hasOption("target") && Triggers::shouldTrigger("RECORDING_END", streamName)){
uint64_t rightNow = Util::epoch();
std::stringstream payl;
payl << streamName << '\n';
payl << config->getString("target") << '\n';
payl << capa["name"].asStringRef() << '\n';
payl << myConn.dataUp() << '\n';
payl << (Util::bootSecs() - myConn.connTime()) << '\n';
payl << (rightNow - (Util::bootSecs() - myConn.connTime())) << '\n';
payl << rightNow << '\n';
if (firstPacketTime != 0xFFFFFFFFFFFFFFFFull){
payl << (lastPacketTime - firstPacketTime) << '\n';
}else{
payl << 0 << '\n';
}
payl << firstPacketTime << '\n';
payl << lastPacketTime << '\n';
Triggers::doTrigger("RECORDING_END", payl.str(), streamName);
if (isRecordingToFile){
recEndTrigger();
}
outputEndTrigger();
/*LTS-END*/
disconnect();
@ -1971,7 +1959,7 @@ namespace Mist{
}
if (!dropTracks.size()){
FAIL_MSG("Could not equalize tracks! This is very very very bad and I am now going to shut down to prevent worse.");
Util::logExitReason("Could not equalize tracks");
Util::logExitReason(ER_INTERNAL_ERROR, "Could not equalize tracks");
parseData = false;
config->is_active = false;
return false;
@ -2099,11 +2087,11 @@ namespace Mist{
//every ~1 second, check if the stream is not offline
if (emptyCount % 100 == 0 && Util::getStreamStatus(streamName) == STRMSTAT_OFF){
if (M.getLive()){
Util::logExitReason("Live stream source shut down");
Util::logExitReason(ER_CLEAN_EOF, "Live stream source shut down");
thisPacket.null();
return true;
}else if (!Util::startInput(streamName)){
Util::logExitReason("VoD stream source shut down and could not be restarted");
Util::logExitReason(ER_UNKNOWN, "VoD stream source shut down and could not be restarted");
thisPacket.null();
return true;
}
@ -2329,6 +2317,40 @@ namespace Mist{
return true;
}
std::string Output::getExitTriggerPayload(){
uint64_t rightNow = Util::epoch();
std::stringstream payl;
payl << streamName << '\n';
payl << config->getString("target") << '\n';
payl << capa["name"].asStringRef() << '\n';
payl << myConn.dataUp() << '\n';
payl << (Util::bootSecs() - myConn.connTime()) << '\n';
payl << (rightNow - (Util::bootSecs() - myConn.connTime())) << '\n';
payl << rightNow << '\n';
if (firstPacketTime != 0xFFFFFFFFFFFFFFFFull){
payl << (lastPacketTime - firstPacketTime) << '\n';
}else{
payl << 0 << '\n';
}
payl << firstPacketTime << '\n';
payl << lastPacketTime << '\n';
payl << Util::mRExitReason << '\n';
payl << Util::exitReason << '\n';
return payl.str();
}
void Output::recEndTrigger(){
if (Util::Config::binaryType == Util::OUTPUT && config->hasOption("target") && Triggers::shouldTrigger("RECORDING_END", streamName)){
Triggers::doTrigger("RECORDING_END", getExitTriggerPayload(), streamName);
}
}
void Output::outputEndTrigger(){
if (Util::Config::binaryType == Util::OUTPUT && config->hasOption("target") && Triggers::shouldTrigger("OUTPUT_END", streamName)){
Triggers::doTrigger("OUTPUT_END", getExitTriggerPayload(), streamName);
}
}
/// Checks if the set streamName allows pushes from this connector/IP/password combination.
/// Runs all appropriate triggers and checks.
/// Returns true if the push should continue, false otherwise.

View file

@ -151,6 +151,9 @@ namespace Mist{
virtual bool isRecording();
virtual bool isFileTarget();
virtual bool isPushing(){return pushing;};
std::string getExitTriggerPayload();
void recEndTrigger();
void outputEndTrigger();
bool allowPush(const std::string &passwd);
void waitForStreamPushReady();

View file

@ -328,7 +328,7 @@ namespace Mist{
if (!newStream.size()){
FAIL_MSG("Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), reqUrl.c_str());
Util::logExitReason(
Util::logExitReason(ER_TRIGGER,
"Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), reqUrl.c_str());
onFail("Push not allowed - rejected by trigger");

View file

@ -169,7 +169,7 @@ namespace Mist{
}else if (command["type"] == "set_speed") {
handleWebsocketSetSpeed(command);
}else if (command["type"] == "stop") {
Util::logExitReason("User requested stop");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "User requested stop");
myConn.close();
}else if (command["type"] == "play") {
parseData = true;

View file

@ -92,7 +92,7 @@ namespace Mist{
char error_buf[200];
mbedtls_strerror(ret, error_buf, 200);
MEDIUM_MSG("Could not handshake, SSL error: %s (%d)", error_buf, ret);
Util::logExitReason("Could not handshake, SSL error: %s (%d)", error_buf, ret);
Util::logExitReason(ER_READ_START_FAILURE, "Could not handshake, SSL error: %s (%d)", error_buf, ret);
C.close();
return;
}else{
@ -111,7 +111,7 @@ namespace Mist{
int fd[2];
if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd) != 0){
FAIL_MSG("Could not open anonymous socket for SSL<->HTTP connection!");
Util::logExitReason("Could not open anonymous socket for SSL<->HTTP connection!");
Util::logExitReason(ER_READ_START_FAILURE, "Could not open anonymous socket for SSL<->HTTP connection!");
return 1;
}
std::deque<std::string> args;
@ -137,7 +137,7 @@ namespace Mist{
close(fd[1]);
if (http_proc < 2){
FAIL_MSG("Could not spawn MistOutHTTP process for SSL connection!");
Util::logExitReason("Could not spawn MistOutHTTP process for SSL connection!");
Util::logExitReason(ER_EXEC_FAILURE, "Could not spawn MistOutHTTP process for SSL connection!");
return 1;
}
Socket::Connection http(fd[0]);
@ -153,7 +153,7 @@ namespace Mist{
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
if (ret <= 0){
HIGH_MSG("SSL disconnect!");
Util::logExitReason("SSL client disconnected");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "SSL client disconnected");
break;
}
// we received ret bytes of data to pass on. Do so.
@ -172,7 +172,7 @@ namespace Mist{
ret = mbedtls_ssl_write(&ssl, (const unsigned char *)http_buf.get().data() + done, toSend - done);
if (ret == MBEDTLS_ERR_NET_CONN_RESET || ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT){
HIGH_MSG("SSL disconnect!");
Util::logExitReason("SSL client disconnected");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "SSL client disconnected");
http.close();
break;
}

View file

@ -1529,7 +1529,7 @@ namespace Mist{
}else if (command["type"] == "set_speed") {
handleWebsocketSetSpeed(command);
}else if (command["type"] == "stop") {
Util::logExitReason("User requested stop");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "User requested stop");
myConn.close();
}else if (command["type"] == "play") {
parseData = true;

View file

@ -1190,7 +1190,7 @@ namespace Mist{
if (!newStream.size()){
FAIL_MSG("Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), reqUrl.c_str());
Util::logExitReason(
Util::logExitReason(ER_TRIGGER,
"Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), reqUrl.c_str());
onFinish();

View file

@ -388,7 +388,7 @@ namespace Mist{
if (!newStream.size()){
FAIL_MSG("Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), qUrl.getUrl().c_str());
Util::logExitReason(
Util::logExitReason(ER_TRIGGER,
"Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), qUrl.getUrl().c_str());
onFinish();

View file

@ -235,7 +235,7 @@ namespace Mist{
}else{
myConn.SendNow(tsData, len);
if (!myConn){
Util::logExitReason("connection closed by peer");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "connection closed by peer");
config->is_active = false;
}
}

View file

@ -167,7 +167,7 @@ namespace Mist{
if (!newStream.size()){
FAIL_MSG("Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), reqUrl.getUrl().c_str());
Util::logExitReason(
Util::logExitReason(ER_TRIGGER,
"Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), reqUrl.getUrl().c_str());
onFinish();
@ -390,14 +390,14 @@ void handleUSR1(int signum, siginfo_t *sigInfo, void *ignore){
if (!sockCount){
INFO_MSG("USR1 received - triggering rolling restart (no connections active)");
Util::Config::is_restarting = true;
Util::logExitReason("signal USR1, no connections");
Util::logExitReason(ER_CLEAN_SIGNAL, "signal USR1, no connections");
///\TODO Update for RIST
//server_socket.close();
Util::Config::is_active = false;
}else{
INFO_MSG("USR1 received - triggering rolling restart when connection count reaches zero");
Util::Config::is_restarting = true;
Util::logExitReason("signal USR1, after disconnect wait");
Util::logExitReason(ER_CLEAN_SIGNAL, "signal USR1, after disconnect wait");
}
}
@ -405,6 +405,7 @@ int main(int argc, char *argv[]){
DTSC::trackValidMask = TRACK_VALID_EXT_HUMAN;
Util::redirectLogsIfNeeded();
Util::Config conf(argv[0]);
Util::Config::binaryType = Util::OUTPUT;
mistOut::init(&conf);
if (conf.parseArgs(argc, argv)){
if (conf.getBool("json")){

View file

@ -104,7 +104,7 @@ namespace Mist{
if (!newStream.size()){
FAIL_MSG("Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), reqUrl.getUrl().c_str());
Util::logExitReason(
Util::logExitReason(ER_TRIGGER,
"Push from %s to URL %s rejected - PUSH_REWRITE trigger blanked the URL",
getConnectedHost().c_str(), reqUrl.getUrl().c_str());
onFinish();
@ -291,7 +291,7 @@ namespace Mist{
srtConn.connect(target.host, target.getPort(), "output", targetParams);
if (!srtConn){Util::sleep(500);}
}else{
Util::logExitReason("SRT connection closed");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "SRT connection closed");
myConn.close();
parseData = false;
return;
@ -301,7 +301,7 @@ namespace Mist{
srtConn.SendNow(packetBuffer, packetBuffer.size());
if (!srtConn){
if (!config->getString("target").size()){
Util::logExitReason("SRT connection closed");
Util::logExitReason(ER_CLEAN_REMOTE_CLOSE, "SRT connection closed");
myConn.close();
parseData = false;
}
@ -366,7 +366,7 @@ namespace Mist{
}
bool OutTSSRT::dropPushTrack(uint32_t trackId, const std::string & dropReason){
Util::logExitReason("track dropped by buffer");
Util::logExitReason(ER_SHM_LOST, "track dropped by buffer");
myConn.close();
srtConn.close();
return Output::dropPushTrack(trackId, dropReason);
@ -401,13 +401,13 @@ void handleUSR1(int signum, siginfo_t *sigInfo, void *ignore){
if (!sockCount){
INFO_MSG("USR1 received - triggering rolling restart (no connections active)");
Util::Config::is_restarting = true;
Util::logExitReason("signal USR1, no connections");
Util::logExitReason(ER_CLEAN_SIGNAL, "signal USR1, no connections");
server_socket.close();
Util::Config::is_active = false;
}else{
INFO_MSG("USR1 received - triggering rolling restart when connection count reaches zero");
Util::Config::is_restarting = true;
Util::logExitReason("signal USR1, after disconnect wait");
Util::logExitReason(ER_CLEAN_SIGNAL, "signal USR1, after disconnect wait");
}
}
@ -437,6 +437,7 @@ int main(int argc, char *argv[]){
DTSC::trackValidMask = TRACK_VALID_EXT_HUMAN;
Util::redirectLogsIfNeeded();
Util::Config conf(argv[0]);
Util::Config::binaryType = Util::OUTPUT;
mistOut::init(&conf);
if (conf.parseArgs(argc, argv)){
if (conf.getBool("json")){

View file

@ -309,7 +309,7 @@ namespace Mist{
if (!parseData){udp.sendPaced(10000);}
//After 10s of no packets, abort
if (Util::bootMS() > lastRecv + 10000){
Util::logExitReason("received no data for 10+ seconds");
Util::logExitReason(ER_CLEAN_INACTIVE, "received no data for 10+ seconds");
config->is_active = false;
}
return;

View file

@ -273,6 +273,7 @@ void sourceThread(void *){
int main(int argc, char *argv[]){
DTSC::trackValidMask = TRACK_VALID_INT_PROCESS;
Util::Config config(argv[0]);
Util::Config::binaryType = Util::PROCESS;
JSON::Value capa;
{

View file

@ -71,6 +71,7 @@ void sourceThread(void *){
int main(int argc, char *argv[]){
DTSC::trackValidMask = TRACK_VALID_INT_PROCESS;
Util::Config config(argv[0]);
Util::Config::binaryType = Util::PROCESS;
JSON::Value capa;
{

View file

@ -248,7 +248,7 @@ namespace Mist{
if (!thisPacket){
Util::sleep(25);
if (userSelect.size() && userSelect.begin()->second.getStatus() == COMM_STATUS_REQDISCONNECT){
Util::logExitReason("buffer requested shutdown");
Util::logExitReason(ER_CLEAN_LIVE_BUFFER_REQ, "buffer requested shutdown");
return;
}
}
@ -486,7 +486,7 @@ void uploadThread(void * num){
attempts++;
Util::sleep(100);//Rate-limit retries
if (attempts > 4){
Util::logExitReason("too many upload failures");
Util::logExitReason(ER_FORMAT_SPECIFIC, "too many upload failures");
conf.is_active = false;
return;
}
@ -497,7 +497,7 @@ void uploadThread(void * num){
Mist::pickRandomBroadcaster();
if (!Mist::currBroadAddr.size()){
FAIL_MSG("Cannot switch to new broadcaster: none available");
Util::logExitReason("no Livepeer broadcasters available");
Util::logExitReason(ER_FORMAT_SPECIFIC, "no Livepeer broadcasters available");
conf.is_active = false;
return;
}
@ -523,6 +523,7 @@ void uploadThread(void * num){
int main(int argc, char *argv[]){
DTSC::trackValidMask = TRACK_VALID_INT_PROCESS;
Util::Config config(argv[0]);
Util::Config::binaryType = Util::PROCESS;
JSON::Value capa;
{

View file

@ -258,7 +258,7 @@ int main(int argc, char **argv){
"\n" + thisReqUrl + "\n" + thisSessionId;
if (!Triggers::doTrigger("USER_NEW", payload, thisStreamName)){
// Mark all connections of this session as finished, since this viewer is not allowed to view this stream
Util::logExitReason("Session rejected by USER_NEW");
Util::logExitReason(ER_TRIGGER, "Session rejected by USER_NEW");
connections.setExit();
connections.finishAll();
}
@ -355,7 +355,7 @@ int main(int argc, char **argv){
"\n" + thisReqUrl + "\n" + thisSessionId;
if (!Triggers::doTrigger("USER_NEW", payload, thisStreamName)){
INFO_MSG("USER_NEW rejected stream %s", thisStreamName.c_str());
Util::logExitReason("Session rejected by USER_NEW");
Util::logExitReason(ER_TRIGGER, "Session rejected by USER_NEW");
connections.setExit();
connections.finishAll();
break;
@ -373,7 +373,7 @@ int main(int argc, char **argv){
shouldSleep = connections.getExit();
}//connections scope end
if (Util::bootSecs() - lastSeen > STATS_DELAY){
Util::logExitReason("Session inactive for %d seconds", STATS_DELAY);
Util::logExitReason(ER_CLEAN_INACTIVE, "Session inactive for %d seconds", STATS_DELAY);
}
// Trigger USER_END