Make getFallbackSelection nullable to indicate disabling of exclusion

PiperOrigin-RevId: 386442542
This commit is contained in:
bachinger 2021-07-23 14:29:42 +01:00
parent cae309123b
commit 2ee6d6d95d
9 changed files with 97 additions and 116 deletions

View File

@ -384,8 +384,7 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
multiSession, multiSession,
/* useDrmSessionsForClearContentTrackTypes= */ new int[0], /* useDrmSessionsForClearContentTrackTypes= */ new int[0],
/* playClearSamplesWithoutKeys= */ false, /* playClearSamplesWithoutKeys= */ false,
new DefaultLoadErrorHandlingPolicy( new DefaultLoadErrorHandlingPolicy(initialDrmRequestRetryCount),
initialDrmRequestRetryCount, /* locationExclusionEnabled= */ false),
DEFAULT_SESSION_KEEPALIVE_MS); DEFAULT_SESSION_KEEPALIVE_MS);
} }

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.upstream;
import static java.lang.Math.min; import static java.lang.Math.min;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.upstream.HttpDataSource.CleartextNotPermittedException; import com.google.android.exoplayer2.upstream.HttpDataSource.CleartextNotPermittedException;
@ -45,7 +46,6 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
private static final int DEFAULT_BEHAVIOR_MIN_LOADABLE_RETRY_COUNT = -1; private static final int DEFAULT_BEHAVIOR_MIN_LOADABLE_RETRY_COUNT = -1;
private final int minimumLoadableRetryCount; private final int minimumLoadableRetryCount;
private final boolean locationExclusionEnabled;
/** /**
* Creates an instance with default behavior. * Creates an instance with default behavior.
@ -54,72 +54,48 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
* #DEFAULT_MIN_LOADABLE_RETRY_COUNT_PROGRESSIVE_LIVE} for {@code dataType} {@link * #DEFAULT_MIN_LOADABLE_RETRY_COUNT_PROGRESSIVE_LIVE} for {@code dataType} {@link
* C#DATA_TYPE_MEDIA_PROGRESSIVE_LIVE}. For other {@code dataType} values, it will return {@link * C#DATA_TYPE_MEDIA_PROGRESSIVE_LIVE}. For other {@code dataType} values, it will return {@link
* #DEFAULT_MIN_LOADABLE_RETRY_COUNT}. * #DEFAULT_MIN_LOADABLE_RETRY_COUNT}.
*
* <p>Exclusion of both fallback types {@link #FALLBACK_TYPE_TRACK} and {@link
* #FALLBACK_TYPE_TRACK} is enabled by default.
*/ */
public DefaultLoadErrorHandlingPolicy() { public DefaultLoadErrorHandlingPolicy() {
this(DEFAULT_BEHAVIOR_MIN_LOADABLE_RETRY_COUNT, /* locationExclusionEnabled= */ true); this(DEFAULT_BEHAVIOR_MIN_LOADABLE_RETRY_COUNT);
}
/** @deprecated Use {@link #DefaultLoadErrorHandlingPolicy(int, boolean)} instead. */
@Deprecated
public DefaultLoadErrorHandlingPolicy(int minimumLoadableRetryCount) {
this(minimumLoadableRetryCount, /* locationExclusionEnabled= */ true);
} }
/** /**
* Creates an instance with the given value for {@link #getMinimumLoadableRetryCount(int)}. * Creates an instance with the given value for {@link #getMinimumLoadableRetryCount(int)}.
* *
* @param minimumLoadableRetryCount See {@link #getMinimumLoadableRetryCount}. * @param minimumLoadableRetryCount See {@link #getMinimumLoadableRetryCount}.
* @param locationExclusionEnabled Whether location exclusion is enabled.
*/ */
public DefaultLoadErrorHandlingPolicy( public DefaultLoadErrorHandlingPolicy(int minimumLoadableRetryCount) {
int minimumLoadableRetryCount, boolean locationExclusionEnabled) {
this.minimumLoadableRetryCount = minimumLoadableRetryCount; this.minimumLoadableRetryCount = minimumLoadableRetryCount;
this.locationExclusionEnabled = locationExclusionEnabled;
} }
/** /**
* Returns the fallback selection. * Returns the fallback selection.
* *
* <p>The exclusion duration is given by {@link #DEFAULT_TRACK_EXCLUSION_MS} or {@link * <p>The exclusion duration is given by {@link #DEFAULT_TRACK_EXCLUSION_MS} or {@link
* #DEFAULT_LOCATION_EXCLUSION_MS}, if the load error was an {@link InvalidResponseCodeException} * #DEFAULT_LOCATION_EXCLUSION_MS} if the load error was not an {@link
* with an HTTP response code indicating an unrecoverable error, or {@link C#TIME_UNSET} * #isRecoverableError(IOException) recoverable error}. In case of a recoverable error null is
* otherwise. * returned to disable exclusion but retry the same load instead.
* *
* <p>If alternative locations are advertised by the {@link * <p>If alternative locations {@link
* LoadErrorHandlingPolicy.FallbackOptions}, {@link #FALLBACK_TYPE_LOCATION} is selected until all * LoadErrorHandlingPolicy.FallbackOptions#isFallbackAvailable(int) are advertised}, {@link
* locations are excluded, {@link #FALLBACK_TYPE_TRACK} otherwise. * #FALLBACK_TYPE_LOCATION} is selected until all locations are excluded, {@link
* #FALLBACK_TYPE_TRACK} otherwise.
*/ */
@Override @Override
@Nullable
public FallbackSelection getFallbackSelectionFor( public FallbackSelection getFallbackSelectionFor(
FallbackOptions fallbackOptions, LoadErrorInfo loadErrorInfo) { FallbackOptions fallbackOptions, LoadErrorInfo loadErrorInfo) {
@FallbackType int fallbackType = FALLBACK_TYPE_TRACK; if (isRecoverableError(loadErrorInfo.exception)) {
boolean fallbackAvailable = // Don't fallback. Retry the same load again.
fallbackOptions.numberOfTracks - fallbackOptions.numberOfExcludedTracks > 1; return null;
if (locationExclusionEnabled
&& fallbackOptions.numberOfLocations - fallbackOptions.numberOfExcludedLocations > 1) {
fallbackType = FALLBACK_TYPE_LOCATION;
fallbackAvailable = true;
} }
long exclusionDurationMs = C.TIME_UNSET; // Prefer location fallbacks to track fallbacks, when both are available.
IOException exception = loadErrorInfo.exception; if (fallbackOptions.isFallbackAvailable(FALLBACK_TYPE_LOCATION)) {
if (fallbackAvailable && exception instanceof InvalidResponseCodeException) { return new FallbackSelection(FALLBACK_TYPE_LOCATION, DEFAULT_LOCATION_EXCLUSION_MS);
int responseCode = ((InvalidResponseCodeException) exception).responseCode; } else if (fallbackOptions.isFallbackAvailable(FALLBACK_TYPE_TRACK)) {
exclusionDurationMs = return new FallbackSelection(FALLBACK_TYPE_TRACK, DEFAULT_TRACK_EXCLUSION_MS);
responseCode == 403 // HTTP 403 Forbidden.
|| responseCode == 404 // HTTP 404 Not Found.
|| responseCode == 410 // HTTP 410 Gone.
|| responseCode == 416 // HTTP 416 Range Not Satisfiable.
|| responseCode == 500 // HTTP 500 Internal Server Error.
|| responseCode == 503 // HTTP 503 Service Unavailable.
? (fallbackType == FALLBACK_TYPE_TRACK
? DEFAULT_TRACK_EXCLUSION_MS
: DEFAULT_LOCATION_EXCLUSION_MS)
: C.TIME_UNSET;
} }
return new FallbackSelection(fallbackType, exclusionDurationMs); return null;
} }
/** /**
@ -153,4 +129,24 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
return minimumLoadableRetryCount; return minimumLoadableRetryCount;
} }
} }
/**
* Returns whether the error is considered recoverable.
*
* @param exception The exception.
* @return Whether the error is considered an recoverable error.
*/
protected boolean isRecoverableError(IOException exception) {
if (!(exception instanceof InvalidResponseCodeException)) {
return true;
}
InvalidResponseCodeException invalidResponseCodeException =
(InvalidResponseCodeException) exception;
return invalidResponseCodeException.responseCode != 403 // HTTP 403 Forbidden.
&& invalidResponseCodeException.responseCode != 404 // HTTP 404 Not Found.
&& invalidResponseCodeException.responseCode != 410 // HTTP 410 Gone.
&& invalidResponseCodeException.responseCode != 416 // HTTP 416 Range Not Satisfiable.
&& invalidResponseCodeException.responseCode != 500 // HTTP 500 Internal Server Error.
&& invalidResponseCodeException.responseCode != 503; // HTTP 503 Service Unavailable.
}
} }

