From 4eee4745557b012f40c43bb0ede2b0ea7cfe4c83 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Fri, 27 Jul 2018 03:56:24 -0700 Subject: [PATCH] Remove minLoadableRetryCount from HLS components Remove minLoadableRetryCount from HLS components in favor of LoadErrorHandlingPolicy#getMinimumLoadableRetryCount. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=206298419 --- .../java/com/google/android/exoplayer2/C.java | 28 +++---- .../DefaultLoadErrorHandlingPolicy.java | 81 ++++++++++++++++++ .../upstream/LoadErrorHandlingPolicy.java | 83 ++++--------------- .../DefaultLoadErrorHandlingPolicyTest.java | 11 +-- .../exoplayer2/source/hls/HlsMediaPeriod.java | 16 ++-- .../exoplayer2/source/hls/HlsMediaSource.java | 70 ++++++++-------- .../source/hls/HlsSampleStreamWrapper.java | 25 +++--- .../playlist/DefaultHlsPlaylistTracker.java | 37 ++++----- 8 files changed, 181 insertions(+), 170 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index b09d570219..587dd50ea2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -488,32 +488,24 @@ public final class C { */ public static final int RESULT_FORMAT_READ = -5; - /** - * A data type constant for data of unknown or unspecified type. - */ + /** A data type constant for data of unknown or unspecified type. */ public static final int DATA_TYPE_UNKNOWN = 0; - /** - * A data type constant for media, typically containing media samples. - */ + /** A data type constant for media, typically containing media samples. */ public static final int DATA_TYPE_MEDIA = 1; - /** - * A data type constant for media, typically containing only initialization data. - */ + /** A data type constant for media, typically containing only initialization data. */ public static final int DATA_TYPE_MEDIA_INITIALIZATION = 2; - /** - * A data type constant for drm or encryption data. - */ + /** A data type constant for drm or encryption data. */ public static final int DATA_TYPE_DRM = 3; - /** - * A data type constant for a manifest file. - */ + /** A data type constant for a manifest file. */ public static final int DATA_TYPE_MANIFEST = 4; - /** - * A data type constant for time synchronization data. - */ + /** A data type constant for time synchronization data. */ public static final int DATA_TYPE_TIME_SYNCHRONIZATION = 5; /** A data type constant for ads loader data. */ public static final int DATA_TYPE_AD = 6; + /** + * A data type constant for progressive media live streams, typically containing media samples. + */ + public static final int DATA_TYPE_MEDIA_LIVE_STREAM = 7; /** * Applications or extensions may define custom {@code DATA_TYPE_*} constants greater than or * equal to this value. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java new file mode 100644 index 0000000000..1c78fb0969 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 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.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; + +/** Default implementation of {@link LoadErrorHandlingPolicy}. */ +public final class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy { + + /** The default minimum number of times to retry loading data prior to propagating the error. */ + public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3; + + private final int minimumLoadableRetryCount; + + /** Creates an instance that returns the default values. */ + public DefaultLoadErrorHandlingPolicy() { + this(DEFAULT_MIN_LOADABLE_RETRY_COUNT); + } + + /** + * Creates an instance with the given value for {@link #getMinimumLoadableRetryCount(int)}. + * + * @param minimumLoadableRetryCount See {@link #getMinimumLoadableRetryCount}. + */ + public DefaultLoadErrorHandlingPolicy(int minimumLoadableRetryCount) { + this.minimumLoadableRetryCount = minimumLoadableRetryCount; + } + + /** + * 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}. + */ + @Override + public long getBlacklistDurationMsFor( + int dataType, long loadDurationMs, IOException exception, int errorCount) { + if (exception instanceof InvalidResponseCodeException) { + int responseCode = ((InvalidResponseCodeException) exception).responseCode; + return responseCode == 404 // HTTP 404 Not Found. + || responseCode == 410 // HTTP 410 Gone. + ? ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS + : C.TIME_UNSET; + } + return C.TIME_UNSET; + } + + /** + * Retries for any exception that is not a subclass of {@link ParserException}. The retry delay is + * calculated as {@code Math.min((errorCount - 1) * 1000, 5000)}. + */ + @Override + public long getRetryDelayMsFor( + int dataType, long loadDurationMs, IOException exception, int errorCount) { + return exception instanceof ParserException + ? C.TIME_UNSET + : Math.min((errorCount - 1) * 1000, 5000); + } + + /** Returns {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}. */ + @Override + public int getMinimumLoadableRetryCount(int dataType) { + return minimumLoadableRetryCount; + } +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/LoadErrorHandlingPolicy.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/LoadErrorHandlingPolicy.java index 8d6c0b9cf1..579169ad94 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/LoadErrorHandlingPolicy.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/LoadErrorHandlingPolicy.java @@ -16,9 +16,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 com.google.android.exoplayer2.upstream.Loader.Callback; import com.google.android.exoplayer2.upstream.Loader.Loadable; import java.io.IOException; @@ -29,74 +26,22 @@ import java.io.IOException; *

