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
Reference in a new issue