From 264bed06f253bc10b2c16c03c3416699e1f0569c Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 5 Jul 2018 04:17:22 -0700 Subject: [PATCH] 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 --- .../exoplayer2/upstream/DataSource.java | 3 +- .../upstream/DefaultDataSource.java | 90 ++++++++++++++----- .../upstream/PriorityDataSource.java | 12 +++ .../exoplayer2/upstream/StatsDataSource.java | 5 ++ .../exoplayer2/upstream/TeeDataSource.java | 15 +++- .../upstream/cache/CacheDataSource.java | 21 +++-- .../upstream/crypto/AesCipherDataSource.java | 11 ++- .../source/hls/Aes128DataSource.java | 13 ++- 8 files changed, 132 insertions(+), 38 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java index cdcdba305b..e9a73959a4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSource.java @@ -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}. */ diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java index 8550eedc62..1a4fc63ebc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java @@ -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 listener; - + private final List> 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 listener, - String userAgent, boolean allowCrossProtocolRedirects) { + public DefaultDataSource( + Context context, + @Nullable TransferListener 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 listener, - String userAgent, int connectTimeoutMillis, int readTimeoutMillis, + public DefaultDataSource( + Context context, + @Nullable TransferListener 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 listener, + public DefaultDataSource( + Context context, + @Nullable TransferListener 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 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 listener) { + if (dataSource != null) { + dataSource.addTransferListener(listener); + } + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java index 729f7fe179..a5afe3d1d7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/PriorityDataSource.java @@ -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 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> getResponseHeaders() { + return upstream.getResponseHeaders(); + } + @Override public void close() throws IOException { upstream.close(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java index 79868806d1..a5b31b1d6d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/StatsDataSource.java @@ -70,6 +70,11 @@ public final class StatsDataSource implements DataSource { return lastResponseHeaders; } + @Override + public void addTransferListener(TransferListener transferListener) { + dataSource.addTransferListener(transferListener); + } + @Override public long open(DataSpec dataSpec) throws IOException { // Reassign defaults in case dataSource.open throws an exception. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/TeeDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/TeeDataSource.java index 6fcb08e6b5..0762f48f43 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/TeeDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/TeeDataSource.java @@ -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 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> getResponseHeaders() { + return upstream.getResponseHeaders(); + } + @Override public void close() throws IOException { try { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java index ceef14ff94..23fb7e12ec 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java @@ -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 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; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java index 2de25b1749..951f111f42 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSource.java @@ -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 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(); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java index 59f6839987..a0dd2af367 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/Aes128DataSource.java @@ -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 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(); }