Improvements and fixes to track wait code

This commit is contained in:
Thulinma 2023-08-07 11:35:17 +02:00
parent 797534b2e2
commit 110a539151
3 changed files with 74 additions and 38 deletions

View file

@ -118,6 +118,7 @@ namespace Mist{
Util::Config::binaryType = Util::OUTPUT;
lastRecv = Util::bootSecs();
outputStartMs = Util::bootMS();
if (myConn){
setBlocking(true);
//Make sure that if the socket is a non-stdio socket, we close it when forking
@ -233,33 +234,59 @@ namespace Mist{
bool Output::isReadyForPlay(){
// If a protocol does not support any codecs, we assume you know what you're doing
if (!capa.isMember("codecs") || !capa["codecs"].size() || !capa["codecs"].isArray() || !capa["codecs"][0u].size()){return true;}
if (!isInitialized){return false;}
meta.reloadReplacedPagesIfNeeded();
if (getSupportedTracks().size()){
size_t minTracks = 2;
size_t minMs = 5000;
if (targetParams.count("waittrackcount")){
minTracks = JSON::Value(targetParams["waittrackcount"]).asInt();
minMs = 120000;
}
if (targetParams.count("maxwaittrackms")){
minMs = JSON::Value(targetParams["maxwaittrackms"]).asInt();
}
if (!userSelect.size()){selectDefaultTracks();}
size_t mainTrack = getMainSelectedTrack();
if (mainTrack != INVALID_TRACK_ID){
DTSC::Keys keys(M.getKeys(mainTrack));
if (keys.getValidCount() >= minTracks || M.getNowms(mainTrack) - M.getFirstms(mainTrack) > minMs){
return true;
}
HIGH_MSG("NOT READY YET (%zu tracks, main track: %zu, with %zu keys)",
M.getValidTracks().size(), getMainSelectedTrack(), keys.getValidCount());
}else{
HIGH_MSG("NOT READY YET (%zu tracks)", getSupportedTracks().size());
}
}else{
HIGH_MSG("NOT READY (%zu tracks)", getSupportedTracks().size());
// Defaults for the below values are configured here, and may be overridden with query parameters:
size_t minTracks = 2; // Supported tracks to attempt to wait for
size_t minMs = 500; // Minimum time that must be buffered for a track to count as available
size_t minKeys = 2; // Minimum keyframes that must be buffered for a track to count as available
size_t maxWait = 5000; // Maximum time to wait for tracks
size_t maxMs = 20000; // If this much time is buffered in any track, don't wait on anything else anymore
if (targetParams.count("waittrackcount")){
minTracks = JSON::Value(targetParams["waittrackcount"]).asInt();
// Non-default wait times get a 2 minute default timeout instead of the usually 5 seconds default.
// (May still be overridden)
maxWait = 120000;
}
if (targetParams.count("mintrackms")){
minMs = JSON::Value(targetParams["mintrackms"]).asInt();
}
if (targetParams.count("maxtrackms")){
maxMs = JSON::Value(targetParams["maxtrackms"]).asInt();
}
if (targetParams.count("mintrackkeys")){
minKeys = JSON::Value(targetParams["mintrackkeys"]).asInt();
}
if (targetParams.count("maxwaittrackms")){
maxWait = JSON::Value(targetParams["maxwaittrackms"]).asInt();
}
if (outputStartMs + maxWait < Util::bootMS()){
HIGH_MSG("isReadyForPlay timed out waiting for tracks (%" PRId64 " > %zu); continuing with what we have", Util::bootMS()-outputStartMs, maxWait);
return true;
}
//This logic is copied from selectDefaultTracks, and should be kept in sync with it
if (!isInitialized){initialize();}
meta.reloadReplacedPagesIfNeeded();
bool autoSeek = buffer.size();
uint64_t seekTarget = buffer.getSyncMode()?currentTime():0;
std::set<size_t> trks = Util::wouldSelect(M, targetParams, capa, UA, autoSeek ? seekTarget : 0);
size_t trkCount = 0;
for (std::set<size_t>::iterator it = trks.begin(); it != trks.end(); ++it){
DTSC::Keys keys(M.keys(*it));
if (keys.getValidCount() >= minKeys || M.getLastms(*it) - M.getFirstms(*it) > minMs){
++trkCount;
if (trkCount >= minTracks){return true;}
}
if (M.getLastms(*it) - M.getFirstms(*it) > maxMs){
HIGH_MSG("isReadyForPlay skipping wait because track %zu has %" PRId64 "ms buffered", *it, M.getLastms(*it) - M.getFirstms(*it));
return true;
}
}
HIGH_MSG("isReadyForPlay waiting for tracks: %zu/%zu/%zu tracks, maxWait %zu, minMs %zu, minKeys %zu", trkCount, trks.size(), minTracks, maxWait, minMs, minKeys);
return false;
}

View file

@ -106,6 +106,7 @@ namespace Mist{
uint32_t seekCount;
bool firstData;
uint64_t lastPushUpdate;
uint64_t outputStartMs; ///< bootMS() at time of output start (unrelated to media start)
bool newUA;
protected: // these are to be messed with by child classes

View file

@ -379,15 +379,23 @@ namespace Mist{
/*LTS-END*/
if (H.hasHeader("User-Agent")){UA = H.GetHeader("User-Agent");}
if (H.GetVar("audio") != ""){targetParams["audio"] = H.GetVar("audio");}
if (H.GetVar("video") != ""){targetParams["video"] = H.GetVar("video");}
if (H.GetVar("meta") != ""){targetParams["meta"] = H.GetVar("meta");}
if (H.GetVar("subtitle") != ""){targetParams["subtitle"] = H.GetVar("subtitle");}
if (H.GetVar("start") != ""){targetParams["start"] = H.GetVar("start");}
if (H.GetVar("stop") != ""){targetParams["stop"] = H.GetVar("stop");}
if (H.GetVar("startunix") != ""){targetParams["startunix"] = H.GetVar("startunix");}
if (H.GetVar("stopunix") != ""){targetParams["stopunix"] = H.GetVar("stopunix");}
if (H.GetVar("duration") != ""){targetParams["duration"] = H.GetVar("duration");}
#define HTTP_CONVERT(var) if (H.GetVar(var) != ""){targetParams[var] = H.GetVar(var);}
HTTP_CONVERT("audio");
HTTP_CONVERT("video");
HTTP_CONVERT("meta");
HTTP_CONVERT("subtitle");
HTTP_CONVERT("start");
HTTP_CONVERT("stop");
HTTP_CONVERT("startunix");
HTTP_CONVERT("stopunix");
HTTP_CONVERT("duration");
HTTP_CONVERT("waittrackcount");
HTTP_CONVERT("mintrackms");
HTTP_CONVERT("maxtrackms");
HTTP_CONVERT("mintrackkeys");
HTTP_CONVERT("maxwaittrackms");
// allow setting of max lead time through buffer variable.
// max lead time is set in MS, but the variable is in integer seconds for simplicity.
if (H.GetVar("buffer") != ""){
@ -461,7 +469,7 @@ namespace Mist{
//Parse JSON and check command type
JSON::Value command = JSON::fromString(webSock->data, webSock->data.size());
if (!command || !command.isMember("type")){return false;}
//Seek command, for changing playback position
if (command["type"] == "seek") {
handleWebsocketSeek(command);
@ -566,7 +574,7 @@ namespace Mist{
parseData = true;
selectDefaultTracks();
}
if (target_rate == 0.0){
r["data"]["play_rate_prev"] = "auto";
}else{
@ -841,7 +849,7 @@ namespace Mist{
if (Comms::tknMode & 0x08){
std::stringstream cookieHeader;
cookieHeader << "tkn=" << tkn << "; Max-Age=" << SESS_TIMEOUT;
H.SetHeader("Set-Cookie", cookieHeader.str());
H.SetHeader("Set-Cookie", cookieHeader.str());
}
}
//Set attachment header to force download, if applicable