Add @FallbackType to LoadErrorHandlingPolicy

No-op change that adds the @FallbackType IntDef and changes the signature of getBlacklistDurationMsFor(LoadErrorInfo) to getExclusionDurationMsFor(@FallbackType, LoadErrorInfo).

PiperOrigin-RevId: 381075496
This commit is contained in:
bachinger 2021-06-23 19:18:54 +01:00 committed by Oliver Woodman
parent 75c06cc4e7
commit ed471fae96
7 changed files with 76 additions and 61 deletions

View File

@ -19,6 +19,8 @@
`ExoPlaybackException.rendererIndex`). `ExoPlaybackException.rendererIndex`).
* `PlaybackException` introduces an `errorCode` which identifies the * `PlaybackException` introduces an `errorCode` which identifies the
cause of the failure in order to simplify error handling. cause of the failure in order to simplify error handling.
* Add `@FallbackType` to `LoadErrorHandlingPolicy` to support
customization of the exclusion duration for locations and tracks.
* Remove deprecated symbols: * Remove deprecated symbols:
* Remove `Player.getPlaybackError`. Use `Player.getPlayerError` instead. * Remove `Player.getPlaybackError`. Use `Player.getPlayerError` instead.
* Remove `Player.getCurrentTag`. Use `Player.getCurrentMediaItem` and * Remove `Player.getCurrentTag`. Use `Player.getCurrentMediaItem` and

View File

