From a1f89bec0dcc30bdc2f3a8889371447f701ae9b7 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Mon, 25 Jun 2018 12:09:27 -0700 Subject: [PATCH] Allow configuration of the Loader retry delay Issue:#3370 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=201996109 --- RELEASENOTES.md | 3 + .../source/ExtractorMediaPeriod.java | 3 +- .../source/SingleSampleMediaPeriod.java | 3 +- .../source/chunk/ChunkSampleStream.java | 3 +- .../android/exoplayer2/upstream/Loader.java | 88 +++++++++++++++---- .../source/dash/DashMediaSource.java | 11 ++- .../source/hls/HlsSampleStreamWrapper.java | 3 +- .../playlist/DefaultHlsPlaylistTracker.java | 5 +- .../source/smoothstreaming/SsMediaSource.java | 3 +- 9 files changed, 92 insertions(+), 30 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b9fdaf0b60..1a31fb06cf 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -13,6 +13,9 @@ ([#3972](https://github.com/google/ExoPlayer/issues/3972)). * Pass `BandwidthMeter` to `TrackSelection.Factory` which can be used to obtain bandwidth estimates in the future. Always null at the moment. +* Error handling: + * Allow configuration of the Loader retry delay + ([#3370](https://github.com/google/ExoPlayer/issues/3370)). * HLS: * Allow injection of custom playlist trackers. * Pass HTTP response headers to `HlsExtractorFactory.createExtractor`. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 63c86c2c96..8719ec1660 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -38,6 +38,7 @@ import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; import com.google.android.exoplayer2.upstream.Loader.Loadable; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.ConditionVariable; @@ -532,7 +533,7 @@ import java.util.Arrays; } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ExtractingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) { boolean isErrorFatal = isLoadableExceptionFatal(error); eventDispatcher.loadError( diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java index 41814c4b40..33bae0bd4d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java @@ -25,6 +25,7 @@ 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.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; import com.google.android.exoplayer2.upstream.Loader.Loadable; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; @@ -228,7 +229,7 @@ import java.util.Arrays; } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) { errorCount++; boolean cancel = treatLoadErrorsAsEndOfStream && errorCount >= minLoadableRetryCount; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index 6cda68bac9..5afcf9a564 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -28,6 +28,7 @@ import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SequenceableLoader; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; import java.io.IOException; @@ -409,7 +410,7 @@ public class ChunkSampleStream implements SampleStream, S } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) { long bytesLoaded = loadable.bytesLoaded(); boolean isMediaChunk = isMediaChunk(loadable); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java index 430948c875..6c6b2708cb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java @@ -23,6 +23,7 @@ import android.os.SystemClock; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.util.Log; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; @@ -110,12 +111,12 @@ public final class Loader implements LoaderErrorThrower { * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the error occurred. * @param loadDurationMs The duration of the load up to the point at which the error occurred. * @param error The load error. - * @return The desired retry action. One of {@link Loader#RETRY}, {@link - * Loader#RETRY_RESET_ERROR_COUNT}, {@link Loader#DONT_RETRY} and {@link - * Loader#DONT_RETRY_FATAL}. + * @return The desired error handling action. One of {@link Loader#RETRY}, {@link + * Loader#RETRY_RESET_ERROR_COUNT}, {@link Loader#DONT_RETRY}, {@link + * Loader#DONT_RETRY_FATAL} or a retry action created by {@link #createRetryAction}. */ - @RetryAction - int onLoadError(T loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error); + LoadErrorAction onLoadError( + T loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error); } /** @@ -130,15 +131,51 @@ public final class Loader implements LoaderErrorThrower { } - /** Actions that can be taken in response to a load error. */ + /** Types of action that can be taken in response to a load error. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({RETRY, RETRY_RESET_ERROR_COUNT, DONT_RETRY, DONT_RETRY_FATAL}) - public @interface RetryAction {} + @IntDef({ + ACTION_TYPE_RETRY, + ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT, + ACTION_TYPE_DONT_RETRY, + ACTION_TYPE_DONT_RETRY_FATAL + }) + private @interface RetryActionType {} - public static final int RETRY = 0; - public static final int RETRY_RESET_ERROR_COUNT = 1; - public static final int DONT_RETRY = 2; - public static final int DONT_RETRY_FATAL = 3; + private static final int ACTION_TYPE_RETRY = 0; + private static final int ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT = 1; + private static final int ACTION_TYPE_DONT_RETRY = 2; + private static final int ACTION_TYPE_DONT_RETRY_FATAL = 3; + + /** Retries the load using the default delay. */ + public static final LoadErrorAction RETRY = + createRetryAction(/* resetErrorCount= */ false, C.TIME_UNSET); + /** Retries the load using the default delay and resets the error count. */ + public static final LoadErrorAction RETRY_RESET_ERROR_COUNT = + createRetryAction(/* resetErrorCount= */ true, C.TIME_UNSET); + /** Discards the failed loading task and ignores any errors that have occurred. */ + public static final LoadErrorAction DONT_RETRY = + new LoadErrorAction(ACTION_TYPE_DONT_RETRY, C.TIME_UNSET); + /** + * Discards the failed load. The next call to {@link #maybeThrowError()} will throw the last load + * error. + */ + public static final LoadErrorAction DONT_RETRY_FATAL = + new LoadErrorAction(ACTION_TYPE_DONT_RETRY_FATAL, C.TIME_UNSET); + + /** + * Action that can be taken in response to {@link Callback#onLoadError(Loadable, long, long, + * IOException)}. + */ + public static final class LoadErrorAction { + + private final @RetryActionType int type; + private final long retryDelayMillis; + + private LoadErrorAction(@RetryActionType int type, long retryDelayMillis) { + this.type = type; + this.retryDelayMillis = retryDelayMillis; + } + } private final ExecutorService downloadExecutorService; @@ -152,6 +189,19 @@ public final class Loader implements LoaderErrorThrower { this.downloadExecutorService = Util.newSingleThreadExecutor(threadName); } + /** + * Creates a {@link LoadErrorAction} for retrying with the given parameters. + * + * @param resetErrorCount Whether the previous error count should be set to zero. + * @param retryDelayMillis The number of milliseconds to wait before retrying. + * @return A {@link LoadErrorAction} for retrying with the given parameters. + */ + public static LoadErrorAction createRetryAction(boolean resetErrorCount, long retryDelayMillis) { + return new LoadErrorAction( + resetErrorCount ? ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT : ACTION_TYPE_RETRY, + retryDelayMillis); + } + /** * Starts loading a {@link Loadable}. * @@ -395,12 +445,16 @@ public final class Loader implements LoaderErrorThrower { break; case MSG_IO_EXCEPTION: currentError = (IOException) msg.obj; - int retryAction = callback.onLoadError(loadable, nowMs, durationMs, currentError); - if (retryAction == DONT_RETRY_FATAL) { + LoadErrorAction action = callback.onLoadError(loadable, nowMs, durationMs, currentError); + if (action.type == ACTION_TYPE_DONT_RETRY_FATAL) { fatalError = currentError; - } else if (retryAction != DONT_RETRY) { - errorCount = retryAction == RETRY_RESET_ERROR_COUNT ? 1 : errorCount + 1; - start(getRetryDelayMillis()); + } else if (action.type != ACTION_TYPE_DONT_RETRY) { + errorCount = + action.type == ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT ? 1 : errorCount + 1; + start( + action.retryDelayMillis != C.TIME_UNSET + ? action.retryDelayMillis + : getRetryDelayMillis()); } break; default: diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 7b854e9d29..f30375823c 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -43,6 +43,7 @@ import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; import com.google.android.exoplayer2.upstream.LoaderErrorThrower; import com.google.android.exoplayer2.upstream.ParsingLoadable; import com.google.android.exoplayer2.util.Assertions; @@ -716,8 +717,7 @@ public final class DashMediaSource extends BaseMediaSource { } } - /* package */ @Loader.RetryAction - int onManifestLoadError( + /* package */ LoadErrorAction onManifestLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, @@ -745,8 +745,7 @@ public final class DashMediaSource extends BaseMediaSource { onUtcTimestampResolved(loadable.getResult() - elapsedRealtimeMs); } - /* package */ @Loader.RetryAction - int onUtcTimestampLoadError( + /* package */ LoadErrorAction onUtcTimestampLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, @@ -1172,7 +1171,7 @@ public final class DashMediaSource extends BaseMediaSource { } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, @@ -1197,7 +1196,7 @@ public final class DashMediaSource extends BaseMediaSource { } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, 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 705320bdad..079df69ffe 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 @@ -40,6 +40,7 @@ import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUr import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; @@ -602,7 +603,7 @@ import java.util.Arrays; } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) { long bytesLoaded = loadable.bytesLoaded(); boolean isMediaChunk = isMediaChunk(loadable); 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 014a302de7..40f260d509 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 @@ -27,6 +27,7 @@ import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUr import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; import com.google.android.exoplayer2.upstream.ParsingLoadable; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.UriUtil; @@ -229,7 +230,7 @@ public final class DefaultHlsPlaylistTracker } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, @@ -485,7 +486,7 @@ public final class DefaultHlsPlaylistTracker } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index 72d1ba1efd..a0b31ae494 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -41,6 +41,7 @@ import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsUtil; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.Loader; +import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction; import com.google.android.exoplayer2.upstream.LoaderErrorThrower; import com.google.android.exoplayer2.upstream.ParsingLoadable; import com.google.android.exoplayer2.util.Assertions; @@ -540,7 +541,7 @@ public final class SsMediaSource extends BaseMediaSource } @Override - public @Loader.RetryAction int onLoadError( + public LoadErrorAction onLoadError( ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs,