diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d7bd90055e..ec11b5b7ed 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -9,6 +9,9 @@ ([#3314](https://github.com/google/ExoPlayer/issues/3314)). * Do not retry failed loads whose error is `FileNotFoundException`. * Prevent Cea608Decoder from generating Subtitles with null Cues list +* Caching: Cache data with unknown length by default. The previous flag to opt in + to this behavior (`DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH`) has been + replaced with an opt out flag (`DataSpec.FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN`). ### 2.9.2 ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 49209023e6..cb154eed30 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -850,6 +850,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; private DataSpec dataSpec; private long length; + @SuppressWarnings("method.invocation.invalid") public ExtractingLoadable( Uri uri, DataSource dataSource, @@ -864,7 +865,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; this.positionHolder = new PositionHolder(); this.pendingExtractorSeek = true; this.length = C.LENGTH_UNSET; - dataSpec = new DataSpec(uri, positionHolder.position, C.LENGTH_UNSET, customCacheKey); + dataSpec = buildDataSpec(/* position= */ 0); } // Loadable implementation. @@ -881,7 +882,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; ExtractorInput input = null; try { long position = positionHolder.position; - dataSpec = new DataSpec(uri, position, C.LENGTH_UNSET, customCacheKey); + dataSpec = buildDataSpec(position); length = dataSource.open(dataSpec); if (length != C.LENGTH_UNSET) { length += position; @@ -915,6 +916,17 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; // Internal methods. + private DataSpec buildDataSpec(long position) { + // Disable caching if the content length cannot be resolved, since this is indicative of a + // progressive live stream. + return new DataSpec( + uri, + position, + C.LENGTH_UNSET, + customCacheKey, + DataSpec.FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN); + } + private void setLoadPosition(long position, long timeUs) { positionHolder.position = position; seekTimeUs = timeUs; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java index 1ac6207454..218bc84b11 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java @@ -287,8 +287,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource { this.durationUs = durationUs; this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; this.treatLoadErrorsAsEndOfStream = treatLoadErrorsAsEndOfStream; - dataSpec = - new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP | DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH); + dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP); timeline = new SinglePeriodTimeline(durationUs, /* isSeekable= */ true, /* isDynamic= */ false, tag); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java index 4a4cc021f4..c33c7c823f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java @@ -32,32 +32,29 @@ public final class DataSpec { /** * The flags that apply to any request for data. Possible flag values are {@link #FLAG_ALLOW_GZIP} - * and {@link #FLAG_ALLOW_CACHING_UNKNOWN_LENGTH}. + * and {@link #FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN}. */ @Documented @Retention(RetentionPolicy.SOURCE) @IntDef( flag = true, - value = {FLAG_ALLOW_GZIP, FLAG_ALLOW_CACHING_UNKNOWN_LENGTH}) + value = {FLAG_ALLOW_GZIP, FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN}) public @interface Flags {} /** - * Permits an underlying network stack to request that the server use gzip compression. - *

- * Should not typically be set if the data being requested is already compressed (e.g. most audio - * and video requests). May be set when requesting other data. - *

- * When a {@link DataSource} is used to request data with this flag set, and if the - * {@link DataSource} does make a network request, then the value returned from - * {@link DataSource#open(DataSpec)} will typically be {@link C#LENGTH_UNSET}. The data read from - * {@link DataSource#read(byte[], int, int)} will be the decompressed data. + * Allows an underlying network stack to request that the server use gzip compression. + * + *

Should not typically be set if the data being requested is already compressed (e.g. most + * audio and video requests). May be set when requesting other data. + * + *

When a {@link DataSource} is used to request data with this flag set, and if the {@link + * DataSource} does make a network request, then the value returned from {@link + * DataSource#open(DataSpec)} will typically be {@link C#LENGTH_UNSET}. The data read from {@link + * DataSource#read(byte[], int, int)} will be the decompressed data. */ public static final int FLAG_ALLOW_GZIP = 1; - /** - * Permits content to be cached even if its length can not be resolved. Typically this's the case - * for progressive live streams and when {@link #FLAG_ALLOW_GZIP} is used. - */ - public static final int FLAG_ALLOW_CACHING_UNKNOWN_LENGTH = 1 << 1; // 2 + /** Prevents caching if the length cannot be resolved when the {@link DataSource} is opened. */ + public static final int FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN = 1 << 1; // 2 /** * The set of HTTP methods that are supported by ExoPlayer {@link HttpDataSource}s. One of {@link diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ParsingLoadable.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ParsingLoadable.java index cdcb3787fa..48e03a0083 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ParsingLoadable.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ParsingLoadable.java @@ -91,11 +91,7 @@ public final class ParsingLoadable implements Loadable { * @param parser Parses the object from the response. */ public ParsingLoadable(DataSource dataSource, Uri uri, int type, Parser parser) { - this( - dataSource, - new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP | DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH), - type, - parser); + this(dataSource, new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP), type, parser); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java index 8d310015f8..e9c3379280 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java @@ -121,7 +121,7 @@ public final class CacheDataSink implements DataSink { @Override public void open(DataSpec dataSpec) throws CacheDataSinkException { if (dataSpec.length == C.LENGTH_UNSET - && !dataSpec.isFlagSet(DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH)) { + && dataSpec.isFlagSet(DataSpec.FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN)) { this.dataSpec = null; return; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java index 1a44fb3144..fd4937ef86 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java @@ -268,7 +268,7 @@ public final class CacheUtil { dataSpec.position + absoluteStreamPosition - dataSpec.absoluteStreamPosition, C.LENGTH_UNSET, dataSpec.key, - dataSpec.flags | DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH); + dataSpec.flags); long resolvedLength = dataSource.open(dataSpec); if (counters.contentLength == C.LENGTH_UNSET && resolvedLength != C.LENGTH_UNSET) { counters.contentLength = dataSpec.absoluteStreamPosition + resolvedLength; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java index 83126ce34a..9182074eb9 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java @@ -602,7 +602,6 @@ public final class CacheDataSourceTest { } private DataSpec buildDataSpec(long position, long length, @Nullable String key) { - return new DataSpec( - testDataUri, position, length, key, DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH); + return new DataSpec(testDataUri, position, length, key); } } diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java index 9d6fbe37e7..664532d3ff 100644 --- a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java +++ b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java @@ -83,7 +83,7 @@ public final class CacheAsserts { * @throws IOException If an error occurred reading from the Cache. */ public static void assertDataCached(Cache cache, Uri uri, byte[] expected) throws IOException { - DataSpec dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH); + DataSpec dataSpec = new DataSpec(uri); assertDataCached(cache, dataSpec, expected); }