diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1dd124c27f..38aed91cc5 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -9,8 +9,9 @@ * Add `Player.onPlayWhenReadyChanged` with reasons. * Add `Player.onPlaybackStateChanged` and deprecate `Player.onPlayerStateChanged`. - * Deprecate and rename getPlaybackError to getPlayerError for consistency. - * Deprecate and rename onLoadingChanged to onIsLoadingChanged for consistency. + * Deprecate and rename `getPlaybackError` to `getPlayerError` for consistency. + * Deprecate and rename `onLoadingChanged` to `onIsLoadingChanged` for + consistency. * Make `MediaSourceEventListener.LoadEventInfo` and `MediaSourceEventListener.MediaLoadData` top-level classes. * Rename `MediaCodecRenderer.onOutputFormatChanged` to @@ -19,7 +20,9 @@ * Move player message-related constants from `C` to `Renderer`, to avoid having the constants class depend on player/renderer classes. * Split out `common` and `extractor` submodules. - * Add `DataSpec.Builder` and `DataSpec.customData`. + * Add `DataSpec.Builder` and deprecate most `DataSpec` constructors. + * Add `DataSpec.customData` to allow applications to pass custom data through + `DataSource` chains. * Text: * Parse `` and `` tags in WebVTT subtitles (rendering is coming later). diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java index b88e42faab..9aed4bfdf2 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java @@ -926,7 +926,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { redirectUrlDataSpec = dataSpec .buildUpon() - .setUri(Uri.parse(newLocationUrl)) + .setUri(newLocationUrl) .setHttpMethod(DataSpec.HTTP_METHOD_GET) .setHttpBody(null) .build(); diff --git a/extensions/cronet/src/test/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java b/extensions/cronet/src/test/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java index dadf5a9ecf..92658c1526 100644 --- a/extensions/cronet/src/test/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java +++ b/extensions/cronet/src/test/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java @@ -120,12 +120,15 @@ public final class CronetDataSourceTest { when(mockUrlRequestBuilder.build()).thenReturn(mockUrlRequest); mockStatusResponse(); - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, C.LENGTH_UNSET, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL)); testPostDataSpec = - new DataSpec(Uri.parse(TEST_URL), TEST_POST_BODY, 0, 0, C.LENGTH_UNSET, null, 0); + new DataSpec.Builder() + .setUri(TEST_URL) + .setHttpMethod(DataSpec.HTTP_METHOD_POST) + .setHttpBody(TEST_POST_BODY) + .build(); testHeadDataSpec = - new DataSpec( - Uri.parse(TEST_URL), DataSpec.HTTP_METHOD_HEAD, null, 0, 0, C.LENGTH_UNSET, null, 0); + new DataSpec.Builder().setUri(TEST_URL).setHttpMethod(DataSpec.HTTP_METHOD_HEAD).build(); testResponseHeader = new HashMap<>(); testResponseHeader.put("Content-Type", TEST_CONTENT_TYPE); // This value can be anything since the DataSpec is unset. @@ -197,7 +200,7 @@ public final class CronetDataSourceTest { @Test public void testRequestSetsRangeHeader() throws HttpDataSourceException { - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000); mockResponseStartSuccess(); dataSourceUnderTest.open(testDataSpec); @@ -207,7 +210,6 @@ public final class CronetDataSourceTest { @Test public void testRequestHeadersSet() throws HttpDataSourceException { - Map headersSet = new HashMap<>(); doAnswer( (invocation) -> { @@ -227,17 +229,14 @@ public final class CronetDataSourceTest { dataSpecRequestProperties.put("defaultHeader3", "dataSpecOverridesAll"); dataSpecRequestProperties.put("dataSourceHeader2", "dataSpecOverridesDataSource"); dataSpecRequestProperties.put("dataSpecHeader1", "dataSpecValue1"); + testDataSpec = - new DataSpec( - /* uri= */ Uri.parse(TEST_URL), - /* httpMethod= */ DataSpec.HTTP_METHOD_GET, - /* httpBody= */ null, - /* absoluteStreamPosition= */ 1000, - /* position= */ 1000, - /* length= */ 5000, - /* key= */ null, - /* flags= */ 0, - dataSpecRequestProperties); + new DataSpec.Builder() + .setUri(TEST_URL) + .setPosition(1000) + .setLength(5000) + .setHttpRequestHeaders(dataSpecRequestProperties) + .build(); mockResponseStartSuccess(); dataSourceUnderTest.open(testDataSpec); @@ -263,7 +262,7 @@ public final class CronetDataSourceTest { @Test public void testRequestOpenGzippedCompressedReturnsDataSpecLength() throws HttpDataSourceException { - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, 5000, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, 5000); testResponseHeader.put("Content-Encoding", "gzip"); testResponseHeader.put("Content-Length", Long.toString(50L)); mockResponseStartSuccess(); @@ -292,14 +291,14 @@ public final class CronetDataSourceTest { @Test public void open_ifBodyIsSetWithoutContentTypeHeader_fails() { testDataSpec = - new DataSpec( - /* uri= */ Uri.parse(TEST_URL), - /* postBody= */ new byte[1024], - /* absoluteStreamPosition= */ 200, - /* position= */ 200, - /* length= */ 1024, - /* key= */ "key", - /* flags= */ 0); + new DataSpec.Builder() + .setUri(TEST_URL) + .setHttpMethod(DataSpec.HTTP_METHOD_POST) + .setHttpBody(new byte[1024]) + .setPosition(200) + .setLength(1024) + .setKey("key") + .build(); try { dataSourceUnderTest.open(testDataSpec); @@ -481,7 +480,7 @@ public final class CronetDataSourceTest { mockResponseStartSuccess(); mockReadSuccess(1000, 5000); testUrlResponseInfo = createUrlResponseInfo(206); // Server supports range requests. - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000); dataSourceUnderTest.open(testDataSpec); @@ -498,7 +497,7 @@ public final class CronetDataSourceTest { mockResponseStartSuccess(); mockReadSuccess(0, 7000); testUrlResponseInfo = createUrlResponseInfo(200); // Server does not support range requests. - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000); dataSourceUnderTest.open(testDataSpec); @@ -571,7 +570,7 @@ public final class CronetDataSourceTest { @Test public void testOverread() throws HttpDataSourceException { - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, 16, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, 16); testResponseHeader.put("Content-Length", Long.toString(16L)); mockResponseStartSuccess(); mockReadSuccess(0, 16); @@ -724,7 +723,7 @@ public final class CronetDataSourceTest { mockResponseStartSuccess(); mockReadSuccess(1000, 5000); testUrlResponseInfo = createUrlResponseInfo(206); // Server supports range requests. - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000); dataSourceUnderTest.open(testDataSpec); @@ -743,7 +742,7 @@ public final class CronetDataSourceTest { mockResponseStartSuccess(); mockReadSuccess(0, 7000); testUrlResponseInfo = createUrlResponseInfo(200); // Server does not support range requests. - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000); dataSourceUnderTest.open(testDataSpec); @@ -792,7 +791,7 @@ public final class CronetDataSourceTest { @Test public void testOverreadByteBuffer() throws HttpDataSourceException { - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, 16, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, 16); testResponseHeader.put("Content-Length", Long.toString(16L)); mockResponseStartSuccess(); mockReadSuccess(0, 16); @@ -1084,7 +1083,7 @@ public final class CronetDataSourceTest { public void testRedirectParseAndAttachCookie_dataSourceHandlesSetCookie_andPreservesOriginalRequestHeadersIncludingByteRangeHeader() throws HttpDataSourceException { - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000); dataSourceUnderTest = new CronetDataSource( mockCronetEngine, @@ -1271,7 +1270,7 @@ public final class CronetDataSourceTest { @Test public void testAllowDirectExecutor() throws HttpDataSourceException { - testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000); mockResponseStartSuccess(); dataSourceUnderTest.open(testDataSpec); diff --git a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorSeekTest.java b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorSeekTest.java index 11c2e970ac..8d91039b31 100644 --- a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorSeekTest.java +++ b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorSeekTest.java @@ -187,7 +187,7 @@ public final class FlacExtractorSeekTest { // Internal methods private long readInputLength() throws IOException { - DataSpec dataSpec = new DataSpec(FILE_URI, 0, C.LENGTH_UNSET, null); + DataSpec dataSpec = new DataSpec(FILE_URI, /* position= */ 0, C.LENGTH_UNSET); long totalInputLength = dataSource.open(dataSpec); Util.closeQuietly(dataSource); return totalInputLength; @@ -276,7 +276,7 @@ public final class FlacExtractorSeekTest { } private ExtractorInput getExtractorInputFromPosition(long position) throws IOException { - DataSpec dataSpec = new DataSpec(FILE_URI, position, totalInputLength, /* key= */ null); + DataSpec dataSpec = new DataSpec(FILE_URI, position, totalInputLength); dataSource.open(dataSpec); return new DefaultExtractorInput(dataSource, position, totalInputLength); } diff --git a/extensions/okhttp/src/test/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceTest.java b/extensions/okhttp/src/test/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceTest.java index dab62b06e8..393c048eec 100644 --- a/extensions/okhttp/src/test/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceTest.java +++ b/extensions/okhttp/src/test/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceTest.java @@ -18,7 +18,6 @@ package com.google.android.exoplayer2.ext.okhttp; import static com.google.common.truth.Truth.assertThat; -import android.net.Uri; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.HttpDataSource; @@ -86,16 +85,12 @@ public class OkHttpDataSourceTest { dataSpecRequestProperties.put("5", dataSpecValue); DataSpec dataSpec = - new DataSpec( - /* uri= */ Uri.parse("http://www.google.com"), - /* httpMethod= */ 1, - /* httpBody= */ null, - /* absoluteStreamPosition= */ 1000, - /* position= */ 1000, - /* length= */ 5000, - /* key= */ null, - /* flags= */ 0, - dataSpecRequestProperties); + new DataSpec.Builder() + .setUri("http://www.google.com") + .setPosition(1000) + .setLength(5000) + .setHttpRequestHeaders(dataSpecRequestProperties) + .build(); Mockito.doAnswer( invocation -> { diff --git a/library/common/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java b/library/common/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java index 2a4eb2f661..571b1ac769 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java @@ -72,7 +72,18 @@ public final class DataSpec { } /** - * Sets {@link DataSpec#uri}. Must be called before {@link #build()}. + * Sets {@link DataSpec#uri}. + * + * @param uriString The {@link DataSpec#uri}. + * @return The builder. + */ + public Builder setUri(String uriString) { + this.uri = Uri.parse(uriString); + return this; + } + + /** + * Sets {@link DataSpec#uri}. * * @param uri The {@link DataSpec#uri}. * @return The builder. @@ -185,7 +196,7 @@ public final class DataSpec { * Builds a {@link DataSpec} with the builder's current values. * * @return The build {@link DataSpec}. - * @throws IllegalStateException If {@link #setUri(Uri)} has not been called. + * @throws IllegalStateException If {@link #setUri} has not been called. */ public DataSpec build() { Assertions.checkStateNotNull(uri, "The uri must be set."); @@ -353,15 +364,39 @@ public final class DataSpec { * @param uri {@link #uri}. */ public DataSpec(Uri uri) { - this(uri, /* flags= */ 0); + this(uri, /* position= */ 0, /* length= */ C.LENGTH_UNSET); } /** * Constructs an instance. * * @param uri {@link #uri}. + * @param position {@link #position}. + * @param length {@link #length}. + */ + public DataSpec(Uri uri, long position, long length) { + this( + uri, + /* uriPositionOffset= */ 0, + HTTP_METHOD_GET, + /* httpBody= */ null, + /* httpRequestHeaders= */ Collections.emptyMap(), + position, + length, + /* key= */ null, + /* flags= */ 0, + /* customData= */ null); + } + + /** + * Constructs an instance. + * + * @deprecated Use {@link Builder}. + * @param uri {@link #uri}. * @param flags {@link #flags}. */ + @SuppressWarnings("deprecation") + @Deprecated public DataSpec(Uri uri, @Flags int flags) { this(uri, /* position= */ 0, C.LENGTH_UNSET, /* key= */ null, flags); } @@ -369,11 +404,14 @@ public final class DataSpec { /** * Constructs an instance. * + * @deprecated Use {@link Builder}. * @param uri {@link #uri}. * @param position {@link #position}. * @param length {@link #length}. * @param key {@link #key}. */ + @SuppressWarnings("deprecation") + @Deprecated public DataSpec(Uri uri, long position, long length, @Nullable String key) { this(uri, position, position, length, key, /* flags= */ 0); } @@ -381,12 +419,15 @@ public final class DataSpec { /** * Constructs an instance. * + * @deprecated Use {@link Builder}. * @param uri {@link #uri}. * @param position {@link #position}. * @param length {@link #length}. * @param key {@link #key}. * @param flags {@link #flags}. */ + @SuppressWarnings("deprecation") + @Deprecated public DataSpec(Uri uri, long position, long length, @Nullable String key, @Flags int flags) { this(uri, position, position, length, key, flags); } @@ -394,6 +435,7 @@ public final class DataSpec { /** * Constructs an instance. * + * @deprecated Use {@link Builder}. * @param uri {@link #uri}. * @param position {@link #position}, equal to {@link #position}. * @param length {@link #length}. @@ -401,6 +443,8 @@ public final class DataSpec { * @param flags {@link #flags}. * @param httpRequestHeaders {@link #httpRequestHeaders} */ + @SuppressWarnings("deprecation") + @Deprecated public DataSpec( Uri uri, long position, @@ -423,6 +467,7 @@ public final class DataSpec { /** * Constructs an instance where {@link #uriPositionOffset} may be non-zero. * + * @deprecated Use {@link Builder}. * @param uri {@link #uri}. * @param absoluteStreamPosition The sum of {@link #uriPositionOffset} and {@link #position}. * @param position {@link #position}. @@ -430,6 +475,8 @@ public final class DataSpec { * @param key {@link #key}. * @param flags {@link #flags}. */ + @SuppressWarnings("deprecation") + @Deprecated public DataSpec( Uri uri, long absoluteStreamPosition, @@ -446,6 +493,7 @@ public final class DataSpec { * set to {@link #HTTP_METHOD_POST}. If {@code postBody} is null then {@link #httpMethod} is set * to {@link #HTTP_METHOD_GET}. * + * @deprecated Use {@link Builder}. * @param uri {@link #uri}. * @param postBody {@link #httpBody} The body of the HTTP request, which is also used to infer the * {@link #httpMethod}. @@ -455,6 +503,8 @@ public final class DataSpec { * @param key {@link #key}. * @param flags {@link #flags}. */ + @SuppressWarnings("deprecation") + @Deprecated public DataSpec( Uri uri, @Nullable byte[] postBody, @@ -477,6 +527,7 @@ public final class DataSpec { /** * Construct a instance where {@link #uriPositionOffset} may be non-zero. * + * @deprecated Use {@link Builder}. * @param uri {@link #uri}. * @param httpMethod {@link #httpMethod}. * @param httpBody {@link #httpBody}. @@ -486,6 +537,8 @@ public final class DataSpec { * @param key {@link #key}. * @param flags {@link #flags}. */ + @SuppressWarnings("deprecation") + @Deprecated public DataSpec( Uri uri, @HttpMethod int httpMethod, @@ -510,6 +563,7 @@ public final class DataSpec { /** * Construct a instance where {@link #uriPositionOffset} may be non-zero. * + * @deprecated Use {@link Builder}. * @param uri {@link #uri}. * @param httpMethod {@link #httpMethod}. * @param httpBody {@link #httpBody}. @@ -520,6 +574,7 @@ public final class DataSpec { * @param flags {@link #flags}. * @param httpRequestHeaders {@link #httpRequestHeaders}. */ + @Deprecated public DataSpec( Uri uri, @HttpMethod int httpMethod, diff --git a/library/common/src/test/java/com/google/android/exoplayer2/upstream/DataSpecTest.java b/library/common/src/test/java/com/google/android/exoplayer2/upstream/DataSpecTest.java index eefd4f8cb6..b3441bbf56 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/upstream/DataSpecTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/upstream/DataSpecTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.TestCase.fail; import android.net.Uri; +import androidx.annotation.Nullable; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.C; import java.util.HashMap; @@ -31,6 +32,7 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class DataSpecTest { + @SuppressWarnings("deprecation") @Test public void createDataSpec_withDefaultValues() { Uri uri = Uri.parse("www.google.com"); @@ -212,11 +214,12 @@ public class DataSpecTest { assertHttpRequestHeadersReadOnly(dataSpec); } + @SuppressWarnings("deprecation") @Test public void createDataSpec_setsHttpMethodAndPostBody() { Uri uri = Uri.parse("www.google.com"); - byte[] postBody = new byte[] {0, 1, 2, 3}; + @Nullable byte[] postBody = new byte[] {0, 1, 2, 3}; DataSpec dataSpec = new DataSpec( uri, @@ -259,7 +262,7 @@ public class DataSpecTest { @Test public void withUri_copiesHttpRequestHeaders() { Map httpRequestHeaders = createHttpRequestHeaders(5); - DataSpec dataSpec = createDataSpecWithHeaders(httpRequestHeaders); + DataSpec dataSpec = createDataSpecWithHttpRequestHeaders(httpRequestHeaders); DataSpec dataSpecCopy = dataSpec.withUri(Uri.parse("www.new-uri.com")); @@ -269,7 +272,7 @@ public class DataSpecTest { @Test public void subrange_copiesHttpRequestHeaders() { Map httpRequestHeaders = createHttpRequestHeaders(5); - DataSpec dataSpec = createDataSpecWithHeaders(httpRequestHeaders); + DataSpec dataSpec = createDataSpecWithHttpRequestHeaders(httpRequestHeaders); DataSpec dataSpecCopy = dataSpec.subrange(2); @@ -279,7 +282,7 @@ public class DataSpecTest { @Test public void subrange_withOffsetAndLength_copiesHttpRequestHeaders() { Map httpRequestHeaders = createHttpRequestHeaders(5); - DataSpec dataSpec = createDataSpecWithHeaders(httpRequestHeaders); + DataSpec dataSpec = createDataSpecWithHttpRequestHeaders(httpRequestHeaders); DataSpec dataSpecCopy = dataSpec.subrange(2, 2); @@ -289,7 +292,7 @@ public class DataSpecTest { @Test public void withRequestHeaders_setsCorrectHeaders() { Map httpRequestHeaders = createHttpRequestHeaders(5); - DataSpec dataSpec = createDataSpecWithHeaders(httpRequestHeaders); + DataSpec dataSpec = createDataSpecWithHttpRequestHeaders(httpRequestHeaders); Map newRequestHeaders = createHttpRequestHeaders(5, 10); DataSpec dataSpecCopy = dataSpec.withRequestHeaders(newRequestHeaders); @@ -300,7 +303,7 @@ public class DataSpecTest { @Test public void withAdditionalHeaders_setsCorrectHeaders() { Map httpRequestHeaders = createHttpRequestHeaders(5); - DataSpec dataSpec = createDataSpecWithHeaders(httpRequestHeaders); + DataSpec dataSpec = createDataSpecWithHttpRequestHeaders(httpRequestHeaders); Map additionalHeaders = createHttpRequestHeaders(5, 10); // additionalHeaders may overwrite a header key String existingKey = httpRequestHeaders.keySet().iterator().next(); @@ -328,17 +331,12 @@ public class DataSpecTest { return httpRequestParameters; } - private static DataSpec createDataSpecWithHeaders(Map httpRequestHeaders) { - return new DataSpec( - Uri.parse("www.google.com"), - /* httpMethod= */ 0, - /* httpBody= */ new byte[] {0, 0, 0, 0}, - /* absoluteStreamPosition= */ 0, - /* position= */ 0, - /* length= */ 1, - /* key= */ "key", - /* flags= */ 0, - httpRequestHeaders); + private static DataSpec createDataSpecWithHttpRequestHeaders( + Map httpRequestHeaders) { + return new DataSpec.Builder() + .setUri("www.google.com") + .setHttpRequestHeaders(httpRequestHeaders) + .build(); } @SuppressWarnings("deprecation") diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java index 492eac9d11..b501f30eb4 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java @@ -97,7 +97,7 @@ public final class ContentDataSourceTest { ContentDataSource dataSource = new ContentDataSource(InstrumentationRegistry.getTargetContext()); try { - DataSpec dataSpec = new DataSpec(contentUri, offset, length, null); + DataSpec dataSpec = new DataSpec(contentUri, offset, length); byte[] completeData = TestUtil.getByteArray(InstrumentationRegistry.getTargetContext(), DATA_PATH); byte[] expectedData = Arrays.copyOfRange(completeData, offset, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java index 15116a23a7..3b87cfb092 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.drm; -import android.net.Uri; import android.text.TextUtils; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -150,15 +149,12 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback { int manualRedirectCount = 0; while (true) { DataSpec dataSpec = - new DataSpec( - Uri.parse(url), - DataSpec.HTTP_METHOD_POST, - httpBody, - /* absoluteStreamPosition= */ 0, - /* position= */ 0, - /* length= */ C.LENGTH_UNSET, - /* key= */ null, - DataSpec.FLAG_ALLOW_GZIP); + new DataSpec.Builder() + .setUri(url) + .setHttpMethod(DataSpec.HTTP_METHOD_POST) + .setHttpBody(httpBody) + .setFlags(DataSpec.FLAG_ALLOW_GZIP) + .build(); DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec); try { return Util.toByteArray(inputStream); @@ -168,7 +164,7 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback { boolean manuallyRedirect = (e.responseCode == 307 || e.responseCode == 308) && manualRedirectCount++ < MAX_MANUAL_REDIRECTS; - String redirectUrl = manuallyRedirect ? getRedirectUrl(e) : null; + @Nullable String redirectUrl = manuallyRedirect ? getRedirectUrl(e) : null; if (redirectUrl == null) { throw e; } @@ -182,12 +178,11 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback { private static @Nullable String getRedirectUrl(InvalidResponseCodeException exception) { Map> headerFields = exception.headerFields; if (headerFields != null) { - List locationHeaders = headerFields.get("Location"); + @Nullable List locationHeaders = headerFields.get("Location"); if (locationHeaders != null && !locationHeaders.isEmpty()) { return locationHeaders.get(0); } } return null; } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java index a73258272c..055410c431 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java @@ -56,12 +56,11 @@ public final class ProgressiveDownloader implements Downloader { public ProgressiveDownloader( Uri uri, @Nullable String customCacheKey, DownloaderConstructorHelper constructorHelper) { this.dataSpec = - new DataSpec( - uri, - /* absoluteStreamPosition= */ 0, - C.LENGTH_UNSET, - customCacheKey, - /* flags= */ DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION); + new DataSpec.Builder() + .setUri(uri) + .setKey(customCacheKey) + .setFlags(DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION) + .build(); this.cache = constructorHelper.getCache(); this.dataSource = constructorHelper.createCacheDataSource(); this.cacheKeyFactory = constructorHelper.getCacheKeyFactory(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java index 4ee958e77f..299998ea88 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java @@ -228,12 +228,7 @@ public abstract class SegmentDownloader> impleme } protected static DataSpec getCompressibleDataSpec(Uri uri) { - return new DataSpec( - uri, - /* absoluteStreamPosition= */ 0, - /* length= */ C.LENGTH_UNSET, - /* key= */ null, - /* flags= */ DataSpec.FLAG_ALLOW_GZIP); + return new DataSpec.Builder().setUri(uri).setFlags(DataSpec.FLAG_ALLOW_GZIP).build(); } private static void mergeSegments(List segments, CacheKeyFactory keyFactory) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java index c811d52e56..e0dbc2ba7c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java @@ -1022,13 +1022,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; 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 | DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION, - ICY_METADATA_HEADERS); + return new DataSpec.Builder() + .setUri(uri) + .setPosition(position) + .setKey(customCacheKey) + .setFlags( + DataSpec.FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN | DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION) + .setHttpRequestHeaders(ICY_METADATA_HEADERS) + .build(); } private void setLoadPosition(long position, long 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 0a987ad86d..455b9cf417 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,7 +287,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource { this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; this.treatLoadErrorsAsEndOfStream = treatLoadErrorsAsEndOfStream; this.tag = tag; - dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP); + dataSpec = new DataSpec.Builder().setUri(uri).setFlags(DataSpec.FLAG_ALLOW_GZIP).build(); timeline = new SinglePeriodTimeline( durationUs, 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 7fceda1700..a60d35e3a7 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 @@ -109,7 +109,11 @@ 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), type, parser); + this( + dataSource, + new DataSpec.Builder().setUri(uri).setFlags(DataSpec.FLAG_ALLOW_GZIP).build(), + type, + parser); } /** diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/ByteArrayDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/ByteArrayDataSourceTest.java index ee64e56c51..9999ef3e58 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/ByteArrayDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/ByteArrayDataSourceTest.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.upstream; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; +import android.net.Uri; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.C; import java.io.IOException; @@ -112,7 +113,7 @@ public final class ByteArrayDataSourceTest { boolean opened = false; try { // Open the source. - long length = dataSource.open(new DataSpec(null, dataOffset, dataLength, null)); + long length = dataSource.open(new DataSpec(Uri.EMPTY, dataOffset, dataLength)); opened = true; assertThat(expectFailOnOpen).isFalse(); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSchemeDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSchemeDataSourceTest.java index 680674a16c..7f068aa6a5 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSchemeDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSchemeDataSourceTest.java @@ -151,7 +151,7 @@ public final class DataSchemeDataSourceTest { } private static DataSpec buildDataSpec(String uriString, int position, int length) { - return new DataSpec(Uri.parse(uriString), position, length, /* key= */ null); + return new DataSpec(Uri.parse(uriString), position, length); } /** diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceTest.java index d724369d93..405fe6c5ee 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceTest.java @@ -18,7 +18,6 @@ package com.google.android.exoplayer2.upstream; import static com.google.common.truth.Truth.assertThat; -import android.net.Uri; import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -89,16 +88,13 @@ public class DefaultHttpDataSourceTest { dataSpecRequestProperties.put("5", dataSpecParameter); DataSpec dataSpec = - new DataSpec( - /* uri= */ Uri.parse("http://www.google.com"), - /* httpMethod= */ 1, - /* httpBody= */ new byte[] {0, 0, 0, 0}, - /* absoluteStreamPosition= */ 0, - /* position= */ 0, - /* length= */ 1, - /* key= */ "key", - /* flags= */ 0, - dataSpecRequestProperties); + new DataSpec.Builder() + .setUri("http://www.google.com") + .setHttpBody(new byte[] {0, 0, 0, 0}) + .setLength(1) + .setKey("key") + .setHttpRequestHeaders(dataSpecRequestProperties) + .build(); defaultHttpDataSource.open(dataSpec); 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 c94e063749..c1a21b6ca8 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 @@ -286,11 +286,7 @@ public final class CacheDataSourceTest { // An unbounded request with offset for not cached content. dataSpec = - new DataSpec( - Uri.parse("https://www.test.com/other"), - TEST_DATA.length - 2, - C.LENGTH_UNSET, - /* key= */ null); + new DataSpec(Uri.parse("https://www.test.com/other"), TEST_DATA.length - 2, C.LENGTH_UNSET); assertThat(cacheDataSource.open(dataSpec)).isEqualTo(C.LENGTH_UNSET); } @@ -624,12 +620,13 @@ public final class CacheDataSourceTest { } private DataSpec buildDataSpec(long position, long length, @Nullable String key) { - return new DataSpec( - testDataUri, - position, - length, - key, - DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION, - httpRequestHeaders); + return new DataSpec.Builder() + .setUri(testDataUri) + .setPosition(position) + .setLength(length) + .setKey(key) + .setFlags(DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION) + .setHttpRequestHeaders(httpRequestHeaders) + .build(); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest2.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest2.java index 05ef69c572..f1baab3b12 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest2.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest2.java @@ -48,25 +48,24 @@ public final class CacheDataSourceTest2 { private static final int EXO_CACHE_MAX_FILESIZE = 128; private static final Uri URI = Uri.parse("http://test.com/content"); - private static final String KEY = "key"; private static final byte[] DATA = TestUtil.buildTestData(8 * EXO_CACHE_MAX_FILESIZE + 1); // A DataSpec that covers the full file. - private static final DataSpec FULL = new DataSpec(URI, 0, DATA.length, KEY); + private static final DataSpec FULL = new DataSpec(URI, 0, DATA.length); private static final int OFFSET_ON_BOUNDARY = EXO_CACHE_MAX_FILESIZE; // A DataSpec that starts at 0 and extends to a cache file boundary. - private static final DataSpec END_ON_BOUNDARY = new DataSpec(URI, 0, OFFSET_ON_BOUNDARY, KEY); + private static final DataSpec END_ON_BOUNDARY = new DataSpec(URI, 0, OFFSET_ON_BOUNDARY); // A DataSpec that starts on the same boundary and extends to the end of the file. - private static final DataSpec START_ON_BOUNDARY = new DataSpec(URI, OFFSET_ON_BOUNDARY, - DATA.length - OFFSET_ON_BOUNDARY, KEY); + private static final DataSpec START_ON_BOUNDARY = + new DataSpec(URI, OFFSET_ON_BOUNDARY, DATA.length - OFFSET_ON_BOUNDARY); private static final int OFFSET_OFF_BOUNDARY = EXO_CACHE_MAX_FILESIZE * 2 + 1; // A DataSpec that starts at 0 and extends to just past a cache file boundary. - private static final DataSpec END_OFF_BOUNDARY = new DataSpec(URI, 0, OFFSET_OFF_BOUNDARY, KEY); + private static final DataSpec END_OFF_BOUNDARY = new DataSpec(URI, 0, OFFSET_OFF_BOUNDARY); // A DataSpec that starts on the same boundary and extends to the end of the file. - private static final DataSpec START_OFF_BOUNDARY = new DataSpec(URI, OFFSET_OFF_BOUNDARY, - DATA.length - OFFSET_OFF_BOUNDARY, KEY); + private static final DataSpec START_OFF_BOUNDARY = + new DataSpec(URI, OFFSET_OFF_BOUNDARY, DATA.length - OFFSET_OFF_BOUNDARY); @Test public void testWithoutEncryption() throws IOException { diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java index 9a449b2ebd..5fa8a35573 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java @@ -126,12 +126,12 @@ public final class CacheUtilTest { // If DataSpec.key is present, returns it. assertThat( CacheUtil.DEFAULT_CACHE_KEY_FACTORY.buildCacheKey( - new DataSpec(testUri, 0, LENGTH_UNSET, key))) + new DataSpec.Builder().setUri(testUri).setKey(key).build())) .isEqualTo(key); // If not generates a new one using DataSpec.uri. assertThat( CacheUtil.DEFAULT_CACHE_KEY_FACTORY.buildCacheKey( - new DataSpec(testUri, 0, LENGTH_UNSET, null))) + new DataSpec(testUri, /* position= */ 0, /* length= */ LENGTH_UNSET))) .isEqualTo(testUri.toString()); } @@ -186,11 +186,7 @@ public final class CacheUtilTest { mockCache.spansAndGaps = new int[] {100, 100, 200}; Pair contentLengthAndBytesCached = CacheUtil.getCached( - new DataSpec( - Uri.parse("test"), - /* absoluteStreamPosition= */ 100, - /* length= */ C.LENGTH_UNSET, - /* key= */ null), + new DataSpec(Uri.parse("test"), /* position= */ 100, /* length= */ C.LENGTH_UNSET), mockCache, /* cacheKeyFactory= */ null); @@ -222,7 +218,7 @@ public final class CacheUtilTest { FakeDataSource dataSource = new FakeDataSource(fakeDataSet); Uri testUri = Uri.parse("test_data"); - DataSpec dataSpec = new DataSpec(testUri, 10, 20, null); + DataSpec dataSpec = new DataSpec(testUri, /* position= */ 10, /* length= */ 20); CachingCounters counters = new CachingCounters(); CacheUtil.cache( dataSpec, cache, /* cacheKeyFactory= */ null, dataSource, counters, /* isCanceled= */ null); @@ -266,7 +262,7 @@ public final class CacheUtilTest { FakeDataSource dataSource = new FakeDataSource(fakeDataSet); Uri testUri = Uri.parse("test_data"); - DataSpec dataSpec = new DataSpec(testUri, 10, 20, null); + DataSpec dataSpec = new DataSpec(testUri, /* position= */ 10, /* length= */ 20); CachingCounters counters = new CachingCounters(); CacheUtil.cache( dataSpec, cache, /* cacheKeyFactory= */ null, dataSource, counters, /* isCanceled= */ null); @@ -292,7 +288,7 @@ public final class CacheUtilTest { FakeDataSource dataSource = new FakeDataSource(fakeDataSet); Uri testUri = Uri.parse("test_data"); - DataSpec dataSpec = new DataSpec(testUri, 0, 1000, null); + DataSpec dataSpec = new DataSpec(testUri, /* position= */ 0, /* length= */ 1000); CachingCounters counters = new CachingCounters(); CacheUtil.cache( dataSpec, cache, /* cacheKeyFactory= */ null, dataSource, counters, /* isCanceled= */ null); @@ -307,7 +303,7 @@ public final class CacheUtilTest { FakeDataSource dataSource = new FakeDataSource(fakeDataSet); Uri testUri = Uri.parse("test_data"); - DataSpec dataSpec = new DataSpec(testUri, 0, 1000, null); + DataSpec dataSpec = new DataSpec(testUri, /* position= */ 0, /* length= */ 1000); try { CacheUtil.cache( @@ -358,8 +354,11 @@ public final class CacheUtilTest { FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100); FakeDataSource dataSource = new FakeDataSource(fakeDataSet); - Uri uri = Uri.parse("test_data"); - DataSpec dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION); + DataSpec dataSpec = + new DataSpec.Builder() + .setUri("test_data") + .setFlags(DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION) + .build(); CacheUtil.cache( dataSpec, cache, diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java index 74e4cb1dea..01fc5965f3 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java @@ -45,6 +45,22 @@ import java.util.List; */ public final class DashUtil { + /** + * Builds a {@link DataSpec} for a given {@link RangedUri} belonging to {@link Representation}. + * + * @param representation The {@link Representation} to which the request belongs. + * @param requestUri The {@link RangedUri} of the data to request. + * @return The {@link DataSpec}. + */ + public static DataSpec buildDataSpec(Representation representation, RangedUri requestUri) { + return new DataSpec.Builder() + .setUri(requestUri.resolveUri(representation.baseUrl)) + .setPosition(requestUri.start) + .setLength(requestUri.length) + .setKey(representation.getCacheKey()) + .build(); + } + /** * Loads a DASH manifest. * @@ -53,8 +69,7 @@ public final class DashUtil { * @return An instance of {@link DashManifest}. * @throws IOException Thrown when there is an error while loading. */ - public static DashManifest loadManifest(DataSource dataSource, Uri uri) - throws IOException { + public static DashManifest loadManifest(DataSource dataSource, Uri uri) throws IOException { return ParsingLoadable.load(dataSource, new DashManifestParser(), uri, C.DATA_TYPE_MANIFEST); } @@ -176,8 +191,7 @@ public final class DashUtil { private static void loadInitializationData(DataSource dataSource, Representation representation, ChunkExtractorWrapper extractorWrapper, RangedUri requestUri) throws IOException, InterruptedException { - DataSpec dataSpec = new DataSpec(requestUri.resolveUri(representation.baseUrl), - requestUri.start, requestUri.length, representation.getCacheKey()); + DataSpec dataSpec = DashUtil.buildDataSpec(representation, requestUri); InitializationChunk initializationChunk = new InitializationChunk(dataSource, dataSpec, representation.format, C.SELECTION_REASON_UNKNOWN, null /* trackSelectionData */, extractorWrapper); diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index a83d0ab3b2..a5ed7b4437 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -487,20 +487,19 @@ public class DefaultDashChunkSource implements DashChunkSource { Object trackSelectionData, RangedUri initializationUri, RangedUri indexUri) { + Representation representation = representationHolder.representation; RangedUri requestUri; - String baseUrl = representationHolder.representation.baseUrl; if (initializationUri != null) { // It's common for initialization and index data to be stored adjacently. Attempt to merge // the two requests together to request both at once. - requestUri = initializationUri.attemptMerge(indexUri, baseUrl); + requestUri = initializationUri.attemptMerge(indexUri, representation.baseUrl); if (requestUri == null) { requestUri = initializationUri; } } else { requestUri = indexUri; } - DataSpec dataSpec = new DataSpec(requestUri.resolveUri(baseUrl), requestUri.start, - requestUri.length, representationHolder.representation.getCacheKey()); + DataSpec dataSpec = DashUtil.buildDataSpec(representation, requestUri); return new InitializationChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, representationHolder.extractorWrapper); } @@ -521,15 +520,14 @@ public class DefaultDashChunkSource implements DashChunkSource { String baseUrl = representation.baseUrl; if (representationHolder.extractorWrapper == null) { long endTimeUs = representationHolder.getSegmentEndTimeUs(firstSegmentNum); - DataSpec dataSpec = new DataSpec(segmentUri.resolveUri(baseUrl), - segmentUri.start, segmentUri.length, representation.getCacheKey()); + DataSpec dataSpec = DashUtil.buildDataSpec(representation, segmentUri); return new SingleSampleMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs, firstSegmentNum, trackType, trackFormat); } else { int segmentCount = 1; for (int i = 1; i < maxSegmentCount; i++) { RangedUri nextSegmentUri = representationHolder.getSegmentUrl(firstSegmentNum + i); - RangedUri mergedSegmentUri = segmentUri.attemptMerge(nextSegmentUri, baseUrl); + @Nullable RangedUri mergedSegmentUri = segmentUri.attemptMerge(nextSegmentUri, baseUrl); if (mergedSegmentUri == null) { // Unable to merge segment fetches because the URIs do not merge. break; @@ -543,8 +541,7 @@ public class DefaultDashChunkSource implements DashChunkSource { periodDurationUs != C.TIME_UNSET && periodDurationUs <= endTimeUs ? periodDurationUs : C.TIME_UNSET; - DataSpec dataSpec = new DataSpec(segmentUri.resolveUri(baseUrl), - segmentUri.start, segmentUri.length, representation.getCacheKey()); + DataSpec dataSpec = DashUtil.buildDataSpec(representation, segmentUri); long sampleOffsetUs = -representation.presentationTimeOffsetUs; return new ContainerMediaChunk( dataSource, @@ -588,11 +585,8 @@ public class DefaultDashChunkSource implements DashChunkSource { @Override public DataSpec getDataSpec() { checkInBounds(); - Representation representation = representationHolder.representation; RangedUri segmentUri = representationHolder.getSegmentUrl(getCurrentIndex()); - Uri resolvedUri = segmentUri.resolveUri(representation.baseUrl); - String cacheKey = representation.getCacheKey(); - return new DataSpec(resolvedUri, segmentUri.start, segmentUri.length, cacheKey); + return DashUtil.buildDataSpec(representationHolder.representation, segmentUri); } @Override diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java index 2754a3341a..7f76e65a42 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java @@ -153,7 +153,7 @@ public final class DashDownloader extends SegmentDownloader { private static void addSegment( long startTimeUs, String baseUrl, RangedUri rangedUri, ArrayList out) { DataSpec dataSpec = - new DataSpec(rangedUri.resolveUri(baseUrl), rangedUri.start, rangedUri.length, null); + new DataSpec(rangedUri.resolveUri(baseUrl), rangedUri.start, rangedUri.length); out.add(new Segment(startTimeUs, dataSpec)); } diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ts/PsExtractorSeekTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ts/PsExtractorSeekTest.java index f974a86622..c28ae49b23 100644 --- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ts/PsExtractorSeekTest.java +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/ts/PsExtractorSeekTest.java @@ -201,8 +201,7 @@ public final class PsExtractorSeekTest { // Internal methods private long readInputLength() throws IOException { - DataSpec dataSpec = - new DataSpec(Uri.parse("asset:///" + PS_FILE_PATH), 0, C.LENGTH_UNSET, null); + DataSpec dataSpec = new DataSpec(Uri.parse("asset:///" + PS_FILE_PATH)); long totalInputLength = dataSource.open(dataSpec); Util.closeQuietly(dataSource); return totalInputLength; @@ -343,8 +342,7 @@ public final class PsExtractorSeekTest { private ExtractorInput getExtractorInputFromPosition(long position) throws IOException { DataSpec dataSpec = - new DataSpec( - Uri.parse("asset:///" + PS_FILE_PATH), position, C.LENGTH_UNSET, /* key= */ null); + new DataSpec(Uri.parse("asset:///" + PS_FILE_PATH), position, C.LENGTH_UNSET); dataSource.open(dataSpec); return new DefaultExtractorInput(dataSource, position, totalInputLength); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index 1a77715e71..0b587fdfb7 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -512,7 +512,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; return null; } - byte[] encryptionKey = keyCache.remove(keyUri); + @Nullable byte[] encryptionKey = keyCache.remove(keyUri); if (encryptionKey != null) { // The key was present in the key cache. We re-insert it to prevent it from being evicted by // the following key addition. Note that removal of the key is necessary to affect the @@ -520,7 +520,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; keyCache.put(keyUri, encryptionKey); return null; } - DataSpec dataSpec = new DataSpec(keyUri, 0, C.LENGTH_UNSET, null, DataSpec.FLAG_ALLOW_GZIP); + DataSpec dataSpec = + new DataSpec.Builder().setUri(keyUri).setFlags(DataSpec.FLAG_ALLOW_GZIP).build(); return new EncryptionKeyChunk( encryptionDataSource, dataSpec, @@ -646,8 +647,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; checkInBounds(); Segment segment = playlist.segments.get((int) getCurrentIndex()); Uri chunkUri = UriUtil.resolveToUri(playlist.baseUri, segment.url); - return new DataSpec( - chunkUri, segment.byterangeOffset, segment.byterangeLength, /* key= */ null); + return new DataSpec(chunkUri, segment.byterangeOffset, segment.byterangeLength); } @Override diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 3849410fe0..b5ebff771e 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -94,9 +94,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; new DataSpec( UriUtil.resolveToUri(mediaPlaylist.baseUri, mediaSegment.url), mediaSegment.byterangeOffset, - mediaSegment.byterangeLength, - /* key= */ null); + mediaSegment.byterangeLength); boolean mediaSegmentEncrypted = mediaSegmentKey != null; + @Nullable byte[] mediaSegmentIv = mediaSegmentEncrypted ? getEncryptionIvArray(Assertions.checkNotNull(mediaSegment.encryptionIV)) @@ -107,20 +107,17 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; HlsMediaPlaylist.Segment initSegment = mediaSegment.initializationSegment; DataSpec initDataSpec = null; boolean initSegmentEncrypted = false; - DataSource initDataSource = null; + @Nullable DataSource initDataSource = null; if (initSegment != null) { initSegmentEncrypted = initSegmentKey != null; + @Nullable byte[] initSegmentIv = initSegmentEncrypted ? getEncryptionIvArray(Assertions.checkNotNull(initSegment.encryptionIV)) : null; Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url); initDataSpec = - new DataSpec( - initSegmentUri, - initSegment.byterangeOffset, - initSegment.byterangeLength, - /* key= */ null); + new DataSpec(initSegmentUri, initSegment.byterangeOffset, initSegment.byterangeLength); initDataSource = buildDataSource(dataSource, initSegmentKey, initSegmentIv); } @@ -129,7 +126,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; int discontinuitySequenceNumber = mediaPlaylist.discontinuitySequence + mediaSegment.relativeDiscontinuitySequence; - Extractor previousExtractor = null; + @Nullable Extractor previousExtractor = null; Id3Decoder id3Decoder; ParsableByteArray scratchId3Data; boolean shouldSpliceIn; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java index 6e6d0afd49..7bf982b83f 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java @@ -141,8 +141,7 @@ public final class HlsDownloader extends SegmentDownloader { } } Uri segmentUri = UriUtil.resolveToUri(baseUri, segment.url); - DataSpec dataSpec = - new DataSpec(segmentUri, segment.byterangeOffset, segment.byterangeLength, /* key= */ null); + DataSpec dataSpec = new DataSpec(segmentUri, segment.byterangeOffset, segment.byterangeLength); out.add(new Segment(startTimeUs, dataSpec)); } } diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java index ec4616a71e..661d0dfdff 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java @@ -241,7 +241,6 @@ public class DefaultSsChunkSource implements SsChunkSource { trackSelection.getSelectedFormat(), dataSource, uri, - null, currentAbsoluteChunkIndex, chunkStartTimeUs, chunkEndTimeUs, @@ -270,7 +269,6 @@ public class DefaultSsChunkSource implements SsChunkSource { Format format, DataSource dataSource, Uri uri, - String cacheKey, int chunkIndex, long chunkStartTimeUs, long chunkEndTimeUs, @@ -278,7 +276,7 @@ public class DefaultSsChunkSource implements SsChunkSource { int trackSelectionReason, Object trackSelectionData, ChunkExtractorWrapper extractorWrapper) { - DataSpec dataSpec = new DataSpec(uri, 0, C.LENGTH_UNSET, cacheKey); + DataSpec dataSpec = new DataSpec(uri); // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // To convert them the absolute timestamps, we need to set sampleOffsetUs to chunkStartTimeUs. long sampleOffsetUs = chunkStartTimeUs; diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java index 219fa1cf57..9e9642c1cb 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java @@ -94,8 +94,7 @@ public final class FakeAdaptiveDataSet extends FakeDataSet { String uri = dataSet.getUri(trackGroupIndex); int chunkIndex = (int) getCurrentIndex(); Segment fakeDataChunk = Util.castNonNull(dataSet.getData(uri)).getSegments().get(chunkIndex); - return new DataSpec( - Uri.parse(uri), fakeDataChunk.byteOffset, fakeDataChunk.length, /* key= */ null); + return new DataSpec(Uri.parse(uri), fakeDataChunk.byteOffset, fakeDataChunk.length); } @Override diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java index e614e82106..24a6efb670 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java @@ -130,8 +130,8 @@ public final class FakeChunkSource implements ChunkSource { String uri = dataSet.getUri(trackGroupIndex); Segment fakeDataChunk = Assertions.checkStateNotNull(dataSet.getData(uri)).getSegments().get(chunkIndex); - DataSpec dataSpec = new DataSpec(Uri.parse(uri), fakeDataChunk.byteOffset, - fakeDataChunk.length, null); + DataSpec dataSpec = + new DataSpec(Uri.parse(uri), fakeDataChunk.byteOffset, fakeDataChunk.length); int trackType = MimeTypes.getTrackType(selectedFormat.sampleMimeType); out.chunk = new SingleSampleMediaChunk(dataSource, dataSpec, selectedFormat, trackSelection.getSelectionReason(), trackSelection.getSelectionData(), startTimeUs, diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java index 6dce2b5428..2e9fdeb546 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaChunkIterator.java @@ -45,11 +45,7 @@ public final class FakeMediaChunkIterator extends BaseMediaChunkIterator { @Override public DataSpec getDataSpec() { checkInBounds(); - return new DataSpec( - Uri.EMPTY, - /* absoluteStreamPosition= */ 0, - chunkLengths[(int) getCurrentIndex()], - /* key= */ null); + return new DataSpec(Uri.EMPTY, /* position= */ 0, chunkLengths[(int) getCurrentIndex()]); } @Override diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java index 1fb3e4f0cc..87819e212e 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java @@ -466,7 +466,7 @@ public class TestUtil { /** Returns an {@link ExtractorInput} to read from the given input at given position. */ public static ExtractorInput getExtractorInputFromPosition( DataSource dataSource, long position, Uri uri) throws IOException { - DataSpec dataSpec = new DataSpec(uri, position, C.LENGTH_UNSET, /* key= */ null); + DataSpec dataSpec = new DataSpec(uri, position, C.LENGTH_UNSET); long length = dataSource.open(dataSpec); if (length != C.LENGTH_UNSET) { length += position; diff --git a/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeDataSourceTest.java b/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeDataSourceTest.java index 9af0c6e1ca..b5ecf5440e 100644 --- a/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeDataSourceTest.java +++ b/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeDataSourceTest.java @@ -69,7 +69,7 @@ public final class FakeDataSourceTest { @Test public void testReadPartialOpenEnded() throws IOException { FakeDataSource dataSource = new FakeDataSource(fakeDataSet); - assertThat(dataSource.open(new DataSpec(uri, 7, C.LENGTH_UNSET, null))).isEqualTo(8); + assertThat(dataSource.open(new DataSpec(uri, 7, C.LENGTH_UNSET))).isEqualTo(8); assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(3); assertBuffer(TEST_DATA_PART_1, 7, 3); assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(5); @@ -81,7 +81,7 @@ public final class FakeDataSourceTest { @Test public void testReadPartialBounded() throws IOException { FakeDataSource dataSource = new FakeDataSource(fakeDataSet); - assertThat(dataSource.open(new DataSpec(uri, 9, 3, null))).isEqualTo(3); + assertThat(dataSource.open(new DataSpec(uri, 9, 3))).isEqualTo(3); assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(1); assertBuffer(TEST_DATA_PART_1, 9, 1); assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(2); @@ -89,7 +89,7 @@ public final class FakeDataSourceTest { assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT); dataSource.close(); - assertThat(dataSource.open(new DataSpec(uri, 11, 4, null))).isEqualTo(4); + assertThat(dataSource.open(new DataSpec(uri, 11, 4))).isEqualTo(4); assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(4); assertBuffer(TEST_DATA_PART_2, 1, 4); assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT); @@ -143,7 +143,7 @@ public final class FakeDataSourceTest { assertThat(e).hasMessageThat().isEqualTo(errorMessage); } dataSource.close(); - assertThat(dataSource.open(new DataSpec(uri, 15, 15, null))).isEqualTo(15); + assertThat(dataSource.open(new DataSpec(uri, 15, 15))).isEqualTo(15); assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(15); assertBuffer(TEST_DATA); assertThat(dataSource.read(BUFFER, 0, BUFFER.length)).isEqualTo(C.RESULT_END_OF_INPUT); @@ -220,7 +220,7 @@ public final class FakeDataSourceTest { .appendReadData(TestUtil.buildTestData(10)) .endData()); try { - dataSource.open(new DataSpec(uri, 5, 10, null)); + dataSource.open(new DataSpec(uri, 5, 10)); fail("IOException expected."); } catch (IOException e) { // Expected.