From b09ebc92ef15e0086716fdfb3b996e3250b54d3c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 15 Oct 2021 00:30:44 +0200 Subject: [PATCH] Ignore audio streams that fall too far behind (#2101). --- src/lib/player.cc | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/lib/player.cc b/src/lib/player.cc index b93bf3f4a..dcc89bab9 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -743,10 +743,38 @@ Player::pass () /* Emit any audio that is ready */ /* Work out the time before which the audio is definitely all here. This is the earliest last_push_end of one - of our streams, or the position of the _silent. + of our streams, or the position of the _silent. First, though we choose only streams that are less than + ignore_streams_behind seconds behind the furthest ahead (we assume that if a stream has fallen that far + behind it has finished). This is so that we don't withhold audio indefinitely awaiting data from a stream + that will never come, causing bugs like #2101. */ - auto pull_to = _playback_length; + constexpr int ignore_streams_behind = 5; + + using state_pair = std::pair; + + /* Find the 'leading' stream (i.e. the one that pushed data most recently) */ + auto latest_last_push_end = std::max_element( + _stream_states.begin(), + _stream_states.end(), + [](state_pair const& a, state_pair const& b) { return a.second.last_push_end < b.second.last_push_end; } + ); + + if (latest_last_push_end != _stream_states.end()) { + LOG_DEBUG_PLAYER("Leading stream is in %1 at %2", latest_last_push_end->second.piece->content->path(0), to_string(latest_last_push_end->second.last_push_end)); + } + + /* Now make a list of those streams that are less than ignore_streams_behind behind the leader */ + std::map alive_stream_states; for (auto const& i: _stream_states) { + if ((latest_last_push_end->second.last_push_end - i.second.last_push_end) < dcpomatic::DCPTime::from_seconds(ignore_streams_behind)) { + alive_stream_states.insert(i); + } else { + LOG_DEBUG_PLAYER("Ignoring stream %1 because it is too far behind", i.second.piece->content->path(0)); + } + } + + auto pull_to = _playback_length; + for (auto const& i: alive_stream_states) { if (!i.second.piece->done && i.second.last_push_end < pull_to) { pull_to = i.second.last_push_end; } -- 2.30.2