mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Use LoadErrorHandlingPolicy in SsMediaSource and DashMediaSource
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=208020030
This commit is contained in:
parent
4ebc455c09
commit
d5c7bff643
@ -178,11 +178,6 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The default minimum number of times to retry loading data prior to failing.
|
|
||||||
*/
|
|
||||||
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
|
|
||||||
|
|
||||||
private final DataSpec dataSpec;
|
private final DataSpec dataSpec;
|
||||||
private final DataSource.Factory dataSourceFactory;
|
private final DataSource.Factory dataSourceFactory;
|
||||||
private final Format format;
|
private final Format format;
|
||||||
@ -204,7 +199,12 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public SingleSampleMediaSource(
|
public SingleSampleMediaSource(
|
||||||
Uri uri, DataSource.Factory dataSourceFactory, Format format, long durationUs) {
|
Uri uri, DataSource.Factory dataSourceFactory, Format format, long durationUs) {
|
||||||
this(uri, dataSourceFactory, format, durationUs, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
this(
|
||||||
|
uri,
|
||||||
|
dataSourceFactory,
|
||||||
|
format,
|
||||||
|
durationUs,
|
||||||
|
DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +27,8 @@ import com.google.android.exoplayer2.source.SampleQueue;
|
|||||||
import com.google.android.exoplayer2.source.SampleStream;
|
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.DefaultLoadErrorHandlingPolicy;
|
||||||
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
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.LoadErrorAction;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
@ -64,7 +66,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
private final T chunkSource;
|
private final T chunkSource;
|
||||||
private final SequenceableLoader.Callback<ChunkSampleStream<T>> callback;
|
private final SequenceableLoader.Callback<ChunkSampleStream<T>> callback;
|
||||||
private final EventDispatcher eventDispatcher;
|
private final EventDispatcher eventDispatcher;
|
||||||
private final int minLoadableRetryCount;
|
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private final Loader loader;
|
private final Loader loader;
|
||||||
private final ChunkHolder nextChunkHolder;
|
private final ChunkHolder nextChunkHolder;
|
||||||
private final ArrayList<BaseMediaChunk> mediaChunks;
|
private final ArrayList<BaseMediaChunk> mediaChunks;
|
||||||
@ -81,6 +83,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
/* package */ boolean loadingFinished;
|
/* package */ boolean loadingFinished;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Constructs an instance.
|
||||||
|
*
|
||||||
* @param primaryTrackType The type of the primary track. One of the {@link C} {@code
|
* @param primaryTrackType The type of the primary track. One of the {@link C} {@code
|
||||||
* TRACK_TYPE_*} constants.
|
* TRACK_TYPE_*} constants.
|
||||||
* @param embeddedTrackTypes The types of any embedded tracks, or null.
|
* @param embeddedTrackTypes The types of any embedded tracks, or null.
|
||||||
@ -92,7 +96,10 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
* @param minLoadableRetryCount The minimum number of times that the source should retry a load
|
* @param minLoadableRetryCount The minimum number of times that the source should retry a load
|
||||||
* before propagating an error.
|
* before propagating an error.
|
||||||
* @param eventDispatcher A dispatcher to notify of events.
|
* @param eventDispatcher A dispatcher to notify of events.
|
||||||
|
* @deprecated Use {@link #ChunkSampleStream(int, int[], Format[], ChunkSource, Callback,
|
||||||
|
* Allocator, long, LoadErrorHandlingPolicy, EventDispatcher)} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public ChunkSampleStream(
|
public ChunkSampleStream(
|
||||||
int primaryTrackType,
|
int primaryTrackType,
|
||||||
int[] embeddedTrackTypes,
|
int[] embeddedTrackTypes,
|
||||||
@ -103,13 +110,49 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
long positionUs,
|
long positionUs,
|
||||||
int minLoadableRetryCount,
|
int minLoadableRetryCount,
|
||||||
EventDispatcher eventDispatcher) {
|
EventDispatcher eventDispatcher) {
|
||||||
|
this(
|
||||||
|
primaryTrackType,
|
||||||
|
embeddedTrackTypes,
|
||||||
|
embeddedTrackFormats,
|
||||||
|
chunkSource,
|
||||||
|
callback,
|
||||||
|
allocator,
|
||||||
|
positionUs,
|
||||||
|
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||||
|
eventDispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance.
|
||||||
|
*
|
||||||
|
* @param primaryTrackType The type of the primary track. One of the {@link C} {@code
|
||||||
|
* TRACK_TYPE_*} constants.
|
||||||
|
* @param embeddedTrackTypes The types of any embedded tracks, or null.
|
||||||
|
* @param embeddedTrackFormats The formats of the embedded tracks, or null.
|
||||||
|
* @param chunkSource A {@link ChunkSource} from which chunks to load are obtained.
|
||||||
|
* @param callback An {@link Callback} for the stream.
|
||||||
|
* @param allocator An {@link Allocator} from which allocations can be obtained.
|
||||||
|
* @param positionUs The position from which to start loading media.
|
||||||
|
* @param loadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy}.
|
||||||
|
* @param eventDispatcher A dispatcher to notify of events.
|
||||||
|
*/
|
||||||
|
public ChunkSampleStream(
|
||||||
|
int primaryTrackType,
|
||||||
|
int[] embeddedTrackTypes,
|
||||||
|
Format[] embeddedTrackFormats,
|
||||||
|
T chunkSource,
|
||||||
|
Callback<ChunkSampleStream<T>> callback,
|
||||||
|
Allocator allocator,
|
||||||
|
long positionUs,
|
||||||
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||||
|
EventDispatcher eventDispatcher) {
|
||||||
this.primaryTrackType = primaryTrackType;
|
this.primaryTrackType = primaryTrackType;
|
||||||
this.embeddedTrackTypes = embeddedTrackTypes;
|
this.embeddedTrackTypes = embeddedTrackTypes;
|
||||||
this.embeddedTrackFormats = embeddedTrackFormats;
|
this.embeddedTrackFormats = embeddedTrackFormats;
|
||||||
this.chunkSource = chunkSource;
|
this.chunkSource = chunkSource;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.eventDispatcher = eventDispatcher;
|
this.eventDispatcher = eventDispatcher;
|
||||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||||
loader = new Loader("Loader:ChunkSampleStream");
|
loader = new Loader("Loader:ChunkSampleStream");
|
||||||
nextChunkHolder = new ChunkHolder();
|
nextChunkHolder = new ChunkHolder();
|
||||||
mediaChunks = new ArrayList<>();
|
mediaChunks = new ArrayList<>();
|
||||||
@ -439,12 +482,15 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
int lastChunkIndex = mediaChunks.size() - 1;
|
int lastChunkIndex = mediaChunks.size() - 1;
|
||||||
boolean cancelable =
|
boolean cancelable =
|
||||||
bytesLoaded == 0 || !isMediaChunk || !haveReadFromMediaChunk(lastChunkIndex);
|
bytesLoaded == 0 || !isMediaChunk || !haveReadFromMediaChunk(lastChunkIndex);
|
||||||
boolean canceled = false;
|
long blacklistDurationMs =
|
||||||
if (chunkSource.onChunkLoadError(loadable, cancelable, error)) {
|
cancelable
|
||||||
if (!cancelable) {
|
? loadErrorHandlingPolicy.getBlacklistDurationMsFor(
|
||||||
Log.w(TAG, "Ignoring attempt to cancel non-cancelable load.");
|
loadable.type, loadDurationMs, error, errorCount)
|
||||||
} else {
|
: C.TIME_UNSET;
|
||||||
canceled = true;
|
LoadErrorAction loadErrorAction = null;
|
||||||
|
if (chunkSource.onChunkLoadError(loadable, cancelable, error, blacklistDurationMs)) {
|
||||||
|
if (cancelable) {
|
||||||
|
loadErrorAction = Loader.DONT_RETRY;
|
||||||
if (isMediaChunk) {
|
if (isMediaChunk) {
|
||||||
BaseMediaChunk removed = discardUpstreamMediaChunksFromIndex(lastChunkIndex);
|
BaseMediaChunk removed = discardUpstreamMediaChunksFromIndex(lastChunkIndex);
|
||||||
Assertions.checkState(removed == loadable);
|
Assertions.checkState(removed == loadable);
|
||||||
@ -452,8 +498,23 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
pendingResetPositionUs = lastSeekPositionUs;
|
pendingResetPositionUs = lastSeekPositionUs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Ignoring attempt to cancel non-cancelable load.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loadErrorAction == null) {
|
||||||
|
// The load was not cancelled. Either the load must be retried or the error propagated.
|
||||||
|
long retryDelayMs =
|
||||||
|
loadErrorHandlingPolicy.getRetryDelayMsFor(
|
||||||
|
loadable.type, loadDurationMs, error, errorCount);
|
||||||
|
loadErrorAction =
|
||||||
|
retryDelayMs != C.TIME_UNSET
|
||||||
|
? Loader.createRetryAction(/* resetErrorCount= */ false, retryDelayMs)
|
||||||
|
: Loader.DONT_RETRY_FATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canceled = !loadErrorAction.isRetry();
|
||||||
eventDispatcher.loadError(
|
eventDispatcher.loadError(
|
||||||
loadable.dataSpec,
|
loadable.dataSpec,
|
||||||
loadable.getUri(),
|
loadable.getUri(),
|
||||||
@ -471,10 +532,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
canceled);
|
canceled);
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
callback.onContinueLoadingRequested(this);
|
callback.onContinueLoadingRequested(this);
|
||||||
return Loader.DONT_RETRY;
|
|
||||||
} else {
|
|
||||||
return Loader.RETRY;
|
|
||||||
}
|
}
|
||||||
|
return loadErrorAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SequenceableLoader implementation
|
// SequenceableLoader implementation
|
||||||
@ -521,7 +580,9 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
mediaChunk.init(mediaChunkOutput);
|
mediaChunk.init(mediaChunkOutput);
|
||||||
mediaChunks.add(mediaChunk);
|
mediaChunks.add(mediaChunk);
|
||||||
}
|
}
|
||||||
long elapsedRealtimeMs = loader.startLoading(loadable, this, minLoadableRetryCount);
|
long elapsedRealtimeMs =
|
||||||
|
loader.startLoading(
|
||||||
|
loadable, this, loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type));
|
||||||
eventDispatcher.loadStarted(
|
eventDispatcher.loadStarted(
|
||||||
loadable.dataSpec,
|
loadable.dataSpec,
|
||||||
loadable.dataSpec.uri,
|
loadable.dataSpec.uri,
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.chunk;
|
package com.google.android.exoplayer2.source.chunk;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.SeekParameters;
|
import com.google.android.exoplayer2.SeekParameters;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -83,8 +84,8 @@ public interface ChunkSource {
|
|||||||
/**
|
/**
|
||||||
* Called when the {@link ChunkSampleStream} has finished loading a chunk obtained from this
|
* Called when the {@link ChunkSampleStream} has finished loading a chunk obtained from this
|
||||||
* source.
|
* source.
|
||||||
* <p>
|
*
|
||||||
* This method should only be called when the source is enabled.
|
* <p>This method should only be called when the source is enabled.
|
||||||
*
|
*
|
||||||
* @param chunk The chunk whose load has been completed.
|
* @param chunk The chunk whose load has been completed.
|
||||||
*/
|
*/
|
||||||
@ -93,15 +94,15 @@ public interface ChunkSource {
|
|||||||
/**
|
/**
|
||||||
* Called when the {@link ChunkSampleStream} encounters an error loading a chunk obtained from
|
* Called when the {@link ChunkSampleStream} encounters an error loading a chunk obtained from
|
||||||
* this source.
|
* this source.
|
||||||
* <p>
|
*
|
||||||
* This method should only be called when the source is enabled.
|
* <p>This method should only be called when the source is enabled.
|
||||||
*
|
*
|
||||||
* @param chunk The chunk whose load encountered the error.
|
* @param chunk The chunk whose load encountered the error.
|
||||||
* @param cancelable Whether the load can be canceled.
|
* @param cancelable Whether the load can be canceled.
|
||||||
* @param e The error.
|
* @param e The error.
|
||||||
* @return Whether the load should be canceled. Should always be false if {@code cancelable} is
|
* @param blacklistDurationMs The duration for which the associated track may be blacklisted, or
|
||||||
* false.
|
* {@link C#TIME_UNSET} if the track may not be blacklisted.
|
||||||
|
* @return Whether the load should be canceled. Must be false if {@code cancelable} is false.
|
||||||
*/
|
*/
|
||||||
boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e);
|
boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e, long blacklistDurationMs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.exoplayer2.source.chunk;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
|
||||||
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for blacklisting tracks in a {@link TrackSelection} when 404 (Not Found) and 410
|
|
||||||
* (Gone) HTTP response codes are encountered.
|
|
||||||
*/
|
|
||||||
public final class ChunkedTrackBlacklistUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default duration for which a track is blacklisted in milliseconds.
|
|
||||||
*/
|
|
||||||
public static final long DEFAULT_TRACK_BLACKLIST_MS = 60000;
|
|
||||||
|
|
||||||
private static final String TAG = "ChunkedTrackBlacklist";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Blacklists {@code trackSelectionIndex} in {@code trackSelection} for
|
|
||||||
* {@link #DEFAULT_TRACK_BLACKLIST_MS} if {@code e} is an {@link InvalidResponseCodeException}
|
|
||||||
* with {@link InvalidResponseCodeException#responseCode} equal to 404 or 410. Else does nothing.
|
|
||||||
* Note that blacklisting will fail if the track is the only non-blacklisted track in the
|
|
||||||
* selection.
|
|
||||||
*
|
|
||||||
* @param trackSelection The track selection.
|
|
||||||
* @param trackSelectionIndex The index in the selection to consider blacklisting.
|
|
||||||
* @param e The error to inspect.
|
|
||||||
* @return Whether the track was blacklisted in the selection.
|
|
||||||
*/
|
|
||||||
public static boolean maybeBlacklistTrack(TrackSelection trackSelection, int trackSelectionIndex,
|
|
||||||
Exception e) {
|
|
||||||
return maybeBlacklistTrack(trackSelection, trackSelectionIndex, e, DEFAULT_TRACK_BLACKLIST_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Blacklists {@code trackSelectionIndex} in {@code trackSelection} for
|
|
||||||
* {@code blacklistDurationMs} if calling {@link #shouldBlacklist(Exception)} for {@code e}
|
|
||||||
* returns true. Else does nothing. Note that blacklisting will fail if the track is the only
|
|
||||||
* non-blacklisted track in the selection.
|
|
||||||
*
|
|
||||||
* @param trackSelection The track selection.
|
|
||||||
* @param trackSelectionIndex The index in the selection to consider blacklisting.
|
|
||||||
* @param e The error to inspect.
|
|
||||||
* @param blacklistDurationMs The duration to blacklist the track for, if it is blacklisted.
|
|
||||||
* @return Whether the track was blacklisted.
|
|
||||||
*/
|
|
||||||
public static boolean maybeBlacklistTrack(TrackSelection trackSelection, int trackSelectionIndex,
|
|
||||||
Exception e, long blacklistDurationMs) {
|
|
||||||
if (shouldBlacklist(e)) {
|
|
||||||
boolean blacklisted = trackSelection.blacklist(trackSelectionIndex, blacklistDurationMs);
|
|
||||||
int responseCode = ((InvalidResponseCodeException) e).responseCode;
|
|
||||||
if (blacklisted) {
|
|
||||||
Log.w(TAG, "Blacklisted: duration=" + blacklistDurationMs + ", responseCode="
|
|
||||||
+ responseCode + ", format=" + trackSelection.getFormat(trackSelectionIndex));
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Blacklisting failed (cannot blacklist last enabled track): responseCode="
|
|
||||||
+ responseCode + ", format=" + trackSelection.getFormat(trackSelectionIndex));
|
|
||||||
}
|
|
||||||
return blacklisted;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether a loading error is an {@link InvalidResponseCodeException} with
|
|
||||||
* {@link InvalidResponseCodeException#responseCode} equal to 404 or 410.
|
|
||||||
*
|
|
||||||
* @param e The loading error.
|
|
||||||
* @return Wheter the loading error is an {@link InvalidResponseCodeException} with
|
|
||||||
* {@link InvalidResponseCodeException#responseCode} equal to 404 or 410.
|
|
||||||
*/
|
|
||||||
public static boolean shouldBlacklist(Exception e) {
|
|
||||||
if (e instanceof InvalidResponseCodeException) {
|
|
||||||
int responseCode = ((InvalidResponseCodeException) e).responseCode;
|
|
||||||
return responseCode == 404 || responseCode == 410;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChunkedTrackBlacklistUtil() {}
|
|
||||||
|
|
||||||
}
|
|
@ -17,7 +17,6 @@ package com.google.android.exoplayer2.upstream;
|
|||||||
|
|
||||||
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.source.chunk.ChunkedTrackBlacklistUtil;
|
|
||||||
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -31,6 +30,8 @@ public final class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPo
|
|||||||
* streams.
|
* streams.
|
||||||
*/
|
*/
|
||||||
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 blacklisted in milliseconds. */
|
||||||
|
public static final long DEFAULT_TRACK_BLACKLIST_MS = 60000;
|
||||||
|
|
||||||
private static final int DEFAULT_BEHAVIOR_MIN_LOADABLE_RETRY_COUNT = -1;
|
private static final int DEFAULT_BEHAVIOR_MIN_LOADABLE_RETRY_COUNT = -1;
|
||||||
|
|
||||||
@ -59,8 +60,7 @@ public final class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPo
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Blacklists resources whose load error was an {@link InvalidResponseCodeException} with response
|
* Blacklists resources whose load error was an {@link InvalidResponseCodeException} with response
|
||||||
* code HTTP 404 or 410. The duration of the blacklisting is {@link
|
* code HTTP 404 or 410. The duration of the blacklisting is {@link #DEFAULT_TRACK_BLACKLIST_MS}.
|
||||||
* ChunkedTrackBlacklistUtil#DEFAULT_TRACK_BLACKLIST_MS}.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public long getBlacklistDurationMsFor(
|
public long getBlacklistDurationMsFor(
|
||||||
@ -69,7 +69,7 @@ public final class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPo
|
|||||||
int responseCode = ((InvalidResponseCodeException) exception).responseCode;
|
int responseCode = ((InvalidResponseCodeException) exception).responseCode;
|
||||||
return responseCode == 404 // HTTP 404 Not Found.
|
return responseCode == 404 // HTTP 404 Not Found.
|
||||||
|| responseCode == 410 // HTTP 410 Gone.
|
|| responseCode == 410 // HTTP 410 Gone.
|
||||||
? ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS
|
? DEFAULT_TRACK_BLACKLIST_MS
|
||||||
: C.TIME_UNSET;
|
: C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
return C.TIME_UNSET;
|
return C.TIME_UNSET;
|
||||||
|
@ -20,9 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
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.source.chunk.ChunkedTrackBlacklistUtil;
|
|
||||||
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
||||||
import com.google.android.exoplayer2.upstream.Loader.Loadable;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -34,56 +32,43 @@ import org.robolectric.RobolectricTestRunner;
|
|||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public final class DefaultLoadErrorHandlingPolicyTest {
|
public final class DefaultLoadErrorHandlingPolicyTest {
|
||||||
|
|
||||||
private static final Loadable DUMMY_LOADABLE =
|
|
||||||
new Loadable() {
|
|
||||||
@Override
|
|
||||||
public void cancelLoad() {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void load() throws IOException, InterruptedException {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBlacklistDurationMsFor_blacklist404() throws Exception {
|
public void getBlacklistDurationMsFor_blacklist404() {
|
||||||
InvalidResponseCodeException exception =
|
InvalidResponseCodeException exception =
|
||||||
new InvalidResponseCodeException(404, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
new InvalidResponseCodeException(404, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
||||||
assertThat(getDefaultPolicyBlacklistOutputFor(exception))
|
assertThat(getDefaultPolicyBlacklistOutputFor(exception))
|
||||||
.isEqualTo(ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS);
|
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBlacklistDurationMsFor_blacklist410() throws Exception {
|
public void getBlacklistDurationMsFor_blacklist410() {
|
||||||
InvalidResponseCodeException exception =
|
InvalidResponseCodeException exception =
|
||||||
new InvalidResponseCodeException(410, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
new InvalidResponseCodeException(410, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
||||||
assertThat(getDefaultPolicyBlacklistOutputFor(exception))
|
assertThat(getDefaultPolicyBlacklistOutputFor(exception))
|
||||||
.isEqualTo(ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS);
|
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBlacklistDurationMsFor_dontBlacklistUnexpectedHttpCodes() throws Exception {
|
public void getBlacklistDurationMsFor_dontBlacklistUnexpectedHttpCodes() {
|
||||||
InvalidResponseCodeException exception =
|
InvalidResponseCodeException exception =
|
||||||
new InvalidResponseCodeException(500, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
new InvalidResponseCodeException(500, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
||||||
assertThat(getDefaultPolicyBlacklistOutputFor(exception)).isEqualTo(C.TIME_UNSET);
|
assertThat(getDefaultPolicyBlacklistOutputFor(exception)).isEqualTo(C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBlacklistDurationMsFor_dontBlacklistUnexpectedExceptions() throws Exception {
|
public void getBlacklistDurationMsFor_dontBlacklistUnexpectedExceptions() {
|
||||||
FileNotFoundException exception = new FileNotFoundException();
|
FileNotFoundException exception = new FileNotFoundException();
|
||||||
assertThat(getDefaultPolicyBlacklistOutputFor(exception)).isEqualTo(C.TIME_UNSET);
|
assertThat(getDefaultPolicyBlacklistOutputFor(exception)).isEqualTo(C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getRetryDelayMsFor_dontRetryParserException() throws Exception {
|
public void getRetryDelayMsFor_dontRetryParserException() {
|
||||||
assertThat(getDefaultPolicyRetryDelayOutputFor(new ParserException(), 1))
|
assertThat(getDefaultPolicyRetryDelayOutputFor(new ParserException(), 1))
|
||||||
.isEqualTo(C.TIME_UNSET);
|
.isEqualTo(C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getRetryDelayMsFor_successiveRetryDelays() throws Exception {
|
public void getRetryDelayMsFor_successiveRetryDelays() {
|
||||||
assertThat(getDefaultPolicyRetryDelayOutputFor(new FileNotFoundException(), 3)).isEqualTo(2000);
|
assertThat(getDefaultPolicyRetryDelayOutputFor(new FileNotFoundException(), 3)).isEqualTo(2000);
|
||||||
assertThat(getDefaultPolicyRetryDelayOutputFor(new FileNotFoundException(), 5)).isEqualTo(4000);
|
assertThat(getDefaultPolicyRetryDelayOutputFor(new FileNotFoundException(), 5)).isEqualTo(4000);
|
||||||
assertThat(getDefaultPolicyRetryDelayOutputFor(new FileNotFoundException(), 9)).isEqualTo(5000);
|
assertThat(getDefaultPolicyRetryDelayOutputFor(new FileNotFoundException(), 9)).isEqualTo(5000);
|
||||||
|
@ -42,6 +42,7 @@ import com.google.android.exoplayer2.source.dash.manifest.Period;
|
|||||||
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
||||||
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.LoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
@ -62,7 +63,7 @@ import java.util.List;
|
|||||||
/* package */ final int id;
|
/* package */ final int id;
|
||||||
private final DashChunkSource.Factory chunkSourceFactory;
|
private final DashChunkSource.Factory chunkSourceFactory;
|
||||||
private final @Nullable TransferListener transferListener;
|
private final @Nullable TransferListener transferListener;
|
||||||
private final int minLoadableRetryCount;
|
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private final long elapsedRealtimeOffset;
|
private final long elapsedRealtimeOffset;
|
||||||
private final LoaderErrorThrower manifestLoaderErrorThrower;
|
private final LoaderErrorThrower manifestLoaderErrorThrower;
|
||||||
private final Allocator allocator;
|
private final Allocator allocator;
|
||||||
@ -89,7 +90,7 @@ import java.util.List;
|
|||||||
int periodIndex,
|
int periodIndex,
|
||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
@Nullable TransferListener transferListener,
|
@Nullable TransferListener transferListener,
|
||||||
int minLoadableRetryCount,
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||||
EventDispatcher eventDispatcher,
|
EventDispatcher eventDispatcher,
|
||||||
long elapsedRealtimeOffset,
|
long elapsedRealtimeOffset,
|
||||||
LoaderErrorThrower manifestLoaderErrorThrower,
|
LoaderErrorThrower manifestLoaderErrorThrower,
|
||||||
@ -101,7 +102,7 @@ import java.util.List;
|
|||||||
this.periodIndex = periodIndex;
|
this.periodIndex = periodIndex;
|
||||||
this.chunkSourceFactory = chunkSourceFactory;
|
this.chunkSourceFactory = chunkSourceFactory;
|
||||||
this.transferListener = transferListener;
|
this.transferListener = transferListener;
|
||||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||||
this.eventDispatcher = eventDispatcher;
|
this.eventDispatcher = eventDispatcher;
|
||||||
this.elapsedRealtimeOffset = elapsedRealtimeOffset;
|
this.elapsedRealtimeOffset = elapsedRealtimeOffset;
|
||||||
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
||||||
@ -612,7 +613,7 @@ import java.util.List;
|
|||||||
this,
|
this,
|
||||||
allocator,
|
allocator,
|
||||||
positionUs,
|
positionUs,
|
||||||
minLoadableRetryCount,
|
loadErrorHandlingPolicy,
|
||||||
eventDispatcher);
|
eventDispatcher);
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
// The map is also accessed on the loading thread so synchronize access.
|
// The map is also accessed on the loading thread so synchronize access.
|
||||||
|
@ -43,6 +43,8 @@ import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
|
|||||||
import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement;
|
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.DefaultLoadErrorHandlingPolicy;
|
||||||
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
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.LoadErrorAction;
|
||||||
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
||||||
@ -77,7 +79,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
|
|
||||||
private @Nullable ParsingLoadable.Parser<? extends DashManifest> manifestParser;
|
private @Nullable ParsingLoadable.Parser<? extends DashManifest> manifestParser;
|
||||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||||
private int minLoadableRetryCount;
|
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private long livePresentationDelayMs;
|
private long livePresentationDelayMs;
|
||||||
private boolean livePresentationDelayOverridesManifest;
|
private boolean livePresentationDelayOverridesManifest;
|
||||||
private boolean isCreateCalled;
|
private boolean isCreateCalled;
|
||||||
@ -107,7 +109,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
@Nullable DataSource.Factory manifestDataSourceFactory) {
|
@Nullable DataSource.Factory manifestDataSourceFactory) {
|
||||||
this.chunkSourceFactory = Assertions.checkNotNull(chunkSourceFactory);
|
this.chunkSourceFactory = Assertions.checkNotNull(chunkSourceFactory);
|
||||||
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
||||||
minLoadableRetryCount = DEFAULT_MIN_LOADABLE_RETRY_COUNT;
|
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||||
livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS;
|
livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS;
|
||||||
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
||||||
}
|
}
|
||||||
@ -128,16 +130,36 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the minimum number of times to retry if a loading error occurs. The default value is
|
* Sets the minimum number of times to retry if a loading error occurs. See {@link
|
||||||
* {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}.
|
* #setLoadErrorHandlingPolicy} for the default value.
|
||||||
|
*
|
||||||
|
* <p>Calling this method is equivalent to calling {@link #setLoadErrorHandlingPolicy} with
|
||||||
|
* {@link DefaultLoadErrorHandlingPolicy (int)
|
||||||
|
* DefaultLoadErrorHandlingPolicy(minLoadableRetryCount)}
|
||||||
*
|
*
|
||||||
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
||||||
* @return This factory, for convenience.
|
* @return This factory, for convenience.
|
||||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||||
|
* @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Factory setMinLoadableRetryCount(int minLoadableRetryCount) {
|
public Factory setMinLoadableRetryCount(int minLoadableRetryCount) {
|
||||||
|
return setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link LoadErrorHandlingPolicy}. The default value is created by calling {@link
|
||||||
|
* DefaultLoadErrorHandlingPolicy()}.
|
||||||
|
*
|
||||||
|
* <p>Calling this method overrides any calls to {@link #setMinLoadableRetryCount(int)}.
|
||||||
|
*
|
||||||
|
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||||
|
*/
|
||||||
|
public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||||
Assertions.checkState(!isCreateCalled);
|
Assertions.checkState(!isCreateCalled);
|
||||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +247,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
/* manifestParser= */ null,
|
/* manifestParser= */ null,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
compositeSequenceableLoaderFactory,
|
compositeSequenceableLoaderFactory,
|
||||||
minLoadableRetryCount,
|
loadErrorHandlingPolicy,
|
||||||
livePresentationDelayMs,
|
livePresentationDelayMs,
|
||||||
livePresentationDelayOverridesManifest,
|
livePresentationDelayOverridesManifest,
|
||||||
tag);
|
tag);
|
||||||
@ -266,7 +288,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
manifestParser,
|
manifestParser,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
compositeSequenceableLoaderFactory,
|
compositeSequenceableLoaderFactory,
|
||||||
minLoadableRetryCount,
|
loadErrorHandlingPolicy,
|
||||||
livePresentationDelayMs,
|
livePresentationDelayMs,
|
||||||
livePresentationDelayOverridesManifest,
|
livePresentationDelayOverridesManifest,
|
||||||
tag);
|
tag);
|
||||||
@ -294,11 +316,6 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The default minimum number of times to retry loading data prior to failing.
|
|
||||||
*/
|
|
||||||
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default presentation delay for live streams. The presentation delay is the duration by
|
* The default presentation delay for live streams. The presentation delay is the duration by
|
||||||
* which the default start position precedes the end of the live window.
|
* which the default start position precedes the end of the live window.
|
||||||
@ -328,7 +345,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
private final DataSource.Factory manifestDataSourceFactory;
|
private final DataSource.Factory manifestDataSourceFactory;
|
||||||
private final DashChunkSource.Factory chunkSourceFactory;
|
private final DashChunkSource.Factory chunkSourceFactory;
|
||||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||||
private final int minLoadableRetryCount;
|
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private final long livePresentationDelayMs;
|
private final long livePresentationDelayMs;
|
||||||
private final boolean livePresentationDelayOverridesManifest;
|
private final boolean livePresentationDelayOverridesManifest;
|
||||||
private final EventDispatcher manifestEventDispatcher;
|
private final EventDispatcher manifestEventDispatcher;
|
||||||
@ -379,7 +396,11 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
Handler eventHandler,
|
Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
MediaSourceEventListener eventListener) {
|
||||||
this(manifest, chunkSourceFactory, DEFAULT_MIN_LOADABLE_RETRY_COUNT, eventHandler,
|
this(
|
||||||
|
manifest,
|
||||||
|
chunkSourceFactory,
|
||||||
|
DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
||||||
|
eventHandler,
|
||||||
eventListener);
|
eventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +428,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
/* manifestParser= */ null,
|
/* manifestParser= */ null,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
new DefaultCompositeSequenceableLoaderFactory(),
|
new DefaultCompositeSequenceableLoaderFactory(),
|
||||||
minLoadableRetryCount,
|
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||||
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
|
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
|
||||||
/* livePresentationDelayOverridesManifest= */ false,
|
/* livePresentationDelayOverridesManifest= */ false,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
@ -436,9 +457,14 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
Handler eventHandler,
|
Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
MediaSourceEventListener eventListener) {
|
||||||
this(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
|
this(
|
||||||
DEFAULT_MIN_LOADABLE_RETRY_COUNT, DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS,
|
manifestUri,
|
||||||
eventHandler, eventListener);
|
manifestDataSourceFactory,
|
||||||
|
chunkSourceFactory,
|
||||||
|
DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
||||||
|
DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS,
|
||||||
|
eventHandler,
|
||||||
|
eventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -515,7 +541,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
manifestParser,
|
manifestParser,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
new DefaultCompositeSequenceableLoaderFactory(),
|
new DefaultCompositeSequenceableLoaderFactory(),
|
||||||
minLoadableRetryCount,
|
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||||
livePresentationDelayMs == DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS
|
livePresentationDelayMs == DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS
|
||||||
? DEFAULT_LIVE_PRESENTATION_DELAY_MS
|
? DEFAULT_LIVE_PRESENTATION_DELAY_MS
|
||||||
: livePresentationDelayMs,
|
: livePresentationDelayMs,
|
||||||
@ -533,7 +559,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
ParsingLoadable.Parser<? extends DashManifest> manifestParser,
|
ParsingLoadable.Parser<? extends DashManifest> manifestParser,
|
||||||
DashChunkSource.Factory chunkSourceFactory,
|
DashChunkSource.Factory chunkSourceFactory,
|
||||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||||
int minLoadableRetryCount,
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||||
long livePresentationDelayMs,
|
long livePresentationDelayMs,
|
||||||
boolean livePresentationDelayOverridesManifest,
|
boolean livePresentationDelayOverridesManifest,
|
||||||
@Nullable Object tag) {
|
@Nullable Object tag) {
|
||||||
@ -543,7 +569,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
||||||
this.manifestParser = manifestParser;
|
this.manifestParser = manifestParser;
|
||||||
this.chunkSourceFactory = chunkSourceFactory;
|
this.chunkSourceFactory = chunkSourceFactory;
|
||||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||||
this.livePresentationDelayMs = livePresentationDelayMs;
|
this.livePresentationDelayMs = livePresentationDelayMs;
|
||||||
this.livePresentationDelayOverridesManifest = livePresentationDelayOverridesManifest;
|
this.livePresentationDelayOverridesManifest = livePresentationDelayOverridesManifest;
|
||||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||||
@ -625,7 +651,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
periodIndex,
|
periodIndex,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
mediaTransferListener,
|
mediaTransferListener,
|
||||||
minLoadableRetryCount,
|
loadErrorHandlingPolicy,
|
||||||
periodEventDispatcher,
|
periodEventDispatcher,
|
||||||
elapsedRealtimeOffsetMs,
|
elapsedRealtimeOffsetMs,
|
||||||
manifestLoadErrorThrower,
|
manifestLoadErrorThrower,
|
||||||
@ -735,7 +761,8 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isManifestStale) {
|
if (isManifestStale) {
|
||||||
if (staleManifestReloadAttempt++ < minLoadableRetryCount) {
|
if (staleManifestReloadAttempt++
|
||||||
|
< loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type)) {
|
||||||
scheduleManifestRefresh(getManifestLoadRetryDelayMillis());
|
scheduleManifestRefresh(getManifestLoadRetryDelayMillis());
|
||||||
} else {
|
} else {
|
||||||
manifestFatalError = new DashManifestStaleException();
|
manifestFatalError = new DashManifestStaleException();
|
||||||
@ -1004,7 +1031,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
startLoading(
|
startLoading(
|
||||||
new ParsingLoadable<>(dataSource, manifestUri, C.DATA_TYPE_MANIFEST, manifestParser),
|
new ParsingLoadable<>(dataSource, manifestUri, C.DATA_TYPE_MANIFEST, manifestParser),
|
||||||
manifestCallback,
|
manifestCallback,
|
||||||
minLoadableRetryCount);
|
loadErrorHandlingPolicy.getMinimumLoadableRetryCount(C.DATA_TYPE_MANIFEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getManifestLoadRetryDelayMillis() {
|
private long getManifestLoadRetryDelayMillis() {
|
||||||
|
@ -34,7 +34,6 @@ import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator;
|
|||||||
import com.google.android.exoplayer2.source.chunk.Chunk;
|
import com.google.android.exoplayer2.source.chunk.Chunk;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper;
|
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkHolder;
|
import com.google.android.exoplayer2.source.chunk.ChunkHolder;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil;
|
|
||||||
import com.google.android.exoplayer2.source.chunk.ContainerMediaChunk;
|
import com.google.android.exoplayer2.source.chunk.ContainerMediaChunk;
|
||||||
import com.google.android.exoplayer2.source.chunk.InitializationChunk;
|
import com.google.android.exoplayer2.source.chunk.InitializationChunk;
|
||||||
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
||||||
@ -380,7 +379,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e) {
|
public boolean onChunkLoadError(
|
||||||
|
Chunk chunk, boolean cancelable, Exception e, long blacklistDurationMs) {
|
||||||
if (!cancelable) {
|
if (!cancelable) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -403,9 +403,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Blacklist if appropriate.
|
return blacklistDurationMs != C.TIME_UNSET
|
||||||
return ChunkedTrackBlacklistUtil.maybeBlacklistTrack(trackSelection,
|
&& trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), blacklistDurationMs);
|
||||||
trackSelection.indexOf(chunk.trackFormat), e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
@ -23,7 +23,6 @@ import com.google.android.exoplayer2.Format;
|
|||||||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.chunk.Chunk;
|
import com.google.android.exoplayer2.source.chunk.Chunk;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil;
|
|
||||||
import com.google.android.exoplayer2.source.chunk.DataChunk;
|
import com.google.android.exoplayer2.source.chunk.DataChunk;
|
||||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl;
|
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl;
|
||||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist;
|
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist;
|
||||||
@ -33,6 +32,7 @@ import com.google.android.exoplayer2.trackselection.BaseTrackSelection;
|
|||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
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.DefaultLoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
||||||
import com.google.android.exoplayer2.util.UriUtil;
|
import com.google.android.exoplayer2.util.UriUtil;
|
||||||
@ -429,7 +429,7 @@ import java.util.List;
|
|||||||
seenExpectedPlaylistError |= expectedPlaylistUrl == url;
|
seenExpectedPlaylistError |= expectedPlaylistUrl == url;
|
||||||
return !shouldBlacklist
|
return !shouldBlacklist
|
||||||
|| trackSelection.blacklist(
|
|| trackSelection.blacklist(
|
||||||
trackSelectionIndex, ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS);
|
trackSelectionIndex, DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private methods.
|
// Private methods.
|
||||||
|
@ -21,11 +21,11 @@ import android.os.SystemClock;
|
|||||||
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.source.MediaSourceEventListener.EventDispatcher;
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil;
|
|
||||||
import com.google.android.exoplayer2.source.hls.HlsDataSourceFactory;
|
import com.google.android.exoplayer2.source.hls.HlsDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl;
|
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl;
|
||||||
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.DefaultLoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
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.LoadErrorAction;
|
||||||
@ -621,7 +621,7 @@ public final class DefaultHlsPlaylistTracker
|
|||||||
*/
|
*/
|
||||||
private boolean blacklistPlaylist() {
|
private boolean blacklistPlaylist() {
|
||||||
blacklistUntilMs =
|
blacklistUntilMs =
|
||||||
SystemClock.elapsedRealtime() + ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS;
|
SystemClock.elapsedRealtime() + DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS;
|
||||||
return primaryHlsUrl == playlistUrl && !maybeSelectNewPrimaryUrl();
|
return primaryHlsUrl == playlistUrl && !maybeSelectNewPrimaryUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
|||||||
import com.google.android.exoplayer2.source.chunk.Chunk;
|
import com.google.android.exoplayer2.source.chunk.Chunk;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper;
|
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkHolder;
|
import com.google.android.exoplayer2.source.chunk.ChunkHolder;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil;
|
|
||||||
import com.google.android.exoplayer2.source.chunk.ContainerMediaChunk;
|
import com.google.android.exoplayer2.source.chunk.ContainerMediaChunk;
|
||||||
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
||||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
|
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
|
||||||
@ -246,9 +245,11 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e) {
|
public boolean onChunkLoadError(
|
||||||
return cancelable && ChunkedTrackBlacklistUtil.maybeBlacklistTrack(trackSelection,
|
Chunk chunk, boolean cancelable, Exception e, long blacklistDurationMs) {
|
||||||
trackSelection.indexOf(chunk.trackFormat), e);
|
return cancelable
|
||||||
|
&& blacklistDurationMs != C.TIME_UNSET
|
||||||
|
&& trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), blacklistDurationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private methods.
|
// Private methods.
|
||||||
|
@ -32,6 +32,7 @@ import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
|
|||||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.ProtectionElement;
|
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.ProtectionElement;
|
||||||
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.LoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -48,7 +49,7 @@ import java.util.ArrayList;
|
|||||||
private final SsChunkSource.Factory chunkSourceFactory;
|
private final SsChunkSource.Factory chunkSourceFactory;
|
||||||
private final @Nullable TransferListener transferListener;
|
private final @Nullable TransferListener transferListener;
|
||||||
private final LoaderErrorThrower manifestLoaderErrorThrower;
|
private final LoaderErrorThrower manifestLoaderErrorThrower;
|
||||||
private final int minLoadableRetryCount;
|
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private final EventDispatcher eventDispatcher;
|
private final EventDispatcher eventDispatcher;
|
||||||
private final Allocator allocator;
|
private final Allocator allocator;
|
||||||
private final TrackGroupArray trackGroups;
|
private final TrackGroupArray trackGroups;
|
||||||
@ -66,14 +67,14 @@ import java.util.ArrayList;
|
|||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
@Nullable TransferListener transferListener,
|
@Nullable TransferListener transferListener,
|
||||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||||
int minLoadableRetryCount,
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||||
EventDispatcher eventDispatcher,
|
EventDispatcher eventDispatcher,
|
||||||
LoaderErrorThrower manifestLoaderErrorThrower,
|
LoaderErrorThrower manifestLoaderErrorThrower,
|
||||||
Allocator allocator) {
|
Allocator allocator) {
|
||||||
this.chunkSourceFactory = chunkSourceFactory;
|
this.chunkSourceFactory = chunkSourceFactory;
|
||||||
this.transferListener = transferListener;
|
this.transferListener = transferListener;
|
||||||
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
||||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||||
this.eventDispatcher = eventDispatcher;
|
this.eventDispatcher = eventDispatcher;
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||||
@ -238,7 +239,7 @@ import java.util.ArrayList;
|
|||||||
this,
|
this,
|
||||||
allocator,
|
allocator,
|
||||||
positionUs,
|
positionUs,
|
||||||
minLoadableRetryCount,
|
loadErrorHandlingPolicy,
|
||||||
eventDispatcher);
|
eventDispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestP
|
|||||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsUtil;
|
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.DefaultLoadErrorHandlingPolicy;
|
||||||
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
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.LoadErrorAction;
|
||||||
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
||||||
@ -65,7 +67,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
|
|
||||||
private @Nullable ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
private @Nullable ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
||||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||||
private int minLoadableRetryCount;
|
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private long livePresentationDelayMs;
|
private long livePresentationDelayMs;
|
||||||
private boolean isCreateCalled;
|
private boolean isCreateCalled;
|
||||||
private @Nullable Object tag;
|
private @Nullable Object tag;
|
||||||
@ -94,7 +96,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
@Nullable DataSource.Factory manifestDataSourceFactory) {
|
@Nullable DataSource.Factory manifestDataSourceFactory) {
|
||||||
this.chunkSourceFactory = Assertions.checkNotNull(chunkSourceFactory);
|
this.chunkSourceFactory = Assertions.checkNotNull(chunkSourceFactory);
|
||||||
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
||||||
minLoadableRetryCount = DEFAULT_MIN_LOADABLE_RETRY_COUNT;
|
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||||
livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS;
|
livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS;
|
||||||
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
||||||
}
|
}
|
||||||
@ -114,16 +116,36 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the minimum number of times to retry if a loading error occurs. The default value is
|
* Sets the minimum number of times to retry if a loading error occurs. See {@link
|
||||||
* {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}.
|
* #setLoadErrorHandlingPolicy} for the default value.
|
||||||
|
*
|
||||||
|
* <p>Calling this method is equivalent to calling {@link #setLoadErrorHandlingPolicy} with
|
||||||
|
* {@link DefaultLoadErrorHandlingPolicy(int)
|
||||||
|
* DefaultLoadErrorHandlingPolicy(minLoadableRetryCount)}
|
||||||
*
|
*
|
||||||
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
||||||
* @return This factory, for convenience.
|
* @return This factory, for convenience.
|
||||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||||
|
* @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public Factory setMinLoadableRetryCount(int minLoadableRetryCount) {
|
public Factory setMinLoadableRetryCount(int minLoadableRetryCount) {
|
||||||
|
return setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link LoadErrorHandlingPolicy}. The default value is created by calling {@link
|
||||||
|
* DefaultLoadErrorHandlingPolicy()}.
|
||||||
|
*
|
||||||
|
* <p>Calling this method overrides any calls to {@link #setMinLoadableRetryCount(int)}.
|
||||||
|
*
|
||||||
|
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||||
|
* @return This factory, for convenience.
|
||||||
|
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||||
|
*/
|
||||||
|
public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||||
Assertions.checkState(!isCreateCalled);
|
Assertions.checkState(!isCreateCalled);
|
||||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +215,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
/* manifestParser= */ null,
|
/* manifestParser= */ null,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
compositeSequenceableLoaderFactory,
|
compositeSequenceableLoaderFactory,
|
||||||
minLoadableRetryCount,
|
loadErrorHandlingPolicy,
|
||||||
livePresentationDelayMs,
|
livePresentationDelayMs,
|
||||||
tag);
|
tag);
|
||||||
}
|
}
|
||||||
@ -233,7 +255,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
manifestParser,
|
manifestParser,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
compositeSequenceableLoaderFactory,
|
compositeSequenceableLoaderFactory,
|
||||||
minLoadableRetryCount,
|
loadErrorHandlingPolicy,
|
||||||
livePresentationDelayMs,
|
livePresentationDelayMs,
|
||||||
tag);
|
tag);
|
||||||
}
|
}
|
||||||
@ -261,10 +283,6 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The default minimum number of times to retry loading data prior to failing.
|
|
||||||
*/
|
|
||||||
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
|
|
||||||
/**
|
/**
|
||||||
* The default presentation delay for live streams. The presentation delay is the duration by
|
* The default presentation delay for live streams. The presentation delay is the duration by
|
||||||
* which the default start position precedes the end of the live window.
|
* which the default start position precedes the end of the live window.
|
||||||
@ -285,7 +303,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
private final DataSource.Factory manifestDataSourceFactory;
|
private final DataSource.Factory manifestDataSourceFactory;
|
||||||
private final SsChunkSource.Factory chunkSourceFactory;
|
private final SsChunkSource.Factory chunkSourceFactory;
|
||||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||||
private final int minLoadableRetryCount;
|
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private final long livePresentationDelayMs;
|
private final long livePresentationDelayMs;
|
||||||
private final EventDispatcher manifestEventDispatcher;
|
private final EventDispatcher manifestEventDispatcher;
|
||||||
private final ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
private final ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
||||||
@ -317,8 +335,12 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
Handler eventHandler,
|
Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
MediaSourceEventListener eventListener) {
|
||||||
this(manifest, chunkSourceFactory, DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
this(
|
||||||
eventHandler, eventListener);
|
manifest,
|
||||||
|
chunkSourceFactory,
|
||||||
|
DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
||||||
|
eventHandler,
|
||||||
|
eventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -345,7 +367,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
/* manifestParser= */ null,
|
/* manifestParser= */ null,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
new DefaultCompositeSequenceableLoaderFactory(),
|
new DefaultCompositeSequenceableLoaderFactory(),
|
||||||
minLoadableRetryCount,
|
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||||
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
|
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
if (eventHandler != null && eventListener != null) {
|
if (eventHandler != null && eventListener != null) {
|
||||||
@ -372,8 +394,13 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
Handler eventHandler,
|
Handler eventHandler,
|
||||||
MediaSourceEventListener eventListener) {
|
MediaSourceEventListener eventListener) {
|
||||||
this(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
|
this(
|
||||||
DEFAULT_MIN_LOADABLE_RETRY_COUNT, DEFAULT_LIVE_PRESENTATION_DELAY_MS, eventHandler,
|
manifestUri,
|
||||||
|
manifestDataSourceFactory,
|
||||||
|
chunkSourceFactory,
|
||||||
|
DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
||||||
|
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
|
||||||
|
eventHandler,
|
||||||
eventListener);
|
eventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +465,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
manifestParser,
|
manifestParser,
|
||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
new DefaultCompositeSequenceableLoaderFactory(),
|
new DefaultCompositeSequenceableLoaderFactory(),
|
||||||
minLoadableRetryCount,
|
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||||
livePresentationDelayMs,
|
livePresentationDelayMs,
|
||||||
/* tag= */ null);
|
/* tag= */ null);
|
||||||
if (eventHandler != null && eventListener != null) {
|
if (eventHandler != null && eventListener != null) {
|
||||||
@ -453,7 +480,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
ParsingLoadable.Parser<? extends SsManifest> manifestParser,
|
ParsingLoadable.Parser<? extends SsManifest> manifestParser,
|
||||||
SsChunkSource.Factory chunkSourceFactory,
|
SsChunkSource.Factory chunkSourceFactory,
|
||||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||||
int minLoadableRetryCount,
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||||
long livePresentationDelayMs,
|
long livePresentationDelayMs,
|
||||||
@Nullable Object tag) {
|
@Nullable Object tag) {
|
||||||
Assertions.checkState(manifest == null || !manifest.isLive);
|
Assertions.checkState(manifest == null || !manifest.isLive);
|
||||||
@ -463,7 +490,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
this.manifestParser = manifestParser;
|
this.manifestParser = manifestParser;
|
||||||
this.chunkSourceFactory = chunkSourceFactory;
|
this.chunkSourceFactory = chunkSourceFactory;
|
||||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||||
this.livePresentationDelayMs = livePresentationDelayMs;
|
this.livePresentationDelayMs = livePresentationDelayMs;
|
||||||
this.manifestEventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
|
this.manifestEventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
@ -506,7 +533,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
chunkSourceFactory,
|
chunkSourceFactory,
|
||||||
mediaTransferListener,
|
mediaTransferListener,
|
||||||
compositeSequenceableLoaderFactory,
|
compositeSequenceableLoaderFactory,
|
||||||
minLoadableRetryCount,
|
loadErrorHandlingPolicy,
|
||||||
eventDispatcher,
|
eventDispatcher,
|
||||||
manifestLoaderErrorThrower,
|
manifestLoaderErrorThrower,
|
||||||
allocator);
|
allocator);
|
||||||
@ -668,7 +695,9 @@ public final class SsMediaSource extends BaseMediaSource
|
|||||||
private void startLoadingManifest() {
|
private void startLoadingManifest() {
|
||||||
ParsingLoadable<SsManifest> loadable = new ParsingLoadable<>(manifestDataSource,
|
ParsingLoadable<SsManifest> loadable = new ParsingLoadable<>(manifestDataSource,
|
||||||
manifestUri, C.DATA_TYPE_MANIFEST, manifestParser);
|
manifestUri, C.DATA_TYPE_MANIFEST, manifestParser);
|
||||||
long elapsedRealtimeMs = manifestLoader.startLoading(loadable, this, minLoadableRetryCount);
|
long elapsedRealtimeMs =
|
||||||
|
manifestLoader.startLoading(
|
||||||
|
loadable, this, loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type));
|
||||||
manifestEventDispatcher.loadStarted(
|
manifestEventDispatcher.loadStarted(
|
||||||
loadable.dataSpec, loadable.dataSpec.uri, loadable.type, elapsedRealtimeMs);
|
loadable.dataSpec, loadable.dataSpec.uri, loadable.type, elapsedRealtimeMs);
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,8 @@ public final class FakeChunkSource implements ChunkSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e) {
|
public boolean onChunkLoadError(
|
||||||
|
Chunk chunk, boolean cancelable, Exception e, long blacklistDurationMs) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user