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:
parent
a16d98b7b2
commit
b0d4422d27
47 changed files with 493 additions and 256 deletions
|
@ -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:
|
||||
|
|
12
lib/config.h
12
lib/config.h
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()){
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(){
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")){
|
||||
|
|
|
@ -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")){
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue