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`).
* `PlaybackException` introduces an `errorCode` which identifies the
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 `Player.getPlaybackError`. Use `Player.getPlayerError` instead.
* Remove `Player.getCurrentTag`. Use `Player.getCurrentMediaItem` and

View File

@ -518,7 +518,8 @@ public class ChunkSampleStream<T extends ChunkSource>
long exclusionDurationMs =
cancelable
? loadErrorHandlingPolicy.getBlacklistDurationMsFor(loadErrorInfo)
? loadErrorHandlingPolicy.getExclusionDurationMsFor(
LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo)
: C.TIME_UNSET;
@Nullable LoadErrorAction loadErrorAction = null;
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;
/** 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;
@ -64,12 +68,14 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
}
/**
* Returns the exclusion duration, given by {@link #DEFAULT_TRACK_BLACKLIST_MS}, if the load error
* was an {@link InvalidResponseCodeException} with response code HTTP 404, 410 or 416, or {@link
* C#TIME_UNSET} otherwise.
* Returns the exclusion duration, given by {@link #DEFAULT_TRACK_EXCLUSION_MS} or {@link
* #DEFAULT_LOCATION_EXCLUSION_MS}, if the load error was an {@link InvalidResponseCodeException}
* with an HTTP response code indicating an unrecoverable error, or {@link C#TIME_UNSET}
* otherwise.
*/
@Override
public long getBlacklistDurationMsFor(LoadErrorInfo loadErrorInfo) {
public long getExclusionDurationMsFor(
@FallbackType int fallbackType, LoadErrorInfo loadErrorInfo) {
IOException exception = loadErrorInfo.exception;
if (exception instanceof InvalidResponseCodeException) {
int responseCode = ((InvalidResponseCodeException) exception).responseCode;
@ -79,7 +85,9 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
|| responseCode == 416 // HTTP 416 Range Not Satisfiable.
|| responseCode == 500 // HTTP 500 Internal Server Error.
|| 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;
}
return C.TIME_UNSET;

View File

@ -15,29 +15,53 @@
*/
package com.google.android.exoplayer2.upstream;
import androidx.annotation.IntDef;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.LoadEventInfo;
import com.google.android.exoplayer2.source.MediaLoadData;
import com.google.android.exoplayer2.upstream.Loader.Callback;
import com.google.android.exoplayer2.upstream.Loader.Loadable;
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.
*
* <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)}
* defines whether the resource should be excluded. Exclusion will succeed unless all of the
* alternatives are already excluded.
* load error occurs. In this case, {@link #getExclusionDurationMsFor(int, LoadErrorInfo)} defines
* whether the resource should be excluded for a given {@link FallbackType fallback type}, and if so
* 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)}
* defines whether the load is retried. An error that's not retried will always be propagated. An
* error that is retried will be propagated according to {@link #getMinimumLoadableRetryCount(int)}.
* <p>When exclusion does not take place, {@link #getRetryDelayMsFor(LoadErrorInfo)} defines whether
* the load is retried. An error that's not retried will always be propagated. An error that is
* retried will be propagated according to {@link #getMinimumLoadableRetryCount(int)}.
*
* <p>Methods are invoked on the playback thread.
*/
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. */
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
* 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.
* @return The exclusion duration in milliseconds, or {@link C#TIME_UNSET} if the resource should
* not be excluded.
*/
@SuppressWarnings("deprecation")
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();
}
long getExclusionDurationMsFor(@FallbackType int fallbackType, LoadErrorInfo loadErrorInfo);
/**
* 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
* C#TIME_UNSET} if the error is fatal and should not be retried.
*/
@SuppressWarnings("deprecation")
default long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) {
return getRetryDelayMsFor(
loadErrorInfo.mediaLoadData.dataType,
loadErrorInfo.loadEventInfo.loadDurationMs,
loadErrorInfo.exception,
loadErrorInfo.errorCount);
}
long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo);
/**
* Called once {@code loadTaskId} will not be associated with any more load errors.

View File

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

View File

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

View File

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