diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index 16e706ae92..eba79ab329 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -32,7 +32,6 @@ import com.google.android.exoplayer2.trackselection.BaseTrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; -import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.UriUtil; @@ -414,10 +413,11 @@ import java.util.List; * Called when a playlist load encounters an error. * * @param url The url of the playlist whose load encountered an error. - * @param shouldBlacklist Whether the playlist should be blacklisted. + * @param blacklistDurationMs The duration for which the playlist should be blacklisted. Or {@link + * C#TIME_UNSET} if the playlist should not be blacklisted. * @return True if blacklisting did not encounter errors. False otherwise. */ - public boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist) { + public boolean onPlaylistError(HlsUrl url, long blacklistDurationMs) { int trackGroupIndex = trackGroup.indexOf(url.format); if (trackGroupIndex == C.INDEX_UNSET) { return true; @@ -427,9 +427,8 @@ import java.util.List; return true; } seenExpectedPlaylistError |= expectedPlaylistUrl == url; - return !shouldBlacklist - || trackSelection.blacklist( - trackSelectionIndex, DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS); + return blacklistDurationMs == C.TIME_UNSET + || trackSelection.blacklist(trackSelectionIndex, blacklistDurationMs); } // Private methods. diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index c8cf8151c5..da50d7cc93 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -330,10 +330,10 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper } @Override - public boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist) { + public boolean onPlaylistError(HlsUrl url, long blacklistDurationMs) { boolean noBlacklistingFailure = true; for (HlsSampleStreamWrapper streamWrapper : sampleStreamWrappers) { - noBlacklistingFailure &= streamWrapper.onPlaylistError(url, shouldBlacklist); + noBlacklistingFailure &= streamWrapper.onPlaylistError(url, blacklistDurationMs); } callback.onContinueLoadingRequested(this); return noBlacklistingFailure; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 7061e3e738..5c63e19f28 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -416,8 +416,8 @@ import java.util.List; chunkSource.setIsTimestampMaster(isTimestampMaster); } - public boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist) { - return chunkSource.onPlaylistError(url, shouldBlacklist); + public boolean onPlaylistError(HlsUrl url, long blacklistDurationMs) { + return chunkSource.onPlaylistError(url, blacklistDurationMs); } // SampleStream implementation. diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java index 60f5619714..896950e6e5 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java @@ -25,7 +25,6 @@ import com.google.android.exoplayer2.source.hls.HlsDataSourceFactory; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment; import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.Loader; import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; @@ -208,7 +207,7 @@ public final class DefaultHlsPlaylistTracker MediaPlaylistBundle primaryBundle = playlistBundles.get(primaryHlsUrl); if (isMediaPlaylist) { // We don't need to load the playlist again. We can use the same result. - primaryBundle.processLoadedPlaylist((HlsMediaPlaylist) result); + primaryBundle.processLoadedPlaylist((HlsMediaPlaylist) result, loadDurationMs); } else { primaryBundle.loadPlaylist(); } @@ -321,11 +320,11 @@ public final class DefaultHlsPlaylistTracker } } - private boolean notifyPlaylistError(HlsUrl playlistUrl, boolean shouldBlacklist) { + private boolean notifyPlaylistError(HlsUrl playlistUrl, long blacklistDurationMs) { int listenersSize = listeners.size(); boolean anyBlacklistingFailed = false; for (int i = 0; i < listenersSize; i++) { - anyBlacklistingFailed |= !listeners.get(i).onPlaylistError(playlistUrl, shouldBlacklist); + anyBlacklistingFailed |= !listeners.get(i).onPlaylistError(playlistUrl, blacklistDurationMs); } return anyBlacklistingFailed; } @@ -473,7 +472,7 @@ public final class DefaultHlsPlaylistTracker ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs) { HlsPlaylist result = loadable.getResult(); if (result instanceof HlsMediaPlaylist) { - processLoadedPlaylist((HlsMediaPlaylist) result); + processLoadedPlaylist((HlsMediaPlaylist) result, loadDurationMs); eventDispatcher.loadCompleted( loadable.dataSpec, loadable.getUri(), @@ -516,9 +515,9 @@ public final class DefaultHlsPlaylistTracker boolean shouldBlacklist = blacklistDurationMs != C.TIME_UNSET; boolean blacklistingFailed = - notifyPlaylistError(playlistUrl, shouldBlacklist) || !shouldBlacklist; + notifyPlaylistError(playlistUrl, blacklistDurationMs) || !shouldBlacklist; if (shouldBlacklist) { - blacklistingFailed |= blacklistPlaylist(); + blacklistingFailed |= blacklistPlaylist(blacklistDurationMs); } if (blacklistingFailed) { @@ -569,7 +568,7 @@ public final class DefaultHlsPlaylistTracker elapsedRealtime); } - private void processLoadedPlaylist(HlsMediaPlaylist loadedPlaylist) { + private void processLoadedPlaylist(HlsMediaPlaylist loadedPlaylist, long loadDurationMs) { // Update the loaded playlist with any inheritable information from the master playlist. loadedPlaylist = loadedPlaylist.copyWithMasterPlaylistInfo(masterPlaylist); @@ -585,17 +584,22 @@ public final class DefaultHlsPlaylistTracker if (loadedPlaylist.mediaSequence + loadedPlaylist.segments.size() < playlistSnapshot.mediaSequence) { // TODO: Allow customization of playlist resets handling. - // The media sequence jumped backwards. The server has probably reset. + // The media sequence jumped backwards. The server has probably reset. We do not try + // blacklisting in this case. playlistError = new PlaylistResetException(playlistUrl.url); - notifyPlaylistError(playlistUrl, false); + notifyPlaylistError(playlistUrl, C.TIME_UNSET); } else if (currentTimeMs - lastSnapshotChangeMs > C.usToMs(playlistSnapshot.targetDurationUs) * PLAYLIST_STUCK_TARGET_DURATION_COEFFICIENT) { // TODO: Allow customization of stuck playlists handling. - // The playlist seems to be stuck. Blacklist it. playlistError = new PlaylistStuckException(playlistUrl.url); - notifyPlaylistError(playlistUrl, true); - blacklistPlaylist(); + long blacklistDurationMs = + loadErrorHandlingPolicy.getBlacklistDurationMsFor( + C.DATA_TYPE_MANIFEST, loadDurationMs, playlistError, /* errorCount= */ 1); + notifyPlaylistError(playlistUrl, blacklistDurationMs); + if (blacklistDurationMs != C.TIME_UNSET) { + blacklistPlaylist(blacklistDurationMs); + } } } // Do not allow the playlist to load again within the target duration if we obtained a new @@ -617,11 +621,12 @@ public final class DefaultHlsPlaylistTracker /** * Blacklists the playlist. * + * @param blacklistDurationMs The number of milliseconds for which the playlist should be + * blacklisted. * @return Whether the playlist is the primary, despite being blacklisted. */ - private boolean blacklistPlaylist() { - blacklistUntilMs = - SystemClock.elapsedRealtime() + DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS; + private boolean blacklistPlaylist(long blacklistDurationMs) { + blacklistUntilMs = SystemClock.elapsedRealtime() + blacklistDurationMs; return primaryHlsUrl == playlistUrl && !maybeSelectNewPrimaryUrl(); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java index 01dce9fcd3..49896bd57b 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java @@ -59,10 +59,11 @@ public interface HlsPlaylistTracker { * Called if an error is encountered while loading a playlist. * * @param url The loaded url that caused the error. - * @param shouldBlacklist Whether the playlist should be blacklisted. + * @param blacklistDurationMs The duration for which the playlist should be blacklisted. Or + * {@link C#TIME_UNSET} if the playlist should not be blacklisted. * @return True if blacklisting did not encounter errors. False otherwise. */ - boolean onPlaylistError(HlsUrl url, boolean shouldBlacklist); + boolean onPlaylistError(HlsUrl url, long blacklistDurationMs); } /** Thrown when a playlist is considered to be stuck due to a server side error. */