Merge branch 'development' into LTS_development
# Conflicts: # src/output/output_http_internal.cpp
This commit is contained in:
		
						commit
						109995809d
					
				
					 13 changed files with 85 additions and 73 deletions
				
			
		
							
								
								
									
										58
									
								
								lib/json.cpp
									
										
									
									
									
								
							
							
						
						
									
										58
									
								
								lib/json.cpp
									
										
									
									
									
								
							|  | @ -607,37 +607,51 @@ bool JSON::Value::operator!=(const JSON::Value & rhs) const { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool JSON::Value::compareExcept(const Value & rhs, const std::set<std::string> & skip) const { | bool JSON::Value::compareExcept(const Value & rhs, const std::set<std::string> & skip) const { | ||||||
|   if (myType != OBJECT) { |   if (myType == OBJECT) { | ||||||
|     return ((*this) == rhs); |     jsonForEachConst(*this, it){ | ||||||
|   } |       if (skip.count(it.key())){continue;} | ||||||
|   jsonForEachConst(*this, it){ |       if (!rhs.isMember(it.key()) || !(*it).compareExcept(rhs[it.key()], skip)) { | ||||||
|     if (skip.count(it.key())){continue;} |         return false; | ||||||
|     if (!rhs.isMember(it.key()) || !(*it).compareExcept(rhs[it.key()], skip)) { |       } | ||||||
|       return false; |  | ||||||
|     } |     } | ||||||
|  |     jsonForEachConst(rhs, it){ | ||||||
|  |       if (skip.count(it.key())){continue;} | ||||||
|  |       if (!(*this).isMember(it.key())){return false;} | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
|   jsonForEachConst(rhs, it){ |   if (myType == ARRAY) { | ||||||
|     if (skip.count(it.key())){continue;} |     if (size() != rhs.size()){return false;} | ||||||
|     if (!(*this).isMember(it.key())){return false;} |     jsonForEachConst(*this, it){ | ||||||
|  |       if (!(*it).compareExcept(rhs[it.num()], skip)){return false;} | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
|   return true; |   return ((*this) == rhs); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool JSON::Value::compareOnly(const Value & rhs, const std::set<std::string> & check) const { | bool JSON::Value::compareOnly(const Value & rhs, const std::set<std::string> & check) const { | ||||||
|   if (myType != OBJECT) { |   if (myType == OBJECT) { | ||||||
|     return ((*this) == rhs); |     jsonForEachConst(*this, it){ | ||||||
|   } |       if (!check.count(it.key())){continue;} | ||||||
|   jsonForEachConst(*this, it){ |       if (!rhs.isMember(it.key()) || !(*it).compareOnly(rhs[it.key()], check)) { | ||||||
|     if (!check.count(it.key())){continue;} |         return false; | ||||||
|     if (!rhs.isMember(it.key()) || !(*it).compareOnly(rhs[it.key()], check)) { |       } | ||||||
|       return false; |  | ||||||
|     } |     } | ||||||
|  |     jsonForEachConst(rhs, it){ | ||||||
|  |       if (!check.count(it.key())){continue;} | ||||||
|  |       if (!(*this).isMember(it.key())){return false;} | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
|   jsonForEachConst(rhs, it){ |   if (myType == ARRAY) { | ||||||
|     if (!check.count(it.key())){continue;} |     if (size() != rhs.size()){return false;} | ||||||
|     if (!(*this).isMember(it.key())){return false;} |     jsonForEachConst(*this, it){ | ||||||
|  |       if (!(*it).compareOnly(rhs[it.num()], check)){return false;} | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
|   return true; |   return ((*this) == rhs); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Completely clears the contents of this value,
 | /// Completely clears the contents of this value,
 | ||||||
|  |  | ||||||
|  | @ -4,14 +4,30 @@ | ||||||
| 
 | 
 | ||||||
| void AnalyserDTSC::init(Util::Config &conf){ | void AnalyserDTSC::init(Util::Config &conf){ | ||||||
|   Analyser::init(conf); |   Analyser::init(conf); | ||||||
|  |   JSON::Value opt; | ||||||
|  |   opt["long"] = "headless"; | ||||||
|  |   opt["short"] = "H"; | ||||||
|  |   opt["help"] = "Parse entire file or streams as a single headless DTSC packet"; | ||||||
|  |   conf.addOption("headless", opt); | ||||||
|  |   opt.null(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AnalyserDTSC::AnalyserDTSC(Util::Config &conf) : Analyser(conf){ | AnalyserDTSC::AnalyserDTSC(Util::Config &conf) : Analyser(conf){ | ||||||
|   conn = Socket::Connection(0, fileno(stdin)); |   conn = Socket::Connection(0, fileno(stdin)); | ||||||
|   totalBytes = 0; |   totalBytes = 0; | ||||||
|  |   headLess = conf.getBool("headless"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool AnalyserDTSC::parsePacket(){ | bool AnalyserDTSC::parsePacket(){ | ||||||
|  |   if (headLess){ | ||||||
|  |     while (conn){ | ||||||
|  |       if (!conn.spool()){Util::sleep(50);} | ||||||
|  |     } | ||||||
|  |     std::string dataBuf = conn.Received().remove(conn.Received().bytes(0xFFFFFFFFul)); | ||||||
|  |     DTSC::Scan S((char*)dataBuf.data(), dataBuf.size()); | ||||||
|  |     std::cout << S.toPrettyString() << std::endl; | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|   P.reInit(conn); |   P.reInit(conn); | ||||||
|   if (conn && !P){ |   if (conn && !P){ | ||||||
|     FAIL_MSG("Invalid DTSC packet @ byte %llu", totalBytes) |     FAIL_MSG("Invalid DTSC packet @ byte %llu", totalBytes) | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ public: | ||||||
|   static void init(Util::Config &conf); |   static void init(Util::Config &conf); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |   bool headLess; | ||||||
|   DTSC::Packet P; |   DTSC::Packet P; | ||||||
|   Socket::Connection conn; |   Socket::Connection conn; | ||||||
|   uint64_t totalBytes; |   uint64_t totalBytes; | ||||||
|  |  | ||||||
|  | @ -173,8 +173,12 @@ namespace Mist{ | ||||||
|   /// Called when stream initialization has failed.
 |   /// Called when stream initialization has failed.
 | ||||||
|   /// The standard implementation will set isInitialized to false and close the client connection,
 |   /// The standard implementation will set isInitialized to false and close the client connection,
 | ||||||
|   /// thus causing the process to exit cleanly.
 |   /// thus causing the process to exit cleanly.
 | ||||||
|   void Output::onFail(){ |   void Output::onFail(const std::string & msg, bool critical){ | ||||||
|     MEDIUM_MSG("onFail"); |     if (critical){ | ||||||
|  |       FAIL_MSG("onFail '%s': %s", streamName.c_str(), msg.c_str()); | ||||||
|  |     }else{ | ||||||
|  |       MEDIUM_MSG("onFail '%s': %s", streamName.c_str(), msg.c_str()); | ||||||
|  |     } | ||||||
|     isInitialized = false; |     isInitialized = false; | ||||||
|     wantRequest = true; |     wantRequest = true; | ||||||
|     parseData= false; |     parseData= false; | ||||||
|  | @ -196,7 +200,7 @@ namespace Mist{ | ||||||
|     reconnect(); |     reconnect(); | ||||||
|     //if the connection failed, fail
 |     //if the connection failed, fail
 | ||||||
|     if (streamName.size() < 1){ |     if (streamName.size() < 1){ | ||||||
|       onFail(); |       onFail("Could not connect to stream", true); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     sought = false; |     sought = false; | ||||||
|  | @ -365,14 +369,12 @@ namespace Mist{ | ||||||
|     if (config->hasOption("noinput") && config->getBool("noinput")){ |     if (config->hasOption("noinput") && config->getBool("noinput")){ | ||||||
|       Util::sanitizeName(streamName); |       Util::sanitizeName(streamName); | ||||||
|       if (!Util::streamAlive(streamName)){ |       if (!Util::streamAlive(streamName)){ | ||||||
|         FAIL_MSG("Stream %s not already active - aborting initialization", streamName.c_str()); |         onFail("Stream not active already, aborting"); | ||||||
|         onFail(); |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     }else{ |     }else{ | ||||||
|       if (!Util::startInput(streamName, "", true, isPushing())){ |       if (!Util::startInput(streamName, "", true, isPushing())){ | ||||||
|         FAIL_MSG("Opening stream %s failed - aborting initialization", streamName.c_str()); |         onFail("Stream open failed", true); | ||||||
|         onFail(); |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -385,16 +387,14 @@ namespace Mist{ | ||||||
|       nProxy.userClient = IPC::sharedClient(userPageName, PLAY_EX_SIZE, true); |       nProxy.userClient = IPC::sharedClient(userPageName, PLAY_EX_SIZE, true); | ||||||
|     } |     } | ||||||
|     if (!nProxy.userClient.isAlive()){ |     if (!nProxy.userClient.isAlive()){ | ||||||
|       FAIL_MSG("Could not register as client for %s", streamName.c_str()); |       onFail("Could not register as client", true); | ||||||
|       onFail(); |  | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     char pageId[NAME_BUFFER_SIZE]; |     char pageId[NAME_BUFFER_SIZE]; | ||||||
|     snprintf(pageId, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, streamName.c_str()); |     snprintf(pageId, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, streamName.c_str()); | ||||||
|     nProxy.metaPages[0].init(pageId, DEFAULT_STRM_PAGE_SIZE); |     nProxy.metaPages[0].init(pageId, DEFAULT_STRM_PAGE_SIZE); | ||||||
|     if (!nProxy.metaPages[0].mapped){ |     if (!nProxy.metaPages[0].mapped){ | ||||||
|       FAIL_MSG("Could not connect to data for %s", streamName.c_str()); |       onFail("Could not connect to stream data", true); | ||||||
|       onFail(); |  | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     isInitialized = true; |     isInitialized = true; | ||||||
|  | @ -1710,12 +1710,7 @@ namespace Mist{ | ||||||
|       snprintf(userPageName, NAME_BUFFER_SIZE, SHM_USERS, streamName.c_str()); |       snprintf(userPageName, NAME_BUFFER_SIZE, SHM_USERS, streamName.c_str()); | ||||||
|       nProxy.userClient = IPC::sharedClient(userPageName, PLAY_EX_SIZE, true); |       nProxy.userClient = IPC::sharedClient(userPageName, PLAY_EX_SIZE, true); | ||||||
|       if (!nProxy.userClient.getData()){ |       if (!nProxy.userClient.getData()){ | ||||||
|         WARN_MSG("Player connection failure - aborting output"); |         onFail("Player connection failure - aborting output", true); | ||||||
|         if (!onFinish()){ |  | ||||||
|           myConn.close(); |  | ||||||
|         }else{ |  | ||||||
|           disconnect(); |  | ||||||
|         } |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -1723,21 +1718,11 @@ namespace Mist{ | ||||||
|       if (isPushing() && !pushIsOngoing){ |       if (isPushing() && !pushIsOngoing){ | ||||||
|         waitForStreamPushReady(); |         waitForStreamPushReady(); | ||||||
|         if (!nProxy.userClient.isAlive()){ |         if (!nProxy.userClient.isAlive()){ | ||||||
|           WARN_MSG("Failed to wait for buffer, aborting incoming push"); |           onFail("Failed to wait for buffer, aborting incoming push", true); | ||||||
|           if (!onFinish()){ |  | ||||||
|             myConn.close(); |  | ||||||
|           }else{ |  | ||||||
|             disconnect(); |  | ||||||
|           } |  | ||||||
|           return; |           return; | ||||||
|         } |         } | ||||||
|       }else{ |       }else{ | ||||||
|         INFO_MSG("Received disconnect request from input"); |         onFail("Received disconnect request from input"); | ||||||
|         if (!onFinish()){ |  | ||||||
|           myConn.close(); |  | ||||||
|         }else{ |  | ||||||
|           disconnect(); |  | ||||||
|         } |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -78,7 +78,7 @@ namespace Mist { | ||||||
|       void disconnect(); |       void disconnect(); | ||||||
|       virtual void initialize(); |       virtual void initialize(); | ||||||
|       virtual void sendHeader(); |       virtual void sendHeader(); | ||||||
|       virtual void onFail(); |       virtual void onFail(const std::string & msg, bool critical = false); | ||||||
|       virtual void requestHandler(); |       virtual void requestHandler(); | ||||||
|       static Util::Config * config; |       static Util::Config * config; | ||||||
|       void playbackSleep(uint64_t millis); |       void playbackSleep(uint64_t millis); | ||||||
|  |  | ||||||
|  | @ -418,7 +418,7 @@ namespace Mist { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     if (H.url.find("hls") == std::string::npos){ |     if (H.url.find("hls") == std::string::npos){ | ||||||
|       onFail(); |       onFail("HLS handler active, but this is not a HLS URL. Eh... What...?"); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -434,11 +434,7 @@ namespace Mist { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     initialize(); |     initialize(); | ||||||
| 
 |     if (!keepGoing()){return;} | ||||||
|     if (!keepGoing()){ |  | ||||||
|       onFail(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (H.url.substr(5 + streamName.size(), 5) == "/push"){ |     if (H.url.substr(5 + streamName.size(), 5) == "/push"){ | ||||||
|       std::string relPushUrl = H.url.substr(10 + streamName.size()); |       std::string relPushUrl = H.url.substr(10 + streamName.size()); | ||||||
|  |  | ||||||
|  | @ -41,13 +41,14 @@ namespace Mist { | ||||||
|     config = cfg; |     config = cfg; | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   void HTTPOutput::onFail(){ |   void HTTPOutput::onFail(const std::string & msg, bool critical){ | ||||||
|  |     INFO_MSG("Failing '%s': %s: %s", streamName.c_str(), H.url.c_str(), msg.c_str()); | ||||||
|     if (!webSock){ |     if (!webSock){ | ||||||
|       H.Clean(); //make sure no parts of old requests are left in any buffers
 |       H.Clean(); //make sure no parts of old requests are left in any buffers
 | ||||||
|       H.SetBody("Stream not found. Sorry, we tried."); |       H.SetBody("Could not retrieve stream: "+msg); | ||||||
|       H.SendResponse("404", "Stream not found", myConn); |       H.SendResponse("404", "Error opening stream", myConn); | ||||||
|     } |     } | ||||||
|     Output::onFail(); |     Output::onFail(msg, critical); | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   bool isMatch(const std::string & url, const std::string & m, std::string & streamname){ |   bool isMatch(const std::string & url, const std::string & m, std::string & streamname){ | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ namespace Mist { | ||||||
|       virtual ~HTTPOutput(); |       virtual ~HTTPOutput(); | ||||||
|       static void init(Util::Config * cfg); |       static void init(Util::Config * cfg); | ||||||
|       void onRequest(); |       void onRequest(); | ||||||
|       virtual void onFail(); |       virtual void onFail(const std::string & msg, bool critical = false); | ||||||
|       virtual void onHTTP(){}; |       virtual void onHTTP(){}; | ||||||
|       virtual void onIdle(){}; |       virtual void onIdle(){}; | ||||||
|       virtual void onWebsocketFrame(){}; |       virtual void onWebsocketFrame(){}; | ||||||
|  |  | ||||||
|  | @ -66,7 +66,7 @@ namespace Mist { | ||||||
|     return !(config->getString("ip").size()); |     return !(config->getString("ip").size()); | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   void OutHTTP::onFail(){ |   void OutHTTP::onFail(const std::string & msg, bool critical){ | ||||||
|     std::string method = H.method; |     std::string method = H.method; | ||||||
|     // send logo icon
 |     // send logo icon
 | ||||||
|     if (H.url.length() > 4 && H.url.substr(H.url.length() - 4, 4) == ".ico"){ |     if (H.url.length() > 4 && H.url.substr(H.url.length() - 4, 4) == ".ico"){ | ||||||
|  | @ -81,6 +81,7 @@ namespace Mist { | ||||||
|       if (websocketHandler()){return;} |       if (websocketHandler()){return;} | ||||||
|       JSON::Value json_resp; |       JSON::Value json_resp; | ||||||
|       json_resp["error"] = "Could not retrieve stream. Sorry."; |       json_resp["error"] = "Could not retrieve stream. Sorry."; | ||||||
|  |       json_resp["error_guru"] = msg; | ||||||
|       if (config->getString("nostreamtext") != ""){ |       if (config->getString("nostreamtext") != ""){ | ||||||
|         json_resp["on_error"] = config->getString("nostreamtext"); |         json_resp["on_error"] = config->getString("nostreamtext"); | ||||||
|       } |       } | ||||||
|  | @ -101,9 +102,7 @@ namespace Mist { | ||||||
|       H.Clean(); |       H.Clean(); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     INFO_MSG("Failing: %s", H.url.c_str()); |     HTTPOutput::onFail(msg, critical); | ||||||
|     HTTPOutput::onFail(); |  | ||||||
|     Output::onFail(); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void OutHTTP::init(Util::Config * cfg){ |   void OutHTTP::init(Util::Config * cfg){ | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ namespace Mist { | ||||||
|       ~OutHTTP(); |       ~OutHTTP(); | ||||||
|       static void init(Util::Config * cfg); |       static void init(Util::Config * cfg); | ||||||
|       static bool listenMode(); |       static bool listenMode(); | ||||||
|       virtual void onFail(); |       virtual void onFail(const std::string & msg, bool critical = false); | ||||||
|       ///preHTTP is disabled in the internal HTTP output, since most don't need the stream alive to work
 |       ///preHTTP is disabled in the internal HTTP output, since most don't need the stream alive to work
 | ||||||
|       virtual void preHTTP(){}; |       virtual void preHTTP(){}; | ||||||
|       void HTMLResponse(); |       void HTMLResponse(); | ||||||
|  |  | ||||||
|  | @ -81,10 +81,10 @@ namespace Mist { | ||||||
|     sentHeader = true; |     sentHeader = true; | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   void OutJSON::onFail(){ |   void OutJSON::onFail(const std::string & msg, bool critical){ | ||||||
|     //Only run failure handle if we're not being persistent
 |     //Only run failure handle if we're not being persistent
 | ||||||
|     if (!keepReselecting){ |     if (!keepReselecting){ | ||||||
|       HTTPOutput::onFail(); |       HTTPOutput::onFail(msg, critical); | ||||||
|     }else{ |     }else{ | ||||||
|       onFinish(); |       onFinish(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ namespace Mist { | ||||||
|       virtual void onWebsocketConnect(); |       virtual void onWebsocketConnect(); | ||||||
|       virtual void preWebsocketConnect(); |       virtual void preWebsocketConnect(); | ||||||
|       bool onFinish(); |       bool onFinish(); | ||||||
|       void onFail(); |       void onFail(const std::string & msg, bool critical = false); | ||||||
|       void sendNext(); |       void sendNext(); | ||||||
|       void sendHeader(); |       void sendHeader(); | ||||||
|       bool doesWebsockets(){return true;} |       bool doesWebsockets(){return true;} | ||||||
|  |  | ||||||
|  | @ -583,7 +583,7 @@ namespace Mist{ | ||||||
|       myConn.SendNow(RTMPStream::SendCTL(1, RTMPStream::chunk_snd_max)); //send chunk size max (msg 1)
 |       myConn.SendNow(RTMPStream::SendCTL(1, RTMPStream::chunk_snd_max)); //send chunk size max (msg 1)
 | ||||||
|       myConn.SendNow(RTMPStream::SendCTL(5, RTMPStream::snd_window_size)); //send window acknowledgement size (msg 5)
 |       myConn.SendNow(RTMPStream::SendCTL(5, RTMPStream::snd_window_size)); //send window acknowledgement size (msg 5)
 | ||||||
|       myConn.SendNow(RTMPStream::SendCTL(6, RTMPStream::rec_window_size)); //send rec window acknowledgement size (msg 6)
 |       myConn.SendNow(RTMPStream::SendCTL(6, RTMPStream::rec_window_size)); //send rec window acknowledgement size (msg 6)
 | ||||||
|       myConn.SendNow(RTMPStream::SendUSR(0, 1)); //send UCM StreamBegin (0), stream 1
 |       //myConn.SendNow(RTMPStream::SendUSR(0, 1)); //send UCM StreamBegin (0), stream 1
 | ||||||
|       //send onBWDone packet - no clue what it is, but real server sends it...
 |       //send onBWDone packet - no clue what it is, but real server sends it...
 | ||||||
|       //amfReply = AMF::Object("container", AMF::AMF0_DDV_CONTAINER);
 |       //amfReply = AMF::Object("container", AMF::AMF0_DDV_CONTAINER);
 | ||||||
|       //amfReply.addContent(AMF::Object("", "onBWDone"));//result
 |       //amfReply.addContent(AMF::Object("", "onBWDone"));//result
 | ||||||
|  | @ -600,7 +600,7 @@ namespace Mist{ | ||||||
|       amfReply.addContent(AMF::Object("", (double)0, AMF::AMF0_NULL)); //null - command info
 |       amfReply.addContent(AMF::Object("", (double)0, AMF::AMF0_NULL)); //null - command info
 | ||||||
|       amfReply.addContent(AMF::Object("", (double)1)); //stream ID - we use 1
 |       amfReply.addContent(AMF::Object("", (double)1)); //stream ID - we use 1
 | ||||||
|       sendCommand(amfReply, messageType, streamId); |       sendCommand(amfReply, messageType, streamId); | ||||||
|       myConn.SendNow(RTMPStream::SendUSR(0, 1)); //send UCM StreamBegin (0), stream 1
 |       //myConn.SendNow(RTMPStream::SendUSR(0, 1)); //send UCM StreamBegin (0), stream 1
 | ||||||
|       return; |       return; | ||||||
|     }//createStream
 |     }//createStream
 | ||||||
|     if (amfData.getContentP(0)->StrValue() == "ping"){ |     if (amfData.getContentP(0)->StrValue() == "ping"){ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Thulinma
						Thulinma