diff --git a/lib/socket.cpp b/lib/socket.cpp index fa993b33..ad152ec1 100644 --- a/lib/socket.cpp +++ b/lib/socket.cpp @@ -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. std::string Socket::resolveHostToBestExternalAddrGuess(const std::string &host, int family, const std::string &hint){ + if (!host.size()){return "";} struct addrinfo *result, *rp, hints; std::string newaddr; diff --git a/src/output/output.cpp b/src/output/output.cpp index f68995ab..a2ddd698 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -812,6 +812,7 @@ namespace Mist{ if (!isInitialized){initialize();} buffer.clear(); thisPacket.null(); + if (!M){return false;} if (toKey){ size_t mainTrack = getMainSelectedTrack(); if (mainTrack == INVALID_TRACK_ID){ @@ -831,11 +832,13 @@ namespace Mist{ MEDIUM_MSG("Seeking to %" PRIu64 "ms (%s)", pos, toKey ? "sync" : "direct"); std::set seekTracks; for (std::map::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 for (std::set::iterator it = seekTracks.begin(); it != seekTracks.end(); it++){ - userSelect[*it].setKeyNum(M.getKeyNumForTime(*it, pos)); + if (userSelect[*it]){ + userSelect[*it].setKeyNum(M.getKeyNumForTime(*it, pos)); + } } bool ret = seekTracks.size(); for (std::set::iterator it = seekTracks.begin(); it != seekTracks.end(); it++){ @@ -1985,6 +1988,10 @@ namespace Mist{ // depending on whether this is probably bad and the current debug level, print a message 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. + if (!M || !M.getValidTracks().count(trackId)){ + DEBUG_MSG(printLevel, "Dropping invalid track %zu: %s", trackId, reason.c_str()); + return; + } if (!userSelect.count(trackId)){ if (M.hasEmbeddedFrames(trackId)){ DEBUG_MSG(printLevel, "Dropping %s track %zu (raw): %s", meta.getCodec(trackId).c_str(), trackId, reason.c_str()); diff --git a/src/output/output_hls.cpp b/src/output/output_hls.cpp index ac5ff769..e6b56eec 100644 --- a/src/output/output_hls.cpp +++ b/src/output/output_hls.cpp @@ -68,11 +68,18 @@ namespace Mist{ << "\r\n"; } } - if (!vidTracks && audioId != INVALID_TRACK_ID){ - result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << (M.getBps(audioId) * 8); - result << ",CODECS=\"" << Util::codecString(M.getCodec(audioId), M.getInit(audioId)) << "\""; - result << "\r\n"; - result << audioId << "/index.m3u8" << tknStr << "\r\n"; + + if (!vidTracks){ + if (audioId != INVALID_TRACK_ID){ + // Audio only playlist + result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << (M.getBps(audioId) * 8); + result << ",CODECS=\"" << Util::codecString(M.getCodec(audioId), M.getInit(audioId)) << "\""; + result << "\r\n"; + result << audioId << "/index.m3u8" << tknStr << "\r\n"; + }else{ + // No compatible tracks at all + return ""; + } } return result.str(); } @@ -260,7 +267,12 @@ namespace Mist{ H.SetHeader("Content-Type", "text/xml"); H.SetHeader("Server", APPIDENT); 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); responded = true; return; @@ -274,19 +286,20 @@ namespace Mist{ return; }// crossdomain.xml - if (H.method == "OPTIONS"){ + if (method == "OPTIONS"){ bool isTS = (HTTP::URL(H.url).getExt().substr(0, 3) != "m3u"); + H.Clean(); H.setCORSHeaders(); if (isTS){ H.SetHeader("Content-Type", "video/mp2t"); }else{ 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; if (M && M.getValidTracks().size()){ 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", "public, max-age=" + @@ -298,7 +311,7 @@ namespace Mist{ H.SetHeader("Cache-Control", "no-store"); } H.SetBody(""); - H.SendResponse("200", "OK", myConn); + H.SendResponse("204", "No content", myConn); responded = true; return; } @@ -374,14 +387,14 @@ namespace Mist{ H.SetHeader("Content-Type", "video/mp2t"); H.setCORSHeaders(); if (!(Comms::tknMode & 0x04) || config->getOption("chunkpath")){ - H.SetHeader("Cache-Control", "no-store"); - }else{ H.SetHeader("Cache-Control", "public, max-age=" + JSON::Value(M.getDuration(getMainSelectedTrack()) / 1000).asString() + ", immutable"); H.SetHeader("Pragma", ""); H.SetHeader("Expires", ""); + }else{ + H.SetHeader("Cache-Control", "no-store"); } if (method == "OPTIONS" || method == "HEAD"){ H.SendResponse("200", "OK", myConn); @@ -418,6 +431,10 @@ namespace Mist{ std::string manifest; if (request.find("/") == std::string::npos){ manifest = liveIndex(); + if (manifest == ""){ + onFail("No HLS compatible tracks found"); + return; + } }else{ size_t idx = atoi(request.substr(0, request.find("/")).c_str()); if (!M.getValidTracks().count(idx)){ diff --git a/src/output/output_http_internal.cpp b/src/output/output_http_internal.cpp index 697ee6ff..71e8059a 100644 --- a/src/output/output_http_internal.cpp +++ b/src/output/output_http_internal.cpp @@ -426,17 +426,6 @@ namespace Mist{ "src=\"player.js\">"); - 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); responded = true; H.Clean();