Loader clients may blacklist a resource when a load error occurs. Blacklisting works around * load errors by loading an alternative resource. Clients do not try blacklisting when a resource * does not have an alternative. When a resource does have valid alternatives, {@link - * #getBlacklistDurationMsFor(T, long, IOException, int)} defines whether the resource should be + * #getBlacklistDurationMsFor(int, long, IOException, int)} defines whether the resource should be * blacklisted. Blacklisting will succeed if any of the alternatives is not in the black list. * - *

When blacklisting does not take place, {@link #getRetryDelayMsFor(T, long, IOException, int)} - * defines whether the load is retried. Errors whose load is not retried are propagated. Load errors - * whose load is retried are propagated according to {@link - * #getMinimumLoadableRetryCount(Loadable)}. - * - * @param The type of the object being loaded. + *

When blacklisting does not take place, {@link #getRetryDelayMsFor(int, long, IOException, + * int)} defines whether the load is retried. Errors whose load is not retried are propagated. Load + * errors whose load is retried are propagated according to {@link + * #getMinimumLoadableRetryCount(int)}. */ -public interface LoadErrorHandlingPolicy { - - /** The default minimum number of times to retry loading data prior to propagating the error. */ - int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3; - - /** Default implementation of {@link LoadErrorHandlingPolicy}. */ - LoadErrorHandlingPolicy DEFAULT = - new LoadErrorHandlingPolicy() { - - /** - * 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}. - */ - @Override - public long getBlacklistDurationMsFor( - Loadable loadable, long loadDurationMs, IOException exception, int errorCount) { - if (exception instanceof InvalidResponseCodeException) { - int responseCode = ((InvalidResponseCodeException) exception).responseCode; - return responseCode == 404 // HTTP 404 Not Found. - || responseCode == 410 // HTTP 410 Gone. - ? ChunkedTrackBlacklistUtil.DEFAULT_TRACK_BLACKLIST_MS - : C.TIME_UNSET; - } - return C.TIME_UNSET; - } - - /** - * Retries for any exception that is not a subclass of {@link ParserException}. The retry - * delay is calculated as {@code Math.min((errorCount - 1) * 1000, 5000)}. - */ - @Override - public long getRetryDelayMsFor( - Loadable loadable, long loadDurationMs, IOException exception, int errorCount) { - return exception instanceof ParserException - ? C.TIME_UNSET - : Math.min((errorCount - 1) * 1000, 5000); - } - - /** Returns {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}. */ - @Override - public int getMinimumLoadableRetryCount(Loadable loadable) { - return DEFAULT_MIN_LOADABLE_RETRY_COUNT; - } - }; - - /** Returns {@link #DEFAULT}. */ - static LoadErrorHandlingPolicy getDefault() { - @SuppressWarnings("unchecked") // Safe contravariant cast. - LoadErrorHandlingPolicy policy = (LoadErrorHandlingPolicy) DEFAULT; - return policy; - } +public interface LoadErrorHandlingPolicy { /** * Returns the number of milliseconds for which a resource associated to a provided load error * should be blacklisted, or {@link C#TIME_UNSET} if the resource should not be blacklisted. * - * @param loadable The loadable whose load failed. + * @param dataType One of the {@link C C.DATA_TYPE_*} constants indicating the type of data to + * load. * @param loadDurationMs The duration in milliseconds of the load up to the point at which the * error occurred, including any previous attempts. * @param exception The load error. @@ -105,7 +50,7 @@ public interface LoadErrorHandlingPolicy { * not be blacklisted. */ long getBlacklistDurationMsFor( - T loadable, long loadDurationMs, IOException exception, int errorCount); + int dataType, long loadDurationMs, IOException exception, int errorCount); /** * Returns the number of milliseconds to wait before attempting the load again, or {@link @@ -115,7 +60,8 @@ public interface LoadErrorHandlingPolicy { * for a specific event before retrying. However, the load is retried if and only if this method * does not return {@link C#TIME_UNSET}. * - * @param loadable The loadable whose load failed. + * @param dataType One of the {@link C C.DATA_TYPE_*} constants indicating the type of data to + * load. * @param loadDurationMs The duration in milliseconds of the load up to the point at which the * error occurred, including any previous attempts. * @param exception The load error. @@ -123,16 +69,17 @@ public interface LoadErrorHandlingPolicy { * @return The number of milliseconds to wait before attempting the load again, or {@link * C#TIME_UNSET} if the error is fatal and should not be retried. */ - long getRetryDelayMsFor(T loadable, long loadDurationMs, IOException exception, int errorCount); + long getRetryDelayMsFor(int dataType, long loadDurationMs, IOException exception, int errorCount); /** * Returns the minimum number of times to retry a load in the case of a load error, before * propagating the error. * - * @param loadable The loadable to load. + * @param dataType One of the {@link C C.DATA_TYPE_*} constants indicating the type of data to + * load. * @return The minimum number of times to retry a load in the case of a load error, before * propagating the error. * @see Loader#startLoading(Loadable, Callback, int) */ - int getMinimumLoadableRetryCount(T loadable); + int getMinimumLoadableRetryCount(int dataType); } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicyTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicyTest.java index 295ebfb518..3879c62650 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicyTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicyTest.java @@ -30,7 +30,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -/** Unit tests for {@link LoadErrorHandlingPolicy#DEFAULT}. */ +/** Unit tests for {@link DefaultLoadErrorHandlingPolicy}. */ @RunWith(RobolectricTestRunner.class) public final class DefaultLoadErrorHandlingPolicyTest { @@ -90,12 +90,13 @@ public final class DefaultLoadErrorHandlingPolicyTest { } private static long getDefaultPolicyBlacklistOutputFor(IOException exception) { - return LoadErrorHandlingPolicy.DEFAULT.getBlacklistDurationMsFor( - DUMMY_LOADABLE, /* loadDurationMs= */ 1000, exception, /* errorCount= */ 1); + return new DefaultLoadErrorHandlingPolicy() + .getBlacklistDurationMsFor( + C.DATA_TYPE_MEDIA, /* loadDurationMs= */ 1000, exception, /* errorCount= */ 1); } private static long getDefaultPolicyRetryDelayOutputFor(IOException exception, int errorCount) { - return LoadErrorHandlingPolicy.DEFAULT.getRetryDelayMsFor( - DUMMY_LOADABLE, /* loadDurationMs= */ 1000, exception, errorCount); + return new DefaultLoadErrorHandlingPolicy() + .getRetryDelayMsFor(C.DATA_TYPE_MEDIA, /* loadDurationMs= */ 1000, exception, errorCount); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 1beb7e2e5a..c8cf8151c5 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -27,7 +27,6 @@ import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SequenceableLoader; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; -import com.google.android.exoplayer2.source.chunk.Chunk; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl; import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; @@ -56,8 +55,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private final HlsPlaylistTracker playlistTracker; private final HlsDataSourceFactory dataSourceFactory; private final @Nullable TransferListener mediaTransferListener; - private final LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy; - private final int minLoadableRetryCount; + private final LoadErrorHandlingPolicy loadErrorHandlingPolicy; private final EventDispatcher eventDispatcher; private final Allocator allocator; private final IdentityHashMap streamWrapperIndices; @@ -82,8 +80,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper * and keys. * @param mediaTransferListener The transfer listener to inform of any media data transfers. May * be null if no listener is available. - * @param chunkLoadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy} for chunk loads. - * @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs. + * @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}. * @param eventDispatcher A dispatcher to notify of events. * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param compositeSequenceableLoaderFactory A factory to create composite {@link @@ -95,8 +92,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper HlsPlaylistTracker playlistTracker, HlsDataSourceFactory dataSourceFactory, @Nullable TransferListener mediaTransferListener, - LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy, - int minLoadableRetryCount, + LoadErrorHandlingPolicy loadErrorHandlingPolicy, EventDispatcher eventDispatcher, Allocator allocator, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, @@ -105,8 +101,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper this.playlistTracker = playlistTracker; this.dataSourceFactory = dataSourceFactory; this.mediaTransferListener = mediaTransferListener; - this.chunkLoadErrorHandlingPolicy = chunkLoadErrorHandlingPolicy; - this.minLoadableRetryCount = minLoadableRetryCount; + this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; this.eventDispatcher = eventDispatcher; this.allocator = allocator; this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory; @@ -532,8 +527,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper allocator, positionUs, muxedAudioFormat, - chunkLoadErrorHandlingPolicy, - minLoadableRetryCount, + loadErrorHandlingPolicy, eventDispatcher); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 112071f1f2..6efa9728e9 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -32,7 +32,6 @@ import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispat import com.google.android.exoplayer2.source.SequenceableLoader; import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.ads.AdsMediaSource; -import com.google.android.exoplayer2.source.chunk.Chunk; import com.google.android.exoplayer2.source.hls.playlist.DefaultHlsPlaylistTracker; import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist; @@ -40,6 +39,7 @@ import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser; import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; 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.ParsingLoadable; import com.google.android.exoplayer2.upstream.TransferListener; @@ -64,8 +64,7 @@ public final class HlsMediaSource extends BaseMediaSource private @Nullable ParsingLoadable.Parser playlistParser; private @Nullable HlsPlaylistTracker playlistTracker; private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; - private LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy; - private int minLoadableRetryCount; + private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private boolean allowChunklessPreparation; private boolean isCreateCalled; private @Nullable Object tag; @@ -90,8 +89,7 @@ public final class HlsMediaSource extends BaseMediaSource public Factory(HlsDataSourceFactory hlsDataSourceFactory) { this.hlsDataSourceFactory = Assertions.checkNotNull(hlsDataSourceFactory); extractorFactory = HlsExtractorFactory.DEFAULT; - chunkLoadErrorHandlingPolicy = LoadErrorHandlingPolicy.getDefault(); - minLoadableRetryCount = DEFAULT_MIN_LOADABLE_RETRY_COUNT; + loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy(); compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory(); } @@ -126,31 +124,41 @@ public final class HlsMediaSource extends BaseMediaSource } /** - * Sets the {@link LoadErrorHandlingPolicy} for chunk loads. The default value is {@link - * LoadErrorHandlingPolicy#DEFAULT}. + * Sets the {@link LoadErrorHandlingPolicy}. The default value is created by calling {@link + * DefaultLoadErrorHandlingPolicy()}. * - * @param chunkLoadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy} for chunk loads. + *

Calling this method overrides any calls to {@link #setMinLoadableRetryCount(int)}. + * + *

If {@link #setPlaylistTracker} is not called on this builder, {@code + * loadErrorHandlingPolicy} is used for creating the used {@link DefaultHlsPlaylistTracker}. + * + * @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 setChunkLoadErrorHandlingPolicy( - LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy) { + public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) { Assertions.checkState(!isCreateCalled); - this.chunkLoadErrorHandlingPolicy = chunkLoadErrorHandlingPolicy; + this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; return this; } /** * Sets the minimum number of times to retry if a loading error occurs. The default value is - * {@link #DEFAULT_MIN_LOADABLE_RETRY_COUNT}. + * {@link DefaultLoadErrorHandlingPolicy#DEFAULT_MIN_LOADABLE_RETRY_COUNT}. + * + *

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) { Assertions.checkState(!isCreateCalled); - this.minLoadableRetryCount = minLoadableRetryCount; + this.loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount); return this; } @@ -234,8 +242,7 @@ public final class HlsMediaSource extends BaseMediaSource playlistTracker = new DefaultHlsPlaylistTracker( hlsDataSourceFactory, - LoadErrorHandlingPolicy.getDefault(), - minLoadableRetryCount, + loadErrorHandlingPolicy, playlistParser != null ? playlistParser : new HlsPlaylistParser()); } return new HlsMediaSource( @@ -243,8 +250,7 @@ public final class HlsMediaSource extends BaseMediaSource hlsDataSourceFactory, extractorFactory, compositeSequenceableLoaderFactory, - chunkLoadErrorHandlingPolicy, - minLoadableRetryCount, + loadErrorHandlingPolicy, playlistTracker, allowChunklessPreparation, tag); @@ -270,19 +276,14 @@ public final class HlsMediaSource extends BaseMediaSource public int[] getSupportedTypes() { return new int[] {C.TYPE_HLS}; } - } - /** - * 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 HlsExtractorFactory extractorFactory; private final Uri manifestUri; private final HlsDataSourceFactory dataSourceFactory; private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; - private final LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy; - private final int minLoadableRetryCount; + private final LoadErrorHandlingPolicy loadErrorHandlingPolicy; private final boolean allowChunklessPreparation; private final HlsPlaylistTracker playlistTracker; private final @Nullable Object tag; @@ -304,7 +305,11 @@ public final class HlsMediaSource extends BaseMediaSource DataSource.Factory dataSourceFactory, Handler eventHandler, MediaSourceEventListener eventListener) { - this(manifestUri, dataSourceFactory, DEFAULT_MIN_LOADABLE_RETRY_COUNT, eventHandler, + this( + manifestUri, + dataSourceFactory, + DefaultLoadErrorHandlingPolicy.DEFAULT_MIN_LOADABLE_RETRY_COUNT, + eventHandler, eventListener); } @@ -363,12 +368,10 @@ public final class HlsMediaSource extends BaseMediaSource dataSourceFactory, extractorFactory, new DefaultCompositeSequenceableLoaderFactory(), - LoadErrorHandlingPolicy.getDefault(), - minLoadableRetryCount, + new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount), new DefaultHlsPlaylistTracker( dataSourceFactory, - LoadErrorHandlingPolicy.getDefault(), - minLoadableRetryCount, + new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount), playlistParser), /* allowChunklessPreparation= */ false, /* tag= */ null); @@ -382,8 +385,7 @@ public final class HlsMediaSource extends BaseMediaSource HlsDataSourceFactory dataSourceFactory, HlsExtractorFactory extractorFactory, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, - LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy, - int minLoadableRetryCount, + LoadErrorHandlingPolicy loadErrorHandlingPolicy, HlsPlaylistTracker playlistTracker, boolean allowChunklessPreparation, @Nullable Object tag) { @@ -391,8 +393,7 @@ public final class HlsMediaSource extends BaseMediaSource this.dataSourceFactory = dataSourceFactory; this.extractorFactory = extractorFactory; this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory; - this.chunkLoadErrorHandlingPolicy = chunkLoadErrorHandlingPolicy; - this.minLoadableRetryCount = minLoadableRetryCount; + this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; this.playlistTracker = playlistTracker; this.allowChunklessPreparation = allowChunklessPreparation; this.tag = tag; @@ -422,8 +423,7 @@ public final class HlsMediaSource extends BaseMediaSource playlistTracker, dataSourceFactory, mediaTransferListener, - chunkLoadErrorHandlingPolicy, - minLoadableRetryCount, + loadErrorHandlingPolicy, eventDispatcher, allocator, compositeSequenceableLoaderFactory, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 73114f43c0..7061e3e738 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -85,8 +85,7 @@ import java.util.List; private final HlsChunkSource chunkSource; private final Allocator allocator; private final Format muxedAudioFormat; - private final LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy; - private final int minLoadableRetryCount; + private final LoadErrorHandlingPolicy loadErrorHandlingPolicy; private final Loader loader; private final EventDispatcher eventDispatcher; private final HlsChunkSource.HlsChunkHolder nextChunkHolder; @@ -141,9 +140,7 @@ import java.util.List; * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param positionUs The position from which to start loading media. * @param muxedAudioFormat Optional muxed audio {@link Format} as defined by the master playlist. - * @param chunkLoadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy} for chunk loads. - * @param minLoadableRetryCount The minimum number of times that the source should retry a load - * before propagating an error. + * @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}. * @param eventDispatcher A dispatcher to notify of events. */ public HlsSampleStreamWrapper( @@ -153,16 +150,14 @@ import java.util.List; Allocator allocator, long positionUs, Format muxedAudioFormat, - LoadErrorHandlingPolicy chunkLoadErrorHandlingPolicy, - int minLoadableRetryCount, + LoadErrorHandlingPolicy loadErrorHandlingPolicy, EventDispatcher eventDispatcher) { this.trackType = trackType; this.callback = callback; this.chunkSource = chunkSource; this.allocator = allocator; this.muxedAudioFormat = muxedAudioFormat; - this.chunkLoadErrorHandlingPolicy = chunkLoadErrorHandlingPolicy; - this.minLoadableRetryCount = minLoadableRetryCount; + this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; this.eventDispatcher = eventDispatcher; loader = new Loader("Loader:HlsSampleStreamWrapper"); nextChunkHolder = new HlsChunkSource.HlsChunkHolder(); @@ -571,7 +566,9 @@ import java.util.List; mediaChunks.add(mediaChunk); upstreamTrackFormat = mediaChunk.trackFormat; } - long elapsedRealtimeMs = loader.startLoading(loadable, this, minLoadableRetryCount); + long elapsedRealtimeMs = + loader.startLoading( + loadable, this, loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type)); eventDispatcher.loadStarted( loadable.dataSpec, loadable.dataSpec.uri, @@ -654,8 +651,8 @@ import java.util.List; if (!isMediaChunk || bytesLoaded == 0) { long blacklistDurationMs = - chunkLoadErrorHandlingPolicy.getBlacklistDurationMsFor( - loadable, loadDurationMs, error, errorCount); + loadErrorHandlingPolicy.getBlacklistDurationMsFor( + loadable.type, loadDurationMs, error, errorCount); if (blacklistDurationMs != C.TIME_UNSET) { blacklistSucceeded = chunkSource.maybeBlacklistTrack(loadable, blacklistDurationMs); } @@ -672,8 +669,8 @@ import java.util.List; loadErrorAction = Loader.DONT_RETRY; } else /* did not blacklist */ { long retryDelayMs = - chunkLoadErrorHandlingPolicy.getRetryDelayMsFor( - loadable, loadDurationMs, error, errorCount); + loadErrorHandlingPolicy.getRetryDelayMsFor( + loadable.type, loadDurationMs, error, errorCount); loadErrorAction = retryDelayMs != C.TIME_UNSET ? Loader.createRetryAction(/* resetErrorCount= */ false, retryDelayMs) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java index 099002a109..5cf3765b71 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java @@ -49,9 +49,7 @@ public final class DefaultHlsPlaylistTracker private final HlsDataSourceFactory dataSourceFactory; private final ParsingLoadable.Parser playlistParser; - private final LoadErrorHandlingPolicy> - playlistLoadErrorHandlingPolicy; - private final int minRetryCount; + private final LoadErrorHandlingPolicy loadErrorHandlingPolicy; private final IdentityHashMap playlistBundles; private final List listeners; @@ -67,21 +65,16 @@ public final class DefaultHlsPlaylistTracker /** * @param dataSourceFactory A factory for {@link DataSource} instances. - * @param playlistLoadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy} for playlist loads. - * @param minRetryCount The minimum number of times loads must be retried before {@link - * #maybeThrowPlaylistRefreshError(HlsUrl)} and {@link - * #maybeThrowPrimaryPlaylistRefreshError()} propagate any loading errors. + * @param loadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy}. * @param playlistParser A {@link ParsingLoadable.Parser} for HLS playlists. */ public DefaultHlsPlaylistTracker( HlsDataSourceFactory dataSourceFactory, - LoadErrorHandlingPolicy> playlistLoadErrorHandlingPolicy, - int minRetryCount, + LoadErrorHandlingPolicy loadErrorHandlingPolicy, ParsingLoadable.Parser playlistParser) { this.dataSourceFactory = dataSourceFactory; - this.minRetryCount = minRetryCount; this.playlistParser = playlistParser; - this.playlistLoadErrorHandlingPolicy = playlistLoadErrorHandlingPolicy; + this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; listeners = new ArrayList<>(); playlistBundles = new IdentityHashMap<>(); initialStartTimeUs = C.TIME_UNSET; @@ -106,7 +99,10 @@ public final class DefaultHlsPlaylistTracker Assertions.checkState(initialPlaylistLoader == null); initialPlaylistLoader = new Loader("DefaultHlsPlaylistTracker:MasterPlaylist"); long elapsedRealtime = - initialPlaylistLoader.startLoading(masterPlaylistLoadable, this, minRetryCount); + initialPlaylistLoader.startLoading( + masterPlaylistLoadable, + this, + loadErrorHandlingPolicy.getMinimumLoadableRetryCount(masterPlaylistLoadable.type)); eventDispatcher.loadStarted( masterPlaylistLoadable.dataSpec, masterPlaylistLoadable.dataSpec.uri, @@ -248,8 +244,8 @@ public final class DefaultHlsPlaylistTracker IOException error, int errorCount) { long retryDelayMs = - playlistLoadErrorHandlingPolicy.getRetryDelayMsFor( - loadable, loadDurationMs, error, errorCount); + loadErrorHandlingPolicy.getRetryDelayMsFor( + loadable.type, loadDurationMs, error, errorCount); boolean isFatal = retryDelayMs == C.TIME_UNSET; eventDispatcher.loadError( loadable.dataSpec, @@ -515,8 +511,8 @@ public final class DefaultHlsPlaylistTracker LoadErrorAction loadErrorAction; long blacklistDurationMs = - playlistLoadErrorHandlingPolicy.getBlacklistDurationMsFor( - loadable, loadDurationMs, error, errorCount); + loadErrorHandlingPolicy.getBlacklistDurationMsFor( + loadable.type, loadDurationMs, error, errorCount); boolean shouldBlacklist = blacklistDurationMs != C.TIME_UNSET; boolean blacklistingFailed = @@ -527,8 +523,8 @@ public final class DefaultHlsPlaylistTracker if (blacklistingFailed) { long retryDelay = - playlistLoadErrorHandlingPolicy.getRetryDelayMsFor( - loadable, loadDurationMs, error, errorCount); + loadErrorHandlingPolicy.getRetryDelayMsFor( + loadable.type, loadDurationMs, error, errorCount); loadErrorAction = retryDelay != C.TIME_UNSET ? Loader.createRetryAction(false, retryDelay) @@ -562,7 +558,10 @@ public final class DefaultHlsPlaylistTracker private void loadPlaylistImmediately() { long elapsedRealtime = - mediaPlaylistLoader.startLoading(mediaPlaylistLoadable, this, minRetryCount); + mediaPlaylistLoader.startLoading( + mediaPlaylistLoadable, + this, + loadErrorHandlingPolicy.getMinimumLoadableRetryCount(mediaPlaylistLoadable.type)); eventDispatcher.loadStarted( mediaPlaylistLoadable.dataSpec, mediaPlaylistLoadable.dataSpec.uri,