diff --git a/src/common/AdaptiveTree.cpp b/src/common/AdaptiveTree.cpp index f3af658eb..bc6d36008 100644 --- a/src/common/AdaptiveTree.cpp +++ b/src/common/AdaptiveTree.cpp @@ -434,9 +434,17 @@ namespace adaptive updLck.lock(); + // Store the interval before it is cleared, skipping a value that a parser + // lowered as a temporary backoff + if (!m_resetInterval && m_tree->m_updateInterval != NO_VALUE && m_tree->m_updateInterval > 0) + m_tree->m_lastValidUpdateInterval = m_tree->m_updateInterval.load(); + // Reset interval value to allow forced update from manifest if (m_resetInterval) + { m_tree->m_updateInterval = PLAYLIST::NO_VALUE; + m_resetInterval = false; + } m_tree->OnUpdateSegments(); } diff --git a/src/common/AdaptiveTree.h b/src/common/AdaptiveTree.h index 223320606..012437701 100644 --- a/src/common/AdaptiveTree.h +++ b/src/common/AdaptiveTree.h @@ -384,6 +384,11 @@ class ATTR_DLL_LOCAL AdaptiveTree // Non-zero value: refresh interval starting from the moment mpd download was initiated // Value 0: refresh each time we need to make new segments std::atomic m_updateInterval{PLAYLIST::NO_VALUE}; + + // Last update interval that came from a manifest, as opposed to one a parser + // applied as a temporary backoff. Since m_updateInterval is set to NO_VALUE + // before each update, a parser that backs off has no other usable base value. + std::atomic m_lastValidUpdateInterval{0}; TreeUpdateThread m_updThread; std::atomic> lastUpdated_{std::chrono::system_clock::now()}; diff --git a/src/parser/HLSTree.cpp b/src/parser/HLSTree.cpp index f7dfb6f6f..0b39a2696 100644 --- a/src/parser/HLSTree.cpp +++ b/src/parser/HLSTree.cpp @@ -32,6 +32,10 @@ namespace // Timescale for ms constexpr uint64_t TIMESCALE = 1000; +// Lower bound for the update interval backoff, in ms, to keep the halving from +// reaching zero and stopping the update thread +constexpr uint64_t MIN_UPDATE_INTERVAL_MS = 500; + // \brief Parse a tag (e.g. #EXT-X-VERSION:1) to extract name and value void ParseTagNameValue(const std::string& line, std::string& tagName, std::string& tagValue) { @@ -1122,7 +1126,7 @@ void adaptive::CHLSTree::OnUpdateSegments() // so avoid requesting updates too quickly but you also need to make sure // that we have segments to mitigate a buffering problem // so try halve the interval time in a temporary way - m_updateInterval = m_updateInterval / 2; + m_updateInterval = std::max(m_lastValidUpdateInterval / 2, MIN_UPDATE_INTERVAL_MS); // Reset the interval on the next update, to restore the original value m_updThread.ResetInterval(); }