mirror of
https://github.com/androidx/media.git
synced 2025-05-18 13:09:56 +08:00
Make OkHttpDataSourceFactory an inner class of OkHttpDataSource
#exofixit PiperOrigin-RevId: 347389531
This commit is contained in:
parent
e18892cd03
commit
6114c894df
@ -62,10 +62,16 @@
|
||||
* Text:
|
||||
* Gracefully handle null-terminated subtitle content in Matroska
|
||||
containers.
|
||||
* OkHttp extension:
|
||||
* Add `OkHttpDataSource.Factory` and deprecate `OkHttpDataSourceFactory`.
|
||||
* Media2 extension
|
||||
* Make media2-extension depend on AndroidX media2:media2-session:1.1.0 to
|
||||
fix a deadlock while creating PlaybackStateCompat internally.
|
||||
([#8011](https://github.com/google/ExoPlayer/issues/8011)).
|
||||
* MediaSession extension:
|
||||
* Support `setPlaybackSpeed(float)` and disable it by default. Use
|
||||
`MediaSessionConnector.setEnabledPlaybackActions(long)` to enable
|
||||
([#8229](https://github.com/google/ExoPlayer/issues/8229)).
|
||||
|
||||
### 2.12.2 (2020-12-01) ###
|
||||
|
||||
@ -128,10 +134,6 @@
|
||||
`STATE_IDLE` or `STATE_ENDED`.
|
||||
* Allow to remove all playlist items that makes the player reset.
|
||||
([#8047](https://github.com/google/ExoPlayer/issues/8047)).
|
||||
* MediaSession extension:
|
||||
* Support `setPlaybackSpeed(float)` and disable it by default. Use
|
||||
`MediaSessionConnector.setEnabledPlaybackActions(long)` to enable
|
||||
([#8229](https://github.com/google/ExoPlayer/issues/8229)).
|
||||
|
||||
### 2.12.1 (2020-10-23) ###
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.ext.okhttp;
|
||||
|
||||
import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT;
|
||||
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
@ -23,9 +24,11 @@ import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||
import com.google.android.exoplayer2.upstream.BaseDataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSourceException;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.base.Predicate;
|
||||
@ -41,6 +44,7 @@ import okhttp3.CacheControl;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
@ -59,6 +63,111 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
|
||||
ExoPlayerLibraryInfo.registerModule("goog.exo.okhttp");
|
||||
}
|
||||
|
||||
/** {@link DataSource.Factory} for {@link OkHttpDataSource} instances. */
|
||||
public static final class Factory implements HttpDataSource.Factory {
|
||||
|
||||
private final RequestProperties defaultRequestProperties;
|
||||
private final Call.Factory callFactory;
|
||||
|
||||
@Nullable private String userAgent;
|
||||
@Nullable private TransferListener transferListener;
|
||||
@Nullable private CacheControl cacheControl;
|
||||
@Nullable private Predicate<String> contentTypePredicate;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param callFactory A {@link Call.Factory} (typically an {@link OkHttpClient}) for use by the
|
||||
* sources created by the factory.
|
||||
*/
|
||||
public Factory(Call.Factory callFactory) {
|
||||
this.callFactory = callFactory;
|
||||
defaultRequestProperties = new RequestProperties();
|
||||
userAgent = DEFAULT_USER_AGENT;
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link #setDefaultRequestProperties(Map)} instead. */
|
||||
@Deprecated
|
||||
@Override
|
||||
public final RequestProperties getDefaultRequestProperties() {
|
||||
return defaultRequestProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Factory setDefaultRequestProperties(Map<String, String> defaultRequestProperties) {
|
||||
this.defaultRequestProperties.clearAndSet(defaultRequestProperties);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user agent that will be used.
|
||||
*
|
||||
* <p>The default is {@link ExoPlayerLibraryInfo#DEFAULT_USER_AGENT}.
|
||||
*
|
||||
* @param userAgent The user agent that will be used.
|
||||
* @return This factory.
|
||||
*/
|
||||
public Factory setUserAgent(String userAgent) {
|
||||
this.userAgent = userAgent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link CacheControl} that will be used.
|
||||
*
|
||||
* <p>The default is {@code null}.
|
||||
*
|
||||
* @param cacheControl The cache control that will be used.
|
||||
* @return This factory.
|
||||
*/
|
||||
public Factory setCacheControl(@Nullable CacheControl cacheControl) {
|
||||
this.cacheControl = cacheControl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a content type {@link Predicate}. If a content type is rejected by the predicate then a
|
||||
* {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link
|
||||
* OkHttpDataSource#open(DataSpec)}.
|
||||
*
|
||||
* <p>The default is {@code null}.
|
||||
*
|
||||
* @param contentTypePredicate The content type {@link Predicate}, or {@code null} to clear a
|
||||
* predicate that was previously set.
|
||||
* @return This factory.
|
||||
*/
|
||||
public Factory setContentTypePredicate(@Nullable Predicate<String> contentTypePredicate) {
|
||||
this.contentTypePredicate = contentTypePredicate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link TransferListener} that will be used.
|
||||
*
|
||||
* <p>The default is {@code null}.
|
||||
*
|
||||
* <p>See {@link DataSource#addTransferListener(TransferListener)}.
|
||||
*
|
||||
* @param transferListener The listener that will be used.
|
||||
* @return This factory.
|
||||
*/
|
||||
public Factory setTransferListener(@Nullable TransferListener transferListener) {
|
||||
this.transferListener = transferListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OkHttpDataSource createDataSource() {
|
||||
OkHttpDataSource dataSource =
|
||||
new OkHttpDataSource(
|
||||
callFactory, userAgent, cacheControl, defaultRequestProperties, contentTypePredicate);
|
||||
if (transferListener != null) {
|
||||
dataSource.addTransferListener(transferListener);
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] SKIP_BUFFER = new byte[4096];
|
||||
|
||||
private final Call.Factory callFactory;
|
||||
@ -80,114 +189,54 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
|
||||
private long bytesSkipped;
|
||||
private long bytesRead;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
|
||||
* by the source.
|
||||
*/
|
||||
/** @deprecated Use {@link OkHttpDataSource.Factory} instead. */
|
||||
@SuppressWarnings("deprecation")
|
||||
@Deprecated
|
||||
public OkHttpDataSource(Call.Factory callFactory) {
|
||||
this(callFactory, ExoPlayerLibraryInfo.DEFAULT_USER_AGENT);
|
||||
this(callFactory, DEFAULT_USER_AGENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
|
||||
* by the source.
|
||||
* @param userAgent An optional User-Agent string.
|
||||
*/
|
||||
/** @deprecated Use {@link OkHttpDataSource.Factory} instead. */
|
||||
@SuppressWarnings("deprecation")
|
||||
@Deprecated
|
||||
public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent) {
|
||||
this(callFactory, userAgent, /* cacheControl= */ null, /* defaultRequestProperties= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
|
||||
* by the source.
|
||||
* @param userAgent An optional User-Agent string.
|
||||
* @param cacheControl An optional {@link CacheControl} for setting the Cache-Control header.
|
||||
* @param defaultRequestProperties Optional default {@link RequestProperties} to be sent to the
|
||||
* server as HTTP headers on every request.
|
||||
*/
|
||||
/** @deprecated Use {@link OkHttpDataSource.Factory} instead. */
|
||||
@Deprecated
|
||||
public OkHttpDataSource(
|
||||
Call.Factory callFactory,
|
||||
@Nullable String userAgent,
|
||||
@Nullable CacheControl cacheControl,
|
||||
@Nullable RequestProperties defaultRequestProperties) {
|
||||
super(/* isNetwork= */ true);
|
||||
this.callFactory = Assertions.checkNotNull(callFactory);
|
||||
this.userAgent = userAgent;
|
||||
this.cacheControl = cacheControl;
|
||||
this.defaultRequestProperties = defaultRequestProperties;
|
||||
this.requestProperties = new RequestProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
|
||||
* by the source.
|
||||
* @param userAgent An optional User-Agent string.
|
||||
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
|
||||
* predicate then a {@link InvalidContentTypeException} is thrown from {@link
|
||||
* #open(DataSpec)}.
|
||||
* @deprecated Use {@link #OkHttpDataSource(Call.Factory, String)} and {@link
|
||||
* #setContentTypePredicate(Predicate)}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Deprecated
|
||||
public OkHttpDataSource(
|
||||
Call.Factory callFactory,
|
||||
@Nullable String userAgent,
|
||||
@Nullable Predicate<String> contentTypePredicate) {
|
||||
this(
|
||||
callFactory,
|
||||
userAgent,
|
||||
contentTypePredicate,
|
||||
/* cacheControl= */ null,
|
||||
/* defaultRequestProperties= */ null);
|
||||
cacheControl,
|
||||
defaultRequestProperties,
|
||||
/* contentTypePredicate= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
|
||||
* by the source.
|
||||
* @param userAgent An optional User-Agent string.
|
||||
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
|
||||
* predicate then a {@link InvalidContentTypeException} is thrown from {@link
|
||||
* #open(DataSpec)}.
|
||||
* @param cacheControl An optional {@link CacheControl} for setting the Cache-Control header.
|
||||
* @param defaultRequestProperties Optional default {@link RequestProperties} to be sent to the
|
||||
* server as HTTP headers on every request.
|
||||
* @deprecated Use {@link #OkHttpDataSource(Call.Factory, String, CacheControl,
|
||||
* RequestProperties)} and {@link #setContentTypePredicate(Predicate)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public OkHttpDataSource(
|
||||
private OkHttpDataSource(
|
||||
Call.Factory callFactory,
|
||||
@Nullable String userAgent,
|
||||
@Nullable Predicate<String> contentTypePredicate,
|
||||
@Nullable CacheControl cacheControl,
|
||||
@Nullable RequestProperties defaultRequestProperties) {
|
||||
@Nullable RequestProperties defaultRequestProperties,
|
||||
@Nullable Predicate<String> contentTypePredicate) {
|
||||
super(/* isNetwork= */ true);
|
||||
this.callFactory = Assertions.checkNotNull(callFactory);
|
||||
this.userAgent = userAgent;
|
||||
this.contentTypePredicate = contentTypePredicate;
|
||||
this.cacheControl = cacheControl;
|
||||
this.defaultRequestProperties = defaultRequestProperties;
|
||||
this.contentTypePredicate = contentTypePredicate;
|
||||
this.requestProperties = new RequestProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a content type {@link Predicate}. If a content type is rejected by the predicate then a
|
||||
* {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link #open(DataSpec)}.
|
||||
*
|
||||
* @param contentTypePredicate The content type {@link Predicate}, or {@code null} to clear a
|
||||
* predicate that was previously set.
|
||||
* @deprecated Use {@link OkHttpDataSource.Factory#setContentTypePredicate(Predicate)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setContentTypePredicate(@Nullable Predicate<String> contentTypePredicate) {
|
||||
this.contentTypePredicate = contentTypePredicate;
|
||||
}
|
||||
@ -274,7 +323,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
|
||||
}
|
||||
|
||||
// Check for a valid content type.
|
||||
MediaType mediaType = responseBody.contentType();
|
||||
@Nullable MediaType mediaType = responseBody.contentType();
|
||||
String contentType = mediaType != null ? mediaType.toString() : "";
|
||||
if (contentTypePredicate != null && !contentTypePredicate.apply(contentType)) {
|
||||
closeConnectionQuietly();
|
||||
@ -357,7 +406,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
|
||||
long position = dataSpec.position;
|
||||
long length = dataSpec.length;
|
||||
|
||||
HttpUrl url = HttpUrl.parse(dataSpec.uri.toString());
|
||||
@Nullable HttpUrl url = HttpUrl.parse(dataSpec.uri.toString());
|
||||
if (url == null) {
|
||||
throw new HttpDataSourceException(
|
||||
"Malformed URL", dataSpec, HttpDataSourceException.TYPE_OPEN);
|
||||
@ -394,7 +443,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
|
||||
builder.addHeader("Accept-Encoding", "identity");
|
||||
}
|
||||
|
||||
RequestBody requestBody = null;
|
||||
@Nullable RequestBody requestBody = null;
|
||||
if (dataSpec.httpBody != null) {
|
||||
requestBody = RequestBody.create(null, dataSpec.httpBody);
|
||||
} else if (dataSpec.httpMethod == DataSpec.HTTP_METHOD_POST) {
|
||||
|
@ -20,14 +20,12 @@ import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AG
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource.Factory;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
import okhttp3.CacheControl;
|
||||
import okhttp3.Call;
|
||||
|
||||
/**
|
||||
* A {@link Factory} that produces {@link OkHttpDataSource}.
|
||||
*/
|
||||
/** @deprecated Use {@link OkHttpDataSource.Factory} instead. */
|
||||
@Deprecated
|
||||
public final class OkHttpDataSourceFactory extends BaseFactory {
|
||||
|
||||
private final Call.Factory callFactory;
|
||||
@ -102,6 +100,8 @@ public final class OkHttpDataSourceFactory extends BaseFactory {
|
||||
this.cacheControl = cacheControl;
|
||||
}
|
||||
|
||||
// Calls deprecated constructor.
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected OkHttpDataSource createDataSourceInternal(
|
||||
HttpDataSource.RequestProperties defaultRequestProperties) {
|
||||
|
@ -59,15 +59,16 @@ public class OkHttpDataSourceTest {
|
||||
MockWebServer mockWebServer = new MockWebServer();
|
||||
mockWebServer.enqueue(new MockResponse());
|
||||
|
||||
String propertyFromConstructor = "fromConstructor";
|
||||
HttpDataSource.RequestProperties constructorProperties = new HttpDataSource.RequestProperties();
|
||||
constructorProperties.set("0", propertyFromConstructor);
|
||||
constructorProperties.set("1", propertyFromConstructor);
|
||||
constructorProperties.set("2", propertyFromConstructor);
|
||||
constructorProperties.set("4", propertyFromConstructor);
|
||||
OkHttpDataSource dataSource =
|
||||
new OkHttpDataSource(
|
||||
new OkHttpClient(), "testAgent", /* cacheControl= */ null, constructorProperties);
|
||||
String propertyFromFactory = "fromFactory";
|
||||
Map<String, String> defaultRequestProperties = new HashMap<>();
|
||||
defaultRequestProperties.put("0", propertyFromFactory);
|
||||
defaultRequestProperties.put("1", propertyFromFactory);
|
||||
defaultRequestProperties.put("2", propertyFromFactory);
|
||||
defaultRequestProperties.put("4", propertyFromFactory);
|
||||
HttpDataSource dataSource =
|
||||
new OkHttpDataSource.Factory(new OkHttpClient())
|
||||
.setDefaultRequestProperties(defaultRequestProperties)
|
||||
.createDataSource();
|
||||
|
||||
String propertyFromSetter = "fromSetter";
|
||||
dataSource.setRequestProperty("1", propertyFromSetter);
|
||||
@ -91,7 +92,7 @@ public class OkHttpDataSourceTest {
|
||||
dataSource.open(dataSpec);
|
||||
|
||||
Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders();
|
||||
assertThat(headers.get("0")).isEqualTo(propertyFromConstructor);
|
||||
assertThat(headers.get("0")).isEqualTo(propertyFromFactory);
|
||||
assertThat(headers.get("1")).isEqualTo(propertyFromSetter);
|
||||
assertThat(headers.get("2")).isEqualTo(propertyFromDataSpec);
|
||||
assertThat(headers.get("3")).isEqualTo(propertyFromDataSpec);
|
||||
@ -101,16 +102,13 @@ public class OkHttpDataSourceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void open_invalidResponseCode() throws Exception {
|
||||
public void open_invalidResponseCode() {
|
||||
MockWebServer mockWebServer = new MockWebServer();
|
||||
mockWebServer.enqueue(new MockResponse().setResponseCode(404).setBody("failure msg"));
|
||||
|
||||
OkHttpDataSource okHttpDataSource =
|
||||
new OkHttpDataSource(
|
||||
new OkHttpClient(),
|
||||
"testAgent",
|
||||
/* cacheControl= */ null,
|
||||
/* defaultRequestProperties= */ null);
|
||||
HttpDataSource okHttpDataSource =
|
||||
new OkHttpDataSource.Factory(new OkHttpClient()).createDataSource();
|
||||
|
||||
DataSpec dataSpec =
|
||||
new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build();
|
||||
|
||||
@ -122,4 +120,22 @@ public class OkHttpDataSourceTest {
|
||||
assertThat(exception.responseCode).isEqualTo(404);
|
||||
assertThat(exception.responseBody).isEqualTo("failure msg".getBytes(Charsets.UTF_8));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void factory_setRequestPropertyAfterCreation_setsCorrectHeaders() throws Exception {
|
||||
MockWebServer mockWebServer = new MockWebServer();
|
||||
mockWebServer.enqueue(new MockResponse());
|
||||
DataSpec dataSpec =
|
||||
new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build();
|
||||
OkHttpDataSource.Factory factory = new OkHttpDataSource.Factory(new OkHttpClient());
|
||||
OkHttpDataSource dataSource = factory.createDataSource();
|
||||
|
||||
Map<String, String> defaultRequestProperties = new HashMap<>();
|
||||
defaultRequestProperties.put("0", "afterCreation");
|
||||
factory.setDefaultRequestProperties(defaultRequestProperties);
|
||||
dataSource.open(dataSpec);
|
||||
|
||||
Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders();
|
||||
assertThat(headers.get("0")).isEqualTo("afterCreation");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user