@ -518,7 +518,8 @@ public class ChunkSampleStream<T extends ChunkSource>
long exclusionDurationMs = long exclusionDurationMs =
cancelable cancelable
? loadErrorHandlingPolicy.getBlacklistDurationMsFor(loadErrorInfo) ? loadErrorHandlingPolicy.getExclusionDurationMsFor(
LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo)
: C.TIME_UNSET; : C.TIME_UNSET;
@Nullable LoadErrorAction loadErrorAction = null; @Nullable LoadErrorAction loadErrorAction = null;
if (chunkSource.onChunkLoadError(loadable, cancelable, error, exclusionDurationMs)) { if (chunkSource.onChunkLoadError(loadable, cancelable, error, exclusionDurationMs)) {

View File

@ -36,7 +36,11 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
*/ */
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT_PROGRESSIVE_LIVE = 6; public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT_PROGRESSIVE_LIVE = 6;
/** The default duration for which a track is excluded in milliseconds. */ /** The default duration for which a track is excluded in milliseconds. */
public static final long DEFAULT_TRACK_BLACKLIST_MS = 60_000; public static final long DEFAULT_TRACK_EXCLUSION_MS = 60_000;
/** @deprecated Use {@link #DEFAULT_TRACK_EXCLUSION_MS} instead. */
@Deprecated public static final long DEFAULT_TRACK_BLACKLIST_MS = DEFAULT_TRACK_EXCLUSION_MS;
/** The default duration for which a location is excluded in milliseconds. */
public static final long DEFAULT_LOCATION_EXCLUSION_MS = 5 * 60_000;
private static final int DEFAULT_BEHAVIOR_MIN_LOADABLE_RETRY_COUNT = -1; private static final int DEFAULT_BEHAVIOR_MIN_LOADABLE_RETRY_COUNT = -1;
@ -64,12 +68,14 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
} }
/** /**
* Returns the exclusion duration, given by {@link #DEFAULT_TRACK_BLACKLIST_MS}, if the load error * Returns the exclusion duration, given by {@link #DEFAULT_TRACK_EXCLUSION_MS} or {@link
* was an {@link InvalidResponseCodeException} with response code HTTP 404, 410 or 416, or {@link * #DEFAULT_LOCATION_EXCLUSION_MS}, if the load error was an {@link InvalidResponseCodeException}
* C#TIME_UNSET} otherwise. * with an HTTP response code indicating an unrecoverable error, or {@link C#TIME_UNSET}
* otherwise.
*/ */
@Override @Override
public long getBlacklistDurationMsFor(LoadErrorInfo loadErrorInfo) { public long getExclusionDurationMsFor(
@FallbackType int fallbackType, LoadErrorInfo loadErrorInfo) {
IOException exception = loadErrorInfo.exception; IOException exception = loadErrorInfo.exception;
if (exception instanceof InvalidResponseCodeException) { if (exception instanceof InvalidResponseCodeException) {
int responseCode = ((InvalidResponseCodeException) exception).responseCode; int responseCode = ((InvalidResponseCodeException) exception).responseCode;
@ -79,7 +85,9 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
|| responseCode == 416 // HTTP 416 Range Not Satisfiable. || responseCode == 416 // HTTP 416 Range Not Satisfiable.
|| responseCode == 500 // HTTP 500 Internal Server Error. || responseCode == 500 // HTTP 500 Internal Server Error.
|| responseCode == 503 // HTTP 503 Service Unavailable. || responseCode == 503 // HTTP 503 Service Unavailable.
? DEFAULT_TRACK_BLACKLIST_MS ? (fallbackType == FALLBACK_TYPE_TRACK
? DEFAULT_TRACK_EXCLUSION_MS
: DEFAULT_LOCATION_EXCLUSION_MS)
: C.TIME_UNSET; : C.TIME_UNSET;
} }
return C.TIME_UNSET; return C.TIME_UNSET;

View File

@ -15,29 +15,53 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import androidx.annotation.IntDef;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.LoadEventInfo; import com.google.android.exoplayer2.source.LoadEventInfo;
import com.google.android.exoplayer2.source.MediaLoadData; import com.google.android.exoplayer2.source.MediaLoadData;
import com.google.android.exoplayer2.upstream.Loader.Callback; import com.google.android.exoplayer2.upstream.Loader.Callback;
import com.google.android.exoplayer2.upstream.Loader.Loadable; import com.google.android.exoplayer2.upstream.Loader.Loadable;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** /**
* Defines how errors encountered by loaders are handled. * Defines how errors encountered by loaders are handled.
* *
* <p>A loader that can choose between one of a number of resources can exclude a resource when a * <p>A loader that can choose between one of a number of resources can exclude a resource when a
* load error occurs. In this case, {@link #getBlacklistDurationMsFor(int, long, IOException, int)} * load error occurs. In this case, {@link #getExclusionDurationMsFor(int, LoadErrorInfo)} defines
* defines whether the resource should be excluded. Exclusion will succeed unless all of the * whether the resource should be excluded for a given {@link FallbackType fallback type}, and if so
* alternatives are already excluded. * for how long. If the policy indicates that a resource should be excluded, the loader will exclude
* it for the specified amount of time unless all of the alternatives for the given fallback type
* are already excluded.
* *
* <p>When exclusion does not take place, {@link #getRetryDelayMsFor(int, long, IOException, int)} * <p>When exclusion does not take place, {@link #getRetryDelayMsFor(LoadErrorInfo)} defines whether
* defines whether the load is retried. An error that's not retried will always be propagated. An * the load is retried. An error that's not retried will always be propagated. An error that is
* error that is retried will be propagated according to {@link #getMinimumLoadableRetryCount(int)}. * retried will be propagated according to {@link #getMinimumLoadableRetryCount(int)}.
* *
* <p>Methods are invoked on the playback thread. * <p>Methods are invoked on the playback thread.
*/ */
public interface LoadErrorHandlingPolicy { public interface LoadErrorHandlingPolicy {
/** Fallback type. One of {@link #FALLBACK_TYPE_LOCATION} or {@link #FALLBACK_TYPE_TRACK}. */
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({FALLBACK_TYPE_LOCATION, FALLBACK_TYPE_TRACK})
@interface FallbackType {}
/**
* Fallback type that is using exclusion of locations (i.e., multiple URLs through which the same
* data is accessible).
*/
int FALLBACK_TYPE_LOCATION = 1;
/**
* Fallback type that is using exclusion of tracks (i.e., multiple URLs through which different
* representations of the same content are available; for example the same video encoded at
* different bitrates or resolutions).
*/
int FALLBACK_TYPE_TRACK = 2;
/** Holds information about a load task error. */ /** Holds information about a load task error. */
final class LoadErrorInfo { final class LoadErrorInfo {
@ -63,36 +87,17 @@ public interface LoadErrorHandlingPolicy {
} }
} }
/** @deprecated Implement {@link #getBlacklistDurationMsFor(LoadErrorInfo)} instead. */
@Deprecated
default long getBlacklistDurationMsFor(
int dataType, long loadDurationMs, IOException exception, int errorCount) {
throw new UnsupportedOperationException();
}
/** /**
* Returns the number of milliseconds for which a resource associated to a provided load error * Returns the number of milliseconds for which a resource associated to a provided load error
* should be excluded, or {@link C#TIME_UNSET} if the resource should not be excluded. * should be excluded for a given {@link FallbackType fallback type}, or {@link C#TIME_UNSET} if
* the resource should not be excluded.
* *
* @param fallbackType The {@link FallbackType fallback type} used for exclusion.
* @param loadErrorInfo A {@link LoadErrorInfo} holding information about the load error. * @param loadErrorInfo A {@link LoadErrorInfo} holding information about the load error.
* @return The exclusion duration in milliseconds, or {@link C#TIME_UNSET} if the resource should * @return The exclusion duration in milliseconds, or {@link C#TIME_UNSET} if the resource should
* not be excluded. * not be excluded.
*/ */
@SuppressWarnings("deprecation") long getExclusionDurationMsFor(@FallbackType int fallbackType, LoadErrorInfo loadErrorInfo);
default long getBlacklistDurationMsFor(LoadErrorInfo loadErrorInfo) {
return getBlacklistDurationMsFor(
loadErrorInfo.mediaLoadData.dataType,
loadErrorInfo.loadEventInfo.loadDurationMs,
loadErrorInfo.exception,
loadErrorInfo.errorCount);
}
/** @deprecated Implement {@link #getRetryDelayMsFor(LoadErrorInfo)} instead. */
@Deprecated
default long getRetryDelayMsFor(
int dataType, long loadDurationMs, IOException exception, int errorCount) {
throw new UnsupportedOperationException();
}
/** /**
* Returns the number of milliseconds to wait before attempting the load again, or {@link * Returns the number of milliseconds to wait before attempting the load again, or {@link
@ -106,14 +111,7 @@ public interface LoadErrorHandlingPolicy {
* @return The number of milliseconds to wait before attempting the load again, or {@link * @return The number of milliseconds to wait before attempting the load again, or {@link
* C#TIME_UNSET} if the error is fatal and should not be retried. * C#TIME_UNSET} if the error is fatal and should not be retried.
*/ */
@SuppressWarnings("deprecation") long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo);
default long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) {
return getRetryDelayMsFor(
loadErrorInfo.mediaLoadData.dataType,
loadErrorInfo.loadEventInfo.loadDurationMs,
loadErrorInfo.exception,
loadErrorInfo.errorCount);
}
/** /**
* Called once {@code loadTaskId} will not be associated with any more load errors. * Called once {@code loadTaskId} will not be associated with any more load errors.

View File

@ -50,50 +50,50 @@ public final class DefaultLoadErrorHandlingPolicyTest {
@Test @Test
public void getExclusionDurationMsFor_responseCode403() { public void getExclusionDurationMsFor_responseCode403() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(403, "Forbidden"); InvalidResponseCodeException exception = buildInvalidResponseCodeException(403, "Forbidden");
assertThat(getDefaultPolicyExclusionDurationMsFor(exception)) assertThat(getDefaultPolicyTrackExclusionDurationMsFor(exception))
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS); .isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_EXCLUSION_MS);
} }
@Test @Test
public void getExclusionDurationMsFor_responseCode404() { public void getExclusionDurationMsFor_responseCode404() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(404, "Not found"); InvalidResponseCodeException exception = buildInvalidResponseCodeException(404, "Not found");
assertThat(getDefaultPolicyExclusionDurationMsFor(exception)) assertThat(getDefaultPolicyTrackExclusionDurationMsFor(exception))
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS); .isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_EXCLUSION_MS);
} }
@Test @Test
public void getExclusionDurationMsFor_responseCode410() { public void getExclusionDurationMsFor_responseCode410() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(410, "Gone"); InvalidResponseCodeException exception = buildInvalidResponseCodeException(410, "Gone");
assertThat(getDefaultPolicyExclusionDurationMsFor(exception)) assertThat(getDefaultPolicyTrackExclusionDurationMsFor(exception))
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS); .isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_EXCLUSION_MS);
} }
@Test @Test
public void getExclusionDurationMsFor_responseCode500() { public void getExclusionDurationMsFor_responseCode500() {
InvalidResponseCodeException exception = InvalidResponseCodeException exception =
buildInvalidResponseCodeException(500, "Internal server error"); buildInvalidResponseCodeException(500, "Internal server error");
assertThat(getDefaultPolicyExclusionDurationMsFor(exception)) assertThat(getDefaultPolicyTrackExclusionDurationMsFor(exception))
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS); .isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_EXCLUSION_MS);
} }
@Test @Test
public void getExclusionDurationMsFor_responseCode503() { public void getExclusionDurationMsFor_responseCode503() {
InvalidResponseCodeException exception = InvalidResponseCodeException exception =
buildInvalidResponseCodeException(503, "Service unavailable"); buildInvalidResponseCodeException(503, "Service unavailable");
assertThat(getDefaultPolicyExclusionDurationMsFor(exception)) assertThat(getDefaultPolicyTrackExclusionDurationMsFor(exception))
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS); .isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_EXCLUSION_MS);
} }
@Test @Test
public void getExclusionDurationMsFor_dontExcludeUnexpectedHttpCodes() { public void getExclusionDurationMsFor_dontExcludeUnexpectedHttpCodes() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(418, "I'm a teapot"); InvalidResponseCodeException exception = buildInvalidResponseCodeException(418, "I'm a teapot");
assertThat(getDefaultPolicyExclusionDurationMsFor(exception)).isEqualTo(C.TIME_UNSET); assertThat(getDefaultPolicyTrackExclusionDurationMsFor(exception)).isEqualTo(C.TIME_UNSET);
} }
@Test @Test
public void getExclusionDurationMsFor_dontExcludeUnexpectedExceptions() { public void getExclusionDurationMsFor_dontExcludeUnexpectedExceptions() {
IOException exception = new IOException(); IOException exception = new IOException();
assertThat(getDefaultPolicyExclusionDurationMsFor(exception)).isEqualTo(C.TIME_UNSET); assertThat(getDefaultPolicyTrackExclusionDurationMsFor(exception)).isEqualTo(C.TIME_UNSET);
} }
@Test @Test
@ -112,14 +112,15 @@ public final class DefaultLoadErrorHandlingPolicyTest {
assertThat(getDefaultPolicyRetryDelayOutputFor(new IOException(), 9)).isEqualTo(5000); assertThat(getDefaultPolicyRetryDelayOutputFor(new IOException(), 9)).isEqualTo(5000);
} }
private static long getDefaultPolicyExclusionDurationMsFor(IOException exception) { private static long getDefaultPolicyTrackExclusionDurationMsFor(IOException exception) {
LoadErrorInfo loadErrorInfo = LoadErrorInfo loadErrorInfo =
new LoadErrorInfo( new LoadErrorInfo(
PLACEHOLDER_LOAD_EVENT_INFO, PLACEHOLDER_LOAD_EVENT_INFO,
PLACEHOLDER_MEDIA_LOAD_DATA, PLACEHOLDER_MEDIA_LOAD_DATA,
exception, exception,
/* errorCount= */ 1); /* errorCount= */ 1);
return new DefaultLoadErrorHandlingPolicy().getBlacklistDurationMsFor(loadErrorInfo); return new DefaultLoadErrorHandlingPolicy()
.getExclusionDurationMsFor(LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo);
} }
private static long getDefaultPolicyRetryDelayOutputFor(IOException exception, int errorCount) { private static long getDefaultPolicyRetryDelayOutputFor(IOException exception, int errorCount) {

View File

@ -893,7 +893,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
LoadErrorInfo loadErrorInfo = LoadErrorInfo loadErrorInfo =
new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount); new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount);
LoadErrorAction loadErrorAction; LoadErrorAction loadErrorAction;
long exclusionDurationMs = loadErrorHandlingPolicy.getBlacklistDurationMsFor(loadErrorInfo); long exclusionDurationMs =
loadErrorHandlingPolicy.getExclusionDurationMsFor(
LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo);
if (exclusionDurationMs != C.TIME_UNSET) { if (exclusionDurationMs != C.TIME_UNSET) {
exclusionSucceeded = chunkSource.maybeExcludeTrack(loadable, exclusionDurationMs); exclusionSucceeded = chunkSource.maybeExcludeTrack(loadable, exclusionDurationMs);
} }