View File

@ -15,7 +15,10 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
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;
@ -109,20 +112,28 @@ public interface LoadErrorHandlingPolicy {
this.numberOfTracks = numberOfTracks; this.numberOfTracks = numberOfTracks;
this.numberOfExcludedTracks = numberOfExcludedTracks; this.numberOfExcludedTracks = numberOfExcludedTracks;
} }
/** Returns whether a fallback is available for the given {@link FallbackType fallback type}. */
public boolean isFallbackAvailable(@FallbackType int type) {
return type == FALLBACK_TYPE_LOCATION
? numberOfLocations - numberOfExcludedLocations > 1
: numberOfTracks - numberOfExcludedTracks > 1;
}
} }
/** The selection of a fallback option determining the fallback behaviour on load error. */ /** The selection of a fallback option determining the fallback behaviour on load error. */
final class FallbackSelection { final class FallbackSelection {
/** The {@link FallbackType fallback type} to use. */ /** The {@link FallbackType fallback type} to use. */
@FallbackType public final int type; @FallbackType public final int type;
/** /** The exclusion duration of the {@link #type}, in milliseconds. */
* The exclusion duration of the {@link #type} in milliseconds, or {@link C#TIME_UNSET} to
* disable exclusion of any fallback type.
*/
public final long exclusionDurationMs; public final long exclusionDurationMs;
/** Creates an instance with the given values. */ /**
* Creates an instance with the given values. The exclusion duration, in milliseconds, needs to
* be a positive integer.
*/
public FallbackSelection(@FallbackType int type, long exclusionDurationMs) { public FallbackSelection(@FallbackType int type, long exclusionDurationMs) {
checkArgument(exclusionDurationMs >= 0);
this.type = type; this.type = type;
this.exclusionDurationMs = exclusionDurationMs; this.exclusionDurationMs = exclusionDurationMs;
} }
@ -130,20 +141,18 @@ public interface LoadErrorHandlingPolicy {
/** /**
* Returns the {@link FallbackSelection fallback selection} that determines the exclusion * Returns the {@link FallbackSelection fallback selection} that determines the exclusion
* behaviour on load error. * behaviour on load error. If null is returned the caller will disable exclusion.
* *
* <p>If {@link FallbackSelection#exclusionDurationMs} is {@link C#TIME_UNSET}, exclusion is * <p>If {@link FallbackSelection#type} is of a type that is not {@link
* disabled for any fallback type, regardless of the value of the {@link FallbackSelection#type * FallbackOptions#isFallbackAvailable(int) advertised as available}, then the caller will disable
* selected fallback type}. * exclusion as if null had been returned.
*
* <p>If {@link FallbackSelection#type} is of a type that is not advertised as available by the
* {@link FallbackOptions}, exclusion is disabled for any fallback type.
* *
* @param fallbackOptions The available fallback options. * @param fallbackOptions The available fallback options.
* @param loadErrorInfo A {@link LoadErrorInfo} holding information about the load error. * @param loadErrorInfo A {@link LoadErrorInfo} holding information about the load error.
* @return The fallback selection indicating whether to apply exclusion, and if so for which type * @return The fallback selection indicating which exclusion type to apply and for how long the
* and how long the resource should be excluded. * resource should be excluded. Returning null indicates to disable exclusion.
*/ */
@Nullable
FallbackSelection getFallbackSelectionFor( FallbackSelection getFallbackSelectionFor(
FallbackOptions fallbackOptions, LoadErrorInfo loadErrorInfo); FallbackOptions fallbackOptions, LoadErrorInfo loadErrorInfo);

View File

@ -16,13 +16,13 @@
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy.DEFAULT_LOCATION_EXCLUSION_MS; import static com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy.DEFAULT_LOCATION_EXCLUSION_MS;
import static com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT;
import static com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_EXCLUSION_MS; import static com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_EXCLUSION_MS;
import static com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION; import static com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION;
import static com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK; import static com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
@ -56,6 +56,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
public void getFallbackSelectionFor_responseCode403() { public void getFallbackSelectionFor_responseCode403() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(403, "Forbidden"); InvalidResponseCodeException exception = buildInvalidResponseCodeException(403, "Forbidden");
@Nullable
LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection = LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
exception, exception,
@ -83,6 +84,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
public void getFallbackSelectionFor_responseCode404() { public void getFallbackSelectionFor_responseCode404() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(404, "Not found"); InvalidResponseCodeException exception = buildInvalidResponseCodeException(404, "Not found");
@Nullable
LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection = LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
exception, exception,
@ -111,6 +113,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
public void getFallbackSelectionFor_responseCode410() { public void getFallbackSelectionFor_responseCode410() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(410, "Gone"); InvalidResponseCodeException exception = buildInvalidResponseCodeException(410, "Gone");
@Nullable
LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection = LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
exception, exception,
@ -140,6 +143,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
InvalidResponseCodeException exception = InvalidResponseCodeException exception =
buildInvalidResponseCodeException(500, "Internal server error"); buildInvalidResponseCodeException(500, "Internal server error");
@Nullable
LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection = LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
exception, exception,
@ -169,6 +173,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
InvalidResponseCodeException exception = InvalidResponseCodeException exception =
buildInvalidResponseCodeException(503, "Service unavailable"); buildInvalidResponseCodeException(503, "Service unavailable");
@Nullable
LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection = LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
exception, exception,
@ -197,6 +202,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
public void getFallbackSelectionFor_dontExcludeUnexpectedHttpCodes() { public void getFallbackSelectionFor_dontExcludeUnexpectedHttpCodes() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(418, "I'm a teapot"); InvalidResponseCodeException exception = buildInvalidResponseCodeException(418, "I'm a teapot");
@Nullable
LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection = LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
exception, exception,
@ -205,8 +211,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
/* numberOfTracks= */ 10, /* numberOfTracks= */ 10,
/* numberOfExcludedTracks= */ 0); /* numberOfExcludedTracks= */ 0);
assertThat(defaultPolicyFallbackSelection.type).isEqualTo(FALLBACK_TYPE_TRACK); assertThat(defaultPolicyFallbackSelection).isNull();
assertThat(defaultPolicyFallbackSelection.exclusionDurationMs).isEqualTo(C.TIME_UNSET);
defaultPolicyFallbackSelection = defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
@ -215,14 +220,14 @@ public final class DefaultLoadErrorHandlingPolicyTest {
/* numberOfExcludedLocations= */ 0, /* numberOfExcludedLocations= */ 0,
/* numberOfTracks= */ 4, /* numberOfTracks= */ 4,
/* numberOfExcludedTracks= */ 1); /* numberOfExcludedTracks= */ 1);
assertThat(defaultPolicyFallbackSelection.type).isEqualTo(FALLBACK_TYPE_LOCATION); assertThat(defaultPolicyFallbackSelection).isNull();
assertThat(defaultPolicyFallbackSelection.exclusionDurationMs).isEqualTo(C.TIME_UNSET);
} }
@Test @Test
public void getFallbackSelectionFor_dontExcludeUnexpectedExceptions() { public void getFallbackSelectionFor_dontExcludeUnexpectedExceptions() {
IOException exception = new IOException(); IOException exception = new IOException();
@Nullable
LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection = LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
exception, exception,
@ -231,8 +236,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
/* numberOfTracks= */ 10, /* numberOfTracks= */ 10,
/* numberOfExcludedTracks= */ 0); /* numberOfExcludedTracks= */ 0);
assertThat(defaultPolicyFallbackSelection.type).isEqualTo(FALLBACK_TYPE_TRACK); assertThat(defaultPolicyFallbackSelection).isNull();
assertThat(defaultPolicyFallbackSelection.exclusionDurationMs).isEqualTo(C.TIME_UNSET);
defaultPolicyFallbackSelection = defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection( getDefaultPolicyFallbackSelection(
@ -241,26 +245,7 @@ public final class DefaultLoadErrorHandlingPolicyTest {
/* numberOfExcludedLocations= */ 0, /* numberOfExcludedLocations= */ 0,
/* numberOfTracks= */ 4, /* numberOfTracks= */ 4,
/* numberOfExcludedTracks= */ 1); /* numberOfExcludedTracks= */ 1);
assertThat(defaultPolicyFallbackSelection.type).isEqualTo(FALLBACK_TYPE_LOCATION); assertThat(defaultPolicyFallbackSelection).isNull();
assertThat(defaultPolicyFallbackSelection.exclusionDurationMs).isEqualTo(C.TIME_UNSET);
}
@Test
public void getFallbackSelectionFor_disabledLocationExclusion_useTrackExclusion() {
InvalidResponseCodeException exception = buildInvalidResponseCodeException(404, "Not found");
LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection =
getDefaultPolicyFallbackSelection(
exception,
/* numberOfLocations= */ 2,
/* numberOfExcludedLocations= */ 0,
/* numberOfTracks= */ 4,
/* numberOfExcludedTracks= */ 1,
new DefaultLoadErrorHandlingPolicy(
DEFAULT_MIN_LOADABLE_RETRY_COUNT, /* locationExclusionEnabled= */ false));
assertThat(defaultPolicyFallbackSelection.type).isEqualTo(FALLBACK_TYPE_TRACK);
assertThat(defaultPolicyFallbackSelection.exclusionDurationMs)
.isEqualTo(DEFAULT_TRACK_EXCLUSION_MS);
} }
@Test @Test
@ -279,28 +264,13 @@ public final class DefaultLoadErrorHandlingPolicyTest {
assertThat(getDefaultPolicyRetryDelayOutputFor(new IOException(), 9)).isEqualTo(5000); assertThat(getDefaultPolicyRetryDelayOutputFor(new IOException(), 9)).isEqualTo(5000);
} }
@Nullable
private static LoadErrorHandlingPolicy.FallbackSelection getDefaultPolicyFallbackSelection( private static LoadErrorHandlingPolicy.FallbackSelection getDefaultPolicyFallbackSelection(
IOException exception, IOException exception,
int numberOfLocations, int numberOfLocations,
int numberOfExcludedLocations, int numberOfExcludedLocations,
int numberOfTracks, int numberOfTracks,
int numberOfExcludedTracks) { int numberOfExcludedTracks) {
return getDefaultPolicyFallbackSelection(
exception,
numberOfLocations,
numberOfExcludedLocations,
numberOfTracks,
numberOfExcludedTracks,
new DefaultLoadErrorHandlingPolicy());
}
private static LoadErrorHandlingPolicy.FallbackSelection getDefaultPolicyFallbackSelection(
IOException exception,
int numberOfLocations,
int numberOfExcludedLocations,
int numberOfTracks,
int numberOfExcludedTracks,
DefaultLoadErrorHandlingPolicy defaultLoadErrorHandlingPolicy) {
LoadErrorInfo loadErrorInfo = LoadErrorInfo loadErrorInfo =
new LoadErrorInfo( new LoadErrorInfo(
PLACEHOLDER_LOAD_EVENT_INFO, PLACEHOLDER_LOAD_EVENT_INFO,
@ -310,7 +280,8 @@ public final class DefaultLoadErrorHandlingPolicyTest {
LoadErrorHandlingPolicy.FallbackOptions fallbackOptions = LoadErrorHandlingPolicy.FallbackOptions fallbackOptions =
new LoadErrorHandlingPolicy.FallbackOptions( new LoadErrorHandlingPolicy.FallbackOptions(
numberOfLocations, numberOfExcludedLocations, numberOfTracks, numberOfExcludedTracks); numberOfLocations, numberOfExcludedLocations, numberOfTracks, numberOfExcludedTracks);
return defaultLoadErrorHandlingPolicy.getFallbackSelectionFor(fallbackOptions, loadErrorInfo); return new DefaultLoadErrorHandlingPolicy()
.getFallbackSelectionFor(fallbackOptions, loadErrorInfo);
} }
private static long getDefaultPolicyRetryDelayOutputFor(IOException exception, int errorCount) { private static long getDefaultPolicyRetryDelayOutputFor(IOException exception, int errorCount) {

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.dash; package com.google.android.exoplayer2.source.dash;
import static com.google.android.exoplayer2.trackselection.TrackSelectionUtil.createFallbackOptions; import static com.google.android.exoplayer2.trackselection.TrackSelectionUtil.createFallbackOptions;
import static com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -490,10 +491,11 @@ public class DefaultDashChunkSource implements DashChunkSource {
// No more alternative tracks remaining. // No more alternative tracks remaining.
return false; return false;
} }
@Nullable
LoadErrorHandlingPolicy.FallbackSelection fallbackSelection = LoadErrorHandlingPolicy.FallbackSelection fallbackSelection =
loadErrorHandlingPolicy.getFallbackSelectionFor(fallbackOptions, loadErrorInfo); loadErrorHandlingPolicy.getFallbackSelectionFor(fallbackOptions, loadErrorInfo);
return fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK return fallbackSelection != null
&& fallbackSelection.exclusionDurationMs != C.TIME_UNSET && fallbackSelection.type == FALLBACK_TYPE_TRACK
&& trackSelection.blacklist( && trackSelection.blacklist(
trackSelection.indexOf(chunk.trackFormat), fallbackSelection.exclusionDurationMs); trackSelection.indexOf(chunk.trackFormat), fallbackSelection.exclusionDurationMs);
} }

View File

@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
@ -186,10 +187,11 @@ public class DefaultDashChunkSourceTest {
DefaultLoadErrorHandlingPolicy loadErrorHandlingPolicy = DefaultLoadErrorHandlingPolicy loadErrorHandlingPolicy =
new DefaultLoadErrorHandlingPolicy() { new DefaultLoadErrorHandlingPolicy() {
@Override @Override
@Nullable
public FallbackSelection getFallbackSelectionFor( public FallbackSelection getFallbackSelectionFor(
FallbackOptions fallbackOptions, LoadErrorInfo loadErrorInfo) { FallbackOptions fallbackOptions, LoadErrorInfo loadErrorInfo) {
// Never exclude, neither tracks nor locations. // Never exclude, neither tracks nor locations.
return new FallbackSelection(FALLBACK_TYPE_TRACK, C.TIME_UNSET); return null;
} }
}; };
DashChunkSource chunkSource = createDashChunkSource(/* numberOfTracks= */ 2); DashChunkSource chunkSource = createDashChunkSource(/* numberOfTracks= */ 2);

View File

@ -562,13 +562,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} }
long exclusionDurationMs = C.TIME_UNSET; long exclusionDurationMs = C.TIME_UNSET;
if (!forceRetry) { if (!forceRetry) {
@Nullable
LoadErrorHandlingPolicy.FallbackSelection fallbackSelection = LoadErrorHandlingPolicy.FallbackSelection fallbackSelection =
loadErrorHandlingPolicy.getFallbackSelectionFor( loadErrorHandlingPolicy.getFallbackSelectionFor(
createFallbackOptions(chunkSource.getTrackSelection()), loadErrorInfo); createFallbackOptions(chunkSource.getTrackSelection()), loadErrorInfo);
exclusionDurationMs = if (fallbackSelection != null
fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK && fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK) {
? fallbackSelection.exclusionDurationMs exclusionDurationMs = fallbackSelection.exclusionDurationMs;
: C.TIME_UNSET; }
} }
return chunkSource.onPlaylistError(playlistUrl, exclusionDurationMs); return chunkSource.onPlaylistError(playlistUrl, exclusionDurationMs);
} }
@ -909,11 +910,12 @@ 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;
@Nullable
LoadErrorHandlingPolicy.FallbackSelection fallbackSelection = LoadErrorHandlingPolicy.FallbackSelection fallbackSelection =
loadErrorHandlingPolicy.getFallbackSelectionFor( loadErrorHandlingPolicy.getFallbackSelectionFor(
createFallbackOptions(chunkSource.getTrackSelection()), loadErrorInfo); createFallbackOptions(chunkSource.getTrackSelection()), loadErrorInfo);
if (fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK if (fallbackSelection != null
&& fallbackSelection.exclusionDurationMs != C.TIME_UNSET) { && fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK) {
exclusionSucceeded = exclusionSucceeded =
chunkSource.maybeExcludeTrack(loadable, fallbackSelection.exclusionDurationMs); chunkSource.maybeExcludeTrack(loadable, fallbackSelection.exclusionDurationMs);
} }

