Commit 6cc507aa by olly Committed by Oliver Woodman

Make all DataSource implementations implement getUri.

In V2 we'll at some point start using DataSource factories
for creating DataSource instances. If there are two DataSource
interfaces this gets unnecessarily awkward.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=118470751
parent d869a8d2
Showing with 256 additions and 215 deletions
...@@ -31,10 +31,11 @@ import com.google.android.exoplayer.drm.MediaDrmCallback; ...@@ -31,10 +31,11 @@ import com.google.android.exoplayer.drm.MediaDrmCallback;
import com.google.android.exoplayer.upstream.BandwidthMeter; import com.google.android.exoplayer.upstream.BandwidthMeter;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.upstream.DefaultUriDataSource; import com.google.android.exoplayer.upstream.DefaultDataSource;
import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.os.Handler; import android.os.Handler;
/** /**
...@@ -68,16 +69,16 @@ public class DashSourceBuilder implements SourceBuilder { ...@@ -68,16 +69,16 @@ public class DashSourceBuilder implements SourceBuilder {
@Override @Override
public SampleSource buildRenderers(DemoPlayer player) { public SampleSource buildRenderers(DemoPlayer player) {
MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser(); MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser();
DefaultUriDataSource manifestDataSource = new DefaultUriDataSource(context, userAgent); DefaultDataSource manifestDataSource = new DefaultDataSource(context, userAgent);
ManifestFetcher<MediaPresentationDescription> manifestFetcher = new ManifestFetcher<>(url, ManifestFetcher<MediaPresentationDescription> manifestFetcher = new ManifestFetcher<>(
manifestDataSource, parser); Uri.parse(url), manifestDataSource, parser);
Handler mainHandler = player.getMainHandler(); Handler mainHandler = player.getMainHandler();
BandwidthMeter bandwidthMeter = player.getBandwidthMeter(); BandwidthMeter bandwidthMeter = player.getBandwidthMeter();
LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE)); LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
// Build the video renderer. // Build the video renderer.
DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource videoDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_VIDEO, ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_VIDEO,
videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS, videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS,
0, mainHandler, player, DemoPlayer.TYPE_VIDEO); 0, mainHandler, player, DemoPlayer.TYPE_VIDEO);
...@@ -85,7 +86,7 @@ public class DashSourceBuilder implements SourceBuilder { ...@@ -85,7 +86,7 @@ public class DashSourceBuilder implements SourceBuilder {
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO);
// Build the audio renderer. // Build the audio renderer.
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource audioDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
ChunkSource audioChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_AUDIO, ChunkSource audioChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_AUDIO,
audioDataSource, null, LIVE_EDGE_LATENCY_MS, 0, mainHandler, player, DemoPlayer.TYPE_AUDIO); audioDataSource, null, LIVE_EDGE_LATENCY_MS, 0, mainHandler, player, DemoPlayer.TYPE_AUDIO);
ChunkSampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl, ChunkSampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl,
...@@ -93,7 +94,7 @@ public class DashSourceBuilder implements SourceBuilder { ...@@ -93,7 +94,7 @@ public class DashSourceBuilder implements SourceBuilder {
DemoPlayer.TYPE_AUDIO); DemoPlayer.TYPE_AUDIO);
// Build the text renderer. // Build the text renderer.
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource textDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
ChunkSource textChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_TEXT, ChunkSource textChunkSource = new DashChunkSource(manifestFetcher, AdaptationSet.TYPE_TEXT,
textDataSource, null, LIVE_EDGE_LATENCY_MS, 0, mainHandler, player, DemoPlayer.TYPE_TEXT); textDataSource, null, LIVE_EDGE_LATENCY_MS, 0, mainHandler, player, DemoPlayer.TYPE_TEXT);
ChunkSampleSource textSampleSource = new ChunkSampleSource(textChunkSource, loadControl, ChunkSampleSource textSampleSource = new ChunkSampleSource(textChunkSource, loadControl,
......
...@@ -22,7 +22,7 @@ import com.google.android.exoplayer.extractor.ExtractorSampleSource; ...@@ -22,7 +22,7 @@ import com.google.android.exoplayer.extractor.ExtractorSampleSource;
import com.google.android.exoplayer.upstream.Allocator; import com.google.android.exoplayer.upstream.Allocator;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.upstream.DefaultUriDataSource; import com.google.android.exoplayer.upstream.DefaultDataSource;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
...@@ -48,8 +48,7 @@ public class ExtractorSourceBuilder implements SourceBuilder { ...@@ -48,8 +48,7 @@ public class ExtractorSourceBuilder implements SourceBuilder {
@Override @Override
public SampleSource buildRenderers(DemoPlayer player) { public SampleSource buildRenderers(DemoPlayer player) {
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE); Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
DataSource dataSource = new DefaultUriDataSource(context, player.getBandwidthMeter(), DataSource dataSource = new DefaultDataSource(context, player.getBandwidthMeter(), userAgent);
userAgent);
return new ExtractorSampleSource(uri, dataSource, allocator, return new ExtractorSampleSource(uri, dataSource, allocator,
BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE, player.getMainHandler(), player, 0); BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE, player.getMainHandler(), player, 0);
} }
......
...@@ -29,10 +29,11 @@ import com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider; ...@@ -29,10 +29,11 @@ import com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider;
import com.google.android.exoplayer.upstream.BandwidthMeter; import com.google.android.exoplayer.upstream.BandwidthMeter;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.upstream.DefaultUriDataSource; import com.google.android.exoplayer.upstream.DefaultDataSource;
import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.os.Handler; import android.os.Handler;
/** /**
...@@ -59,8 +60,8 @@ public class HlsSourceBuilder implements SourceBuilder { ...@@ -59,8 +60,8 @@ public class HlsSourceBuilder implements SourceBuilder {
@Override @Override
public SampleSource buildRenderers(DemoPlayer player) { public SampleSource buildRenderers(DemoPlayer player) {
HlsPlaylistParser parser = new HlsPlaylistParser(); HlsPlaylistParser parser = new HlsPlaylistParser();
DefaultUriDataSource manifestDataSource = new DefaultUriDataSource(context, userAgent); DefaultDataSource manifestDataSource = new DefaultDataSource(context, userAgent);
ManifestFetcher<HlsPlaylist> manifestFetcher = new ManifestFetcher<>(url, ManifestFetcher<HlsPlaylist> manifestFetcher = new ManifestFetcher<>(Uri.parse(url),
manifestDataSource, parser); manifestDataSource, parser);
Handler mainHandler = player.getMainHandler(); Handler mainHandler = player.getMainHandler();
...@@ -68,20 +69,20 @@ public class HlsSourceBuilder implements SourceBuilder { ...@@ -68,20 +69,20 @@ public class HlsSourceBuilder implements SourceBuilder {
LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE)); LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider(); PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();
DataSource defaultDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource defaultDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource defaultChunkSource = new HlsChunkSource(manifestFetcher, HlsChunkSource defaultChunkSource = new HlsChunkSource(manifestFetcher,
HlsChunkSource.TYPE_DEFAULT, defaultDataSource, timestampAdjusterProvider, HlsChunkSource.TYPE_DEFAULT, defaultDataSource, timestampAdjusterProvider,
new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter)); new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter));
HlsSampleSource defaultSampleSource = new HlsSampleSource(defaultChunkSource, loadControl, HlsSampleSource defaultSampleSource = new HlsSampleSource(defaultChunkSource, loadControl,
MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO);
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource audioDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource audioChunkSource = new HlsChunkSource(manifestFetcher, HlsChunkSource.TYPE_AUDIO, HlsChunkSource audioChunkSource = new HlsChunkSource(manifestFetcher, HlsChunkSource.TYPE_AUDIO,
audioDataSource, timestampAdjusterProvider, null); audioDataSource, timestampAdjusterProvider, null);
HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl, HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl,
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO); AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO);
DataSource subtitleDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource subtitleDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource subtitleChunkSource = new HlsChunkSource(manifestFetcher, HlsChunkSource subtitleChunkSource = new HlsChunkSource(manifestFetcher,
HlsChunkSource.TYPE_SUBTITLE, subtitleDataSource, timestampAdjusterProvider, null); HlsChunkSource.TYPE_SUBTITLE, subtitleDataSource, timestampAdjusterProvider, null);
HlsSampleSource subtitleSampleSource = new HlsSampleSource(subtitleChunkSource, loadControl, HlsSampleSource subtitleSampleSource = new HlsSampleSource(subtitleChunkSource, loadControl,
......
...@@ -30,12 +30,13 @@ import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifestParse ...@@ -30,12 +30,13 @@ import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifestParse
import com.google.android.exoplayer.upstream.BandwidthMeter; import com.google.android.exoplayer.upstream.BandwidthMeter;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.upstream.DefaultDataSource;
import com.google.android.exoplayer.upstream.DefaultHttpDataSource; import com.google.android.exoplayer.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
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;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.os.Handler; import android.os.Handler;
/** /**
...@@ -66,14 +67,14 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder { ...@@ -66,14 +67,14 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder {
@Override @Override
public SampleSource buildRenderers(DemoPlayer player) { public SampleSource buildRenderers(DemoPlayer player) {
SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(); SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser();
ManifestFetcher<SmoothStreamingManifest> manifestFetcher = new ManifestFetcher<>(url, ManifestFetcher<SmoothStreamingManifest> manifestFetcher = new ManifestFetcher<>(Uri.parse(url),
new DefaultHttpDataSource(userAgent, null), parser); new DefaultHttpDataSource(userAgent, null), parser);
Handler mainHandler = player.getMainHandler(); Handler mainHandler = player.getMainHandler();
BandwidthMeter bandwidthMeter = player.getBandwidthMeter(); BandwidthMeter bandwidthMeter = player.getBandwidthMeter();
LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE)); LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
// Build the video renderer. // Build the video renderer.
DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource videoDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher, ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
SmoothStreamingManifest.StreamElement.TYPE_VIDEO, SmoothStreamingManifest.StreamElement.TYPE_VIDEO,
videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS); videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS);
...@@ -82,7 +83,7 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder { ...@@ -82,7 +83,7 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder {
DemoPlayer.TYPE_VIDEO); DemoPlayer.TYPE_VIDEO);
// Build the audio renderer. // Build the audio renderer.
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource audioDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
ChunkSource audioChunkSource = new SmoothStreamingChunkSource(manifestFetcher, ChunkSource audioChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
SmoothStreamingManifest.StreamElement.TYPE_AUDIO, audioDataSource, null, SmoothStreamingManifest.StreamElement.TYPE_AUDIO, audioDataSource, null,
LIVE_EDGE_LATENCY_MS); LIVE_EDGE_LATENCY_MS);
...@@ -90,7 +91,7 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder { ...@@ -90,7 +91,7 @@ public class SmoothStreamingSourceBuilder implements SourceBuilder {
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO); AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO);
// Build the text renderer. // Build the text renderer.
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource textDataSource = new DefaultDataSource(context, bandwidthMeter, userAgent);
ChunkSource textChunkSource = new SmoothStreamingChunkSource(manifestFetcher, ChunkSource textChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
SmoothStreamingManifest.StreamElement.TYPE_TEXT, textDataSource, null, SmoothStreamingManifest.StreamElement.TYPE_TEXT, textDataSource, null,
LIVE_EDGE_LATENCY_MS); LIVE_EDGE_LATENCY_MS);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer.dash.mpd; package com.google.android.exoplayer.dash.mpd;
import android.net.Uri;
import android.test.InstrumentationTestCase; import android.test.InstrumentationTestCase;
import java.io.IOException; import java.io.IOException;
...@@ -34,7 +35,7 @@ public class MediaPresentationDescriptionParserTest extends InstrumentationTestC ...@@ -34,7 +35,7 @@ public class MediaPresentationDescriptionParserTest extends InstrumentationTestC
InputStream inputStream = InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_MPD_1); getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_MPD_1);
// Simple test to ensure that the sample manifest parses without throwing any exceptions. // Simple test to ensure that the sample manifest parses without throwing any exceptions.
parser.parse("https://example.com/test.mpd", inputStream); parser.parse(Uri.parse("https://example.com/test.mpd"), inputStream);
} }
public void testParseMediaPresentationDescriptionWithUnknownMimeType() throws IOException { public void testParseMediaPresentationDescriptionWithUnknownMimeType() throws IOException {
...@@ -43,7 +44,7 @@ public class MediaPresentationDescriptionParserTest extends InstrumentationTestC ...@@ -43,7 +44,7 @@ public class MediaPresentationDescriptionParserTest extends InstrumentationTestC
.open(SAMPLE_MPD_2_UNKNOWN_MIME_TYPE); .open(SAMPLE_MPD_2_UNKNOWN_MIME_TYPE);
// Simple test to ensure that the sample manifest with an unknown mime type parses without // Simple test to ensure that the sample manifest with an unknown mime type parses without
// throwing any exceptions. // throwing any exceptions.
parser.parse("https://example.com/test.mpd", inputStream); parser.parse(Uri.parse("https://example.com/test.mpd"), inputStream);
} }
} }
...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.hls; ...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.hls;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import android.net.Uri;
import junit.framework.TestCase; import junit.framework.TestCase;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
...@@ -30,7 +32,7 @@ import java.util.List; ...@@ -30,7 +32,7 @@ import java.util.List;
public class HlsMasterPlaylistParserTest extends TestCase { public class HlsMasterPlaylistParserTest extends TestCase {
public void testParseMasterPlaylist() { public void testParseMasterPlaylist() {
String playlistUrl = "https://example.com/test.m3u8"; Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
String playlistString = "#EXTM3U\n" String playlistString = "#EXTM3U\n"
+ "\n" + "\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
...@@ -50,7 +52,7 @@ public class HlsMasterPlaylistParserTest extends TestCase { ...@@ -50,7 +52,7 @@ public class HlsMasterPlaylistParserTest extends TestCase {
ByteArrayInputStream inputStream = new ByteArrayInputStream( ByteArrayInputStream inputStream = new ByteArrayInputStream(
playlistString.getBytes(Charset.forName(C.UTF8_NAME))); playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
try { try {
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUrl, inputStream); HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
assertNotNull(playlist); assertNotNull(playlist);
assertEquals(HlsPlaylist.TYPE_MASTER, playlist.type); assertEquals(HlsPlaylist.TYPE_MASTER, playlist.type);
......
...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.hls; ...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.hls;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import android.net.Uri;
import junit.framework.TestCase; import junit.framework.TestCase;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
...@@ -32,7 +34,7 @@ import java.util.Locale; ...@@ -32,7 +34,7 @@ import java.util.Locale;
public class HlsMediaPlaylistParserTest extends TestCase { public class HlsMediaPlaylistParserTest extends TestCase {
public void testParseMediaPlaylist() { public void testParseMediaPlaylist() {
String playlistUrl = "https://example.com/test.m3u8"; Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
String playlistString = "#EXTM3U\n" String playlistString = "#EXTM3U\n"
+ "#EXT-X-VERSION:3\n" + "#EXT-X-VERSION:3\n"
+ "#EXT-X-TARGETDURATION:8\n" + "#EXT-X-TARGETDURATION:8\n"
...@@ -66,7 +68,7 @@ public class HlsMediaPlaylistParserTest extends TestCase { ...@@ -66,7 +68,7 @@ public class HlsMediaPlaylistParserTest extends TestCase {
InputStream inputStream = new ByteArrayInputStream( InputStream inputStream = new ByteArrayInputStream(
playlistString.getBytes(Charset.forName(C.UTF8_NAME))); playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
try { try {
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUrl, inputStream); HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
assertNotNull(playlist); assertNotNull(playlist);
assertEquals(HlsPlaylist.TYPE_MEDIA, playlist.type); assertEquals(HlsPlaylist.TYPE_MEDIA, playlist.type);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer.smoothstreaming; package com.google.android.exoplayer.smoothstreaming;
import android.net.Uri;
import android.test.InstrumentationTestCase; import android.test.InstrumentationTestCase;
import java.io.IOException; import java.io.IOException;
...@@ -34,11 +35,11 @@ public class SmoothStreamingManifestParserTest extends InstrumentationTestCase { ...@@ -34,11 +35,11 @@ public class SmoothStreamingManifestParserTest extends InstrumentationTestCase {
// SystemID UUID in the manifest is not wrapped in braces. // SystemID UUID in the manifest is not wrapped in braces.
InputStream inputStream1 = InputStream inputStream1 =
getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_ISMC_1); getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_ISMC_1);
parser.parse("https://example.com/test.ismc", inputStream1); parser.parse(Uri.parse("https://example.com/test.ismc"), inputStream1);
// Simple test to ensure that the sample manifest parses without throwing any exceptions. // Simple test to ensure that the sample manifest parses without throwing any exceptions.
// SystemID UUID in the manifest is wrapped in braces. // SystemID UUID in the manifest is wrapped in braces.
InputStream inputStream2 = InputStream inputStream2 =
getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_ISMC_2); getInstrumentation().getContext().getResources().getAssets().open(SAMPLE_ISMC_2);
parser.parse("https://example.com/test.ismc", inputStream2); parser.parse(Uri.parse("https://example.com/test.ismc"), inputStream2);
} }
} }
...@@ -20,6 +20,8 @@ import com.google.android.exoplayer.upstream.DataSource; ...@@ -20,6 +20,8 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec; import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -44,6 +46,7 @@ public final class FakeDataSource implements DataSource { ...@@ -44,6 +46,7 @@ public final class FakeDataSource implements DataSource {
private final boolean simulateUnknownLength; private final boolean simulateUnknownLength;
private final long totalLength; private final long totalLength;
private Uri uri;
private boolean opened; private boolean opened;
private int currentSegmentIndex; private int currentSegmentIndex;
private long bytesRemaining; private long bytesRemaining;
...@@ -63,6 +66,7 @@ public final class FakeDataSource implements DataSource { ...@@ -63,6 +66,7 @@ public final class FakeDataSource implements DataSource {
Assertions.checkState(!opened); Assertions.checkState(!opened);
// DataSpec requires a matching close call even if open fails. // DataSpec requires a matching close call even if open fails.
opened = true; opened = true;
uri = dataSpec.uri;
// If the source knows that the request is unsatisfiable then fail. // If the source knows that the request is unsatisfiable then fail.
if (dataSpec.position >= totalLength) { if (dataSpec.position >= totalLength) {
throw new IOException("Unsatisfiable position"); throw new IOException("Unsatisfiable position");
...@@ -95,18 +99,6 @@ public final class FakeDataSource implements DataSource { ...@@ -95,18 +99,6 @@ public final class FakeDataSource implements DataSource {
} }
@Override @Override
public void close() throws IOException {
Assertions.checkState(opened);
opened = false;
if (currentSegmentIndex < segments.size()) {
Segment current = segments.get(currentSegmentIndex);
if (current.isErrorSegment() && current.exceptionThrown) {
current.exceptionCleared = true;
}
}
}
@Override
public int read(byte[] buffer, int offset, int readLength) throws IOException { public int read(byte[] buffer, int offset, int readLength) throws IOException {
Assertions.checkState(opened); Assertions.checkState(opened);
while (true) { while (true) {
...@@ -138,6 +130,24 @@ public final class FakeDataSource implements DataSource { ...@@ -138,6 +130,24 @@ public final class FakeDataSource implements DataSource {
} }
} }
@Override
public Uri getUri() {
return uri;
}
@Override
public void close() throws IOException {
Assertions.checkState(opened);
opened = false;
uri = null;
if (currentSegmentIndex < segments.size()) {
Segment current = segments.get(currentSegmentIndex);
if (current.isErrorSegment() && current.exceptionThrown) {
current.exceptionCleared = true;
}
}
}
private static class Segment { private static class Segment {
public final IOException exception; public final IOException exception;
......
...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.dash.mpd; ...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.dash.mpd;
import com.google.android.exoplayer.util.ManifestFetcher.RedirectingManifest; import com.google.android.exoplayer.util.ManifestFetcher.RedirectingManifest;
import android.net.Uri;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
...@@ -39,13 +41,13 @@ public class MediaPresentationDescription implements RedirectingManifest { ...@@ -39,13 +41,13 @@ public class MediaPresentationDescription implements RedirectingManifest {
public final UtcTimingElement utcTiming; public final UtcTimingElement utcTiming;
public final String location; public final Uri location;
private final List<Period> periods; private final List<Period> periods;
public MediaPresentationDescription(long availabilityStartTime, long duration, long minBufferTime, public MediaPresentationDescription(long availabilityStartTime, long duration, long minBufferTime,
boolean dynamic, long minUpdatePeriod, long timeShiftBufferDepth, UtcTimingElement utcTiming, boolean dynamic, long minUpdatePeriod, long timeShiftBufferDepth, UtcTimingElement utcTiming,
String location, List<Period> periods) { Uri location, List<Period> periods) {
this.availabilityStartTime = availabilityStartTime; this.availabilityStartTime = availabilityStartTime;
this.duration = duration; this.duration = duration;
this.minBufferTime = minBufferTime; this.minBufferTime = minBufferTime;
...@@ -58,7 +60,7 @@ public class MediaPresentationDescription implements RedirectingManifest { ...@@ -58,7 +60,7 @@ public class MediaPresentationDescription implements RedirectingManifest {
} }
@Override @Override
public final String getNextManifestUri() { public final Uri getNextManifestUri() {
return location; return location;
} }
......
...@@ -30,6 +30,7 @@ import com.google.android.exoplayer.util.ParserUtil; ...@@ -30,6 +30,7 @@ import com.google.android.exoplayer.util.ParserUtil;
import com.google.android.exoplayer.util.UriUtil; import com.google.android.exoplayer.util.UriUtil;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
...@@ -88,7 +89,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler ...@@ -88,7 +89,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
// MPD parsing. // MPD parsing.
@Override @Override
public MediaPresentationDescription parse(String connectionUrl, InputStream inputStream) public MediaPresentationDescription parse(Uri uri, InputStream inputStream)
throws IOException, ParserException { throws IOException, ParserException {
try { try {
XmlPullParser xpp = xmlParserFactory.newPullParser(); XmlPullParser xpp = xmlParserFactory.newPullParser();
...@@ -98,7 +99,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler ...@@ -98,7 +99,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
throw new ParserException( throw new ParserException(
"inputStream does not contain a valid media presentation description"); "inputStream does not contain a valid media presentation description");
} }
return parseMediaPresentationDescription(xpp, connectionUrl); return parseMediaPresentationDescription(xpp, uri.toString());
} catch (XmlPullParserException e) { } catch (XmlPullParserException e) {
throw new ParserException(e); throw new ParserException(e);
} catch (ParseException e) { } catch (ParseException e) {
...@@ -116,7 +117,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler ...@@ -116,7 +117,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
long minUpdateTimeMs = (dynamic) ? parseDuration(xpp, "minimumUpdatePeriod", -1) : -1; long minUpdateTimeMs = (dynamic) ? parseDuration(xpp, "minimumUpdatePeriod", -1) : -1;
long timeShiftBufferDepthMs = (dynamic) ? parseDuration(xpp, "timeShiftBufferDepth", -1) : -1; long timeShiftBufferDepthMs = (dynamic) ? parseDuration(xpp, "timeShiftBufferDepth", -1) : -1;
UtcTimingElement utcTiming = null; UtcTimingElement utcTiming = null;
String location = null; Uri location = null;
List<Period> periods = new ArrayList<>(); List<Period> periods = new ArrayList<>();
long nextPeriodStartMs = dynamic ? -1 : 0; long nextPeriodStartMs = dynamic ? -1 : 0;
...@@ -132,7 +133,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler ...@@ -132,7 +133,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
} else if (ParserUtil.isStartTag(xpp, "UTCTiming")) { } else if (ParserUtil.isStartTag(xpp, "UTCTiming")) {
utcTiming = parseUtcTiming(xpp); utcTiming = parseUtcTiming(xpp);
} else if (ParserUtil.isStartTag(xpp, "Location")) { } else if (ParserUtil.isStartTag(xpp, "Location")) {
location = xpp.nextText(); location = Uri.parse(xpp.nextText());
} else if (ParserUtil.isStartTag(xpp, "Period") && !seenEarlyAccessPeriod) { } else if (ParserUtil.isStartTag(xpp, "Period") && !seenEarlyAccessPeriod) {
Pair<Period, Long> periodWithDurationMs = parsePeriod(xpp, baseUrl, nextPeriodStartMs); Pair<Period, Long> periodWithDurationMs = parsePeriod(xpp, baseUrl, nextPeriodStartMs);
Period period = periodWithDurationMs.first; Period period = periodWithDurationMs.first;
...@@ -172,7 +173,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler ...@@ -172,7 +173,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
protected MediaPresentationDescription buildMediaPresentationDescription( protected MediaPresentationDescription buildMediaPresentationDescription(
long availabilityStartTime, long durationMs, long minBufferTimeMs, boolean dynamic, long availabilityStartTime, long durationMs, long minBufferTimeMs, boolean dynamic,
long minUpdateTimeMs, long timeShiftBufferDepthMs, UtcTimingElement utcTiming, long minUpdateTimeMs, long timeShiftBufferDepthMs, UtcTimingElement utcTiming,
String location, List<Period> periods) { Uri location, List<Period> periods) {
return new MediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs, return new MediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs,
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, utcTiming, location, periods); dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, utcTiming, location, periods);
} }
......
...@@ -16,13 +16,14 @@ ...@@ -16,13 +16,14 @@
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.DataSource;
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.UriDataSource;
import com.google.android.exoplayer.upstream.UriLoadable; import com.google.android.exoplayer.upstream.UriLoadable;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri;
import android.os.SystemClock; import android.os.SystemClock;
import java.io.BufferedReader; import java.io.BufferedReader;
...@@ -64,7 +65,7 @@ public final class UtcTimingElementResolver implements Loader.Callback { ...@@ -64,7 +65,7 @@ public final class UtcTimingElementResolver implements Loader.Callback {
void onTimestampError(UtcTimingElement utcTiming, IOException e); void onTimestampError(UtcTimingElement utcTiming, IOException e);
} }
private final UriDataSource uriDataSource; private final DataSource dataSource;
private final UtcTimingElement timingElement; private final UtcTimingElement timingElement;
private final long timingElementElapsedRealtime; private final long timingElementElapsedRealtime;
private final UtcTimingCallback callback; private final UtcTimingCallback callback;
...@@ -75,23 +76,22 @@ public final class UtcTimingElementResolver implements Loader.Callback { ...@@ -75,23 +76,22 @@ public final class UtcTimingElementResolver implements Loader.Callback {
/** /**
* Resolves a {@link UtcTimingElement}. * Resolves a {@link UtcTimingElement}.
* *
* @param uriDataSource A source to use should loading from a URI be necessary. * @param dataSource A {@link DataSource} to use should loading from a {@link Uri} 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(UriDataSource uriDataSource, public static void resolveTimingElement(DataSource dataSource, UtcTimingElement timingElement,
UtcTimingElement timingElement, long timingElementElapsedRealtime, long timingElementElapsedRealtime, UtcTimingCallback callback) {
UtcTimingCallback callback) { UtcTimingElementResolver resolver = new UtcTimingElementResolver(dataSource, timingElement,
UtcTimingElementResolver resolver = new UtcTimingElementResolver(uriDataSource, timingElement,
timingElementElapsedRealtime, callback); timingElementElapsedRealtime, callback);
resolver.resolve(); resolver.resolve();
} }
private UtcTimingElementResolver(UriDataSource uriDataSource, UtcTimingElement timingElement, private UtcTimingElementResolver(DataSource dataSource, UtcTimingElement timingElement,
long timingElementElapsedRealtime, UtcTimingCallback callback) { long timingElementElapsedRealtime, UtcTimingCallback callback) {
this.uriDataSource = uriDataSource; this.dataSource = dataSource;
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);
...@@ -124,7 +124,7 @@ public final class UtcTimingElementResolver implements Loader.Callback { ...@@ -124,7 +124,7 @@ public final class UtcTimingElementResolver implements Loader.Callback {
private void resolveHttp(UriLoadable.Parser<Long> parser) { private void resolveHttp(UriLoadable.Parser<Long> parser) {
singleUseLoader = new Loader("utctiming"); singleUseLoader = new Loader("utctiming");
singleUseLoadable = new UriLoadable<>(timingElement.value, uriDataSource, parser); singleUseLoadable = new UriLoadable<>(Uri.parse(timingElement.value), dataSource, parser);
singleUseLoader.startLoading(singleUseLoadable, this); singleUseLoader.startLoading(singleUseLoadable, this);
} }
...@@ -153,8 +153,7 @@ public final class UtcTimingElementResolver implements Loader.Callback { ...@@ -153,8 +153,7 @@ public final class UtcTimingElementResolver implements Loader.Callback {
private static class XsDateTimeParser implements UriLoadable.Parser<Long> { private static class XsDateTimeParser implements UriLoadable.Parser<Long> {
@Override @Override
public Long parse(String connectionUrl, InputStream inputStream) throws ParserException, public Long parse(Uri uri, InputStream inputStream) 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);
...@@ -168,8 +167,7 @@ public final class UtcTimingElementResolver implements Loader.Callback { ...@@ -168,8 +167,7 @@ public final class UtcTimingElementResolver implements Loader.Callback {
private static class Iso8601Parser implements UriLoadable.Parser<Long> { private static class Iso8601Parser implements UriLoadable.Parser<Long> {
@Override @Override
public Long parse(String connectionUrl, InputStream inputStream) throws ParserException, public Long parse(Uri uri, InputStream inputStream) 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.
......
...@@ -21,6 +21,8 @@ import com.google.android.exoplayer.upstream.DataSourceInputStream; ...@@ -21,6 +21,8 @@ import com.google.android.exoplayer.upstream.DataSourceInputStream;
import com.google.android.exoplayer.upstream.DataSpec; import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
...@@ -105,4 +107,9 @@ import javax.crypto.spec.SecretKeySpec; ...@@ -105,4 +107,9 @@ import javax.crypto.spec.SecretKeySpec;
return bytesRead; return bytesRead;
} }
@Override
public Uri getUri() {
return upstream.getUri();
}
} }
...@@ -656,7 +656,7 @@ public class HlsChunkSource { ...@@ -656,7 +656,7 @@ public class HlsChunkSource {
DataSpec dataSpec = new DataSpec(mediaPlaylistUri, 0, C.LENGTH_UNBOUNDED, null, DataSpec dataSpec = new DataSpec(mediaPlaylistUri, 0, C.LENGTH_UNBOUNDED, null,
DataSpec.FLAG_ALLOW_GZIP); DataSpec.FLAG_ALLOW_GZIP);
return new MediaPlaylistChunk(dataSource, dataSpec, variants[variantIndex].format, scratchSpace, return new MediaPlaylistChunk(dataSource, dataSpec, variants[variantIndex].format, scratchSpace,
playlistParser, variantIndex, mediaPlaylistUri.toString()); playlistParser, variantIndex, mediaPlaylistUri);
} }
private EncryptionKeyChunk newEncryptionKeyChunk(Uri keyUri, String iv, int variantIndex) { private EncryptionKeyChunk newEncryptionKeyChunk(Uri keyUri, String iv, int variantIndex) {
...@@ -735,23 +735,23 @@ public class HlsChunkSource { ...@@ -735,23 +735,23 @@ public class HlsChunkSource {
public final int variantIndex; public final int variantIndex;
private final HlsPlaylistParser playlistParser; private final HlsPlaylistParser playlistParser;
private final String playlistUrl; private final Uri playlistUri;
private HlsMediaPlaylist result; private HlsMediaPlaylist result;
public MediaPlaylistChunk(DataSource dataSource, DataSpec dataSpec, Format format, public MediaPlaylistChunk(DataSource dataSource, DataSpec dataSpec, Format format,
byte[] scratchSpace, HlsPlaylistParser playlistParser, int variantIndex, byte[] scratchSpace, HlsPlaylistParser playlistParser, int variantIndex,
String playlistUrl) { Uri playlistUri) {
super(dataSource, dataSpec, Chunk.TYPE_MANIFEST, Chunk.TRIGGER_UNSPECIFIED, format, super(dataSource, dataSpec, Chunk.TYPE_MANIFEST, Chunk.TRIGGER_UNSPECIFIED, format,
Chunk.NO_PARENT_ID, scratchSpace); Chunk.NO_PARENT_ID, scratchSpace);
this.variantIndex = variantIndex; this.variantIndex = variantIndex;
this.playlistParser = playlistParser; this.playlistParser = playlistParser;
this.playlistUrl = playlistUrl; this.playlistUri = playlistUri;
} }
@Override @Override
protected void consume(byte[] data, int limit) throws IOException { protected void consume(byte[] data, int limit) throws IOException {
result = (HlsMediaPlaylist) playlistParser.parse(playlistUrl, result = (HlsMediaPlaylist) playlistParser.parse(playlistUri,
new ByteArrayInputStream(data, 0, limit)); new ByteArrayInputStream(data, 0, limit));
} }
......
...@@ -22,6 +22,8 @@ import com.google.android.exoplayer.hls.HlsMediaPlaylist.Segment; ...@@ -22,6 +22,8 @@ import com.google.android.exoplayer.hls.HlsMediaPlaylist.Segment;
import com.google.android.exoplayer.upstream.UriLoadable; import com.google.android.exoplayer.upstream.UriLoadable;
import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.MimeTypes;
import android.net.Uri;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
...@@ -107,8 +109,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist> ...@@ -107,8 +109,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist>
// HlsParserUtil.compileBooleanAttrPattern(DEFAULT_ATTR); // HlsParserUtil.compileBooleanAttrPattern(DEFAULT_ATTR);
@Override @Override
public HlsPlaylist parse(String connectionUrl, InputStream inputStream) public HlsPlaylist parse(Uri uri, InputStream inputStream) throws IOException, ParserException {
throws IOException, ParserException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
Queue<String> extraLines = new LinkedList<>(); Queue<String> extraLines = new LinkedList<>();
String line; String line;
...@@ -119,7 +120,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist> ...@@ -119,7 +120,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist>
// Do nothing. // Do nothing.
} else if (line.startsWith(STREAM_INF_TAG)) { } else if (line.startsWith(STREAM_INF_TAG)) {
extraLines.add(line); extraLines.add(line);
return parseMasterPlaylist(new LineIterator(extraLines, reader), connectionUrl); return parseMasterPlaylist(new LineIterator(extraLines, reader), uri.toString());
} else if (line.startsWith(TARGET_DURATION_TAG) } else if (line.startsWith(TARGET_DURATION_TAG)
|| line.startsWith(MEDIA_SEQUENCE_TAG) || line.startsWith(MEDIA_SEQUENCE_TAG)
|| line.startsWith(MEDIA_DURATION_TAG) || line.startsWith(MEDIA_DURATION_TAG)
...@@ -129,7 +130,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist> ...@@ -129,7 +130,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist>
|| line.equals(DISCONTINUITY_SEQUENCE_TAG) || line.equals(DISCONTINUITY_SEQUENCE_TAG)
|| line.equals(ENDLIST_TAG)) { || line.equals(ENDLIST_TAG)) {
extraLines.add(line); extraLines.add(line);
return parseMediaPlaylist(new LineIterator(extraLines, reader), connectionUrl); return parseMediaPlaylist(new LineIterator(extraLines, reader), uri.toString());
} else { } else {
extraLines.add(line); extraLines.add(line);
} }
......
...@@ -26,6 +26,7 @@ import com.google.android.exoplayer.util.CodecSpecificDataUtil; ...@@ -26,6 +26,7 @@ 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.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Base64; import android.util.Base64;
import android.util.Pair; import android.util.Pair;
...@@ -61,13 +62,13 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS ...@@ -61,13 +62,13 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
} }
@Override @Override
public SmoothStreamingManifest parse(String connectionUrl, InputStream inputStream) public SmoothStreamingManifest parse(Uri uri, InputStream inputStream)
throws IOException, ParserException { throws IOException, ParserException {
try { try {
XmlPullParser xmlParser = xmlParserFactory.newPullParser(); XmlPullParser xmlParser = xmlParserFactory.newPullParser();
xmlParser.setInput(inputStream, null); xmlParser.setInput(inputStream, null);
SmoothStreamMediaParser smoothStreamMediaParser = SmoothStreamMediaParser smoothStreamMediaParser =
new SmoothStreamMediaParser(null, connectionUrl); new SmoothStreamMediaParser(null, uri.toString());
return (SmoothStreamingManifest) smoothStreamMediaParser.parse(xmlParser); return (SmoothStreamingManifest) smoothStreamMediaParser.parse(xmlParser);
} catch (XmlPullParserException e) { } catch (XmlPullParserException e) {
throw new ParserException(e); throw new ParserException(e);
......
...@@ -19,15 +19,16 @@ import com.google.android.exoplayer.C; ...@@ -19,15 +19,16 @@ import com.google.android.exoplayer.C;
import android.content.Context; import android.content.Context;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.net.Uri;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/** /**
* A local asset {@link UriDataSource}. * A local asset {@link DataSource}.
*/ */
public final class AssetDataSource implements UriDataSource { public final class AssetDataSource implements DataSource {
/** /**
* Thrown when an {@link IOException} is encountered reading a local asset. * Thrown when an {@link IOException} is encountered reading a local asset.
...@@ -43,7 +44,7 @@ public final class AssetDataSource implements UriDataSource { ...@@ -43,7 +44,7 @@ public final class AssetDataSource implements UriDataSource {
private final AssetManager assetManager; private final AssetManager assetManager;
private final TransferListener listener; private final TransferListener listener;
private String uriString; private Uri uri;
private InputStream inputStream; private InputStream inputStream;
private long bytesRemaining; private long bytesRemaining;
private boolean opened; private boolean opened;
...@@ -68,14 +69,13 @@ public final class AssetDataSource implements UriDataSource { ...@@ -68,14 +69,13 @@ public final class AssetDataSource implements UriDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws AssetDataSourceException { public long open(DataSpec dataSpec) throws AssetDataSourceException {
try { try {
uriString = dataSpec.uri.toString(); uri = dataSpec.uri;
String path = dataSpec.uri.getPath(); String path = uri.getPath();
if (path.startsWith("/android_asset/")) { if (path.startsWith("/android_asset/")) {
path = path.substring(15); path = path.substring(15);
} else if (path.startsWith("/")) { } else if (path.startsWith("/")) {
path = path.substring(1); path = path.substring(1);
} }
uriString = dataSpec.uri.toString();
inputStream = assetManager.open(path, AssetManager.ACCESS_RANDOM); inputStream = assetManager.open(path, AssetManager.ACCESS_RANDOM);
long skipped = inputStream.skip(dataSpec.position); long skipped = inputStream.skip(dataSpec.position);
if (skipped < dataSpec.position) { if (skipped < dataSpec.position) {
...@@ -133,13 +133,13 @@ public final class AssetDataSource implements UriDataSource { ...@@ -133,13 +133,13 @@ public final class AssetDataSource implements UriDataSource {
} }
@Override @Override
public String getUri() { public Uri getUri() {
return uriString; return uri;
} }
@Override @Override
public void close() throws AssetDataSourceException { public void close() throws AssetDataSourceException {
uriString = null; uri = null;
if (inputStream != null) { if (inputStream != null) {
try { try {
inputStream.close(); inputStream.close();
......
...@@ -18,6 +18,8 @@ package com.google.android.exoplayer.upstream; ...@@ -18,6 +18,8 @@ package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
/** /**
...@@ -26,6 +28,8 @@ import java.io.IOException; ...@@ -26,6 +28,8 @@ import java.io.IOException;
public final class ByteArrayDataSource implements DataSource { public final class ByteArrayDataSource implements DataSource {
private final byte[] data; private final byte[] data;
private Uri uri;
private int readPosition; private int readPosition;
private int remainingBytes; private int remainingBytes;
...@@ -40,6 +44,7 @@ public final class ByteArrayDataSource implements DataSource { ...@@ -40,6 +44,7 @@ public final class ByteArrayDataSource implements DataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
uri = dataSpec.uri;
readPosition = (int) dataSpec.position; readPosition = (int) dataSpec.position;
remainingBytes = (int) ((dataSpec.length == C.LENGTH_UNBOUNDED) remainingBytes = (int) ((dataSpec.length == C.LENGTH_UNBOUNDED)
? (data.length - dataSpec.position) : dataSpec.length); ? (data.length - dataSpec.position) : dataSpec.length);
...@@ -51,11 +56,6 @@ public final class ByteArrayDataSource implements DataSource { ...@@ -51,11 +56,6 @@ public final class ByteArrayDataSource implements DataSource {
} }
@Override @Override
public void close() throws IOException {
// Do nothing.
}
@Override
public int read(byte[] buffer, int offset, int length) throws IOException { public int read(byte[] buffer, int offset, int length) throws IOException {
if (remainingBytes == 0) { if (remainingBytes == 0) {
return -1; return -1;
...@@ -66,5 +66,16 @@ public final class ByteArrayDataSource implements DataSource { ...@@ -66,5 +66,16 @@ public final class ByteArrayDataSource implements DataSource {
remainingBytes -= length; remainingBytes -= length;
return length; return length;
} }
@Override
public Uri getUri() {
return uri;
}
@Override
public void close() throws IOException {
uri = null;
}
} }
...@@ -20,6 +20,7 @@ import com.google.android.exoplayer.C; ...@@ -20,6 +20,7 @@ import com.google.android.exoplayer.C;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.res.AssetFileDescriptor; import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import java.io.EOFException; import java.io.EOFException;
import java.io.FileInputStream; import java.io.FileInputStream;
...@@ -27,9 +28,9 @@ import java.io.IOException; ...@@ -27,9 +28,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
/** /**
* A content URI {@link UriDataSource}. * A content URI {@link DataSource}.
*/ */
public final class ContentDataSource implements UriDataSource { public final class ContentDataSource implements DataSource {
/** /**
* Thrown when an {@link IOException} is encountered reading from a content URI. * Thrown when an {@link IOException} is encountered reading from a content URI.
...@@ -45,8 +46,8 @@ public final class ContentDataSource implements UriDataSource { ...@@ -45,8 +46,8 @@ public final class ContentDataSource implements UriDataSource {
private final ContentResolver resolver; private final ContentResolver resolver;
private final TransferListener listener; private final TransferListener listener;
private Uri uri;
private InputStream inputStream; private InputStream inputStream;
private String uriString;
private long bytesRemaining; private long bytesRemaining;
private boolean opened; private boolean opened;
...@@ -70,8 +71,8 @@ public final class ContentDataSource implements UriDataSource { ...@@ -70,8 +71,8 @@ public final class ContentDataSource implements UriDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws ContentDataSourceException { public long open(DataSpec dataSpec) throws ContentDataSourceException {
try { try {
uriString = dataSpec.uri.toString(); uri = dataSpec.uri;
AssetFileDescriptor assetFd = resolver.openAssetFileDescriptor(dataSpec.uri, "r"); AssetFileDescriptor assetFd = resolver.openAssetFileDescriptor(uri, "r");
inputStream = new FileInputStream(assetFd.getFileDescriptor()); inputStream = new FileInputStream(assetFd.getFileDescriptor());
long skipped = inputStream.skip(dataSpec.position); long skipped = inputStream.skip(dataSpec.position);
if (skipped < dataSpec.position) { if (skipped < dataSpec.position) {
...@@ -130,13 +131,13 @@ public final class ContentDataSource implements UriDataSource { ...@@ -130,13 +131,13 @@ public final class ContentDataSource implements UriDataSource {
} }
@Override @Override
public String getUri() { public Uri getUri() {
return uriString; return uri;
} }
@Override @Override
public void close() throws ContentDataSourceException { public void close() throws ContentDataSourceException {
uriString = null; uri = null;
if (inputStream != null) { if (inputStream != null) {
try { try {
inputStream.close(); inputStream.close();
......
...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream; ...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
/** /**
...@@ -44,16 +46,6 @@ public interface DataSource { ...@@ -44,16 +46,6 @@ public interface DataSource {
long open(DataSpec dataSpec) throws IOException; long open(DataSpec dataSpec) throws IOException;
/** /**
* Closes the {@link DataSource}.
* <p>
* Note: This method will be called even if the corresponding call to {@link #open(DataSpec)}
* threw an {@link IOException}. See {@link #open(DataSpec)} for more details.
*
* @throws IOException If an error occurs closing the source.
*/
void close() throws IOException;
/**
* Reads up to {@code length} bytes of data and stores them into {@code buffer}, starting at * Reads up to {@code length} bytes of data and stores them into {@code buffer}, starting at
* index {@code offset}. * index {@code offset}.
* <p> * <p>
...@@ -69,4 +61,25 @@ public interface DataSource { ...@@ -69,4 +61,25 @@ public interface DataSource {
*/ */
int read(byte[] buffer, int offset, int readLength) throws IOException; int read(byte[] buffer, int offset, int readLength) throws IOException;
/**
* When the source is open, returns the {@link Uri} from which data is being read.
* <p>
* The returned {@link Uri} will be identical to the one passed {@link #open(DataSpec)} in the
* {@link DataSpec} unless redirection has occurred. If redirection has occurred, the {@link Uri}
* after redirection is returned.
*
* @return When the source is open, the {@link Uri} from which data is being read. Null otherwise.
*/
Uri getUri();
/**
* Closes the {@link DataSource}.
* <p>
* Note: This method will be called even if the corresponding call to {@link #open(DataSpec)}
* threw an {@link IOException}. See {@link #open(DataSpec)} for more details.
*
* @throws IOException If an error occurs closing the source.
*/
void close() throws IOException;
} }
...@@ -19,11 +19,12 @@ import com.google.android.exoplayer.util.Assertions; ...@@ -19,11 +19,12 @@ import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
/** /**
* A {@link UriDataSource} that supports multiple URI schemes. The supported schemes are: * A {@link DataSource} that supports multiple URI schemes. The supported schemes are:
* *
* <ul> * <ul>
* <li>http(s): For fetching data over HTTP and HTTPS (e.g. https://www.something.com/media.mp4). * <li>http(s): For fetching data over HTTP and HTTPS (e.g. https://www.something.com/media.mp4).
...@@ -34,34 +35,34 @@ import java.io.IOException; ...@@ -34,34 +35,34 @@ import java.io.IOException;
* <li>content: For fetching data from a content URI (e.g. content://authority/path/123). * <li>content: For fetching data from a content URI (e.g. content://authority/path/123).
* </ul> * </ul>
*/ */
public final class DefaultUriDataSource implements UriDataSource { public final class DefaultDataSource implements DataSource {
private static final String SCHEME_ASSET = "asset"; private static final String SCHEME_ASSET = "asset";
private static final String SCHEME_CONTENT = "content"; private static final String SCHEME_CONTENT = "content";
private final UriDataSource httpDataSource; private final DataSource httpDataSource;
private final UriDataSource fileDataSource; private final DataSource fileDataSource;
private final UriDataSource assetDataSource; private final DataSource assetDataSource;
private final UriDataSource contentDataSource; private final DataSource contentDataSource;
/** /**
* {@code null} if no data source is open. Otherwise, equal to {@link #fileDataSource} if the open * {@code null} if no data source is open. Otherwise, equal to {@link #fileDataSource} if the open
* data source is a file, or {@link #httpDataSource} otherwise. * data source is a file, or {@link #httpDataSource} otherwise.
*/ */
private UriDataSource dataSource; private DataSource dataSource;
/** /**
* Constructs a new instance. * Constructs a new instance.
* <p> * <p>
* The constructed instance will not follow cross-protocol redirects (i.e. redirects from HTTP to * The constructed instance will not follow cross-protocol redirects (i.e. redirects from HTTP to
* HTTPS or vice versa) when fetching remote data. Cross-protocol redirects can be enabled by * HTTPS or vice versa) when fetching remote data. Cross-protocol redirects can be enabled by
* using {@link #DefaultUriDataSource(Context, TransferListener, String, boolean)} and passing * using {@link #DefaultDataSource(Context, TransferListener, String, boolean)} and passing
* {@code true} as the final argument. * {@code true} as the final argument.
* *
* @param context A context. * @param context A context.
* @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.
*/ */
public DefaultUriDataSource(Context context, String userAgent) { public DefaultDataSource(Context context, String userAgent) {
this(context, null, userAgent, false); this(context, null, userAgent, false);
} }
...@@ -70,14 +71,14 @@ public final class DefaultUriDataSource implements UriDataSource { ...@@ -70,14 +71,14 @@ public final class DefaultUriDataSource implements UriDataSource {
* <p> * <p>
* The constructed instance will not follow cross-protocol redirects (i.e. redirects from HTTP to * The constructed instance will not follow cross-protocol redirects (i.e. redirects from HTTP to
* HTTPS or vice versa) when fetching remote data. Cross-protocol redirects can be enabled by * HTTPS or vice versa) when fetching remote data. Cross-protocol redirects can be enabled by
* using {@link #DefaultUriDataSource(Context, TransferListener, String, boolean)} and passing * using {@link #DefaultDataSource(Context, TransferListener, String, boolean)} and passing
* {@code true} as the final argument. * {@code true} as the final argument.
* *
* @param context A context. * @param context A context.
* @param listener An optional {@link TransferListener}. * @param listener An optional {@link TransferListener}.
* @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.
*/ */
public DefaultUriDataSource(Context context, TransferListener listener, String userAgent) { public DefaultDataSource(Context context, TransferListener listener, String userAgent) {
this(context, listener, userAgent, false); this(context, listener, userAgent, false);
} }
...@@ -90,7 +91,7 @@ public final class DefaultUriDataSource implements UriDataSource { ...@@ -90,7 +91,7 @@ public final class DefaultUriDataSource implements UriDataSource {
* @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP
* to HTTPS and vice versa) are enabled when fetching remote data.. * to HTTPS and vice versa) are enabled when fetching remote data..
*/ */
public DefaultUriDataSource(Context context, TransferListener listener, String userAgent, public DefaultDataSource(Context context, TransferListener listener, String userAgent,
boolean allowCrossProtocolRedirects) { boolean allowCrossProtocolRedirects) {
this(context, listener, this(context, listener,
new DefaultHttpDataSource(userAgent, null, listener, new DefaultHttpDataSource(userAgent, null, listener,
...@@ -103,10 +104,10 @@ public final class DefaultUriDataSource implements UriDataSource { ...@@ -103,10 +104,10 @@ public final class DefaultUriDataSource implements UriDataSource {
* *
* @param context A context. * @param context A context.
* @param listener An optional {@link TransferListener}. * @param listener An optional {@link TransferListener}.
* @param httpDataSource {@link UriDataSource} to use for non-file URIs. * @param httpDataSource {@link DataSource} to use for non-file URIs.
*/ */
public DefaultUriDataSource(Context context, TransferListener listener, public DefaultDataSource(Context context, TransferListener listener,
UriDataSource httpDataSource) { DataSource httpDataSource) {
this.httpDataSource = Assertions.checkNotNull(httpDataSource); this.httpDataSource = Assertions.checkNotNull(httpDataSource);
this.fileDataSource = new FileDataSource(listener); this.fileDataSource = new FileDataSource(listener);
this.assetDataSource = new AssetDataSource(context, listener); this.assetDataSource = new AssetDataSource(context, listener);
...@@ -141,7 +142,7 @@ public final class DefaultUriDataSource implements UriDataSource { ...@@ -141,7 +142,7 @@ public final class DefaultUriDataSource implements UriDataSource {
} }
@Override @Override
public String getUri() { public Uri getUri() {
return dataSource == null ? null : dataSource.getUri(); return dataSource == null ? null : dataSource.getUri();
} }
......
...@@ -20,6 +20,7 @@ import com.google.android.exoplayer.util.Assertions; ...@@ -20,6 +20,7 @@ import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Predicate; import com.google.android.exoplayer.util.Predicate;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
...@@ -149,8 +150,8 @@ public class DefaultHttpDataSource implements HttpDataSource { ...@@ -149,8 +150,8 @@ public class DefaultHttpDataSource implements HttpDataSource {
} }
@Override @Override
public String getUri() { public Uri getUri() {
return connection == null ? null : connection.getURL().toString(); return connection == null ? null : Uri.parse(connection.getURL().toString());
} }
@Override @Override
......
...@@ -17,14 +17,16 @@ package com.google.android.exoplayer.upstream; ...@@ -17,14 +17,16 @@ package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import android.net.Uri;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
/** /**
* A local file {@link UriDataSource}. * A local file {@link DataSource}.
*/ */
public final class FileDataSource implements UriDataSource { public final class FileDataSource implements DataSource {
/** /**
* Thrown when IOException is encountered during local file read operation. * Thrown when IOException is encountered during local file read operation.
...@@ -40,7 +42,7 @@ public final class FileDataSource implements UriDataSource { ...@@ -40,7 +42,7 @@ public final class FileDataSource implements UriDataSource {
private final TransferListener listener; private final TransferListener listener;
private RandomAccessFile file; private RandomAccessFile file;
private String uriString; private Uri uri;
private long bytesRemaining; private long bytesRemaining;
private boolean opened; private boolean opened;
...@@ -63,7 +65,7 @@ public final class FileDataSource implements UriDataSource { ...@@ -63,7 +65,7 @@ public final class FileDataSource implements UriDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws FileDataSourceException { public long open(DataSpec dataSpec) throws FileDataSourceException {
try { try {
uriString = dataSpec.uri.toString(); uri = dataSpec.uri;
file = new RandomAccessFile(dataSpec.uri.getPath(), "r"); file = new RandomAccessFile(dataSpec.uri.getPath(), "r");
file.seek(dataSpec.position); file.seek(dataSpec.position);
bytesRemaining = dataSpec.length == C.LENGTH_UNBOUNDED ? file.length() - dataSpec.position bytesRemaining = dataSpec.length == C.LENGTH_UNBOUNDED ? file.length() - dataSpec.position
...@@ -107,13 +109,13 @@ public final class FileDataSource implements UriDataSource { ...@@ -107,13 +109,13 @@ public final class FileDataSource implements UriDataSource {
} }
@Override @Override
public String getUri() { public Uri getUri() {
return uriString; return uri;
} }
@Override @Override
public void close() throws FileDataSourceException { public void close() throws FileDataSourceException {
uriString = null; uri = null;
if (file != null) { if (file != null) {
try { try {
file.close(); file.close();
......
...@@ -25,9 +25,9 @@ import java.util.List; ...@@ -25,9 +25,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* An HTTP specific extension to {@link UriDataSource}. * An HTTP specific extension to {@link DataSource}.
*/ */
public interface HttpDataSource extends UriDataSource { public interface HttpDataSource extends DataSource {
/** /**
* A {@link Predicate} that rejects content types often used for pay-walls. * A {@link Predicate} that rejects content types often used for pay-walls.
......
...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream; ...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
/** /**
...@@ -51,6 +53,11 @@ public final class PriorityDataSource implements DataSource { ...@@ -51,6 +53,11 @@ public final class PriorityDataSource implements DataSource {
} }
@Override @Override
public Uri getUri() {
return upstream.getUri();
}
@Override
public void close() throws IOException { public void close() throws IOException {
upstream.close(); upstream.close();
} }
......
...@@ -18,6 +18,8 @@ package com.google.android.exoplayer.upstream; ...@@ -18,6 +18,8 @@ package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
/** /**
...@@ -60,6 +62,11 @@ public final class TeeDataSource implements DataSource { ...@@ -60,6 +62,11 @@ public final class TeeDataSource implements DataSource {
} }
@Override @Override
public Uri getUri() {
return upstream.getUri();
}
@Override
public void close() throws IOException { public void close() throws IOException {
try { try {
upstream.close(); upstream.close();
......
...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream; ...@@ -17,6 +17,8 @@ package com.google.android.exoplayer.upstream;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import android.net.Uri;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramPacket; import java.net.DatagramPacket;
import java.net.DatagramSocket; import java.net.DatagramSocket;
...@@ -27,7 +29,7 @@ import java.net.MulticastSocket; ...@@ -27,7 +29,7 @@ import java.net.MulticastSocket;
/** /**
* A UDP {@link DataSource}. * A UDP {@link DataSource}.
*/ */
public final class UdpDataSource implements UriDataSource { public final class UdpDataSource implements DataSource {
/** /**
* Thrown when an error is encountered when trying to read from a {@link UdpDataSource}. * Thrown when an error is encountered when trying to read from a {@link UdpDataSource}.
...@@ -52,7 +54,7 @@ public final class UdpDataSource implements UriDataSource { ...@@ -52,7 +54,7 @@ public final class UdpDataSource implements UriDataSource {
private final TransferListener listener; private final TransferListener listener;
private final DatagramPacket packet; private final DatagramPacket packet;
private DataSpec dataSpec; private Uri uri;
private DatagramSocket socket; private DatagramSocket socket;
private MulticastSocket multicastSocket; private MulticastSocket multicastSocket;
private InetAddress address; private InetAddress address;
...@@ -81,9 +83,9 @@ public final class UdpDataSource implements UriDataSource { ...@@ -81,9 +83,9 @@ public final class UdpDataSource implements UriDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws UdpDataSourceException { public long open(DataSpec dataSpec) throws UdpDataSourceException {
this.dataSpec = dataSpec; uri = dataSpec.uri;
String host = dataSpec.uri.getHost(); String host = uri.getHost();
int port = dataSpec.uri.getPort(); int port = uri.getPort();
try { try {
address = InetAddress.getByName(host); address = InetAddress.getByName(host);
...@@ -130,7 +132,13 @@ public final class UdpDataSource implements UriDataSource { ...@@ -130,7 +132,13 @@ public final class UdpDataSource implements UriDataSource {
} }
@Override @Override
public Uri getUri() {
return uri;
}
@Override
public void close() { public void close() {
uri = null;
if (multicastSocket != null) { if (multicastSocket != null) {
try { try {
multicastSocket.leaveGroup(address); multicastSocket.leaveGroup(address);
...@@ -154,9 +162,4 @@ public final class UdpDataSource implements UriDataSource { ...@@ -154,9 +162,4 @@ public final class UdpDataSource implements UriDataSource {
} }
} }
@Override
public String getUri() {
return dataSpec == null ? null : dataSpec.uri.toString();
}
} }
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.upstream;
/**
* A component that provides media data from a URI.
*/
public interface UriDataSource extends DataSource {
/**
* When the source is open, returns the URI from which data is being read.
* <p>
* If redirection occurred, the URI after redirection is the one returned.
*
* @return When the source is open, the URI from which data is being read. Null otherwise.
*/
String getUri();
}
...@@ -38,32 +38,32 @@ public final class UriLoadable<T> implements Loadable { ...@@ -38,32 +38,32 @@ public final class UriLoadable<T> implements Loadable {
/** /**
* Parses an object from a response. * Parses an object from a response.
* *
* @param connectionUrl The source of the response, after any redirection. * @param uri 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.
* @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) throws ParserException, IOException; T parse(Uri uri, InputStream inputStream) throws ParserException, IOException;
} }
private final DataSpec dataSpec; private final DataSpec dataSpec;
private final UriDataSource uriDataSource; private final DataSource dataSource;
private final Parser<T> parser; private final Parser<T> parser;
private volatile T result; private volatile T result;
private volatile boolean isCanceled; private volatile boolean isCanceled;
/** /**
* @param url The url from which the object should be loaded. * @param uri The {@link Uri} from which the object should be loaded.
* @param uriDataSource A {@link UriDataSource} to use when loading the data. * @param dataSource A {@link DataSource} to use when loading the data.
* @param parser Parses the object from the response. * @param parser Parses the object from the response.
*/ */
public UriLoadable(String url, UriDataSource uriDataSource, Parser<T> parser) { public UriLoadable(Uri uri, DataSource dataSource, Parser<T> parser) {
this.uriDataSource = uriDataSource; this.dataSource = dataSource;
this.parser = parser; this.parser = parser;
dataSpec = new DataSpec(Uri.parse(url), DataSpec.FLAG_ALLOW_GZIP); dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP);
} }
/** /**
...@@ -87,10 +87,10 @@ public final class UriLoadable<T> implements Loadable { ...@@ -87,10 +87,10 @@ public final class UriLoadable<T> implements Loadable {
@Override @Override
public final void load() throws IOException, InterruptedException { public final void load() throws IOException, InterruptedException {
DataSourceInputStream inputStream = new DataSourceInputStream(uriDataSource, dataSpec); DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try { try {
inputStream.open(); inputStream.open();
result = parser.parse(uriDataSource.getUri(), inputStream); result = parser.parse(dataSource.getUri(), inputStream);
} finally { } finally {
inputStream.close(); inputStream.close();
} }
......
...@@ -167,7 +167,13 @@ public final class CacheDataSource implements DataSource { ...@@ -167,7 +167,13 @@ public final class CacheDataSource implements DataSource {
} }
@Override @Override
public Uri getUri() {
return currentDataSource == upstreamDataSource ? currentDataSource.getUri() : uri;
}
@Override
public void close() throws IOException { public void close() throws IOException {
uri = null;
notifyBytesRead(); notifyBytesRead();
try { try {
closeCurrentSource(); closeCurrentSource();
......
...@@ -15,14 +15,14 @@ ...@@ -15,14 +15,14 @@
*/ */
package com.google.android.exoplayer.util; package com.google.android.exoplayer.util;
import com.google.android.exoplayer.upstream.DataSource;
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.UriDataSource;
import com.google.android.exoplayer.upstream.UriLoadable; import com.google.android.exoplayer.upstream.UriLoadable;
import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.SystemClock; import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import java.io.IOException; import java.io.IOException;
...@@ -62,19 +62,19 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -62,19 +62,19 @@ public class ManifestFetcher<T> implements Loader.Callback {
public interface RedirectingManifest { public interface RedirectingManifest {
/** /**
* Returns the URI from which subsequent manifests should be requested, or null to continue * Returns the {@link Uri} from which subsequent manifests should be requested, or null to
* using the current URI. * continue using the current {@link Uri}.
*/ */
public String getNextManifestUri(); public Uri getNextManifestUri();
} }
private final UriLoadable.Parser<T> parser; private final UriLoadable.Parser<T> parser;
private final UriDataSource uriDataSource; private final DataSource dataSource;
private final Handler eventHandler; private final Handler eventHandler;
private final EventListener eventListener; private final EventListener eventListener;
/* package */ volatile String manifestUri; private volatile Uri manifestUri;
private int enabledCount; private int enabledCount;
private Loader loader; private Loader loader;
...@@ -90,38 +90,37 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -90,38 +90,37 @@ public class ManifestFetcher<T> implements Loader.Callback {
private volatile long manifestLoadCompleteTimestamp; private volatile long manifestLoadCompleteTimestamp;
/** /**
* @param manifestUri The manifest location. * @param manifestUri The manifest {@link Uri}.
* @param uriDataSource The {@link UriDataSource} to use when loading the manifest. * @param dataSource The {@link DataSource} 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 manifestUri, UriDataSource uriDataSource, public ManifestFetcher(Uri manifestUri, DataSource dataSource, UriLoadable.Parser<T> parser) {
UriLoadable.Parser<T> parser) { this(manifestUri, dataSource, parser, null, null);
this(manifestUri, uriDataSource, parser, null, null);
} }
/** /**
* @param manifestUri The manifest location. * @param manifestUri The manifest {@link Uri}.
* @param uriDataSource The {@link UriDataSource} to use when loading the manifest. * @param dataSource The {@link DataSource} 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 manifestUri, UriDataSource uriDataSource, public ManifestFetcher(Uri manifestUri, DataSource dataSource, UriLoadable.Parser<T> parser,
UriLoadable.Parser<T> parser, Handler eventHandler, EventListener eventListener) { Handler eventHandler, EventListener eventListener) {
this.parser = parser; this.parser = parser;
this.manifestUri = manifestUri; this.manifestUri = manifestUri;
this.uriDataSource = uriDataSource; this.dataSource = dataSource;
this.eventHandler = eventHandler; this.eventHandler = eventHandler;
this.eventListener = eventListener; this.eventListener = eventListener;
} }
/** /**
* Updates the manifest location. * Updates the manifest {@link Uri}.
* *
* @param manifestUri The manifest location. * @param manifestUri The manifest {@link Uri}.
*/ */
public void updateManifestUri(String manifestUri) { public void updateManifestUri(Uri manifestUri) {
this.manifestUri = manifestUri; this.manifestUri = manifestUri;
} }
...@@ -205,7 +204,7 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -205,7 +204,7 @@ public class ManifestFetcher<T> implements Loader.Callback {
loader = new Loader("manifestLoader"); loader = new Loader("manifestLoader");
} }
if (!loader.isLoading()) { if (!loader.isLoading()) {
currentLoadable = new UriLoadable<>(manifestUri, uriDataSource, parser); currentLoadable = new UriLoadable<>(manifestUri, dataSource, parser);
currentLoadStartTimestamp = SystemClock.elapsedRealtime(); currentLoadStartTimestamp = SystemClock.elapsedRealtime();
loader.startLoading(currentLoadable, this); loader.startLoading(currentLoadable, this);
notifyManifestRefreshStarted(); notifyManifestRefreshStarted();
...@@ -227,9 +226,9 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -227,9 +226,9 @@ public class ManifestFetcher<T> implements Loader.Callback {
if (manifest instanceof RedirectingManifest) { if (manifest instanceof RedirectingManifest) {
RedirectingManifest redirectingManifest = (RedirectingManifest) manifest; RedirectingManifest redirectingManifest = (RedirectingManifest) manifest;
String nextLocation = redirectingManifest.getNextManifestUri(); Uri nextUri = redirectingManifest.getNextManifestUri();
if (!TextUtils.isEmpty(nextLocation)) { if (nextUri != null) {
manifestUri = nextLocation; manifestUri = nextUri;
} }
} }
...@@ -255,12 +254,6 @@ public class ManifestFetcher<T> implements Loader.Callback { ...@@ -255,12 +254,6 @@ public class ManifestFetcher<T> implements Loader.Callback {
notifyManifestError(loadException); notifyManifestError(loadException);
} }
/* package */ void onSingleFetchCompleted(T result, long loadStartTimestamp) {
manifest = result;
manifestLoadStartTimestamp = loadStartTimestamp;
manifestLoadCompleteTimestamp = SystemClock.elapsedRealtime();
}
private long getRetryDelayMillis(long errorCount) { private long getRetryDelayMillis(long errorCount) {
return Math.min((errorCount - 1) * 1000, 5000); return Math.min((errorCount - 1) * 1000, 5000);
} }
......
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