Various output fixes:
- Fixed several possible segfaults when selecting non-existing tracks in HLS - Fixed error when requesting a stream with no compatible HLS tracks - Fix a possible segfault when playing back an invalid track - Fixed HLS cache control logic - Fixed slow lookup of blank hostnames (now skips lookup entirely) - HLS output replies with 204 rather than 200 for OPTIONS requests - Removed out-of-the-box compatibility with iOS 10 and lower in the HTML output, in favor of better iOS 11+ support.
This commit is contained in:
		
							parent
							
								
									456fd2d555
								
							
						
					
					
						commit
						2ee0259483
					
				
					 4 changed files with 39 additions and 25 deletions
				
			
		| 
						 | 
					@ -242,6 +242,7 @@ void Socket::hostBytesToStr(const char *bytes, size_t len, std::string &target){
 | 
				
			||||||
/// Returns empty string if no reasonable match could be made.
 | 
					/// Returns empty string if no reasonable match could be made.
 | 
				
			||||||
std::string Socket::resolveHostToBestExternalAddrGuess(const std::string &host, int family,
 | 
					std::string Socket::resolveHostToBestExternalAddrGuess(const std::string &host, int family,
 | 
				
			||||||
                                                       const std::string &hint){
 | 
					                                                       const std::string &hint){
 | 
				
			||||||
 | 
					  if (!host.size()){return "";}
 | 
				
			||||||
  struct addrinfo *result, *rp, hints;
 | 
					  struct addrinfo *result, *rp, hints;
 | 
				
			||||||
  std::string newaddr;
 | 
					  std::string newaddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -812,6 +812,7 @@ namespace Mist{
 | 
				
			||||||
    if (!isInitialized){initialize();}
 | 
					    if (!isInitialized){initialize();}
 | 
				
			||||||
    buffer.clear();
 | 
					    buffer.clear();
 | 
				
			||||||
    thisPacket.null();
 | 
					    thisPacket.null();
 | 
				
			||||||
 | 
					    if (!M){return false;}
 | 
				
			||||||
    if (toKey){
 | 
					    if (toKey){
 | 
				
			||||||
      size_t mainTrack = getMainSelectedTrack();
 | 
					      size_t mainTrack = getMainSelectedTrack();
 | 
				
			||||||
      if (mainTrack == INVALID_TRACK_ID){
 | 
					      if (mainTrack == INVALID_TRACK_ID){
 | 
				
			||||||
| 
						 | 
					@ -831,12 +832,14 @@ namespace Mist{
 | 
				
			||||||
    MEDIUM_MSG("Seeking to %" PRIu64 "ms (%s)", pos, toKey ? "sync" : "direct");
 | 
					    MEDIUM_MSG("Seeking to %" PRIu64 "ms (%s)", pos, toKey ? "sync" : "direct");
 | 
				
			||||||
    std::set<size_t> seekTracks;
 | 
					    std::set<size_t> seekTracks;
 | 
				
			||||||
    for (std::map<size_t, Comms::Users>::iterator it = userSelect.begin(); it != userSelect.end(); it++){
 | 
					    for (std::map<size_t, Comms::Users>::iterator it = userSelect.begin(); it != userSelect.end(); it++){
 | 
				
			||||||
      seekTracks.insert(it->first);
 | 
					      if (M.trackValid(it->first)){seekTracks.insert(it->first);}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    //Seek all seek positions, first
 | 
					    //Seek all seek positions, first
 | 
				
			||||||
    for (std::set<size_t>::iterator it = seekTracks.begin(); it != seekTracks.end(); it++){
 | 
					    for (std::set<size_t>::iterator it = seekTracks.begin(); it != seekTracks.end(); it++){
 | 
				
			||||||
 | 
					      if (userSelect[*it]){
 | 
				
			||||||
        userSelect[*it].setKeyNum(M.getKeyNumForTime(*it, pos));
 | 
					        userSelect[*it].setKeyNum(M.getKeyNumForTime(*it, pos));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    bool ret = seekTracks.size();
 | 
					    bool ret = seekTracks.size();
 | 
				
			||||||
    for (std::set<size_t>::iterator it = seekTracks.begin(); it != seekTracks.end(); it++){
 | 
					    for (std::set<size_t>::iterator it = seekTracks.begin(); it != seekTracks.end(); it++){
 | 
				
			||||||
      ret &= seek(*it, pos, false);
 | 
					      ret &= seek(*it, pos, false);
 | 
				
			||||||
| 
						 | 
					@ -1985,6 +1988,10 @@ namespace Mist{
 | 
				
			||||||
    // depending on whether this is probably bad and the current debug level, print a message
 | 
					    // depending on whether this is probably bad and the current debug level, print a message
 | 
				
			||||||
    size_t printLevel = (probablyBad ? DLVL_WARN : DLVL_INFO);
 | 
					    size_t printLevel = (probablyBad ? DLVL_WARN : DLVL_INFO);
 | 
				
			||||||
    //The rest of the operations depends on userSelect, so we ignore it if it doesn't exist.
 | 
					    //The rest of the operations depends on userSelect, so we ignore it if it doesn't exist.
 | 
				
			||||||
 | 
					    if (!M || !M.getValidTracks().count(trackId)){
 | 
				
			||||||
 | 
					      DEBUG_MSG(printLevel, "Dropping invalid track %zu: %s", trackId, reason.c_str());
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (!userSelect.count(trackId)){
 | 
					    if (!userSelect.count(trackId)){
 | 
				
			||||||
      if (M.hasEmbeddedFrames(trackId)){
 | 
					      if (M.hasEmbeddedFrames(trackId)){
 | 
				
			||||||
        DEBUG_MSG(printLevel, "Dropping %s track %zu (raw): %s", meta.getCodec(trackId).c_str(), trackId, reason.c_str());
 | 
					        DEBUG_MSG(printLevel, "Dropping %s track %zu (raw): %s", meta.getCodec(trackId).c_str(), trackId, reason.c_str());
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,11 +68,18 @@ namespace Mist{
 | 
				
			||||||
               << "\r\n";
 | 
					               << "\r\n";
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!vidTracks && audioId != INVALID_TRACK_ID){
 | 
					
 | 
				
			||||||
 | 
					    if (!vidTracks){
 | 
				
			||||||
 | 
					      if (audioId != INVALID_TRACK_ID){
 | 
				
			||||||
 | 
					        // Audio only playlist
 | 
				
			||||||
        result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << (M.getBps(audioId) * 8);
 | 
					        result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << (M.getBps(audioId) * 8);
 | 
				
			||||||
        result << ",CODECS=\"" << Util::codecString(M.getCodec(audioId), M.getInit(audioId)) << "\"";
 | 
					        result << ",CODECS=\"" << Util::codecString(M.getCodec(audioId), M.getInit(audioId)) << "\"";
 | 
				
			||||||
        result << "\r\n";
 | 
					        result << "\r\n";
 | 
				
			||||||
        result << audioId << "/index.m3u8" << tknStr << "\r\n";
 | 
					        result << audioId << "/index.m3u8" << tknStr << "\r\n";
 | 
				
			||||||
 | 
					      }else{
 | 
				
			||||||
 | 
					        // No compatible tracks at all
 | 
				
			||||||
 | 
					        return "";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return result.str();
 | 
					    return result.str();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -260,7 +267,12 @@ namespace Mist{
 | 
				
			||||||
      H.SetHeader("Content-Type", "text/xml");
 | 
					      H.SetHeader("Content-Type", "text/xml");
 | 
				
			||||||
      H.SetHeader("Server", APPIDENT);
 | 
					      H.SetHeader("Server", APPIDENT);
 | 
				
			||||||
      H.setCORSHeaders();
 | 
					      H.setCORSHeaders();
 | 
				
			||||||
      if (method == "OPTIONS" || method == "HEAD"){
 | 
					      if (method == "OPTIONS"){
 | 
				
			||||||
 | 
					        H.SendResponse("204", "No content", myConn);
 | 
				
			||||||
 | 
					        responded = true;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (method == "HEAD"){
 | 
				
			||||||
        H.SendResponse("200", "OK", myConn);
 | 
					        H.SendResponse("200", "OK", myConn);
 | 
				
			||||||
        responded = true;
 | 
					        responded = true;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
| 
						 | 
					@ -274,19 +286,20 @@ namespace Mist{
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }// crossdomain.xml
 | 
					    }// crossdomain.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (H.method == "OPTIONS"){
 | 
					    if (method == "OPTIONS"){
 | 
				
			||||||
      bool isTS = (HTTP::URL(H.url).getExt().substr(0, 3) != "m3u");
 | 
					      bool isTS = (HTTP::URL(H.url).getExt().substr(0, 3) != "m3u");
 | 
				
			||||||
 | 
					      H.Clean();
 | 
				
			||||||
      H.setCORSHeaders();
 | 
					      H.setCORSHeaders();
 | 
				
			||||||
      if (isTS){
 | 
					      if (isTS){
 | 
				
			||||||
        H.SetHeader("Content-Type", "video/mp2t");
 | 
					        H.SetHeader("Content-Type", "video/mp2t");
 | 
				
			||||||
      }else{
 | 
					      }else{
 | 
				
			||||||
        H.SetHeader("Content-Type", "application/vnd.apple.mpegurl");
 | 
					        H.SetHeader("Content-Type", "application/vnd.apple.mpegurl");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (isTS && (!(Comms::tknMode & 0x04) || config->getOption("chunkpath"))){
 | 
					      if (isTS && !(!(Comms::tknMode & 0x04) || config->getOption("chunkpath"))){
 | 
				
			||||||
        uint64_t dura = 120000;
 | 
					        uint64_t dura = 120000;
 | 
				
			||||||
        if (M && M.getValidTracks().size()){
 | 
					        if (M && M.getValidTracks().size()){
 | 
				
			||||||
          size_t mTrk = M.mainTrack();
 | 
					          size_t mTrk = M.mainTrack();
 | 
				
			||||||
          if (mTrk != INVALID_TRACK_ID){dura = M.getDuration(dura);}
 | 
					          if (mTrk != INVALID_TRACK_ID){dura = M.getDuration(mTrk);}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        H.SetHeader("Cache-Control",
 | 
					        H.SetHeader("Cache-Control",
 | 
				
			||||||
                    "public, max-age=" +
 | 
					                    "public, max-age=" +
 | 
				
			||||||
| 
						 | 
					@ -298,7 +311,7 @@ namespace Mist{
 | 
				
			||||||
        H.SetHeader("Cache-Control", "no-store");
 | 
					        H.SetHeader("Cache-Control", "no-store");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      H.SetBody("");
 | 
					      H.SetBody("");
 | 
				
			||||||
      H.SendResponse("200", "OK", myConn);
 | 
					      H.SendResponse("204", "No content", myConn);
 | 
				
			||||||
      responded = true;
 | 
					      responded = true;
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -374,14 +387,14 @@ namespace Mist{
 | 
				
			||||||
      H.SetHeader("Content-Type", "video/mp2t");
 | 
					      H.SetHeader("Content-Type", "video/mp2t");
 | 
				
			||||||
      H.setCORSHeaders();
 | 
					      H.setCORSHeaders();
 | 
				
			||||||
      if (!(Comms::tknMode & 0x04) || config->getOption("chunkpath")){
 | 
					      if (!(Comms::tknMode & 0x04) || config->getOption("chunkpath")){
 | 
				
			||||||
        H.SetHeader("Cache-Control", "no-store");
 | 
					 | 
				
			||||||
      }else{
 | 
					 | 
				
			||||||
        H.SetHeader("Cache-Control",
 | 
					        H.SetHeader("Cache-Control",
 | 
				
			||||||
                    "public, max-age=" +
 | 
					                    "public, max-age=" +
 | 
				
			||||||
                        JSON::Value(M.getDuration(getMainSelectedTrack()) / 1000).asString() +
 | 
					                        JSON::Value(M.getDuration(getMainSelectedTrack()) / 1000).asString() +
 | 
				
			||||||
                        ", immutable");
 | 
					                        ", immutable");
 | 
				
			||||||
        H.SetHeader("Pragma", "");
 | 
					        H.SetHeader("Pragma", "");
 | 
				
			||||||
        H.SetHeader("Expires", "");
 | 
					        H.SetHeader("Expires", "");
 | 
				
			||||||
 | 
					      }else{
 | 
				
			||||||
 | 
					        H.SetHeader("Cache-Control", "no-store");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (method == "OPTIONS" || method == "HEAD"){
 | 
					      if (method == "OPTIONS" || method == "HEAD"){
 | 
				
			||||||
        H.SendResponse("200", "OK", myConn);
 | 
					        H.SendResponse("200", "OK", myConn);
 | 
				
			||||||
| 
						 | 
					@ -418,6 +431,10 @@ namespace Mist{
 | 
				
			||||||
      std::string manifest;
 | 
					      std::string manifest;
 | 
				
			||||||
      if (request.find("/") == std::string::npos){
 | 
					      if (request.find("/") == std::string::npos){
 | 
				
			||||||
        manifest = liveIndex();
 | 
					        manifest = liveIndex();
 | 
				
			||||||
 | 
					        if (manifest == ""){
 | 
				
			||||||
 | 
					          onFail("No HLS compatible tracks found");
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }else{
 | 
					      }else{
 | 
				
			||||||
        size_t idx = atoi(request.substr(0, request.find("/")).c_str());
 | 
					        size_t idx = atoi(request.substr(0, request.find("/")).c_str());
 | 
				
			||||||
        if (!M.getValidTracks().count(idx)){
 | 
					        if (!M.getValidTracks().count(idx)){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -426,17 +426,6 @@ namespace Mist{
 | 
				
			||||||
              "src=\"player.js\"></script><script>var mv ={reference:false}; mistPlay('" +
 | 
					              "src=\"player.js\"></script><script>var mv ={reference:false}; mistPlay('" +
 | 
				
			||||||
              streamName + "',{host:'" + fullURL.getUrl() + "',target:document.getElementById('" + streamName +
 | 
					              streamName + "',{host:'" + fullURL.getUrl() + "',target:document.getElementById('" + streamName +
 | 
				
			||||||
              "'),MistVideoObject:mv" + forceType + devSkin + "});" + seekTo + "</script></div></body></html>");
 | 
					              "'),MistVideoObject:mv" + forceType + devSkin + "});" + seekTo + "</script></div></body></html>");
 | 
				
			||||||
    if ((uAgent.find("iPad") != std::string::npos) || (uAgent.find("iPod") != std::string::npos) ||
 | 
					 | 
				
			||||||
        (uAgent.find("iPhone") != std::string::npos)){
 | 
					 | 
				
			||||||
      if (uAgent.find("OS 11") == std::string::npos && uAgent.find("OS 12") == std::string::npos &&
 | 
					 | 
				
			||||||
          uAgent.find("OS 13") == std::string::npos && uAgent.find("OS 14") == std::string::npos &&
 | 
					 | 
				
			||||||
          uAgent.find("OS 15") == std::string::npos && uAgent.find("OS 16") == std::string::npos){
 | 
					 | 
				
			||||||
        H.SetHeader("Location", hlsUrl);
 | 
					 | 
				
			||||||
        H.SendResponse("307", "HLS redirect", myConn);
 | 
					 | 
				
			||||||
        responded = true;
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    H.SendResponse("200", "OK", myConn);
 | 
					    H.SendResponse("200", "OK", myConn);
 | 
				
			||||||
    responded = true;
 | 
					    responded = true;
 | 
				
			||||||
    H.Clean();
 | 
					    H.Clean();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue