Forward addTransferListener for all wrapping data sources.

This allows to register a listener on an outer wrapping data source which
receives data transfer events from the wrapped source.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=203358981
This commit is contained in:
tonihei 2018-07-05 04:17:22 -07:00 committed by Oliver Woodman
parent 5047a5a4da
commit 264bed06f2
8 changed files with 132 additions and 38 deletions

View File

@ -52,8 +52,7 @@ public interface DataSource {
}
/**
* Adds a {@link TransferListener} to listen to data transfers. Must be called before the first
* call to {@link #open(DataSpec)}.
* Adds a {@link TransferListener} to listen to data transfers. This method is not thread-safe.
*
* @param transferListener A {@link TransferListener}.
*/

View File

@ -17,10 +17,12 @@ package com.google.android.exoplayer2.upstream;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -55,19 +57,18 @@ public final class DefaultDataSource implements DataSource {
private static final String SCHEME_RAW = RawResourceDataSource.RAW_RESOURCE_SCHEME;
private final Context context;
private final TransferListener<? super DataSource> listener;
private final List<TransferListener<? super DataSource>> transferListeners;
private final DataSource baseDataSource;
// Lazily initialized.
private DataSource fileDataSource;
private DataSource assetDataSource;
private DataSource contentDataSource;
private DataSource rtmpDataSource;
private DataSource dataSchemeDataSource;
private DataSource rawResourceDataSource;
private @Nullable DataSource fileDataSource;
private @Nullable DataSource assetDataSource;
private @Nullable DataSource contentDataSource;
private @Nullable DataSource rtmpDataSource;
private @Nullable DataSource dataSchemeDataSource;
private @Nullable DataSource rawResourceDataSource;
private DataSource dataSource;
private @Nullable DataSource dataSource;
/**
* Constructs a new instance, optionally configured to follow cross-protocol redirects.
@ -78,8 +79,11 @@ public final class DefaultDataSource implements DataSource {
* @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP
* to HTTPS and vice versa) are enabled when fetching remote data.
*/
public DefaultDataSource(Context context, TransferListener<? super DataSource> listener,
String userAgent, boolean allowCrossProtocolRedirects) {
public DefaultDataSource(
Context context,
@Nullable TransferListener<? super DataSource> listener,
String userAgent,
boolean allowCrossProtocolRedirects) {
this(context, listener, userAgent, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, allowCrossProtocolRedirects);
}
@ -92,13 +96,17 @@ public final class DefaultDataSource implements DataSource {
* @param userAgent The User-Agent string that should be used when requesting remote data.
* @param connectTimeoutMillis The connection timeout that should be used when requesting remote
* data, in milliseconds. A timeout of zero is interpreted as an infinite timeout.
* @param readTimeoutMillis The read timeout that should be used when requesting remote data,
* in milliseconds. A timeout of zero is interpreted as an infinite timeout.
* @param readTimeoutMillis The read timeout that should be used when requesting remote data, in
* milliseconds. A timeout of zero is interpreted as an infinite timeout.
* @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP
* to HTTPS and vice versa) are enabled when fetching remote data.
*/
public DefaultDataSource(Context context, TransferListener<? super DataSource> listener,
String userAgent, int connectTimeoutMillis, int readTimeoutMillis,
public DefaultDataSource(
Context context,
@Nullable TransferListener<? super DataSource> listener,
String userAgent,
int connectTimeoutMillis,
int readTimeoutMillis,
boolean allowCrossProtocolRedirects) {
this(context, listener,
new DefaultHttpDataSource(userAgent, null, listener, connectTimeoutMillis,
@ -114,11 +122,28 @@ public final class DefaultDataSource implements DataSource {
* @param baseDataSource A {@link DataSource} to use for URI schemes other than file, asset and
* content. This {@link DataSource} should normally support at least http(s).
*/
public DefaultDataSource(Context context, TransferListener<? super DataSource> listener,
public DefaultDataSource(
Context context,
@Nullable TransferListener<? super DataSource> listener,
DataSource baseDataSource) {
this.context = context.getApplicationContext();
this.listener = listener;
this.baseDataSource = Assertions.checkNotNull(baseDataSource);
transferListeners = new ArrayList<>();
if (listener != null) {
transferListeners.add(listener);
}
}
@Override
public void addTransferListener(TransferListener<? super DataSource> transferListener) {
baseDataSource.addTransferListener(transferListener);
transferListeners.add(transferListener);
maybeAddListenerToDataSource(fileDataSource, transferListener);
maybeAddListenerToDataSource(assetDataSource, transferListener);
maybeAddListenerToDataSource(contentDataSource, transferListener);
maybeAddListenerToDataSource(rtmpDataSource, transferListener);
maybeAddListenerToDataSource(dataSchemeDataSource, transferListener);
maybeAddListenerToDataSource(rawResourceDataSource, transferListener);
}
@Override
@ -151,11 +176,11 @@ public final class DefaultDataSource implements DataSource {
@Override
public int read(byte[] buffer, int offset, int readLength) throws IOException {
return dataSource.read(buffer, offset, readLength);
return Assertions.checkNotNull(dataSource).read(buffer, offset, readLength);
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return dataSource == null ? null : dataSource.getUri();
}
@ -179,21 +204,24 @@ public final class DefaultDataSource implements DataSource {
private DataSource getFileDataSource() {
if (fileDataSource == null) {
fileDataSource = new FileDataSource(listener);
fileDataSource = new FileDataSource();
addListenersToDataSource(fileDataSource);
}
return fileDataSource;
}
private DataSource getAssetDataSource() {
if (assetDataSource == null) {
assetDataSource = new AssetDataSource(context, listener);
assetDataSource = new AssetDataSource(context);
addListenersToDataSource(assetDataSource);
}
return assetDataSource;
}
private DataSource getContentDataSource() {
if (contentDataSource == null) {
contentDataSource = new ContentDataSource(context, listener);
contentDataSource = new ContentDataSource(context);
addListenersToDataSource(contentDataSource);
}
return contentDataSource;
}
@ -205,6 +233,7 @@ public final class DefaultDataSource implements DataSource {
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.rtmp.RtmpDataSource");
rtmpDataSource = (DataSource) clazz.getConstructor().newInstance();
// LINT.ThenChange(../../../../../../../../proguard-rules.txt)
addListenersToDataSource(rtmpDataSource);
} catch (ClassNotFoundException e) {
// Expected if the app was built without the RTMP extension.
Log.w(TAG, "Attempting to play RTMP stream without depending on the RTMP extension");
@ -222,14 +251,29 @@ public final class DefaultDataSource implements DataSource {
private DataSource getDataSchemeDataSource() {
if (dataSchemeDataSource == null) {
dataSchemeDataSource = new DataSchemeDataSource();
addListenersToDataSource(dataSchemeDataSource);
}
return dataSchemeDataSource;
}
private DataSource getRawResourceDataSource() {
if (rawResourceDataSource == null) {
rawResourceDataSource = new RawResourceDataSource(context, listener);
rawResourceDataSource = new RawResourceDataSource(context);
addListenersToDataSource(rawResourceDataSource);
}
return rawResourceDataSource;
}
private void addListenersToDataSource(DataSource dataSource) {
for (int i = 0; i < transferListeners.size(); i++) {
dataSource.addTransferListener(transferListeners.get(i));
}
}
private void maybeAddListenerToDataSource(
@Nullable DataSource dataSource, TransferListener<? super DataSource> listener) {
if (dataSource != null) {
dataSource.addTransferListener(listener);
}
}
}

View File

@ -20,6 +20,8 @@ import android.support.annotation.Nullable;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.PriorityTaskManager;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* A {@link DataSource} that can be used as part of a task registered with a
@ -51,6 +53,11 @@ public final class PriorityDataSource implements DataSource {
this.priority = priority;
}
@Override
public void addTransferListener(TransferListener<? super DataSource> transferListener) {
upstream.addTransferListener(transferListener);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
priorityTaskManager.proceedOrThrow(priority);
@ -68,6 +75,11 @@ public final class PriorityDataSource implements DataSource {
return upstream.getUri();
}
@Override
public Map<String, List<String>> getResponseHeaders() {
return upstream.getResponseHeaders();
}
@Override
public void close() throws IOException {
upstream.close();

View File

@ -70,6 +70,11 @@ public final class StatsDataSource implements DataSource {
return lastResponseHeaders;
}
@Override
public void addTransferListener(TransferListener<? super DataSource> transferListener) {
dataSource.addTransferListener(transferListener);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
// Reassign defaults in case dataSource.open throws an exception.

View File

@ -16,9 +16,12 @@
package com.google.android.exoplayer2.upstream;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* Tees data into a {@link DataSink} as the data is read.
@ -40,6 +43,11 @@ public final class TeeDataSource implements DataSource {
this.dataSink = Assertions.checkNotNull(dataSink);
}
@Override
public void addTransferListener(TransferListener<? super DataSource> transferListener) {
upstream.addTransferListener(transferListener);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
bytesRemaining = upstream.open(dataSpec);
@ -79,10 +87,15 @@ public final class TeeDataSource implements DataSource {
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return upstream.getUri();
}
@Override
public Map<String, List<String>> getResponseHeaders() {
return upstream.getResponseHeaders();
}
@Override
public void close() throws IOException {
try {

View File

@ -25,6 +25,7 @@ import com.google.android.exoplayer2.upstream.DataSourceException;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.TeeDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.upstream.cache.Cache.CacheException;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
@ -119,7 +120,7 @@ public final class CacheDataSource implements DataSource {
private final Cache cache;
private final DataSource cacheReadDataSource;
private final DataSource cacheWriteDataSource;
private final @Nullable DataSource cacheWriteDataSource;
private final DataSource upstreamDataSource;
private final CacheKeyFactory cacheKeyFactory;
@Nullable private final EventListener eventListener;
@ -128,15 +129,15 @@ public final class CacheDataSource implements DataSource {
private final boolean ignoreCacheOnError;
private final boolean ignoreCacheForUnsetLengthRequests;
private DataSource currentDataSource;
private @Nullable DataSource currentDataSource;
private boolean currentDataSpecLengthUnset;
private Uri uri;
private Uri actualUri;
private @Nullable Uri uri;
private @Nullable Uri actualUri;
private int flags;
private String key;
private @Nullable String key;
private long readPosition;
private long bytesRemaining;
private CacheSpan currentHoleSpan;
private @Nullable CacheSpan currentHoleSpan;
private boolean seenCacheError;
private boolean currentRequestIgnoresCache;
private long totalCachedBytesRead;
@ -256,6 +257,12 @@ public final class CacheDataSource implements DataSource {
this.eventListener = eventListener;
}
@Override
public void addTransferListener(TransferListener<? super DataSource> transferListener) {
cacheReadDataSource.addTransferListener(transferListener);
upstreamDataSource.addTransferListener(transferListener);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
try {
@ -330,7 +337,7 @@ public final class CacheDataSource implements DataSource {
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return actualUri;
}

View File

@ -16,9 +16,11 @@
package com.google.android.exoplayer2.upstream.crypto;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.TransferListener;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@ -32,13 +34,18 @@ public final class AesCipherDataSource implements DataSource {
private final DataSource upstream;
private final byte[] secretKey;
private AesFlushingCipher cipher;
private @Nullable AesFlushingCipher cipher;
public AesCipherDataSource(byte[] secretKey, DataSource upstream) {
this.upstream = upstream;
this.secretKey = secretKey;
}
@Override
public void addTransferListener(TransferListener<? super DataSource> transferListener) {
upstream.addTransferListener(transferListener);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
long dataLength = upstream.open(dataSpec);
@ -62,7 +69,7 @@ public final class AesCipherDataSource implements DataSource {
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return upstream.getUri();
}

View File

@ -16,10 +16,12 @@
package com.google.android.exoplayer2.source.hls;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSourceInputStream;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
@ -49,7 +51,7 @@ import javax.crypto.spec.SecretKeySpec;
private final byte[] encryptionKey;
private final byte[] encryptionIv;
private CipherInputStream cipherInputStream;
private @Nullable CipherInputStream cipherInputStream;
/**
* @param upstream The upstream {@link DataSource}.
@ -62,6 +64,11 @@ import javax.crypto.spec.SecretKeySpec;
this.encryptionIv = encryptionIv;
}
@Override
public void addTransferListener(TransferListener<? super DataSource> transferListener) {
upstream.addTransferListener(transferListener);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
Cipher cipher;
@ -89,7 +96,7 @@ import javax.crypto.spec.SecretKeySpec;
@Override
public int read(byte[] buffer, int offset, int readLength) throws IOException {
Assertions.checkState(cipherInputStream != null);
Assertions.checkNotNull(cipherInputStream);
int bytesRead = cipherInputStream.read(buffer, offset, readLength);
if (bytesRead < 0) {
return C.RESULT_END_OF_INPUT;
@ -98,7 +105,7 @@ import javax.crypto.spec.SecretKeySpec;
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return upstream.getUri();
}