diff --git a/src/connectors/conn_http.cpp b/src/connectors/conn_http.cpp index 2fdd401f..9dd4adaa 100644 --- a/src/connectors/conn_http.cpp +++ b/src/connectors/conn_http.cpp @@ -691,6 +691,10 @@ namespace Connector_HTTP { int main(int argc, char ** argv){ Util::Config conf(argv[0], PACKAGE_VERSION); JSON::Value capa; + capa["optional"]["debug"]["name"] = "debug"; + capa["optional"]["debug"]["help"] = "The debug level at which messages need to be printed."; + capa["optional"]["debug"]["option"] = "--debug"; + capa["optional"]["debug"]["type"] = "uint"; capa["desc"] = "Enables the generic HTTP listener, required by all other HTTP protocols. Needs other HTTP protocols enabled to do much of anything."; capa["deps"] = ""; conf.addConnectorOptions(8080, capa); diff --git a/src/controller/controller.cpp b/src/controller/controller.cpp index f0b0fb88..c59a42fb 100644 --- a/src/controller/controller.cpp +++ b/src/controller/controller.cpp @@ -231,9 +231,6 @@ namespace Controller { Log("CONF", std::string("New configuration value ") + jit->first); } } - if (out["config"]["basepath"].asString()[out["config"]["basepath"].asString().size() - 1] == '/'){ - out["config"]["basepath"] = out["config"]["basepath"].asString().substr(0, out["config"]["basepath"].asString().size() - 1); - } for (JSON::ObjIter jit = out.ObjBegin(); jit != out.ObjEnd(); jit++){ if (jit->first == "version" || jit->first == "time"){ continue; @@ -243,6 +240,12 @@ namespace Controller { } } out = in; + if (out["basepath"].asString()[out["basepath"].asString().size() - 1] == '/'){ + out["basepath"] = out["basepath"].asString().substr(0, out["basepath"].asString().size() - 1); + } + if (out.isMember("debug")){ + Util::Config::printDebugLevel = out["debug"].asInt(); + } } } //Controller namespace @@ -349,7 +352,13 @@ int main(int argc, char ** argv){ } //Input custom config here Controller::Storage = JSON::fromFile(Controller::conf.getString("configFile")); - + + if (Controller::conf.getOption("debug",true).size() > 1){ + Controller::Storage["config"]["debug"] = Controller::conf.getInteger("debug"); + } + if (Controller::Storage.isMember("config") && Controller::Storage["config"].isMember("debug")){ + Util::Config::printDebugLevel = Controller::Storage["config"]["debug"].asInt(); + } //check for port, interface and username in arguments //if they are not there, take them from config file, if there if (Controller::conf.getOption("listen_port", true).size() <= 1){ diff --git a/src/controller/controller_connectors.cpp b/src/controller/controller_connectors.cpp index f600f653..454792c3 100644 --- a/src/controller/controller_connectors.cpp +++ b/src/controller/controller_connectors.cpp @@ -6,10 +6,12 @@ #include #include #include +#include #include "controller_storage.h" #include "controller_connectors.h" #include +#include ///\brief Holds everything unique to the controller. @@ -70,6 +72,21 @@ namespace Controller { if (pipedCapa.isMember("required")){builPipedPart(p, argarr, argnum, pipedCapa["required"]);} if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);} } + + void handleMsg(void * err){ + char buf[1024]; + FILE * output = fdopen((long long int)err, "r"); + while (fgets(buf, 1024, output)){ + for (unsigned int i = 0; i < 9 && buf[i] != ' '; i++){} + if(i < 9){ + buf[i] = NULL; + Log(buf,buf+i+1); + }else{ + printf("%s\n",buf); + } + } + } + ///\brief Checks current protocol coguration, updates state of enabled connectors if neccesary. ///\param p An object containing all protocols. @@ -141,7 +158,13 @@ namespace Controller { // get args for this connector buildPipedArguments(p[(long long unsigned)iter->first], (char **)&argarr, capabilities); // start piped w/ generated args - Util::Procs::StartPiped(toConn(iter->first), argarr, &zero, &out, &err); + err = -1; + Util::Procs::StartPiped(toConn(iter->first), argarr, &zero, &out, &err);//redirects output to out. Must make a new pipe, redirect std err + if(err != -1){ + //spawn new thread where err is read, it reads err until there is nothing more to be read + tthread::thread * msghandler = new tthread::thread(handleMsg, (void*) err); + msghandler->detach(); + } } } diff --git a/src/controller/controller_storage.cpp b/src/controller/controller_storage.cpp index 44a494ca..3d253006 100644 --- a/src/controller/controller_storage.cpp +++ b/src/controller/controller_storage.cpp @@ -7,24 +7,12 @@ namespace Controller { JSON::Value Storage; ///< Global storage of data. - + tthread::mutex logMutex;///< Mutex for log thread. ///\brief Store and print a log message. ///\param kind The type of message. ///\param message The message to be logged. void Log(std::string kind, std::string message){ - //if last log message equals this one, do not log. - if (Storage["log"].size() > 0){ - JSON::ArrIter it = Storage["log"].ArrEnd(); - int repeats = Storage["log"].size(); - if (repeats > 10){repeats = 10;} - do{ - it--; - if (( *it)[2] == message && ( *it)[1] == kind){ - return; - } - repeats--; - }while (repeats > 0); - } + tthread::lock_guard guard(logMutex); JSON::Value m; m.append(Util::epoch()); m.append(kind); diff --git a/src/controller/controller_storage.h b/src/controller/controller_storage.h index 54a296d8..57f18ba7 100644 --- a/src/controller/controller_storage.h +++ b/src/controller/controller_storage.h @@ -1,10 +1,13 @@ #include #include +#include namespace Controller { extern JSON::Value Storage; ///< Global storage of data. + extern tthread::mutex logMutex;///< Mutex for log thread. + /// Store and print a log message. void Log(std::string kind, std::string message); diff --git a/src/controller/controller_streams.cpp b/src/controller/controller_streams.cpp index ef6316a5..907b279a 100644 --- a/src/controller/controller_streams.cpp +++ b/src/controller/controller_streams.cpp @@ -88,28 +88,6 @@ namespace Controller { } } if ( !getMeta && data.isMember("meta") && data["meta"].isMember("tracks")){ - for (JSON::ObjIter trIt = data["meta"]["tracks"].ObjBegin(); trIt != data["meta"]["tracks"].ObjEnd(); trIt++){ - if (trIt->second["codec"] == "H264"){ - if ( !trIt->second.isMember("init")){ - getMeta = true; - }else{ - if (trIt->second["init"].asString().size() < 4){ - Log("WARN", "Source file "+URL+" does not contain H264 init data that MistServer can interpret."); - data["error"] = "Stream offline: Invalid?"; - }else{ - if (trIt->second["init"].asString().c_str()[1] != 0x42){ - Log("WARN", "Source file "+URL+" is not H264 Baseline - convert to baseline profile for best compatibility."); - data["error"] = "Not optimal (details in log)"; - }else{ - if (trIt->second["init"].asString().c_str()[3] > 30){ - Log("WARN", "Source file "+URL+" is higher than H264 level 3.0 - convert to a level <= 3.0 for best compatibility."); - data["error"] = "Not optimal (details in log)"; - } - } - } - } - } - } if ( !data["meta"] || !data["meta"]["tracks"]){ Log("WARN", "Source file " + URL + " seems to be corrupt."); data["error"] = "Stream offline: Corrupt file?"; @@ -212,24 +190,7 @@ namespace Controller { checker[jit->first].lastms = trIt->second["lastms"].asInt(); checker[jit->first].last_active = currTime; } - if (trIt->second["codec"] == "H264"){ - if (trIt->second.isMember("init")){ - if (trIt->second["init"].asString().size() < 4){ - Log("WARN", "Live stream "+jit->first+" does not contain H264 init data that MistServer can interpret."); - jit->second["error"] = "Stream offline: Invalid?"; - }else{ - if (trIt->second["init"].asString().c_str()[1] != 0x42){ - Log("WARN", "Live stream "+jit->first+" is not H264 Baseline - convert to baseline profile for best compatibility."); - jit->second["error"] = "Not optimal (details in log)"; - }else{ - if (trIt->second["init"].asString().c_str()[3] > 30){ - Log("WARN", "Live stream "+jit->first+" is higher than H264 level 3.0 - convert to a level <= 3.0 for best compatibility."); - jit->second["error"] = "Not optimal (details in log)"; - } - } - } - } - } + } } // mark stream as offline if no activity for 5 seconds diff --git a/src/output/output.cpp b/src/output/output.cpp index e660db78..98758270 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -25,6 +25,13 @@ namespace Mist { return ((long long int)timePoint[0] << 56) | ((long long int)timePoint[1] << 48) | ((long long int)timePoint[2] << 40) | ((long long int)timePoint[3] << 32) | ((long long int)timePoint[4] << 24) | ((long long int)timePoint[5] << 16) | ((long long int)timePoint[6] << 8) | timePoint[7]; } + void Output::init(Util::Config * cfg){ + capa["optional"]["debug"]["name"] = "debug"; + capa["optional"]["debug"]["help"] = "The debug level at which messages need to be printed."; + capa["optional"]["debug"]["option"] = "--debug"; + capa["optional"]["debug"]["type"] = "uint"; + } + Output::Output(Socket::Connection & conn) : myConn(conn) { firstTime = 0; parseData = false; diff --git a/src/output/output.h b/src/output/output.h index f8b5c02a..7208b65f 100644 --- a/src/output/output.h +++ b/src/output/output.h @@ -37,7 +37,7 @@ namespace Mist { Output(Socket::Connection & conn); virtual ~Output(); //static members for initialization and capabilities - static void init(Util::Config * cfg) {} + static void init(Util::Config * cfg); static JSON::Value capa; //non-virtual generic functions int run(); diff --git a/src/output/output_hds.cpp b/src/output/output_hds.cpp index 771bc53b..a27f4bf8 100644 --- a/src/output/output_hds.cpp +++ b/src/output/output_hds.cpp @@ -135,6 +135,7 @@ namespace Mist { OutHDS::~OutHDS() {} void OutHDS::init(Util::Config * cfg){ + Output::init(cfg); capa["desc"] = "Enables HTTP protocol Adobe-specific dynamic streaming (also known as HDS)."; capa["deps"] = "HTTP"; capa["url_rel"] = "/dynamic/$/manifest.f4m"; diff --git a/src/output/output_hls.cpp b/src/output/output_hls.cpp index f230c370..7784760f 100644 --- a/src/output/output_hls.cpp +++ b/src/output/output_hls.cpp @@ -87,6 +87,7 @@ namespace Mist { } void OutHLS::init(Util::Config * cfg){ + Output::init(cfg); capa["name"] = "HTTP_Live"; capa["desc"] = "Enables HTTP protocol Apple-specific streaming (also known as HLS)."; capa["deps"] = "HTTP"; diff --git a/src/output/output_hss.cpp b/src/output/output_hss.cpp index 07174e9e..b368f008 100644 --- a/src/output/output_hss.cpp +++ b/src/output/output_hss.cpp @@ -49,6 +49,7 @@ namespace Mist { OutHSS::~OutHSS() {} void OutHSS::init(Util::Config * cfg) { + Output::init(cfg); capa["name"] = "HTTP_Smooth"; capa["desc"] = "Enables HTTP protocol Microsoft-specific smooth streaming through silverlight (also known as HSS)."; capa["deps"] = "HTTP"; diff --git a/src/output/output_json.cpp b/src/output/output_json.cpp index 94a83e5f..3dce10cb 100644 --- a/src/output/output_json.cpp +++ b/src/output/output_json.cpp @@ -11,6 +11,7 @@ namespace Mist { OutJSON::~OutJSON() {} void OutJSON::init(Util::Config * cfg){ + Output::init(cfg); capa["desc"] = "Enables HTTP protocol JSON streaming."; capa["deps"] = "HTTP"; capa["url_rel"] = "/$.json"; diff --git a/src/output/output_progressive_flv.cpp b/src/output/output_progressive_flv.cpp index 36c2ec51..c5dc285e 100644 --- a/src/output/output_progressive_flv.cpp +++ b/src/output/output_progressive_flv.cpp @@ -8,6 +8,7 @@ namespace Mist { OutProgressiveFLV::~OutProgressiveFLV() {} void OutProgressiveFLV::init(Util::Config * cfg){ + Output::init(cfg); capa["name"] = "HTTP_Progressive_FLV"; capa["desc"] = "Enables HTTP protocol progressive streaming."; capa["deps"] = "HTTP"; diff --git a/src/output/output_progressive_mp3.cpp b/src/output/output_progressive_mp3.cpp index cd9a42d2..8b978cfa 100644 --- a/src/output/output_progressive_mp3.cpp +++ b/src/output/output_progressive_mp3.cpp @@ -8,6 +8,7 @@ namespace Mist { OutProgressiveMP3::~OutProgressiveMP3() {} void OutProgressiveMP3::init(Util::Config * cfg){ + Output::init(cfg); capa["name"] = "HTTP_Progressive_MP3"; capa["desc"] = "Enables HTTP protocol progressive streaming."; capa["deps"] = "HTTP"; diff --git a/src/output/output_progressive_mp4.cpp b/src/output/output_progressive_mp4.cpp index 900ce264..532b34d8 100644 --- a/src/output/output_progressive_mp4.cpp +++ b/src/output/output_progressive_mp4.cpp @@ -9,6 +9,7 @@ namespace Mist { OutProgressiveMP4::~OutProgressiveMP4() {} void OutProgressiveMP4::init(Util::Config * cfg){ + Output::init(cfg); capa["name"] = "HTTP_Progressive_MP4"; capa["desc"] = "Enables HTTP protocol progressive streaming."; capa["deps"] = "HTTP"; diff --git a/src/output/output_raw.cpp b/src/output/output_raw.cpp index 2bd71204..d0b1de71 100644 --- a/src/output/output_raw.cpp +++ b/src/output/output_raw.cpp @@ -30,6 +30,7 @@ namespace Mist { OutRaw::~OutRaw() {} void OutRaw::init(Util::Config * cfg){ + Output::init(cfg); capa["name"] = "RAW"; capa["desc"] = "Enables raw DTSC over TCP."; capa["deps"] = ""; diff --git a/src/output/output_rtmp.cpp b/src/output/output_rtmp.cpp index 5dec2a71..d2c8c9da 100644 --- a/src/output/output_rtmp.cpp +++ b/src/output/output_rtmp.cpp @@ -39,6 +39,7 @@ namespace Mist { OutRTMP::~OutRTMP() {} void OutRTMP::init(Util::Config * cfg) { + Output::init(cfg); capa["name"] = "RTMP"; capa["desc"] = "Enables the RTMP protocol which is used by Adobe Flash Player."; capa["deps"] = ""; diff --git a/src/output/output_srt.cpp b/src/output/output_srt.cpp index ae5fb1f8..77397f7c 100644 --- a/src/output/output_srt.cpp +++ b/src/output/output_srt.cpp @@ -19,6 +19,7 @@ namespace Mist { OutProgressiveSRT::~OutProgressiveSRT() {} void OutProgressiveSRT::init(Util::Config * cfg){ + Output::init(cfg); capa["desc"] = "Enables HTTP protocol subtitle streaming."; capa["deps"] = "HTTP"; capa["url_rel"] = "/$.srt"; diff --git a/src/output/output_ts.cpp b/src/output/output_ts.cpp index 1c37f386..7d01d06c 100644 --- a/src/output/output_ts.cpp +++ b/src/output/output_ts.cpp @@ -34,6 +34,7 @@ namespace Mist { OutTS::~OutTS() {} void OutTS::init(Util::Config * cfg){ + Output::init(cfg); capa["name"] = "TS"; capa["desc"] = "Enables the raw MPEG Transport Stream protocol over TCP."; capa["deps"] = "";