View File

@ -290,12 +290,13 @@ public class DefaultSsChunkSource implements SsChunkSource {
boolean cancelable, boolean cancelable,
LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo, LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo,
LoadErrorHandlingPolicy loadErrorHandlingPolicy) { LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
@Nullable
FallbackSelection fallbackSelection = FallbackSelection fallbackSelection =
loadErrorHandlingPolicy.getFallbackSelectionFor( loadErrorHandlingPolicy.getFallbackSelectionFor(
createFallbackOptions(trackSelection), loadErrorInfo); createFallbackOptions(trackSelection), loadErrorInfo);
return cancelable return cancelable
&& fallbackSelection != null
&& fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK && fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK
&& fallbackSelection.exclusionDurationMs != C.TIME_UNSET
&& trackSelection.blacklist( && trackSelection.blacklist(
trackSelection.indexOf(chunk.trackFormat), fallbackSelection.exclusionDurationMs); trackSelection.indexOf(chunk.trackFormat), fallbackSelection.exclusionDurationMs);
} }

View File

@ -177,8 +177,7 @@ public class FakeAdaptiveMediaPeriod
positionUs, positionUs,
DrmSessionManager.DRM_UNSUPPORTED, DrmSessionManager.DRM_UNSUPPORTED,
new DrmSessionEventListener.EventDispatcher(), new DrmSessionEventListener.EventDispatcher(),
new DefaultLoadErrorHandlingPolicy( new DefaultLoadErrorHandlingPolicy(/* minimumLoadableRetryCount= */ 3),
/* minimumLoadableRetryCount= */ 3, /* locationExclusionEnabled= */ true),
mediaSourceEventDispatcher); mediaSourceEventDispatcher);
streams[i] = sampleStream; streams[i] = sampleStream;
sampleStreams.add(sampleStream); sampleStreams.add(sampleStream);