summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2021-10-15 00:30:44 +0200
committerCarl Hetherington <cth@carlh.net>2021-10-15 19:49:42 +0200
commitcdd2f62fe5dd2c54ab41d4b4de02eea77e833430 (patch)
treec743f9499b0d10d7965b15102895790f7a49cd0e
parent18ed20b9191d7122d78251d047f9ff7873c313d6 (diff)
Ignore audio streams that fall too far behind (#2101).
-rw-r--r--src/lib/player.cc32
1 files 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<AudioStreamPtr, StreamState>;
+
+ /* 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<AudioStreamPtr, StreamState> 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;
}