Allow configuration of the Loader retry delay
Issue:#3370 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=201996109
This commit is contained in:
parent
eb8c686243
commit
a1f89bec0d
@ -13,6 +13,9 @@
|
|||||||
([#3972](https://github.com/google/ExoPlayer/issues/3972)).
|
([#3972](https://github.com/google/ExoPlayer/issues/3972)).
|
||||||
* Pass `BandwidthMeter` to `TrackSelection.Factory` which can be used to obtain
|
* Pass `BandwidthMeter` to `TrackSelection.Factory` which can be used to obtain
|
||||||
bandwidth estimates in the future. Always null at the moment.
|
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:
|
* HLS:
|
||||||
* Allow injection of custom playlist trackers.
|
* Allow injection of custom playlist trackers.
|
||||||
* Pass HTTP response headers to `HlsExtractorFactory.createExtractor`.
|
* Pass HTTP response headers to `HlsExtractorFactory.createExtractor`.
|
||||||
|
@ -38,6 +38,7 @@ import com.google.android.exoplayer2.upstream.Allocator;
|
|||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
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.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.ConditionVariable;
|
import com.google.android.exoplayer2.util.ConditionVariable;
|
||||||
@ -532,7 +533,7 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
ExtractingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) {
|
ExtractingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) {
|
||||||
boolean isErrorFatal = isLoadableExceptionFatal(error);
|
boolean isErrorFatal = isLoadableExceptionFatal(error);
|
||||||
eventDispatcher.loadError(
|
eventDispatcher.loadError(
|
||||||
|
@ -25,6 +25,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelection;
|
|||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
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.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
@ -228,7 +229,7 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) {
|
SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) {
|
||||||
errorCount++;
|
errorCount++;
|
||||||
boolean cancel = treatLoadErrorsAsEndOfStream && errorCount >= minLoadableRetryCount;
|
boolean cancel = treatLoadErrorsAsEndOfStream && errorCount >= minLoadableRetryCount;
|
||||||
|
@ -28,6 +28,7 @@ import com.google.android.exoplayer2.source.SampleStream;
|
|||||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
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.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -409,7 +410,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) {
|
Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) {
|
||||||
long bytesLoaded = loadable.bytesLoaded();
|
long bytesLoaded = loadable.bytesLoaded();
|
||||||
boolean isMediaChunk = isMediaChunk(loadable);
|
boolean isMediaChunk = isMediaChunk(loadable);
|
||||||
|
@ -23,6 +23,7 @@ import android.os.SystemClock;
|
|||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.TraceUtil;
|
import com.google.android.exoplayer2.util.TraceUtil;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
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 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 loadDurationMs The duration of the load up to the point at which the error occurred.
|
||||||
* @param error The load error.
|
* @param error The load error.
|
||||||
* @return The desired retry action. One of {@link Loader#RETRY}, {@link
|
* @return The desired error handling action. One of {@link Loader#RETRY}, {@link
|
||||||
* Loader#RETRY_RESET_ERROR_COUNT}, {@link Loader#DONT_RETRY} and {@link
|
* Loader#RETRY_RESET_ERROR_COUNT}, {@link Loader#DONT_RETRY}, {@link
|
||||||
* Loader#DONT_RETRY_FATAL}.
|
* Loader#DONT_RETRY_FATAL} or a retry action created by {@link #createRetryAction}.
|
||||||
*/
|
*/
|
||||||
@RetryAction
|
LoadErrorAction onLoadError(
|
||||||
int onLoadError(T loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error);
|
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)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({RETRY, RETRY_RESET_ERROR_COUNT, DONT_RETRY, DONT_RETRY_FATAL})
|
@IntDef({
|
||||||
public @interface RetryAction {}
|
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;
|
private static final int ACTION_TYPE_RETRY = 0;
|
||||||
public static final int RETRY_RESET_ERROR_COUNT = 1;
|
private static final int ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT = 1;
|
||||||
public static final int DONT_RETRY = 2;
|
private static final int ACTION_TYPE_DONT_RETRY = 2;
|
||||||
public static final int DONT_RETRY_FATAL = 3;
|
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;
|
private final ExecutorService downloadExecutorService;
|
||||||
|
|
||||||
@ -152,6 +189,19 @@ public final class Loader implements LoaderErrorThrower {
|
|||||||
this.downloadExecutorService = Util.newSingleThreadExecutor(threadName);
|
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}.
|
* Starts loading a {@link Loadable}.
|
||||||
*
|
*
|
||||||
@ -395,12 +445,16 @@ public final class Loader implements LoaderErrorThrower {
|
|||||||
break;
|
break;
|
||||||
case MSG_IO_EXCEPTION:
|
case MSG_IO_EXCEPTION:
|
||||||
currentError = (IOException) msg.obj;
|
currentError = (IOException) msg.obj;
|
||||||
int retryAction = callback.onLoadError(loadable, nowMs, durationMs, currentError);
|
LoadErrorAction action = callback.onLoadError(loadable, nowMs, durationMs, currentError);
|
||||||
if (retryAction == DONT_RETRY_FATAL) {
|
if (action.type == ACTION_TYPE_DONT_RETRY_FATAL) {
|
||||||
fatalError = currentError;
|
fatalError = currentError;
|
||||||
} else if (retryAction != DONT_RETRY) {
|
} else if (action.type != ACTION_TYPE_DONT_RETRY) {
|
||||||
errorCount = retryAction == RETRY_RESET_ERROR_COUNT ? 1 : errorCount + 1;
|
errorCount =
|
||||||
start(getRetryDelayMillis());
|
action.type == ACTION_TYPE_RETRY_AND_RESET_ERROR_COUNT ? 1 : errorCount + 1;
|
||||||
|
start(
|
||||||
|
action.retryDelayMillis != C.TIME_UNSET
|
||||||
|
? action.retryDelayMillis
|
||||||
|
: getRetryDelayMillis());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -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.Allocator;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
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.LoaderErrorThrower;
|
||||||
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
@ -716,8 +717,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ @Loader.RetryAction
|
/* package */ LoadErrorAction onManifestLoadError(
|
||||||
int onManifestLoadError(
|
|
||||||
ParsingLoadable<DashManifest> loadable,
|
ParsingLoadable<DashManifest> loadable,
|
||||||
long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
long loadDurationMs,
|
long loadDurationMs,
|
||||||
@ -745,8 +745,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
onUtcTimestampResolved(loadable.getResult() - elapsedRealtimeMs);
|
onUtcTimestampResolved(loadable.getResult() - elapsedRealtimeMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ @Loader.RetryAction
|
/* package */ LoadErrorAction onUtcTimestampLoadError(
|
||||||
int onUtcTimestampLoadError(
|
|
||||||
ParsingLoadable<Long> loadable,
|
ParsingLoadable<Long> loadable,
|
||||||
long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
long loadDurationMs,
|
long loadDurationMs,
|
||||||
@ -1172,7 +1171,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
ParsingLoadable<DashManifest> loadable,
|
ParsingLoadable<DashManifest> loadable,
|
||||||
long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
long loadDurationMs,
|
long loadDurationMs,
|
||||||
@ -1197,7 +1196,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
ParsingLoadable<Long> loadable,
|
ParsingLoadable<Long> loadable,
|
||||||
long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
long loadDurationMs,
|
long loadDurationMs,
|
||||||
|
@ -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.trackselection.TrackSelection;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
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.Assertions;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
@ -602,7 +603,7 @@ import java.util.Arrays;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) {
|
Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error) {
|
||||||
long bytesLoaded = loadable.bytesLoaded();
|
long bytesLoaded = loadable.bytesLoaded();
|
||||||
boolean isMediaChunk = isMediaChunk(loadable);
|
boolean isMediaChunk = isMediaChunk(loadable);
|
||||||
|
@ -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.source.hls.playlist.HlsMediaPlaylist.Segment;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
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.upstream.ParsingLoadable;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.UriUtil;
|
import com.google.android.exoplayer2.util.UriUtil;
|
||||||
@ -229,7 +230,7 @@ public final class DefaultHlsPlaylistTracker
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
ParsingLoadable<HlsPlaylist> loadable,
|
ParsingLoadable<HlsPlaylist> loadable,
|
||||||
long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
long loadDurationMs,
|
long loadDurationMs,
|
||||||
@ -485,7 +486,7 @@ public final class DefaultHlsPlaylistTracker
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
ParsingLoadable<HlsPlaylist> loadable,
|
ParsingLoadable<HlsPlaylist> loadable,
|
||||||
long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
long loadDurationMs,
|
long loadDurationMs,
|
||||||
|
@ -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.Allocator;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
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.LoaderErrorThrower;
|
||||||
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
@ -540,7 +541,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Loader.RetryAction int onLoadError(
|
public LoadErrorAction onLoadError(
|
||||||
ParsingLoadable<SsManifest> loadable,
|
ParsingLoadable<SsManifest> loadable,
|
||||||
long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
long loadDurationMs,
|
long loadDurationMs,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user