View File

@ -631,7 +631,9 @@ public final class DefaultHlsPlaylistTracker
LoadErrorInfo loadErrorInfo = LoadErrorInfo loadErrorInfo =
new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount); new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount);
LoadErrorAction loadErrorAction; LoadErrorAction loadErrorAction;
long exclusionDurationMs = loadErrorHandlingPolicy.getBlacklistDurationMsFor(loadErrorInfo); long exclusionDurationMs =
loadErrorHandlingPolicy.getExclusionDurationMsFor(
LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo);
boolean shouldExclude = exclusionDurationMs != C.TIME_UNSET; boolean shouldExclude = exclusionDurationMs != C.TIME_UNSET;
boolean exclusionFailed = boolean exclusionFailed =
@ -730,7 +732,8 @@ public final class DefaultHlsPlaylistTracker
playlistError, playlistError,
/* errorCount= */ 1); /* errorCount= */ 1);
long exclusionDurationMs = long exclusionDurationMs =
loadErrorHandlingPolicy.getBlacklistDurationMsFor(loadErrorInfo); loadErrorHandlingPolicy.getExclusionDurationMsFor(
LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo);
notifyPlaylistError(playlistUrl, exclusionDurationMs); notifyPlaylistError(playlistUrl, exclusionDurationMs);
if (exclusionDurationMs != C.TIME_UNSET) { if (exclusionDurationMs != C.TIME_UNSET) {
excludePlaylist(exclusionDurationMs); excludePlaylist(exclusionDurationMs);