Improvements and fixes to track wait code
This commit is contained in:
parent
797534b2e2
commit
110a539151
3 changed files with 74 additions and 38 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue