Commit 006986cc by Oliver Woodman

Make NetworkLoadable use an injected HttpDataSource.

Note: I'm fairly confident that NetworkLoadable.Parser implementations
can live without the inputEncoding being specified. But not completely
100%...

Issue: #311
Issue: #56
parent 2ce17b60
...@@ -52,6 +52,8 @@ import com.google.android.exoplayer.text.webvtt.WebvttParser; ...@@ -52,6 +52,8 @@ import com.google.android.exoplayer.text.webvtt.WebvttParser;
import com.google.android.exoplayer.upstream.BufferPool; import com.google.android.exoplayer.upstream.BufferPool;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer.upstream.HttpDataSource;
import com.google.android.exoplayer.upstream.UriDataSource; import com.google.android.exoplayer.upstream.UriDataSource;
import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback; import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
...@@ -100,6 +102,7 @@ public class DashRendererBuilder implements RendererBuilder, ...@@ -100,6 +102,7 @@ public class DashRendererBuilder implements RendererBuilder,
private DemoPlayer player; private DemoPlayer player;
private RendererBuilderCallback callback; private RendererBuilderCallback callback;
private ManifestFetcher<MediaPresentationDescription> manifestFetcher; private ManifestFetcher<MediaPresentationDescription> manifestFetcher;
private HttpDataSource manifestDataSource;
private MediaPresentationDescription manifest; private MediaPresentationDescription manifest;
private long elapsedRealtimeOffset; private long elapsedRealtimeOffset;
...@@ -118,7 +121,9 @@ public class DashRendererBuilder implements RendererBuilder, ...@@ -118,7 +121,9 @@ public class DashRendererBuilder implements RendererBuilder,
this.player = player; this.player = player;
this.callback = callback; this.callback = callback;
MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser(); MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser();
manifestFetcher = new ManifestFetcher<MediaPresentationDescription>(url, userAgent, parser); manifestDataSource = new DefaultHttpDataSource(userAgent, null);
manifestFetcher = new ManifestFetcher<MediaPresentationDescription>(url, manifestDataSource,
parser);
manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this); manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this);
} }
...@@ -126,7 +131,7 @@ public class DashRendererBuilder implements RendererBuilder, ...@@ -126,7 +131,7 @@ public class DashRendererBuilder implements RendererBuilder,
public void onSingleManifest(MediaPresentationDescription manifest) { public void onSingleManifest(MediaPresentationDescription manifest) {
this.manifest = manifest; this.manifest = manifest;
if (manifest.dynamic && manifest.utcTiming != null) { if (manifest.dynamic && manifest.utcTiming != null) {
UtcTimingElementResolver.resolveTimingElement(userAgent, manifest.utcTiming, UtcTimingElementResolver.resolveTimingElement(manifestDataSource, manifest.utcTiming,
manifestFetcher.getManifestLoadTimestamp(), this); manifestFetcher.getManifestLoadTimestamp(), this);
} else { } else {
buildRenderers(); buildRenderers();
......
...@@ -29,6 +29,7 @@ import com.google.android.exoplayer.metadata.MetadataTrackRenderer; ...@@ -29,6 +29,7 @@ import com.google.android.exoplayer.metadata.MetadataTrackRenderer;
import com.google.android.exoplayer.text.eia608.Eia608TrackRenderer; import com.google.android.exoplayer.text.eia608.Eia608TrackRenderer;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer.upstream.UriDataSource; import com.google.android.exoplayer.upstream.UriDataSource;
import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback; import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
...@@ -60,7 +61,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls ...@@ -60,7 +61,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
this.callback = callback; this.callback = callback;
HlsPlaylistParser parser = new HlsPlaylistParser(); HlsPlaylistParser parser = new HlsPlaylistParser();
ManifestFetcher<HlsPlaylist> playlistFetcher = ManifestFetcher<HlsPlaylist> playlistFetcher =
new ManifestFetcher<HlsPlaylist>(url, userAgent, parser); new ManifestFetcher<HlsPlaylist>(url, new DefaultHttpDataSource(userAgent, null), parser);
playlistFetcher.singleLoad(player.getMainHandler().getLooper(), this); playlistFetcher.singleLoad(player.getMainHandler().getLooper(), this);
} }
......
...@@ -42,6 +42,7 @@ import com.google.android.exoplayer.text.ttml.TtmlParser; ...@@ -42,6 +42,7 @@ import com.google.android.exoplayer.text.ttml.TtmlParser;
import com.google.android.exoplayer.upstream.BufferPool; import com.google.android.exoplayer.upstream.BufferPool;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer.upstream.UriDataSource; import com.google.android.exoplayer.upstream.UriDataSource;
import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
...@@ -90,8 +91,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder, ...@@ -90,8 +91,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
this.player = player; this.player = player;
this.callback = callback; this.callback = callback;
SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(); SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser();
manifestFetcher = new ManifestFetcher<SmoothStreamingManifest>(url + "/Manifest", userAgent, manifestFetcher = new ManifestFetcher<SmoothStreamingManifest>(url + "/Manifest",
parser); new DefaultHttpDataSource(userAgent, null), parser);
manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this); manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this);
} }
......
...@@ -21,9 +21,9 @@ import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentList; ...@@ -21,9 +21,9 @@ import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentList;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentTemplate; import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentTemplate;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentTimelineElement; import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentTimelineElement;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SingleSegmentBase; import com.google.android.exoplayer.dash.mpd.SegmentBase.SingleSegmentBase;
import com.google.android.exoplayer.upstream.NetworkLoadable;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.NetworkLoadable;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri; import android.net.Uri;
...@@ -73,11 +73,11 @@ public class MediaPresentationDescriptionParser extends DefaultHandler ...@@ -73,11 +73,11 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
// MPD parsing. // MPD parsing.
@Override @Override
public MediaPresentationDescription parse(String connectionUrl, InputStream inputStream, public MediaPresentationDescription parse(String connectionUrl, InputStream inputStream)
String inputEncoding) throws IOException, ParserException { throws IOException, ParserException {
try { try {
XmlPullParser xpp = xmlParserFactory.newPullParser(); XmlPullParser xpp = xmlParserFactory.newPullParser();
xpp.setInput(inputStream, inputEncoding); xpp.setInput(inputStream, null);
int eventType = xpp.next(); int eventType = xpp.next();
if (eventType != XmlPullParser.START_TAG || !"MPD".equals(xpp.getName())) { if (eventType != XmlPullParser.START_TAG || !"MPD".equals(xpp.getName())) {
throw new ParserException( throw new ParserException(
......
...@@ -16,10 +16,11 @@ ...@@ -16,10 +16,11 @@
package com.google.android.exoplayer.dash.mpd; package com.google.android.exoplayer.dash.mpd;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.upstream.HttpDataSource;
import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.upstream.Loader.Loadable; import com.google.android.exoplayer.upstream.Loader.Loadable;
import com.google.android.exoplayer.upstream.NetworkLoadable;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.NetworkLoadable;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.os.SystemClock; import android.os.SystemClock;
...@@ -62,7 +63,7 @@ public class UtcTimingElementResolver implements Loader.Callback { ...@@ -62,7 +63,7 @@ public class UtcTimingElementResolver implements Loader.Callback {
void onTimestampError(UtcTimingElement utcTiming, IOException e); void onTimestampError(UtcTimingElement utcTiming, IOException e);
} }
private final String userAgent; private final HttpDataSource httpDataSource;
private final UtcTimingElement timingElement; private final UtcTimingElement timingElement;
private final long timingElementElapsedRealtime; private final long timingElementElapsedRealtime;
private final UtcTimingCallback callback; private final UtcTimingCallback callback;
...@@ -73,22 +74,23 @@ public class UtcTimingElementResolver implements Loader.Callback { ...@@ -73,22 +74,23 @@ public class UtcTimingElementResolver implements Loader.Callback {
/** /**
* Resolves a {@link UtcTimingElement}. * Resolves a {@link UtcTimingElement}.
* *
* @param userAgent A user agent to use should network requests be necessary. * @param httpDataSource A source to use should network requests be necessary.
* @param timingElement The element to resolve. * @param timingElement The element to resolve.
* @param timingElementElapsedRealtime The {@link SystemClock#elapsedRealtime()} timestamp at * @param timingElementElapsedRealtime The {@link SystemClock#elapsedRealtime()} timestamp at
* which the element was obtained. Used if the element contains a timestamp directly. * which the element was obtained. Used if the element contains a timestamp directly.
* @param callback The callback to invoke on resolution or failure. * @param callback The callback to invoke on resolution or failure.
*/ */
public static void resolveTimingElement(String userAgent, UtcTimingElement timingElement, public static void resolveTimingElement(HttpDataSource httpDataSource,
long timingElementElapsedRealtime, UtcTimingCallback callback) { UtcTimingElement timingElement, long timingElementElapsedRealtime,
UtcTimingElementResolver resolver = new UtcTimingElementResolver(userAgent, timingElement, UtcTimingCallback callback) {
UtcTimingElementResolver resolver = new UtcTimingElementResolver(httpDataSource, timingElement,
timingElementElapsedRealtime, callback); timingElementElapsedRealtime, callback);
resolver.resolve(); resolver.resolve();
} }
private UtcTimingElementResolver(String userAgent, UtcTimingElement timingElement, private UtcTimingElementResolver(HttpDataSource httpDataSource, UtcTimingElement timingElement,
long timingElementElapsedRealtime, UtcTimingCallback callback) { long timingElementElapsedRealtime, UtcTimingCallback callback) {
this.userAgent = userAgent; this.httpDataSource = httpDataSource;
this.timingElement = Assertions.checkNotNull(timingElement); this.timingElement = Assertions.checkNotNull(timingElement);
this.timingElementElapsedRealtime = timingElementElapsedRealtime; this.timingElementElapsedRealtime = timingElementElapsedRealtime;
this.callback = Assertions.checkNotNull(callback); this.callback = Assertions.checkNotNull(callback);
...@@ -121,7 +123,7 @@ public class UtcTimingElementResolver implements Loader.Callback { ...@@ -121,7 +123,7 @@ public class UtcTimingElementResolver implements Loader.Callback {
private void resolveHttp(NetworkLoadable.Parser<Long> parser) { private void resolveHttp(NetworkLoadable.Parser<Long> parser) {
singleUseLoader = new Loader("utctiming"); singleUseLoader = new Loader("utctiming");
singleUseLoadable = new NetworkLoadable<Long>(timingElement.value, userAgent, parser); singleUseLoadable = new NetworkLoadable<Long>(timingElement.value, httpDataSource, parser);
singleUseLoader.startLoading(singleUseLoadable, this); singleUseLoader.startLoading(singleUseLoadable, this);
} }
...@@ -150,8 +152,8 @@ public class UtcTimingElementResolver implements Loader.Callback { ...@@ -150,8 +152,8 @@ public class UtcTimingElementResolver implements Loader.Callback {
private static class XsDateTimeParser implements NetworkLoadable.Parser<Long> { private static class XsDateTimeParser implements NetworkLoadable.Parser<Long> {
@Override @Override
public Long parse(String connectionUrl, InputStream inputStream, String inputEncoding) public Long parse(String connectionUrl, InputStream inputStream) throws ParserException,
throws ParserException, IOException { IOException {
String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine(); String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine();
try { try {
return Util.parseXsDateTime(firstLine); return Util.parseXsDateTime(firstLine);
...@@ -165,8 +167,8 @@ public class UtcTimingElementResolver implements Loader.Callback { ...@@ -165,8 +167,8 @@ public class UtcTimingElementResolver implements Loader.Callback {
private static class Iso8601Parser implements NetworkLoadable.Parser<Long> { private static class Iso8601Parser implements NetworkLoadable.Parser<Long> {
@Override @Override
public Long parse(String connectionUrl, InputStream inputStream, String inputEncoding) public Long parse(String connectionUrl, InputStream inputStream) throws ParserException,
throws ParserException, IOException { IOException {
String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine(); String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine();
try { try {
// TODO: It may be necessary to handle timestamp offsets from UTC. // TODO: It may be necessary to handle timestamp offsets from UTC.
......
...@@ -558,7 +558,7 @@ public class HlsChunkSource { ...@@ -558,7 +558,7 @@ public class HlsChunkSource {
@Override @Override
protected void consume(byte[] data, int limit) throws IOException { protected void consume(byte[] data, int limit) throws IOException {
HlsPlaylist playlist = playlistParser.parse(playlistUrl, HlsPlaylist playlist = playlistParser.parse(playlistUrl,
new ByteArrayInputStream(data, 0, limit), null); new ByteArrayInputStream(data, 0, limit));
Assertions.checkState(playlist.type == HlsPlaylist.TYPE_MEDIA); Assertions.checkState(playlist.type == HlsPlaylist.TYPE_MEDIA);
HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist; HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist;
setMediaPlaylist(variantIndex, mediaPlaylist); setMediaPlaylist(variantIndex, mediaPlaylist);
......
...@@ -18,7 +18,7 @@ package com.google.android.exoplayer.hls; ...@@ -18,7 +18,7 @@ package com.google.android.exoplayer.hls;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.hls.HlsMediaPlaylist.Segment; import com.google.android.exoplayer.hls.HlsMediaPlaylist.Segment;
import com.google.android.exoplayer.util.NetworkLoadable; import com.google.android.exoplayer.upstream.NetworkLoadable;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri; import android.net.Uri;
...@@ -84,11 +84,10 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli ...@@ -84,11 +84,10 @@ public final class HlsPlaylistParser implements NetworkLoadable.Parser<HlsPlayli
Pattern.compile(IV_ATTR + "=([^,.*]+)"); Pattern.compile(IV_ATTR + "=([^,.*]+)");
@Override @Override
public HlsPlaylist parse(String connectionUrl, InputStream inputStream, String inputEncoding) public HlsPlaylist parse(String connectionUrl, InputStream inputStream)
throws IOException, ParserException { throws IOException, ParserException {
Uri baseUri = Util.parseBaseUri(connectionUrl); Uri baseUri = Util.parseBaseUri(connectionUrl);
BufferedReader reader = new BufferedReader((inputEncoding == null) BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
? new InputStreamReader(inputStream) : new InputStreamReader(inputStream, inputEncoding));
Queue<String> extraLines = new LinkedList<String>(); Queue<String> extraLines = new LinkedList<String>();
String line; String line;
try { try {
......
...@@ -19,10 +19,10 @@ import com.google.android.exoplayer.ParserException; ...@@ -19,10 +19,10 @@ import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.ProtectionElement; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.ProtectionElement;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.TrackElement; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.TrackElement;
import com.google.android.exoplayer.upstream.NetworkLoadable;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.CodecSpecificDataUtil; import com.google.android.exoplayer.util.CodecSpecificDataUtil;
import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.NetworkLoadable;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri; import android.net.Uri;
...@@ -60,11 +60,11 @@ public class SmoothStreamingManifestParser implements ...@@ -60,11 +60,11 @@ public class SmoothStreamingManifestParser implements
} }
@Override @Override
public SmoothStreamingManifest parse(String connectionUrl, InputStream inputStream, public SmoothStreamingManifest parse(String connectionUrl, InputStream inputStream)
String inputEncoding) throws IOException, ParserException { throws IOException, ParserException {
try { try {
XmlPullParser xmlParser = xmlParserFactory.newPullParser(); XmlPullParser xmlParser = xmlParserFactory.newPullParser();
xmlParser.setInput(inputStream, inputEncoding); xmlParser.setInput(inputStream, null);
SmoothStreamMediaParser smoothStreamMediaParser = new SmoothStreamMediaParser(null, SmoothStreamMediaParser smoothStreamMediaParser = new SmoothStreamMediaParser(null,
Util.parseBaseUri(connectionUrl)); Util.parseBaseUri(connectionUrl));
return (SmoothStreamingManifest) smoothStreamMediaParser.parse(xmlParser); return (SmoothStreamingManifest) smoothStreamMediaParser.parse(xmlParser);
......
...@@ -43,6 +43,19 @@ public class DataSourceInputStream extends InputStream { ...@@ -43,6 +43,19 @@ public class DataSourceInputStream extends InputStream {
singleByteArray = new byte[1]; singleByteArray = new byte[1];
} }
/**
* Optional call to open the underlying {@link DataSource}.
* <p>
* Calling this method does nothing if the {@link DataSource} is already open. Calling this
* method is optional, since the read and skip methods will automatically open the underlying
* {@link DataSource} if it's not open already.
*
* @throws IOException If an error occurs opening the {@link DataSource}.
*/
public void open() throws IOException {
checkOpened();
}
@Override @Override
public int read() throws IOException { public int read() throws IOException {
read(singleByteArray); read(singleByteArray);
......
...@@ -13,15 +13,15 @@ ...@@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer.util; package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.upstream.Loader.Loadable; import com.google.android.exoplayer.upstream.Loader.Loadable;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
/** /**
* A {@link Loadable} for loading an object over the network. * A {@link Loadable} for loading an object over the network.
...@@ -40,21 +40,16 @@ public final class NetworkLoadable<T> implements Loadable { ...@@ -40,21 +40,16 @@ public final class NetworkLoadable<T> implements Loadable {
* *
* @param connectionUrl The source of the response, after any redirection. * @param connectionUrl The source of the response, after any redirection.
* @param inputStream An {@link InputStream} from which the response data can be read. * @param inputStream An {@link InputStream} from which the response data can be read.
* @param inputEncoding The encoding of the data, if available.
* @return The parsed object. * @return The parsed object.
* @throws ParserException If an error occurs parsing the data. * @throws ParserException If an error occurs parsing the data.
* @throws IOException If an error occurs reading data from the stream. * @throws IOException If an error occurs reading data from the stream.
*/ */
T parse(String connectionUrl, InputStream inputStream, String inputEncoding) T parse(String connectionUrl, InputStream inputStream) throws ParserException, IOException;
throws ParserException, IOException;
} }
public static final int DEFAULT_TIMEOUT_MILLIS = 10000; private final DataSpec dataSpec;
private final HttpDataSource httpDataSource;
private final String url;
private final String userAgent;
private final int timeoutMillis;
private final Parser<T> parser; private final Parser<T> parser;
private volatile T result; private volatile T result;
...@@ -62,24 +57,13 @@ public final class NetworkLoadable<T> implements Loadable { ...@@ -62,24 +57,13 @@ public final class NetworkLoadable<T> implements Loadable {
/** /**
* @param url The url from which the object should be loaded. * @param url The url from which the object should be loaded.
* @param userAgent The user agent to use when requesting the object. * @param httpDataSource A {@link HttpDataSource} to use when loading the data.
* @param parser Parses the object from the network response. * @param parser Parses the object from the network response.
*/ */
public NetworkLoadable(String url, String userAgent, Parser<T> parser) { public NetworkLoadable(String url, HttpDataSource httpDataSource, Parser<T> parser) {
this(url, userAgent, DEFAULT_TIMEOUT_MILLIS, parser); this.httpDataSource = httpDataSource;
}
/**
* @param url The url from which the object should be loaded.
* @param userAgent The user agent to use when requesting the object.
* @param timeoutMillis The desired http timeout in milliseconds.
* @param parser Parses the object from the network response.
*/
public NetworkLoadable(String url, String userAgent, int timeoutMillis, Parser<T> parser) {
this.url = url;
this.userAgent = userAgent;
this.timeoutMillis = timeoutMillis;
this.parser = parser; this.parser = parser;
dataSpec = new DataSpec(Uri.parse(url));
} }
/** /**
...@@ -103,28 +87,13 @@ public final class NetworkLoadable<T> implements Loadable { ...@@ -103,28 +87,13 @@ public final class NetworkLoadable<T> implements Loadable {
@Override @Override
public final void load() throws IOException, InterruptedException { public final void load() throws IOException, InterruptedException {
String inputEncoding; DataSourceInputStream inputStream = new DataSourceInputStream(httpDataSource, dataSpec);
InputStream inputStream = null;
try { try {
URLConnection connection = configureConnection(new URL(url)); inputStream.open();
inputStream = connection.getInputStream(); result = parser.parse(httpDataSource.getUrl(), inputStream);
inputEncoding = connection.getContentEncoding();
result = parser.parse(connection.getURL().toString(), inputStream, inputEncoding);
} finally { } finally {
if (inputStream != null) {
inputStream.close(); inputStream.close();
} }
} }
}
private URLConnection configureConnection(URL url) throws IOException {
URLConnection connection = url.openConnection();
connection.setConnectTimeout(timeoutMillis);
connection.setReadTimeout(timeoutMillis);
connection.setDoOutput(false);
connection.setRequestProperty("User-Agent", userAgent);
connection.connect();
return connection;
}
} }
...@@ -37,14 +37,14 @@ public final class UriDataSource implements DataSource { ...@@ -37,14 +37,14 @@ public final class UriDataSource implements DataSource {
/** /**
* Constructs a new data source that delegates to a {@link FileDataSource} for file URIs and an * Constructs a new data source that delegates to a {@link FileDataSource} for file URIs and an
* {@link HttpDataSource} for other URIs. * {@link DefaultHttpDataSource} for other URIs.
* *
* @param userAgent The User-Agent string that should be used when requesting remote data. * @param userAgent The User-Agent string that should be used when requesting remote data.
* @param transferListener An optional listener. * @param transferListener An optional listener.
*/ */
public UriDataSource(String userAgent, TransferListener transferListener) { public UriDataSource(String userAgent, TransferListener transferListener) {
this(new FileDataSource(transferListener), this(new FileDataSource(transferListener),
new HttpDataSource(userAgent, null, transferListener)); new DefaultHttpDataSource(userAgent, null, transferListener));
} }
/** /**
......
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
*/ */
package com.google.android.exoplayer.util; package com.google.android.exoplayer.util;
import com.google.android.exoplayer.upstream.HttpDataSource;
import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.upstream.Loader.Loadable; import com.google.android.exoplayer.upstream.Loader.Loadable;
import com.google.android.exoplayer.upstream.NetworkLoadable;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
...@@ -28,6 +30,18 @@ import java.util.concurrent.CancellationException; ...@@ -28,6 +30,18 @@ import java.util.concurrent.CancellationException;
/** /**
* Performs both single and repeated loads of media manifests. * Performs both single and repeated loads of media manifests.
* <p>
* Client code is responsible for ensuring that only one load is taking place at any one time.
* Typical usage of this class is as follows:
* <ol>
* <li>Create an instance.</li>
* <li>Obtain an initial manifest by calling {@link #singleLoad(Looper, ManifestCallback)} and
* waiting for the callback to be invoked.</li>
* <li>For on-demand playbacks, the loader is no longer required. For live playbacks, the loader
* may be required to periodically refresh the manifest. In this case it is injected into any
* components that require it. These components will call {@link #requestRefresh()} on the
* loader whenever a refresh is required.</li>
* </ol>
* *
* @param <T> The type of manifest. * @param <T> The type of manifest.
*/ */
...@@ -70,7 +84,7 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -70,7 +84,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
} }
private final NetworkLoadable.Parser<T> parser; private final NetworkLoadable.Parser<T> parser;
private final String userAgent; private final HttpDataSource httpDataSource;
private final Handler eventHandler; private final Handler eventHandler;
private final EventListener eventListener; private final EventListener eventListener;
...@@ -89,26 +103,27 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -89,26 +103,27 @@ public class ManifestFetcher<T> implements Loader.Callback {
/** /**
* @param manifestUrl The manifest location. * @param manifestUrl The manifest location.
* @param userAgent The User-Agent string that should be used. * @param httpDataSource The {@link HttpDataSource} to use when loading the manifest.
* @param parser A parser to parse the loaded manifest data. * @param parser A parser to parse the loaded manifest data.
*/ */
public ManifestFetcher(String manifestUrl, String userAgent, NetworkLoadable.Parser<T> parser) { public ManifestFetcher(String manifestUrl, HttpDataSource httpDataSource,
this(manifestUrl, userAgent, parser, null, null); NetworkLoadable.Parser<T> parser) {
this(manifestUrl, httpDataSource, parser, null, null);
} }
/** /**
* @param manifestUrl The manifest location. * @param manifestUrl The manifest location.
* @param userAgent The User-Agent string that should be used. * @param httpDataSource The {@link HttpDataSource} to use when loading the manifest.
* @param parser A parser to parse the loaded manifest data. * @param parser A parser to parse the loaded manifest data.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required. * null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required. * @param eventListener A listener of events. May be null if delivery of events is not required.
*/ */
public ManifestFetcher(String manifestUrl, String userAgent, NetworkLoadable.Parser<T> parser, public ManifestFetcher(String manifestUrl, HttpDataSource httpDataSource,
Handler eventHandler, EventListener eventListener) { NetworkLoadable.Parser<T> parser, Handler eventHandler, EventListener eventListener) {
this.parser = parser; this.parser = parser;
this.manifestUrl = manifestUrl; this.manifestUrl = manifestUrl;
this.userAgent = userAgent; this.httpDataSource = httpDataSource;
this.eventHandler = eventHandler; this.eventHandler = eventHandler;
this.eventListener = eventListener; this.eventListener = eventListener;
} }
...@@ -131,7 +146,7 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -131,7 +146,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
*/ */
public void singleLoad(Looper callbackLooper, final ManifestCallback<T> callback) { public void singleLoad(Looper callbackLooper, final ManifestCallback<T> callback) {
SingleFetchHelper fetchHelper = new SingleFetchHelper( SingleFetchHelper fetchHelper = new SingleFetchHelper(
new NetworkLoadable<T>(manifestUrl, userAgent, parser), callbackLooper, callback); new NetworkLoadable<T>(manifestUrl, httpDataSource, parser), callbackLooper, callback);
fetchHelper.startLoading(); fetchHelper.startLoading();
} }
...@@ -204,7 +219,7 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -204,7 +219,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
loader = new Loader("manifestLoader"); loader = new Loader("manifestLoader");
} }
if (!loader.isLoading()) { if (!loader.isLoading()) {
currentLoadable = new NetworkLoadable<T>(manifestUrl, userAgent, parser); currentLoadable = new NetworkLoadable<T>(manifestUrl, httpDataSource, parser);
loader.startLoading(currentLoadable, this); loader.startLoading(currentLoadable, this);
notifyManifestRefreshStarted(); notifyManifestRefreshStarted();
} }
......
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