Commit 985160a4 by tonihei Committed by Oliver Woodman

Use BaseDataSource for all internal leaf data sources.

This allows all leaf data sources (i.e. ones which do not forward the requests
to other data sources) to accept multiple listeners.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=203097587
parent e48b712a
......@@ -20,6 +20,8 @@ import android.support.annotation.NonNull;
import android.support.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;
......@@ -42,10 +44,8 @@ import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* An {@link HttpDataSource} that delegates to Square's {@link Call.Factory}.
*/
public class OkHttpDataSource implements HttpDataSource {
/** An {@link HttpDataSource} that delegates to Square's {@link Call.Factory}. */
public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
static {
ExoPlayerLibraryInfo.registerModule("goog.exo.okhttp");
......@@ -58,7 +58,6 @@ public class OkHttpDataSource implements HttpDataSource {
@Nullable private final String userAgent;
@Nullable private final Predicate<String> contentTypePredicate;
@Nullable private final TransferListener<? super OkHttpDataSource> listener;
@Nullable private final CacheControl cacheControl;
@Nullable private final RequestProperties defaultRequestProperties;
......@@ -90,13 +89,15 @@ public class OkHttpDataSource implements HttpDataSource {
* 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)}.
* predicate then a {@link InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @param listener An optional listener.
*/
public OkHttpDataSource(@NonNull Call.Factory callFactory, @Nullable String userAgent,
public OkHttpDataSource(
@NonNull Call.Factory callFactory,
@Nullable String userAgent,
@Nullable Predicate<String> contentTypePredicate,
@Nullable TransferListener<? super OkHttpDataSource> listener) {
@Nullable TransferListener<? super DataSource> listener) {
this(callFactory, userAgent, contentTypePredicate, listener, null, null);
}
......@@ -105,24 +106,30 @@ public class OkHttpDataSource implements HttpDataSource {
* 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)}.
* predicate then a {@link InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @param listener An optional listener.
* @param cacheControl An optional {@link CacheControl} for setting the Cache-Control header.
* @param defaultRequestProperties The optional default {@link RequestProperties} to be sent to
* the server as HTTP headers on every request.
* the server as HTTP headers on every request.
*/
public OkHttpDataSource(@NonNull Call.Factory callFactory, @Nullable String userAgent,
public OkHttpDataSource(
@NonNull Call.Factory callFactory,
@Nullable String userAgent,
@Nullable Predicate<String> contentTypePredicate,
@Nullable TransferListener<? super OkHttpDataSource> listener,
@Nullable CacheControl cacheControl, @Nullable RequestProperties defaultRequestProperties) {
@Nullable TransferListener<? super DataSource> listener,
@Nullable CacheControl cacheControl,
@Nullable RequestProperties defaultRequestProperties) {
super(DataSource.TYPE_REMOTE);
this.callFactory = Assertions.checkNotNull(callFactory);
this.userAgent = userAgent;
this.contentTypePredicate = contentTypePredicate;
this.listener = listener;
this.cacheControl = cacheControl;
this.defaultRequestProperties = defaultRequestProperties;
this.requestProperties = new RequestProperties();
if (listener != null) {
addTransferListener(listener);
}
}
@Override
......@@ -203,9 +210,7 @@ public class OkHttpDataSource implements HttpDataSource {
}
opened = true;
if (listener != null) {
listener.onTransferStart(this, dataSpec);
}
transferStarted(dataSpec);
return bytesToRead;
}
......@@ -224,9 +229,7 @@ public class OkHttpDataSource implements HttpDataSource {
public void close() throws HttpDataSourceException {
if (opened) {
opened = false;
if (listener != null) {
listener.onTransferEnd(this);
}
transferEnded();
closeConnectionQuietly();
}
}
......@@ -333,9 +336,7 @@ public class OkHttpDataSource implements HttpDataSource {
throw new EOFException();
}
bytesSkipped += read;
if (listener != null) {
listener.onBytesTransferred(this, read);
}
bytesTransferred(read);
}
// Release the shared skip buffer.
......@@ -378,9 +379,7 @@ public class OkHttpDataSource implements HttpDataSource {
}
bytesRead += read;
if (listener != null) {
listener.onBytesTransferred(this, read);
}
bytesTransferred(read);
return read;
}
......
......@@ -19,6 +19,7 @@ import android.net.Uri;
import android.support.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.DataSpec;
import com.google.android.exoplayer2.upstream.TransferListener;
......@@ -26,17 +27,13 @@ import java.io.IOException;
import net.butterflytv.rtmp_client.RtmpClient;
import net.butterflytv.rtmp_client.RtmpClient.RtmpIOException;
/**
* A Real-Time Messaging Protocol (RTMP) {@link DataSource}.
*/
public final class RtmpDataSource implements DataSource {
/** A Real-Time Messaging Protocol (RTMP) {@link DataSource}. */
public final class RtmpDataSource extends BaseDataSource {
static {
ExoPlayerLibraryInfo.registerModule("goog.exo.rtmp");
}
@Nullable private final TransferListener<? super RtmpDataSource> listener;
private RtmpClient rtmpClient;
private Uri uri;
......@@ -44,11 +41,12 @@ public final class RtmpDataSource implements DataSource {
this(null);
}
/**
* @param listener An optional listener.
*/
public RtmpDataSource(@Nullable TransferListener<? super RtmpDataSource> listener) {
this.listener = listener;
/** @param listener An optional listener. */
public RtmpDataSource(@Nullable TransferListener<? super DataSource> listener) {
super(DataSource.TYPE_REMOTE);
if (listener != null) {
addTransferListener(listener);
}
}
@Override
......@@ -57,9 +55,7 @@ public final class RtmpDataSource implements DataSource {
rtmpClient.open(dataSpec.uri.toString(), false);
this.uri = dataSpec.uri;
if (listener != null) {
listener.onTransferStart(this, dataSpec);
}
transferStarted(dataSpec);
return C.LENGTH_UNSET;
}
......@@ -69,9 +65,7 @@ public final class RtmpDataSource implements DataSource {
if (bytesRead == -1) {
return C.RESULT_END_OF_INPUT;
}
if (listener != null) {
listener.onBytesTransferred(this, bytesRead);
}
bytesTransferred(bytesRead);
return bytesRead;
}
......@@ -79,9 +73,7 @@ public final class RtmpDataSource implements DataSource {
public void close() {
if (uri != null) {
uri = null;
if (listener != null) {
listener.onTransferEnd(this);
}
transferEnded();
}
if (rtmpClient != null) {
rtmpClient.close();
......
......@@ -25,17 +25,14 @@ import com.google.android.exoplayer2.upstream.TransferListener;
*/
public final class RtmpDataSourceFactory implements DataSource.Factory {
@Nullable
private final TransferListener<? super RtmpDataSource> listener;
private final @Nullable TransferListener<? super DataSource> listener;
public RtmpDataSourceFactory() {
this(null);
}
/**
* @param listener An optional listener.
*/
public RtmpDataSourceFactory(@Nullable TransferListener<? super RtmpDataSource> listener) {
/** @param listener An optional listener. */
public RtmpDataSourceFactory(@Nullable TransferListener<? super DataSource> listener) {
this.listener = listener;
}
......
......@@ -18,15 +18,14 @@ package com.google.android.exoplayer2.upstream;
import android.content.Context;
import android.content.res.AssetManager;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
/**
* A {@link DataSource} for reading from a local asset.
*/
public final class AssetDataSource implements DataSource {
/** A {@link DataSource} for reading from a local asset. */
public final class AssetDataSource extends BaseDataSource {
/**
* Thrown when an {@link IOException} is encountered reading a local asset.
......@@ -40,10 +39,9 @@ public final class AssetDataSource implements DataSource {
}
private final AssetManager assetManager;
private final TransferListener<? super AssetDataSource> listener;
private Uri uri;
private InputStream inputStream;
private @Nullable Uri uri;
private @Nullable InputStream inputStream;
private long bytesRemaining;
private boolean opened;
......@@ -58,9 +56,12 @@ public final class AssetDataSource implements DataSource {
* @param context A context.
* @param listener An optional listener.
*/
public AssetDataSource(Context context, TransferListener<? super AssetDataSource> listener) {
public AssetDataSource(Context context, @Nullable TransferListener<? super DataSource> listener) {
super(DataSource.TYPE_LOCAL);
this.assetManager = context.getAssets();
this.listener = listener;
if (listener != null) {
addTransferListener(listener);
}
}
@Override
......@@ -96,9 +97,7 @@ public final class AssetDataSource implements DataSource {
}
opened = true;
if (listener != null) {
listener.onTransferStart(this, dataSpec);
}
transferStarted(dataSpec);
return bytesRemaining;
}
......@@ -129,14 +128,12 @@ public final class AssetDataSource implements DataSource {
if (bytesRemaining != C.LENGTH_UNSET) {
bytesRemaining -= bytesRead;
}
if (listener != null) {
listener.onBytesTransferred(this, bytesRead);
}
bytesTransferred(bytesRead);
return bytesRead;
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return uri;
}
......@@ -153,9 +150,7 @@ public final class AssetDataSource implements DataSource {
inputStream = null;
if (opened) {
opened = false;
if (listener != null) {
listener.onTransferEnd(this);
}
transferEnded();
}
}
}
......
......@@ -16,25 +16,26 @@
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;
/**
* A {@link DataSource} for reading from a byte array.
*/
public final class ByteArrayDataSource implements DataSource {
/** A {@link DataSource} for reading from a byte array. */
public final class ByteArrayDataSource extends BaseDataSource {
private final byte[] data;
private Uri uri;
private @Nullable Uri uri;
private int readPosition;
private int bytesRemaining;
private boolean opened;
/**
* @param data The data to be read.
*/
public ByteArrayDataSource(byte[] data) {
super(DataSource.TYPE_LOCAL);
Assertions.checkNotNull(data);
Assertions.checkArgument(data.length > 0);
this.data = data;
......@@ -50,6 +51,8 @@ public final class ByteArrayDataSource implements DataSource {
throw new IOException("Unsatisfiable range: [" + readPosition + ", " + dataSpec.length
+ "], length: " + data.length);
}
opened = true;
transferStarted(dataSpec);
return bytesRemaining;
}
......@@ -65,16 +68,21 @@ public final class ByteArrayDataSource implements DataSource {
System.arraycopy(data, readPosition, buffer, offset, readLength);
readPosition += readLength;
bytesRemaining -= readLength;
bytesTransferred(readLength);
return readLength;
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return uri;
}
@Override
public void close() throws IOException {
if (opened) {
opened = false;
transferEnded();
}
uri = null;
}
......
......@@ -19,6 +19,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import java.io.EOFException;
import java.io.FileInputStream;
......@@ -26,10 +27,8 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.channels.FileChannel;
/**
* A {@link DataSource} for reading from a content URI.
*/
public final class ContentDataSource implements DataSource {
/** A {@link DataSource} for reading from a content URI. */
public final class ContentDataSource extends BaseDataSource {
/**
* Thrown when an {@link IOException} is encountered reading from a content URI.
......@@ -43,11 +42,10 @@ public final class ContentDataSource implements DataSource {
}
private final ContentResolver resolver;
private final TransferListener<? super ContentDataSource> listener;
private Uri uri;
private AssetFileDescriptor assetFileDescriptor;
private FileInputStream inputStream;
private @Nullable Uri uri;
private @Nullable AssetFileDescriptor assetFileDescriptor;
private @Nullable FileInputStream inputStream;
private long bytesRemaining;
private boolean opened;
......@@ -62,9 +60,13 @@ public final class ContentDataSource implements DataSource {
* @param context A context.
* @param listener An optional listener.
*/
public ContentDataSource(Context context, TransferListener<? super ContentDataSource> listener) {
public ContentDataSource(
Context context, @Nullable TransferListener<? super DataSource> listener) {
super(DataSource.TYPE_LOCAL);
this.resolver = context.getContentResolver();
this.listener = listener;
if (listener != null) {
addTransferListener(listener);
}
}
@Override
......@@ -102,9 +104,7 @@ public final class ContentDataSource implements DataSource {
}
opened = true;
if (listener != null) {
listener.onTransferStart(this, dataSpec);
}
transferStarted(dataSpec);
return bytesRemaining;
}
......@@ -136,14 +136,12 @@ public final class ContentDataSource implements DataSource {
if (bytesRemaining != C.LENGTH_UNSET) {
bytesRemaining -= bytesRead;
}
if (listener != null) {
listener.onBytesTransferred(this, bytesRead);
}
bytesTransferred(bytesRead);
return bytesRead;
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return uri;
}
......@@ -168,9 +166,7 @@ public final class ContentDataSource implements DataSource {
assetFileDescriptor = null;
if (opened) {
opened = false;
if (listener != null) {
listener.onTransferEnd(this);
}
transferEnded();
}
}
}
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.util.Base64;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException;
......@@ -23,16 +24,18 @@ import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.net.URLDecoder;
/**
* A {@link DataSource} for reading data URLs, as defined by RFC 2397.
*/
public final class DataSchemeDataSource implements DataSource {
/** A {@link DataSource} for reading data URLs, as defined by RFC 2397. */
public final class DataSchemeDataSource extends BaseDataSource {
public static final String SCHEME_DATA = "data";
private DataSpec dataSpec;
private @Nullable DataSpec dataSpec;
private int bytesRead;
private byte[] data;
private @Nullable byte[] data;
public DataSchemeDataSource() {
super(DataSource.TYPE_LOCAL);
}
@Override
public long open(DataSpec dataSpec) throws IOException {
......@@ -57,6 +60,7 @@ public final class DataSchemeDataSource implements DataSource {
// TODO: Add support for other charsets.
data = URLDecoder.decode(dataString, C.ASCII_NAME).getBytes();
}
transferStarted(dataSpec);
return data.length;
}
......@@ -72,18 +76,22 @@ public final class DataSchemeDataSource implements DataSource {
readLength = Math.min(readLength, remainingBytes);
System.arraycopy(data, bytesRead, buffer, offset, readLength);
bytesRead += readLength;
bytesTransferred(readLength);
return readLength;
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return dataSpec != null ? dataSpec.uri : null;
}
@Override
public void close() throws IOException {
if (data != null) {
data = null;
transferEnded();
}
dataSpec = null;
data = null;
}
}
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.exoplayer2.C;
......@@ -41,13 +42,13 @@ import java.util.regex.Pattern;
/**
* An {@link HttpDataSource} that uses Android's {@link HttpURLConnection}.
* <p>
* By default this implementation will not follow cross-protocol redirects (i.e. redirects from
* HTTP to HTTPS or vice versa). Cross-protocol redirects can be enabled by using the
* {@link #DefaultHttpDataSource(String, Predicate, TransferListener, int, int, boolean,
*
* <p>By default this implementation will not follow cross-protocol redirects (i.e. redirects from
* HTTP to HTTPS or vice versa). Cross-protocol redirects can be enabled by using the {@link
* #DefaultHttpDataSource(String, Predicate, TransferListener, int, int, boolean,
* RequestProperties)} constructor and passing {@code true} as the second last argument.
*/
public class DefaultHttpDataSource implements HttpDataSource {
public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSource {
/**
* The default connection timeout, in milliseconds.
......@@ -69,14 +70,13 @@ public class DefaultHttpDataSource implements HttpDataSource {
private final int connectTimeoutMillis;
private final int readTimeoutMillis;
private final String userAgent;
private final Predicate<String> contentTypePredicate;
private final RequestProperties defaultRequestProperties;
private final @Nullable Predicate<String> contentTypePredicate;
private final @Nullable RequestProperties defaultRequestProperties;
private final RequestProperties requestProperties;
private final TransferListener<? super DefaultHttpDataSource> listener;
private DataSpec dataSpec;
private HttpURLConnection connection;
private InputStream inputStream;
private @Nullable DataSpec dataSpec;
private @Nullable HttpURLConnection connection;
private @Nullable InputStream inputStream;
private boolean opened;
private long bytesToSkip;
......@@ -88,22 +88,24 @@ public class DefaultHttpDataSource implements HttpDataSource {
/**
* @param userAgent The User-Agent string that should be used.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from
* {@link #open(DataSpec)}.
* predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
*/
public DefaultHttpDataSource(String userAgent, Predicate<String> contentTypePredicate) {
public DefaultHttpDataSource(String userAgent, @Nullable Predicate<String> contentTypePredicate) {
this(userAgent, contentTypePredicate, null);
}
/**
* @param userAgent The User-Agent string that should be used.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from
* {@link #open(DataSpec)}.
* predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @param listener An optional listener.
*/
public DefaultHttpDataSource(String userAgent, Predicate<String> contentTypePredicate,
TransferListener<? super DefaultHttpDataSource> listener) {
public DefaultHttpDataSource(
String userAgent,
@Nullable Predicate<String> contentTypePredicate,
@Nullable TransferListener<? super DataSource> listener) {
this(userAgent, contentTypePredicate, listener, DEFAULT_CONNECT_TIMEOUT_MILLIS,
DEFAULT_READ_TIMEOUT_MILLIS);
}
......@@ -111,16 +113,19 @@ public class DefaultHttpDataSource implements HttpDataSource {
/**
* @param userAgent The User-Agent string that should be used.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from
* {@link #open(DataSpec)}.
* predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @param listener An optional listener.
* @param connectTimeoutMillis The connection timeout, in milliseconds. A timeout of zero is
* interpreted as an infinite timeout.
* @param readTimeoutMillis The read timeout, in milliseconds. A timeout of zero is interpreted
* as an infinite timeout.
* @param readTimeoutMillis The read timeout, in milliseconds. A timeout of zero is interpreted as
* an infinite timeout.
*/
public DefaultHttpDataSource(String userAgent, Predicate<String> contentTypePredicate,
TransferListener<? super DefaultHttpDataSource> listener, int connectTimeoutMillis,
public DefaultHttpDataSource(
String userAgent,
@Nullable Predicate<String> contentTypePredicate,
@Nullable TransferListener<? super DataSource> listener,
int connectTimeoutMillis,
int readTimeoutMillis) {
this(userAgent, contentTypePredicate, listener, connectTimeoutMillis, readTimeoutMillis, false,
null);
......@@ -129,35 +134,42 @@ public class DefaultHttpDataSource implements HttpDataSource {
/**
* @param userAgent The User-Agent string that should be used.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from
* {@link #open(DataSpec)}.
* predicate then a {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @param listener An optional listener.
* @param connectTimeoutMillis The connection timeout, in milliseconds. A timeout of zero is
* interpreted as an infinite timeout. Pass {@link #DEFAULT_CONNECT_TIMEOUT_MILLIS} to use
* the default value.
* @param readTimeoutMillis The read timeout, in milliseconds. A timeout of zero is interpreted
* as an infinite timeout. Pass {@link #DEFAULT_READ_TIMEOUT_MILLIS} to use the default value.
* interpreted as an infinite timeout. Pass {@link #DEFAULT_CONNECT_TIMEOUT_MILLIS} to use the
* default value.
* @param readTimeoutMillis The read timeout, in milliseconds. A timeout of zero is interpreted as
* an infinite timeout. Pass {@link #DEFAULT_READ_TIMEOUT_MILLIS} to use the default value.
* @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP
* to HTTPS and vice versa) are enabled.
* @param defaultRequestProperties The default request properties to be sent to the server as
* HTTP headers or {@code null} if not required.
* @param defaultRequestProperties The default request properties to be sent to the server as HTTP
* headers or {@code null} if not required.
*/
public DefaultHttpDataSource(String userAgent, Predicate<String> contentTypePredicate,
TransferListener<? super DefaultHttpDataSource> listener, int connectTimeoutMillis,
int readTimeoutMillis, boolean allowCrossProtocolRedirects,
RequestProperties defaultRequestProperties) {
public DefaultHttpDataSource(
String userAgent,
@Nullable Predicate<String> contentTypePredicate,
@Nullable TransferListener<? super DataSource> listener,
int connectTimeoutMillis,
int readTimeoutMillis,
boolean allowCrossProtocolRedirects,
@Nullable RequestProperties defaultRequestProperties) {
super(DataSource.TYPE_REMOTE);
this.userAgent = Assertions.checkNotEmpty(userAgent);
this.contentTypePredicate = contentTypePredicate;
this.listener = listener;
this.requestProperties = new RequestProperties();
this.connectTimeoutMillis = connectTimeoutMillis;
this.readTimeoutMillis = readTimeoutMillis;
this.allowCrossProtocolRedirects = allowCrossProtocolRedirects;
this.defaultRequestProperties = defaultRequestProperties;
if (listener != null) {
addTransferListener(listener);
}
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return connection == null ? null : Uri.parse(connection.getURL().toString());
}
......@@ -254,9 +266,7 @@ public class DefaultHttpDataSource implements HttpDataSource {
}
opened = true;
if (listener != null) {
listener.onTransferStart(this, dataSpec);
}
transferStarted(dataSpec);
return bytesToRead;
}
......@@ -287,9 +297,7 @@ public class DefaultHttpDataSource implements HttpDataSource {
closeConnectionQuietly();
if (opened) {
opened = false;
if (listener != null) {
listener.onTransferEnd(this);
}
transferEnded();
}
}
}
......@@ -534,9 +542,7 @@ public class DefaultHttpDataSource implements HttpDataSource {
throw new EOFException();
}
bytesSkipped += read;
if (listener != null) {
listener.onBytesTransferred(this, read);
}
bytesTransferred(read);
}
// Release the shared skip buffer.
......@@ -579,9 +585,7 @@ public class DefaultHttpDataSource implements HttpDataSource {
}
bytesRead += read;
if (listener != null) {
listener.onBytesTransferred(this, read);
}
bytesTransferred(read);
return read;
}
......
......@@ -16,15 +16,14 @@
package com.google.android.exoplayer2.upstream;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import java.io.EOFException;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* A {@link DataSource} for reading local files.
*/
public final class FileDataSource implements DataSource {
/** A {@link DataSource} for reading local files. */
public final class FileDataSource extends BaseDataSource {
/**
* Thrown when IOException is encountered during local file read operation.
......@@ -37,10 +36,8 @@ public final class FileDataSource implements DataSource {
}
private final TransferListener<? super FileDataSource> listener;
private RandomAccessFile file;
private Uri uri;
private @Nullable RandomAccessFile file;
private @Nullable Uri uri;
private long bytesRemaining;
private boolean opened;
......@@ -48,11 +45,12 @@ public final class FileDataSource implements DataSource {
this(null);
}
/**
* @param listener An optional listener.
*/
public FileDataSource(TransferListener<? super FileDataSource> listener) {
this.listener = listener;
/** @param listener An optional listener. */
public FileDataSource(@Nullable TransferListener<? super DataSource> listener) {
super(DataSource.TYPE_LOCAL);
if (listener != null) {
addTransferListener(listener);
}
}
@Override
......@@ -71,9 +69,7 @@ public final class FileDataSource implements DataSource {
}
opened = true;
if (listener != null) {
listener.onTransferStart(this, dataSpec);
}
transferStarted(dataSpec);
return bytesRemaining;
}
......@@ -94,9 +90,7 @@ public final class FileDataSource implements DataSource {
if (bytesRead > 0) {
bytesRemaining -= bytesRead;
if (listener != null) {
listener.onBytesTransferred(this, bytesRead);
}
bytesTransferred(bytesRead);
}
return bytesRead;
......@@ -104,7 +98,7 @@ public final class FileDataSource implements DataSource {
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return uri;
}
......@@ -121,9 +115,7 @@ public final class FileDataSource implements DataSource {
file = null;
if (opened) {
opened = false;
if (listener != null) {
listener.onTransferEnd(this);
}
transferEnded();
}
}
}
......
......@@ -15,18 +15,20 @@
*/
package com.google.android.exoplayer2.upstream;
import android.support.annotation.Nullable;
/**
* A {@link DataSource.Factory} that produces {@link FileDataSource}.
*/
public final class FileDataSourceFactory implements DataSource.Factory {
private final TransferListener<? super FileDataSource> listener;
private final @Nullable TransferListener<? super DataSource> listener;
public FileDataSourceFactory() {
this(null);
}
public FileDataSourceFactory(TransferListener<? super FileDataSource> listener) {
public FileDataSourceFactory(@Nullable TransferListener<? super DataSource> listener) {
this.listener = listener;
}
......
......@@ -19,6 +19,7 @@ import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.google.android.exoplayer2.C;
import java.io.EOFException;
......@@ -28,12 +29,12 @@ import java.io.InputStream;
/**
* A {@link DataSource} for reading a raw resource inside the APK.
* <p>
* URIs supported by this source are of the form {@code rawresource:///rawResourceId}, where
*
* <p>URIs supported by this source are of the form {@code rawresource:///rawResourceId}, where
* rawResourceId is the integer identifier of a raw resource. {@link #buildRawResourceUri(int)} can
* be used to build {@link Uri}s in this format.
*/
public final class RawResourceDataSource implements DataSource {
public final class RawResourceDataSource extends BaseDataSource {
/**
* Thrown when an {@link IOException} is encountered reading from a raw resource.
......@@ -62,11 +63,10 @@ public final class RawResourceDataSource implements DataSource {
public static final String RAW_RESOURCE_SCHEME = "rawresource";
private final Resources resources;
private final TransferListener<? super RawResourceDataSource> listener;
private Uri uri;
private AssetFileDescriptor assetFileDescriptor;
private InputStream inputStream;
private @Nullable Uri uri;
private @Nullable AssetFileDescriptor assetFileDescriptor;
private @Nullable InputStream inputStream;
private long bytesRemaining;
private boolean opened;
......@@ -81,10 +81,13 @@ public final class RawResourceDataSource implements DataSource {
* @param context A context.
* @param listener An optional listener.
*/
public RawResourceDataSource(Context context,
TransferListener<? super RawResourceDataSource> listener) {
public RawResourceDataSource(
Context context, @Nullable TransferListener<? super DataSource> listener) {
super(DataSource.TYPE_LOCAL);
this.resources = context.getResources();
this.listener = listener;
if (listener != null) {
addTransferListener(listener);
}
}
@Override
......@@ -124,9 +127,7 @@ public final class RawResourceDataSource implements DataSource {
}
opened = true;
if (listener != null) {
listener.onTransferStart(this, dataSpec);
}
transferStarted(dataSpec);
return bytesRemaining;
}
......@@ -158,14 +159,12 @@ public final class RawResourceDataSource implements DataSource {
if (bytesRemaining != C.LENGTH_UNSET) {
bytesRemaining -= bytesRead;
}
if (listener != null) {
listener.onBytesTransferred(this, bytesRead);
}
bytesTransferred(bytesRead);
return bytesRead;
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return uri;
}
......@@ -190,9 +189,7 @@ public final class RawResourceDataSource implements DataSource {
assetFileDescriptor = null;
if (opened) {
opened = false;
if (listener != null) {
listener.onTransferEnd(this);
}
transferEnded();
}
}
}
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import java.io.IOException;
import java.net.DatagramPacket;
......@@ -25,10 +26,8 @@ import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
/**
* A UDP {@link DataSource}.
*/
public final class UdpDataSource implements DataSource {
/** A UDP {@link DataSource}. */
public final class UdpDataSource extends BaseDataSource {
/**
* Thrown when an error is encountered when trying to read from a {@link UdpDataSource}.
......@@ -51,24 +50,21 @@ public final class UdpDataSource implements DataSource {
*/
public static final int DEAFULT_SOCKET_TIMEOUT_MILLIS = 8 * 1000;
private final TransferListener<? super UdpDataSource> listener;
private final int socketTimeoutMillis;
private final byte[] packetBuffer;
private final DatagramPacket packet;
private Uri uri;
private DatagramSocket socket;
private MulticastSocket multicastSocket;
private InetAddress address;
private InetSocketAddress socketAddress;
private @Nullable Uri uri;
private @Nullable DatagramSocket socket;
private @Nullable MulticastSocket multicastSocket;
private @Nullable InetAddress address;
private @Nullable InetSocketAddress socketAddress;
private boolean opened;
private int packetRemaining;
/**
* @param listener An optional listener.
*/
public UdpDataSource(TransferListener<? super UdpDataSource> listener) {
/** @param listener An optional listener. */
public UdpDataSource(@Nullable TransferListener<? super DataSource> listener) {
this(listener, DEFAULT_MAX_PACKET_SIZE);
}
......@@ -76,7 +72,7 @@ public final class UdpDataSource implements DataSource {
* @param listener An optional listener.
* @param maxPacketSize The maximum datagram packet size, in bytes.
*/
public UdpDataSource(TransferListener<? super UdpDataSource> listener, int maxPacketSize) {
public UdpDataSource(@Nullable TransferListener<? super DataSource> listener, int maxPacketSize) {
this(listener, maxPacketSize, DEAFULT_SOCKET_TIMEOUT_MILLIS);
}
......@@ -86,12 +82,17 @@ public final class UdpDataSource implements DataSource {
* @param socketTimeoutMillis The socket timeout in milliseconds. A timeout of zero is interpreted
* as an infinite timeout.
*/
public UdpDataSource(TransferListener<? super UdpDataSource> listener, int maxPacketSize,
public UdpDataSource(
@Nullable TransferListener<? super DataSource> listener,
int maxPacketSize,
int socketTimeoutMillis) {
this.listener = listener;
super(DataSource.TYPE_REMOTE);
this.socketTimeoutMillis = socketTimeoutMillis;
packetBuffer = new byte[maxPacketSize];
packet = new DatagramPacket(packetBuffer, 0, maxPacketSize);
if (listener != null) {
addTransferListener(listener);
}
}
@Override
......@@ -121,9 +122,7 @@ public final class UdpDataSource implements DataSource {
}
opened = true;
if (listener != null) {
listener.onTransferStart(this, dataSpec);
}
transferStarted(dataSpec);
return C.LENGTH_UNSET;
}
......@@ -141,9 +140,7 @@ public final class UdpDataSource implements DataSource {
throw new UdpDataSourceException(e);
}
packetRemaining = packet.getLength();
if (listener != null) {
listener.onBytesTransferred(this, packetRemaining);
}
bytesTransferred(packetRemaining);
}
int packetOffset = packet.getLength() - packetRemaining;
......@@ -154,7 +151,7 @@ public final class UdpDataSource implements DataSource {
}
@Override
public Uri getUri() {
public @Nullable Uri getUri() {
return uri;
}
......@@ -178,9 +175,7 @@ public final class UdpDataSource implements DataSource {
packetRemaining = 0;
if (opened) {
opened = false;
if (listener != null) {
listener.onTransferEnd(this);
}
transferEnded();
}
}
......
......@@ -20,6 +20,7 @@ import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData;
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment;
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;
......@@ -32,18 +33,20 @@ import java.util.ArrayList;
* A fake {@link DataSource} capable of simulating various scenarios. It uses a {@link FakeDataSet}
* instance which determines the response to data access calls.
*/
public class FakeDataSource implements DataSource {
public class FakeDataSource extends BaseDataSource {
/**
* Factory to create a {@link FakeDataSource}.
*/
public static class Factory implements DataSource.Factory {
protected final TransferListener<? super FakeDataSource> transferListener;
protected final TransferListener<? super DataSource> transferListener;
protected FakeDataSet fakeDataSet;
protected @DataSource.Type int dataSourceType;
public Factory(@Nullable TransferListener<? super FakeDataSource> transferListener) {
public Factory(@Nullable TransferListener<? super DataSource> transferListener) {
this.transferListener = transferListener;
this.dataSourceType = DataSource.TYPE_LOCAL;
}
public final Factory setFakeDataSet(FakeDataSet fakeDataSet) {
......@@ -51,19 +54,23 @@ public class FakeDataSource implements DataSource {
return this;
}
public final Factory setDataSourceType(@DataSource.Type int dataSourceType) {
this.dataSourceType = dataSourceType;
return this;
}
@Override
public DataSource createDataSource() {
return new FakeDataSource(fakeDataSet, transferListener);
return new FakeDataSource(fakeDataSet, transferListener, dataSourceType);
}
}
private final FakeDataSet fakeDataSet;
private final TransferListener<? super FakeDataSource> transferListener;
private final ArrayList<DataSpec> openedDataSpecs;
private Uri uri;
private boolean opened;
private boolean openCalled;
private boolean sourceOpened;
private FakeData fakeData;
private int currentSegmentIndex;
private long bytesRemaining;
......@@ -73,15 +80,20 @@ public class FakeDataSource implements DataSource {
}
public FakeDataSource(FakeDataSet fakeDataSet) {
this(fakeDataSet, null);
this(fakeDataSet, null, DataSource.TYPE_LOCAL);
}
public FakeDataSource(FakeDataSet fakeDataSet,
@Nullable TransferListener<? super FakeDataSource> transferListener) {
public FakeDataSource(
FakeDataSet fakeDataSet,
@Nullable TransferListener<? super DataSource> transferListener,
@DataSource.Type int dataSourceType) {
super(dataSourceType);
Assertions.checkNotNull(fakeDataSet);
this.fakeDataSet = fakeDataSet;
this.transferListener = transferListener;
this.openedDataSpecs = new ArrayList<>();
if (transferListener != null) {
addTransferListener(transferListener);
}
}
public final FakeDataSet getDataSet() {
......@@ -90,9 +102,9 @@ public class FakeDataSource implements DataSource {
@Override
public final long open(DataSpec dataSpec) throws IOException {
Assertions.checkState(!opened);
Assertions.checkState(!openCalled);
openCalled = true;
// DataSpec requires a matching close call even if open fails.
opened = true;
uri = dataSpec.uri;
openedDataSpecs.add(dataSpec);
......@@ -129,9 +141,8 @@ public class FakeDataSource implements DataSource {
currentSegmentIndex++;
}
}
if (transferListener != null) {
transferListener.onTransferStart(this, dataSpec);
}
sourceOpened = true;
transferStarted(dataSpec);
// Configure bytesRemaining, and return.
if (dataSpec.length == C.LENGTH_UNSET) {
bytesRemaining = totalLength - dataSpec.position;
......@@ -144,7 +155,7 @@ public class FakeDataSource implements DataSource {
@Override
public final int read(byte[] buffer, int offset, int readLength) throws IOException {
Assertions.checkState(opened);
Assertions.checkState(sourceOpened);
while (true) {
if (currentSegmentIndex == fakeData.getSegments().size() || bytesRemaining == 0) {
return C.RESULT_END_OF_INPUT;
......@@ -171,9 +182,7 @@ public class FakeDataSource implements DataSource {
System.arraycopy(current.data, current.bytesRead, buffer, offset, readLength);
}
onDataRead(readLength);
if (transferListener != null) {
transferListener.onBytesTransferred(this, readLength);
}
bytesTransferred(readLength);
bytesRemaining -= readLength;
current.bytesRead += readLength;
if (current.bytesRead == current.length) {
......@@ -191,8 +200,8 @@ public class FakeDataSource implements DataSource {
@Override
public final void close() throws IOException {
Assertions.checkState(opened);
opened = false;
Assertions.checkState(openCalled);
openCalled = false;
uri = null;
if (fakeData != null && currentSegmentIndex < fakeData.getSegments().size()) {
Segment current = fakeData.getSegments().get(currentSegmentIndex);
......@@ -200,8 +209,9 @@ public class FakeDataSource implements DataSource {
current.exceptionCleared = true;
}
}
if (transferListener != null) {
transferListener.onTransferEnd(this);
if (sourceOpened) {
sourceOpened = false;
transferEnded();
}
fakeData = null;
}
......@@ -219,7 +229,7 @@ public class FakeDataSource implements DataSource {
/** Returns whether the data source is currently opened. */
public final boolean isOpened() {
return opened;
return sourceOpened;
}
protected void onDataRead(int bytesRead) throws IOException {
......
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