Commit 14d3ed09 by olly Committed by Oliver Woodman

Add DataSpec.Builder

PiperOrigin-RevId: 294518763
parent 7a849e11
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* Move player message-related constants from `C` to `Renderer`, to avoid * Move player message-related constants from `C` to `Renderer`, to avoid
having the constants class depend on player/renderer classes. having the constants class depend on player/renderer classes.
* Split out `common` and `extractor` submodules. * Split out `common` and `extractor` submodules.
* Add `DataSpec.Builder`.
* Text: * Text:
* Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming * Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming
later). later).
......
...@@ -924,16 +924,12 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { ...@@ -924,16 +924,12 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
// For POST redirects that aren't 307 or 308, the redirect is followed but request is // For POST redirects that aren't 307 or 308, the redirect is followed but request is
// transformed into a GET. // transformed into a GET.
redirectUrlDataSpec = redirectUrlDataSpec =
new DataSpec( dataSpec
Uri.parse(newLocationUrl), .buildUpon()
DataSpec.HTTP_METHOD_GET, .setUri(Uri.parse(newLocationUrl))
/* httpBody= */ null, .setHttpMethod(DataSpec.HTTP_METHOD_GET)
dataSpec.absoluteStreamPosition, .setHttpBody(null)
dataSpec.position, .build();
dataSpec.length,
dataSpec.key,
dataSpec.flags,
dataSpec.httpRequestHeaders);
} else { } else {
redirectUrlDataSpec = dataSpec.withUri(Uri.parse(newLocationUrl)); redirectUrlDataSpec = dataSpec.withUri(Uri.parse(newLocationUrl));
} }
......
...@@ -32,6 +32,163 @@ import java.util.Map; ...@@ -32,6 +32,163 @@ import java.util.Map;
*/ */
public final class DataSpec { public final class DataSpec {
/** Builds {@link DataSpec} instances. */
public static final class Builder {
@Nullable private Uri uri;
private long uriPositionOffset;
@HttpMethod private int httpMethod;
@Nullable private byte[] httpBody;
private Map<String, String> httpRequestHeaders;
private long position;
private long length;
@Nullable private String key;
@Flags private int flags;
/** Creates a new instance with default values. */
public Builder() {
httpMethod = HTTP_METHOD_GET;
httpRequestHeaders = Collections.emptyMap();
length = C.LENGTH_UNSET;
}
/**
* Creates a new instance to build upon the provided {@link DataSpec}.
*
* @param dataSpec The {@link DataSpec} to build upon.
*/
private Builder(DataSpec dataSpec) {
uri = dataSpec.uri;
uriPositionOffset = dataSpec.uriPositionOffset;
httpMethod = dataSpec.httpMethod;
httpBody = dataSpec.httpBody;
httpRequestHeaders = dataSpec.httpRequestHeaders;
position = dataSpec.position;
length = dataSpec.length;
key = dataSpec.key;
flags = dataSpec.flags;
}
/**
* Sets {@link DataSpec#uri}. Must be called before {@link #build()}.
*
* @param uri The {@link DataSpec#uri}.
* @return The builder.
*/
public Builder setUri(Uri uri) {
this.uri = uri;
return this;
}
/**
* Sets the {@link DataSpec#uriPositionOffset}. The default value is 0.
*
* @param uriPositionOffset The {@link DataSpec#uriPositionOffset}.
* @return The builder.
*/
public Builder setUriPositionOffset(long uriPositionOffset) {
this.uriPositionOffset = uriPositionOffset;
return this;
}
/**
* Sets {@link DataSpec#httpMethod}. The default value is {@link #HTTP_METHOD_GET}.
*
* @param httpMethod The {@link DataSpec#httpMethod}.
* @return The builder.
*/
public Builder setHttpMethod(@HttpMethod int httpMethod) {
this.httpMethod = httpMethod;
return this;
}
/**
* Sets {@link DataSpec#httpBody}. The default value is {@code null}.
*
* @param httpBody The {@link DataSpec#httpBody}.
* @return The builder.
*/
public Builder setHttpBody(@Nullable byte[] httpBody) {
this.httpBody = httpBody;
return this;
}
/**
* Sets the {@link DataSpec#httpRequestHeaders}. The default value is an empty map.
*
* @param httpRequestHeaders The {@link DataSpec#httpRequestHeaders}.
* @return The builder.
*/
public Builder setHttpRequestHeaders(Map<String, String> httpRequestHeaders) {
this.httpRequestHeaders = httpRequestHeaders;
return this;
}
/**
* Sets the {@link DataSpec#position}. The default value is 0.
*
* @param position The {@link DataSpec#position}.
* @return The builder.
*/
public Builder setPosition(long position) {
this.position = position;
return this;
}
/**
* Sets the {@link DataSpec#length}. The default value is {@link C#LENGTH_UNSET}.
*
* @param length The {@link DataSpec#length}.
* @return The builder.
*/
public Builder setLength(long length) {
this.length = length;
return this;
}
/**
* Sets the {@link DataSpec#key}. The default value is {@code null}.
*
* @param key The {@link DataSpec#key}.
* @return The builder.
*/
public Builder setKey(@Nullable String key) {
this.key = key;
return this;
}
/**
* Sets the {@link DataSpec#flags}. The default value is 0.
*
* @param flags The {@link DataSpec#flags}.
* @return The builder.
*/
public Builder setFlags(@Flags int flags) {
this.flags = flags;
return this;
}
/**
* 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.
*/
public DataSpec build() {
Assertions.checkStateNotNull(uri, "The uri must be set.");
return new DataSpec(
uri,
uriPositionOffset,
httpMethod,
httpBody,
httpRequestHeaders,
position,
length,
key,
flags);
}
}
/** /**
* The flags that apply to any request for data. Possible flag values are {@link * The flags that apply to any request for data. Possible flag values are {@link
* #FLAG_ALLOW_GZIP}, {@link #FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN}, {@link * #FLAG_ALLOW_GZIP}, {@link #FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN}, {@link
...@@ -131,7 +288,7 @@ public final class DataSpec { ...@@ -131,7 +288,7 @@ public final class DataSpec {
* The HTTP method to use when requesting the data. This value will be ignored by non-HTTP {@link * The HTTP method to use when requesting the data. This value will be ignored by non-HTTP {@link
* DataSource} implementations. * DataSource} implementations.
*/ */
public final @HttpMethod int httpMethod; @HttpMethod public final int httpMethod;
/** /**
* The HTTP request body, null otherwise. If the body is non-null, then {@code httpBody.length} * The HTTP request body, null otherwise. If the body is non-null, then {@code httpBody.length}
...@@ -166,7 +323,7 @@ public final class DataSpec { ...@@ -166,7 +323,7 @@ public final class DataSpec {
@Nullable public final String key; @Nullable public final String key;
/** Request {@link Flags flags}. */ /** Request {@link Flags flags}. */
public final @Flags int flags; @Flags public final int flags;
/** /**
* Constructs an instance. * Constructs an instance.
...@@ -408,6 +565,11 @@ public final class DataSpec { ...@@ -408,6 +565,11 @@ public final class DataSpec {
return getStringForHttpMethod(httpMethod); return getStringForHttpMethod(httpMethod);
} }
/** Returns a {@link DataSpec.Builder} initialized with the values of this instance. */
public DataSpec.Builder buildUpon() {
return new Builder(this);
}
/** /**
* Returns a data spec that represents a subrange of the data defined by this DataSpec. The * Returns a data spec that represents a subrange of the data defined by this DataSpec. The
* subrange includes data from the offset up to the end of this DataSpec. * subrange includes data from the offset up to the end of this DataSpec.
......
...@@ -94,13 +94,19 @@ public class DataSpecTest { ...@@ -94,13 +94,19 @@ public class DataSpecTest {
assertDefaultDataSpec(dataSpec, uri); assertDefaultDataSpec(dataSpec, uri);
} }
@SuppressWarnings("deprecation")
@Test @Test
public void createDataSpec_setsCustomValues() { public void createDataSpec_withBuilder_withDefaultValues() {
Uri uri = Uri.parse("www.google.com"); Uri uri = Uri.parse("www.google.com");
Map<String, String> httpRequestHeaders = createHttpRequestHeaders(3); DataSpec dataSpec = new DataSpec.Builder().setUri(uri).build();
assertDefaultDataSpec(dataSpec, uri);
}
@SuppressWarnings("deprecation")
@Test
public void createDataSpec_setsValues() {
Uri uri = Uri.parse("www.google.com");
Map<String, String> httpRequestHeaders = createHttpRequestHeaders(3);
byte[] httpBody = new byte[] {0, 1, 2, 3}; byte[] httpBody = new byte[] {0, 1, 2, 3};
DataSpec dataSpec = DataSpec dataSpec =
...@@ -129,6 +135,77 @@ public class DataSpecTest { ...@@ -129,6 +135,77 @@ public class DataSpecTest {
assertHttpRequestHeadersReadOnly(dataSpec); assertHttpRequestHeadersReadOnly(dataSpec);
} }
@SuppressWarnings("deprecation")
@Test
public void createDataSpec_withBuilder_setsValues() {
Uri uri = Uri.parse("www.google.com");
Map<String, String> httpRequestHeaders = createHttpRequestHeaders(3);
byte[] httpBody = new byte[] {0, 1, 2, 3};
DataSpec dataSpec =
new DataSpec.Builder()
.setUri(uri)
.setUriPositionOffset(50)
.setHttpMethod(DataSpec.HTTP_METHOD_POST)
.setHttpBody(httpBody)
.setPosition(150)
.setLength(5)
.setKey("key")
.setFlags(DataSpec.FLAG_ALLOW_GZIP)
.setHttpRequestHeaders(httpRequestHeaders)
.build();
assertThat(dataSpec.uri).isEqualTo(uri);
assertThat(dataSpec.uriPositionOffset).isEqualTo(50);
assertThat(dataSpec.httpMethod).isEqualTo(DataSpec.HTTP_METHOD_POST);
assertThat(dataSpec.httpBody).isEqualTo(httpBody);
assertThat(dataSpec.httpRequestHeaders).isEqualTo(httpRequestHeaders);
// absoluteStreamPosition = uriPositionOffset + position
assertThat(dataSpec.absoluteStreamPosition).isEqualTo(200);
assertThat(dataSpec.position).isEqualTo(150);
assertThat(dataSpec.length).isEqualTo(5);
assertThat(dataSpec.key).isEqualTo("key");
assertThat(dataSpec.flags).isEqualTo(DataSpec.FLAG_ALLOW_GZIP);
assertHttpRequestHeadersReadOnly(dataSpec);
}
@SuppressWarnings("deprecation")
@Test
public void buildUponDataSpec_setsValues() {
Uri uri = Uri.parse("www.google.com");
Map<String, String> httpRequestHeaders = createHttpRequestHeaders(3);
byte[] httpBody = new byte[] {0, 1, 2, 3};
DataSpec dataSpec =
new DataSpec.Builder()
.setUri(uri)
.setUriPositionOffset(50)
.setHttpMethod(DataSpec.HTTP_METHOD_POST)
.setHttpBody(httpBody)
.setPosition(150)
.setLength(5)
.setKey("key")
.setFlags(DataSpec.FLAG_ALLOW_GZIP)
.setHttpRequestHeaders(httpRequestHeaders)
.build();
// Build upon the DataSpec.
dataSpec = dataSpec.buildUpon().build();
assertThat(dataSpec.uri).isEqualTo(uri);
assertThat(dataSpec.uriPositionOffset).isEqualTo(50);
assertThat(dataSpec.httpMethod).isEqualTo(DataSpec.HTTP_METHOD_POST);
assertThat(dataSpec.httpBody).isEqualTo(httpBody);
assertThat(dataSpec.httpRequestHeaders).isEqualTo(httpRequestHeaders);
// absoluteStreamPosition = uriPositionOffset + position
assertThat(dataSpec.absoluteStreamPosition).isEqualTo(200);
assertThat(dataSpec.position).isEqualTo(150);
assertThat(dataSpec.length).isEqualTo(5);
assertThat(dataSpec.key).isEqualTo("key");
assertThat(dataSpec.flags).isEqualTo(DataSpec.FLAG_ALLOW_GZIP);
assertHttpRequestHeadersReadOnly(dataSpec);
}
@Test @Test
public void createDataSpec_setsHttpMethodAndPostBody() { public void createDataSpec_setsHttpMethodAndPostBody() {
Uri uri = Uri.parse("www.google.com"); Uri uri = Uri.parse("www.google.com");
......
...@@ -23,7 +23,6 @@ import com.google.android.exoplayer2.upstream.DataSink; ...@@ -23,7 +23,6 @@ import com.google.android.exoplayer2.upstream.DataSink;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSourceException; import com.google.android.exoplayer2.upstream.DataSourceException;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DataSpec.HttpMethod;
import com.google.android.exoplayer2.upstream.FileDataSource; import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.TeeDataSource; import com.google.android.exoplayer2.upstream.TeeDataSource;
import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.upstream.TransferListener;
...@@ -132,15 +131,10 @@ public final class CacheDataSource implements DataSource { ...@@ -132,15 +131,10 @@ public final class CacheDataSource implements DataSource {
private final boolean ignoreCacheOnError; private final boolean ignoreCacheOnError;
private final boolean ignoreCacheForUnsetLengthRequests; private final boolean ignoreCacheForUnsetLengthRequests;
@Nullable private Uri actualUri;
@Nullable private DataSpec requestDataSpec;
@Nullable private DataSource currentDataSource; @Nullable private DataSource currentDataSource;
private boolean currentDataSpecLengthUnset; private boolean currentDataSpecLengthUnset;
@Nullable private Uri uri;
@Nullable private Uri actualUri;
@HttpMethod private int httpMethod;
@Nullable private byte[] httpBody;
private Map<String, String> httpRequestHeaders = Collections.emptyMap();
@DataSpec.Flags private int flags;
@Nullable private String key;
private long readPosition; private long readPosition;
private long bytesRemaining; private long bytesRemaining;
@Nullable private CacheSpan currentHoleSpan; @Nullable private CacheSpan currentHoleSpan;
...@@ -259,13 +253,9 @@ public final class CacheDataSource implements DataSource { ...@@ -259,13 +253,9 @@ public final class CacheDataSource implements DataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
try { try {
key = cacheKeyFactory.buildCacheKey(dataSpec); String key = cacheKeyFactory.buildCacheKey(dataSpec);
uri = dataSpec.uri; requestDataSpec = dataSpec.buildUpon().setKey(key).build();
actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri); actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ requestDataSpec.uri);
httpMethod = dataSpec.httpMethod;
httpBody = dataSpec.httpBody;
httpRequestHeaders = dataSpec.httpRequestHeaders;
flags = dataSpec.flags;
readPosition = dataSpec.position; readPosition = dataSpec.position;
int reason = shouldIgnoreCacheForRequest(dataSpec); int reason = shouldIgnoreCacheForRequest(dataSpec);
...@@ -351,14 +341,9 @@ public final class CacheDataSource implements DataSource { ...@@ -351,14 +341,9 @@ public final class CacheDataSource implements DataSource {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
uri = null; requestDataSpec = null;
actualUri = null; actualUri = null;
httpMethod = DataSpec.HTTP_METHOD_GET;
httpBody = null;
httpRequestHeaders = Collections.emptyMap();
flags = 0;
readPosition = 0; readPosition = 0;
key = null;
notifyBytesRead(); notifyBytesRead();
try { try {
closeCurrentSource(); closeCurrentSource();
...@@ -384,6 +369,7 @@ public final class CacheDataSource implements DataSource { ...@@ -384,6 +369,7 @@ public final class CacheDataSource implements DataSource {
*/ */
private void openNextSource(boolean checkCache) throws IOException { private void openNextSource(boolean checkCache) throws IOException {
@Nullable CacheSpan nextSpan; @Nullable CacheSpan nextSpan;
String key = requestDataSpec.key;
if (currentRequestIgnoresCache) { if (currentRequestIgnoresCache) {
nextSpan = null; nextSpan = null;
} else if (blockOnCache) { } else if (blockOnCache) {
...@@ -404,27 +390,24 @@ public final class CacheDataSource implements DataSource { ...@@ -404,27 +390,24 @@ public final class CacheDataSource implements DataSource {
// from upstream. // from upstream.
nextDataSource = upstreamDataSource; nextDataSource = upstreamDataSource;
nextDataSpec = nextDataSpec =
new DataSpec( requestDataSpec.buildUpon().setPosition(readPosition).setLength(bytesRemaining).build();
uri,
httpMethod,
httpBody,
readPosition,
readPosition,
bytesRemaining,
key,
flags,
httpRequestHeaders);
} else if (nextSpan.isCached) { } else if (nextSpan.isCached) {
// Data is cached, read from cache. // Data is cached in a span file starting at nextSpan.position.
Uri fileUri = Uri.fromFile(nextSpan.file); Uri fileUri = Uri.fromFile(nextSpan.file);
long filePosition = readPosition - nextSpan.position; long filePositionOffset = nextSpan.position;
long length = nextSpan.length - filePosition; long positionInFile = readPosition - filePositionOffset;
long length = nextSpan.length - positionInFile;
if (bytesRemaining != C.LENGTH_UNSET) { if (bytesRemaining != C.LENGTH_UNSET) {
length = Math.min(length, bytesRemaining); length = Math.min(length, bytesRemaining);
} }
// Deliberately skip the HTTP-related parameters since we're reading from the cache, not nextDataSpec =
// making an HTTP request. requestDataSpec
nextDataSpec = new DataSpec(fileUri, readPosition, filePosition, length, key, flags); .buildUpon()
.setUri(fileUri)
.setUriPositionOffset(filePositionOffset)
.setPosition(positionInFile)
.setLength(length)
.build();
nextDataSource = cacheReadDataSource; nextDataSource = cacheReadDataSource;
} else { } else {
// Data is not cached, and data is not locked, read from upstream with cache backing. // Data is not cached, and data is not locked, read from upstream with cache backing.
...@@ -438,16 +421,7 @@ public final class CacheDataSource implements DataSource { ...@@ -438,16 +421,7 @@ public final class CacheDataSource implements DataSource {
} }
} }
nextDataSpec = nextDataSpec =
new DataSpec( requestDataSpec.buildUpon().setPosition(readPosition).setLength(length).build();
uri,
httpMethod,
httpBody,
readPosition,
readPosition,
length,
key,
flags,
httpRequestHeaders);
if (cacheWriteDataSource != null) { if (cacheWriteDataSource != null) {
nextDataSource = cacheWriteDataSource; nextDataSource = cacheWriteDataSource;
} else { } else {
...@@ -494,7 +468,7 @@ public final class CacheDataSource implements DataSource { ...@@ -494,7 +468,7 @@ public final class CacheDataSource implements DataSource {
} }
if (isReadingFromUpstream()) { if (isReadingFromUpstream()) {
actualUri = currentDataSource.getUri(); actualUri = currentDataSource.getUri();
boolean isRedirected = !uri.equals(actualUri); boolean isRedirected = !requestDataSpec.uri.equals(actualUri);
ContentMetadataMutations.setRedirectedUri(mutations, isRedirected ? actualUri : null); ContentMetadataMutations.setRedirectedUri(mutations, isRedirected ? actualUri : null);
} }
if (isWritingToCache()) { if (isWritingToCache()) {
...@@ -507,7 +481,7 @@ public final class CacheDataSource implements DataSource { ...@@ -507,7 +481,7 @@ public final class CacheDataSource implements DataSource {
if (isWritingToCache()) { if (isWritingToCache()) {
ContentMetadataMutations mutations = new ContentMetadataMutations(); ContentMetadataMutations mutations = new ContentMetadataMutations();
ContentMetadataMutations.setContentLength(mutations, readPosition); ContentMetadataMutations.setContentLength(mutations, readPosition);
cache.applyContentMetadataMutations(key, mutations); cache.applyContentMetadataMutations(requestDataSpec.key, mutations);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment