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 DataSource.Factory dataSourceFactory;
|
||||
private final Format format;
|
||||
@ -204,7 +199,12 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
|
||||
@Deprecated
|
||||
public SingleSampleMediaSource(
|
||||
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.SequenceableLoader;
|
||||
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.LoadErrorAction;
|
||||
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 SequenceableLoader.Callback<ChunkSampleStream<T>> callback;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final int minLoadableRetryCount;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final Loader loader;
|
||||
private final ChunkHolder nextChunkHolder;
|
||||
private final ArrayList<BaseMediaChunk> mediaChunks;
|
||||
@ -81,6 +83,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
||||
/* package */ boolean loadingFinished;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -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
|
||||
* before propagating an error.
|
||||
* @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(
|
||||
int primaryTrackType,
|
||||
int[] embeddedTrackTypes,
|
||||
@ -103,13 +110,49 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
||||
long positionUs,
|
||||
int minLoadableRetryCount,
|
||||
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.embeddedTrackTypes = embeddedTrackTypes;
|
||||
this.embeddedTrackFormats = embeddedTrackFormats;
|
||||
this.chunkSource = chunkSource;
|
||||
this.callback = callback;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
loader = new Loader("Loader:ChunkSampleStream");
|
||||
nextChunkHolder = new ChunkHolder();
|
||||
mediaChunks = new ArrayList<>();
|
||||
@ -439,12 +482,15 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
||||
int lastChunkIndex = mediaChunks.size() - 1;
|
||||
boolean cancelable =
|
||||
bytesLoaded == 0 || !isMediaChunk || !haveReadFromMediaChunk(lastChunkIndex);
|
||||
boolean canceled = false;
|
||||
if (chunkSource.onChunkLoadError(loadable, cancelable, error)) {
|
||||
if (!cancelable) {
|
||||
Log.w(TAG, "Ignoring attempt to cancel non-cancelable load.");
|
||||
} else {
|
||||
canceled = true;
|
||||
long blacklistDurationMs =
|
||||
cancelable
|
||||
? loadErrorHandlingPolicy.getBlacklistDurationMsFor(
|
||||
loadable.type, loadDurationMs, error, errorCount)
|
||||
: C.TIME_UNSET;
|
||||
LoadErrorAction loadErrorAction = null;
|
||||
if (chunkSource.onChunkLoadError(loadable, cancelable, error, blacklistDurationMs)) {
|
||||
if (cancelable) {
|
||||
loadErrorAction = Loader.DONT_RETRY;
|
||||
if (isMediaChunk) {
|
||||
BaseMediaChunk removed = discardUpstreamMediaChunksFromIndex(lastChunkIndex);
|
||||
Assertions.checkState(removed == loadable);
|
||||
@ -452,8 +498,23 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
||||
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(
|
||||
loadable.dataSpec,
|
||||
loadable.getUri(),
|
||||
@ -471,10 +532,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
||||
canceled);
|
||||
if (canceled) {
|
||||
callback.onContinueLoadingRequested(this);
|
||||
return Loader.DONT_RETRY;
|
||||
} else {
|
||||
return Loader.RETRY;
|
||||
}
|
||||
return loadErrorAction;
|
||||
}
|
||||
|
||||
// SequenceableLoader implementation
|
||||
@ -521,7 +580,9 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
||||
mediaChunk.init(mediaChunkOutput);
|
||||
mediaChunks.add(mediaChunk);
|
||||
}
|
||||
long elapsedRealtimeMs = loader.startLoading(loadable, this, minLoadableRetryCount);
|
||||
long elapsedRealtimeMs =
|
||||
loader.startLoading(
|
||||
loadable, this, loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type));
|
||||
eventDispatcher.loadStarted(
|
||||
loadable.dataSpec,
|
||||
loadable.dataSpec.uri,
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.chunk;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
@ -83,8 +84,8 @@ public interface ChunkSource {
|
||||
/**
|
||||
* Called when the {@link ChunkSampleStream} has finished loading a chunk obtained from 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 has been completed.
|
||||
*/
|
||||
@ -93,15 +94,15 @@ public interface ChunkSource {
|
||||
/**
|
||||
* Called when the {@link ChunkSampleStream} encounters an error loading a chunk obtained from
|
||||
* 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 cancelable Whether the load can be canceled.
|
||||
* @param e The error.
|
||||
* @return Whether the load should be canceled. Should always be false if {@code cancelable} is
|
||||
* false.
|
||||
* @param blacklistDurationMs The duration for which the associated track may be blacklisted, or
|
||||
* {@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.ParserException;
|
||||
import com.google.android.exoplayer2.source.chunk.ChunkedTrackBlacklistUtil;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
||||
import java.io.IOException;
|
||||
|
||||
@ -31,6 +30,8 @@ public final class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPo
|
||||
* streams.
|
||||
*/
|
||||
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;
|
||||
|
||||
@ -59,8 +60,7 @@ public final class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPo
|
||||
|
||||
/**
|
||||
* Blacklists resources whose load error was an {@link InvalidResponseCodeException} with response
|
||||
* code HTTP 404 or 410. The duration of the blacklisting is {@link
|
||||
* ChunkedTrackBlacklistUtil#DEFAULT_TRACK_BLACKLIST_MS}.
|
||||
* code HTTP 404 or 410. The duration of the blacklisting is {@link #DEFAULT_TRACK_BLACKLIST_MS}.
|
||||
*/
|
||||
@Override
|
||||
public long getBlacklistDurationMsFor(
|
||||
@ -69,7 +69,7 @@ public final class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPo
|
||||
int responseCode = ((InvalidResponseCodeException) exception).responseCode;
|
||||
return responseCode == 404 // HTTP 404 Not Found.
|
||||
|| responseCode == 410 // HTTP 410 Gone.
|
||||
? ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS
|
||||
? DEFAULT_TRACK_BLACKLIST_MS
|
||||
: C.TIME_UNSET;
|
||||
}
|
||||
return C.TIME_UNSET;
|
||||
|
@ -20,9 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import android.net.Uri;
|
||||
import com.google.android.exoplayer2.C;
|
||||
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.Loader.Loadable;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
@ -34,56 +32,43 @@ import org.robolectric.RobolectricTestRunner;
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
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
|
||||
public void getBlacklistDurationMsFor_blacklist404() throws Exception {
|
||||
public void getBlacklistDurationMsFor_blacklist404() {
|
||||
InvalidResponseCodeException exception =
|
||||
new InvalidResponseCodeException(404, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
||||
assertThat(getDefaultPolicyBlacklistOutputFor(exception))
|
||||
.isEqualTo(ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS);
|
||||
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBlacklistDurationMsFor_blacklist410() throws Exception {
|
||||
public void getBlacklistDurationMsFor_blacklist410() {
|
||||
InvalidResponseCodeException exception =
|
||||
new InvalidResponseCodeException(410, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
||||
assertThat(getDefaultPolicyBlacklistOutputFor(exception))
|
||||
.isEqualTo(ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS);
|
||||
.isEqualTo(DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBlacklistDurationMsFor_dontBlacklistUnexpectedHttpCodes() throws Exception {
|
||||
public void getBlacklistDurationMsFor_dontBlacklistUnexpectedHttpCodes() {
|
||||
InvalidResponseCodeException exception =
|
||||
new InvalidResponseCodeException(500, Collections.emptyMap(), new DataSpec(Uri.EMPTY));
|
||||
assertThat(getDefaultPolicyBlacklistOutputFor(exception)).isEqualTo(C.TIME_UNSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBlacklistDurationMsFor_dontBlacklistUnexpectedExceptions() throws Exception {
|
||||
public void getBlacklistDurationMsFor_dontBlacklistUnexpectedExceptions() {
|
||||
FileNotFoundException exception = new FileNotFoundException();
|
||||
assertThat(getDefaultPolicyBlacklistOutputFor(exception)).isEqualTo(C.TIME_UNSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRetryDelayMsFor_dontRetryParserException() throws Exception {
|
||||
public void getRetryDelayMsFor_dontRetryParserException() {
|
||||
assertThat(getDefaultPolicyRetryDelayOutputFor(new ParserException(), 1))
|
||||
.isEqualTo(C.TIME_UNSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRetryDelayMsFor_successiveRetryDelays() throws Exception {
|
||||
public void getRetryDelayMsFor_successiveRetryDelays() {
|
||||
assertThat(getDefaultPolicyRetryDelayOutputFor(new FileNotFoundException(), 3)).isEqualTo(2000);
|
||||
assertThat(getDefaultPolicyRetryDelayOutputFor(new FileNotFoundException(), 5)).isEqualTo(4000);
|
||||
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.trackselection.TrackSelection;
|
||||
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.TransferListener;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
@ -62,7 +63,7 @@ import java.util.List;
|
||||
/* package */ final int id;
|
||||
private final DashChunkSource.Factory chunkSourceFactory;
|
||||
private final @Nullable TransferListener transferListener;
|
||||
private final int minLoadableRetryCount;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final long elapsedRealtimeOffset;
|
||||
private final LoaderErrorThrower manifestLoaderErrorThrower;
|
||||
private final Allocator allocator;
|
||||
@ -89,7 +90,7 @@ import java.util.List;
|
||||
int periodIndex,
|
||||
DashChunkSource.Factory chunkSourceFactory,
|
||||
@Nullable TransferListener transferListener,
|
||||
int minLoadableRetryCount,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
long elapsedRealtimeOffset,
|
||||
LoaderErrorThrower manifestLoaderErrorThrower,
|
||||
@ -101,7 +102,7 @@ import java.util.List;
|
||||
this.periodIndex = periodIndex;
|
||||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
this.transferListener = transferListener;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.elapsedRealtimeOffset = elapsedRealtimeOffset;
|
||||
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
||||
@ -612,7 +613,7 @@ import java.util.List;
|
||||
this,
|
||||
allocator,
|
||||
positionUs,
|
||||
minLoadableRetryCount,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher);
|
||||
synchronized (this) {
|
||||
// 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.upstream.Allocator;
|
||||
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.LoadErrorAction;
|
||||
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 CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private int minLoadableRetryCount;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private long livePresentationDelayMs;
|
||||
private boolean livePresentationDelayOverridesManifest;
|
||||
private boolean isCreateCalled;
|
||||
@ -107,7 +109,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
@Nullable DataSource.Factory manifestDataSourceFactory) {
|
||||
this.chunkSourceFactory = Assertions.checkNotNull(chunkSourceFactory);
|
||||
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
||||
minLoadableRetryCount = DEFAULT_MIN_LOADABLE_RETRY_COUNT;
|
||||
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||
livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS;
|
||||
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
|
||||
* {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}.
|
||||
* Sets the minimum number of times to retry if a loading error occurs. See {@link
|
||||
* #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.
|
||||
* @return This factory, for convenience.
|
||||
* @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) {
|
||||
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);
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -225,7 +247,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
/* manifestParser= */ null,
|
||||
chunkSourceFactory,
|
||||
compositeSequenceableLoaderFactory,
|
||||
minLoadableRetryCount,
|
||||
loadErrorHandlingPolicy,
|
||||
livePresentationDelayMs,
|
||||
livePresentationDelayOverridesManifest,
|
||||
tag);
|
||||
@ -266,7 +288,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
manifestParser,
|
||||
chunkSourceFactory,
|
||||
compositeSequenceableLoaderFactory,
|
||||
minLoadableRetryCount,
|
||||
loadErrorHandlingPolicy,
|
||||
livePresentationDelayMs,
|
||||
livePresentationDelayOverridesManifest,
|
||||
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
|
||||
* 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 DashChunkSource.Factory chunkSourceFactory;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private final int minLoadableRetryCount;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final long livePresentationDelayMs;
|
||||
private final boolean livePresentationDelayOverridesManifest;
|
||||
private final EventDispatcher manifestEventDispatcher;
|
||||
@ -379,7 +396,11 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
DashChunkSource.Factory chunkSourceFactory,
|
||||
Handler eventHandler,
|
||||
MediaSourceEventListener eventListener) {
|
||||
this(manifest, chunkSourceFactory, DEFAULT_MIN_LOADABLE_RETRY_COUNT, eventHandler,
|
||||
this(
|
||||
manifest,
|
||||
chunkSourceFactory,
|
||||
DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
||||
eventHandler,
|
||||
eventListener);
|
||||
}
|
||||
|
||||
@ -407,7 +428,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
/* manifestParser= */ null,
|
||||
chunkSourceFactory,
|
||||
new DefaultCompositeSequenceableLoaderFactory(),
|
||||
minLoadableRetryCount,
|
||||
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
|
||||
/* livePresentationDelayOverridesManifest= */ false,
|
||||
/* tag= */ null);
|
||||
@ -436,9 +457,14 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
DashChunkSource.Factory chunkSourceFactory,
|
||||
Handler eventHandler,
|
||||
MediaSourceEventListener eventListener) {
|
||||
this(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
|
||||
DEFAULT_MIN_LOADABLE_RETRY_COUNT, DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS,
|
||||
eventHandler, eventListener);
|
||||
this(
|
||||
manifestUri,
|
||||
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,
|
||||
chunkSourceFactory,
|
||||
new DefaultCompositeSequenceableLoaderFactory(),
|
||||
minLoadableRetryCount,
|
||||
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||
livePresentationDelayMs == DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS
|
||||
? DEFAULT_LIVE_PRESENTATION_DELAY_MS
|
||||
: livePresentationDelayMs,
|
||||
@ -533,7 +559,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
ParsingLoadable.Parser<? extends DashManifest> manifestParser,
|
||||
DashChunkSource.Factory chunkSourceFactory,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
int minLoadableRetryCount,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
long livePresentationDelayMs,
|
||||
boolean livePresentationDelayOverridesManifest,
|
||||
@Nullable Object tag) {
|
||||
@ -543,7 +569,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
||||
this.manifestParser = manifestParser;
|
||||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.livePresentationDelayMs = livePresentationDelayMs;
|
||||
this.livePresentationDelayOverridesManifest = livePresentationDelayOverridesManifest;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
@ -625,7 +651,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
periodIndex,
|
||||
chunkSourceFactory,
|
||||
mediaTransferListener,
|
||||
minLoadableRetryCount,
|
||||
loadErrorHandlingPolicy,
|
||||
periodEventDispatcher,
|
||||
elapsedRealtimeOffsetMs,
|
||||
manifestLoadErrorThrower,
|
||||
@ -735,7 +761,8 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
}
|
||||
|
||||
if (isManifestStale) {
|
||||
if (staleManifestReloadAttempt++ < minLoadableRetryCount) {
|
||||
if (staleManifestReloadAttempt++
|
||||
< loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type)) {
|
||||
scheduleManifestRefresh(getManifestLoadRetryDelayMillis());
|
||||
} else {
|
||||
manifestFatalError = new DashManifestStaleException();
|
||||
@ -1004,7 +1031,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
startLoading(
|
||||
new ParsingLoadable<>(dataSource, manifestUri, C.DATA_TYPE_MANIFEST, manifestParser),
|
||||
manifestCallback,
|
||||
minLoadableRetryCount);
|
||||
loadErrorHandlingPolicy.getMinimumLoadableRetryCount(C.DATA_TYPE_MANIFEST));
|
||||
}
|
||||
|
||||
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.ChunkExtractorWrapper;
|
||||
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.InitializationChunk;
|
||||
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
||||
@ -380,7 +379,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e) {
|
||||
public boolean onChunkLoadError(
|
||||
Chunk chunk, boolean cancelable, Exception e, long blacklistDurationMs) {
|
||||
if (!cancelable) {
|
||||
return false;
|
||||
}
|
||||
@ -403,9 +403,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Blacklist if appropriate.
|
||||
return ChunkedTrackBlacklistUtil.maybeBlacklistTrack(trackSelection,
|
||||
trackSelection.indexOf(chunk.trackFormat), e);
|
||||
return blacklistDurationMs != C.TIME_UNSET
|
||||
&& trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), blacklistDurationMs);
|
||||
}
|
||||
|
||||
// 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.TrackGroup;
|
||||
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.hls.playlist.HlsMasterPlaylist.HlsUrl;
|
||||
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.upstream.DataSource;
|
||||
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.util.TimestampAdjuster;
|
||||
import com.google.android.exoplayer2.util.UriUtil;
|
||||
@ -429,7 +429,7 @@ import java.util.List;
|
||||
seenExpectedPlaylistError |= expectedPlaylistUrl == url;
|
||||
return !shouldBlacklist
|
||||
|| trackSelection.blacklist(
|
||||
trackSelectionIndex, ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS);
|
||||
trackSelectionIndex, DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS);
|
||||
}
|
||||
|
||||
// Private methods.
|
||||
|
@ -21,11 +21,11 @@ import android.os.SystemClock;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
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.playlist.HlsMasterPlaylist.HlsUrl;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment;
|
||||
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.LoadErrorAction;
|
||||
@ -621,7 +621,7 @@ public final class DefaultHlsPlaylistTracker
|
||||
*/
|
||||
private boolean blacklistPlaylist() {
|
||||
blacklistUntilMs =
|
||||
SystemClock.elapsedRealtime() + ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS;
|
||||
SystemClock.elapsedRealtime() + DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS;
|
||||
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.ChunkExtractorWrapper;
|
||||
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.MediaChunk;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
|
||||
@ -246,9 +245,11 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e) {
|
||||
return cancelable && ChunkedTrackBlacklistUtil.maybeBlacklistTrack(trackSelection,
|
||||
trackSelection.indexOf(chunk.trackFormat), e);
|
||||
public boolean onChunkLoadError(
|
||||
Chunk chunk, boolean cancelable, Exception e, long blacklistDurationMs) {
|
||||
return cancelable
|
||||
&& blacklistDurationMs != C.TIME_UNSET
|
||||
&& trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), blacklistDurationMs);
|
||||
}
|
||||
|
||||
// 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.trackselection.TrackSelection;
|
||||
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.TransferListener;
|
||||
import java.io.IOException;
|
||||
@ -48,7 +49,7 @@ import java.util.ArrayList;
|
||||
private final SsChunkSource.Factory chunkSourceFactory;
|
||||
private final @Nullable TransferListener transferListener;
|
||||
private final LoaderErrorThrower manifestLoaderErrorThrower;
|
||||
private final int minLoadableRetryCount;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final Allocator allocator;
|
||||
private final TrackGroupArray trackGroups;
|
||||
@ -66,14 +67,14 @@ import java.util.ArrayList;
|
||||
SsChunkSource.Factory chunkSourceFactory,
|
||||
@Nullable TransferListener transferListener,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
int minLoadableRetryCount,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
LoaderErrorThrower manifestLoaderErrorThrower,
|
||||
Allocator allocator) {
|
||||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
this.transferListener = transferListener;
|
||||
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.allocator = allocator;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
@ -238,7 +239,7 @@ import java.util.ArrayList;
|
||||
this,
|
||||
allocator,
|
||||
positionUs,
|
||||
minLoadableRetryCount,
|
||||
loadErrorHandlingPolicy,
|
||||
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.upstream.Allocator;
|
||||
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.LoadErrorAction;
|
||||
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 CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private int minLoadableRetryCount;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private long livePresentationDelayMs;
|
||||
private boolean isCreateCalled;
|
||||
private @Nullable Object tag;
|
||||
@ -94,7 +96,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
@Nullable DataSource.Factory manifestDataSourceFactory) {
|
||||
this.chunkSourceFactory = Assertions.checkNotNull(chunkSourceFactory);
|
||||
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
||||
minLoadableRetryCount = DEFAULT_MIN_LOADABLE_RETRY_COUNT;
|
||||
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||
livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS;
|
||||
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
|
||||
* {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}.
|
||||
* Sets the minimum number of times to retry if a loading error occurs. See {@link
|
||||
* #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.
|
||||
* @return This factory, for convenience.
|
||||
* @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) {
|
||||
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);
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -193,7 +215,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
/* manifestParser= */ null,
|
||||
chunkSourceFactory,
|
||||
compositeSequenceableLoaderFactory,
|
||||
minLoadableRetryCount,
|
||||
loadErrorHandlingPolicy,
|
||||
livePresentationDelayMs,
|
||||
tag);
|
||||
}
|
||||
@ -233,7 +255,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
manifestParser,
|
||||
chunkSourceFactory,
|
||||
compositeSequenceableLoaderFactory,
|
||||
minLoadableRetryCount,
|
||||
loadErrorHandlingPolicy,
|
||||
livePresentationDelayMs,
|
||||
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
|
||||
* 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 SsChunkSource.Factory chunkSourceFactory;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private final int minLoadableRetryCount;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final long livePresentationDelayMs;
|
||||
private final EventDispatcher manifestEventDispatcher;
|
||||
private final ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
||||
@ -317,8 +335,12 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
SsChunkSource.Factory chunkSourceFactory,
|
||||
Handler eventHandler,
|
||||
MediaSourceEventListener eventListener) {
|
||||
this(manifest, chunkSourceFactory, DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
||||
eventHandler, eventListener);
|
||||
this(
|
||||
manifest,
|
||||
chunkSourceFactory,
|
||||
DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
||||
eventHandler,
|
||||
eventListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -345,7 +367,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
/* manifestParser= */ null,
|
||||
chunkSourceFactory,
|
||||
new DefaultCompositeSequenceableLoaderFactory(),
|
||||
minLoadableRetryCount,
|
||||
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
|
||||
/* tag= */ null);
|
||||
if (eventHandler != null && eventListener != null) {
|
||||
@ -372,8 +394,13 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
SsChunkSource.Factory chunkSourceFactory,
|
||||
Handler eventHandler,
|
||||
MediaSourceEventListener eventListener) {
|
||||
this(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
|
||||
DEFAULT_MIN_LOADABLE_RETRY_COUNT, DEFAULT_LIVE_PRESENTATION_DELAY_MS, eventHandler,
|
||||
this(
|
||||
manifestUri,
|
||||
manifestDataSourceFactory,
|
||||
chunkSourceFactory,
|
||||
DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT,
|
||||
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
|
||||
eventHandler,
|
||||
eventListener);
|
||||
}
|
||||
|
||||
@ -438,7 +465,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
manifestParser,
|
||||
chunkSourceFactory,
|
||||
new DefaultCompositeSequenceableLoaderFactory(),
|
||||
minLoadableRetryCount,
|
||||
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
|
||||
livePresentationDelayMs,
|
||||
/* tag= */ null);
|
||||
if (eventHandler != null && eventListener != null) {
|
||||
@ -453,7 +480,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
ParsingLoadable.Parser<? extends SsManifest> manifestParser,
|
||||
SsChunkSource.Factory chunkSourceFactory,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
int minLoadableRetryCount,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
long livePresentationDelayMs,
|
||||
@Nullable Object tag) {
|
||||
Assertions.checkState(manifest == null || !manifest.isLive);
|
||||
@ -463,7 +490,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
this.manifestParser = manifestParser;
|
||||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.livePresentationDelayMs = livePresentationDelayMs;
|
||||
this.manifestEventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
|
||||
this.tag = tag;
|
||||
@ -506,7 +533,7 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
chunkSourceFactory,
|
||||
mediaTransferListener,
|
||||
compositeSequenceableLoaderFactory,
|
||||
minLoadableRetryCount,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher,
|
||||
manifestLoaderErrorThrower,
|
||||
allocator);
|
||||
@ -668,7 +695,9 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
private void startLoadingManifest() {
|
||||
ParsingLoadable<SsManifest> loadable = new ParsingLoadable<>(manifestDataSource,
|
||||
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(
|
||||
loadable.dataSpec, loadable.dataSpec.uri, loadable.type, elapsedRealtimeMs);
|
||||
}
|
||||
|
@ -138,7 +138,8 @@ public final class FakeChunkSource implements ChunkSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e) {
|
||||
public boolean onChunkLoadError(
|
||||
Chunk chunk, boolean cancelable, Exception e, long blacklistDurationMs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user