Commit 175a0100 by olly Committed by Oliver Woodman

Remove ability to query Downloader implementations

This was adding a lot of code, and the multiple use cases
for Downloader was pretty confusing (in particular the
ordering of method calls was unclear). It's also not
performant (e.g. it requires loading/parsing manifest(s)
and initialization segments from disk).

In practice I think apps will need to keep a record of
what's offlined in their app's database (or equivalent),
which they can update by registering as a listener on
DownloadManager. This will be done for the demo app in
a subsequent change.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=194932876
parent d4f75963
Showing with 196 additions and 388 deletions
......@@ -24,15 +24,6 @@ import java.io.IOException;
public interface Downloader {
/**
* Initializes the downloader.
*
* @throws DownloadException Thrown if the media cannot be downloaded.
* @throws InterruptedException If the thread has been interrupted.
* @throws IOException Thrown when there is an io error while reading from cache.
*/
void init() throws InterruptedException, IOException;
/**
* Downloads the media.
*
* @throws DownloadException Thrown if the media cannot be downloaded.
......@@ -41,13 +32,6 @@ public interface Downloader {
*/
void download() throws InterruptedException, IOException;
/**
* Removes all of the downloaded data of the media.
*
* @throws InterruptedException Thrown if the thread was interrupted.
*/
void remove() throws InterruptedException;
/** Returns the total number of downloaded bytes. */
long getDownloadedBytes();
......@@ -56,4 +40,11 @@ public interface Downloader {
* available.
*/
float getDownloadPercentage();
/**
* Removes the media.
*
* @throws InterruptedException Thrown if the thread was interrupted.
*/
void remove() throws InterruptedException;
}
......@@ -54,28 +54,24 @@ public final class ProgressiveDownloader implements Downloader {
}
@Override
public void init() {
CacheUtil.getCached(dataSpec, cache, cachingCounters);
}
@Override
public void download() throws InterruptedException, IOException {
priorityTaskManager.add(C.PRIORITY_DOWNLOAD);
try {
byte[] buffer = new byte[BUFFER_SIZE_BYTES];
CacheUtil.cache(dataSpec, cache, dataSource, buffer, priorityTaskManager, C.PRIORITY_DOWNLOAD,
cachingCounters, true);
CacheUtil.cache(
dataSpec,
cache,
dataSource,
new byte[BUFFER_SIZE_BYTES],
priorityTaskManager,
C.PRIORITY_DOWNLOAD,
cachingCounters,
/* enableEOFException= */ true);
} finally {
priorityTaskManager.remove(C.PRIORITY_DOWNLOAD);
}
}
@Override
public void remove() {
CacheUtil.remove(cache, CacheUtil.getKey(dataSpec));
}
@Override
public long getDownloadedBytes() {
return cachingCounters.totalCachedBytes();
}
......@@ -88,4 +84,8 @@ public final class ProgressiveDownloader implements Downloader {
: ((cachingCounters.totalCachedBytes() * 100f) / contentLength);
}
@Override
public void remove() {
CacheUtil.remove(cache, CacheUtil.getKey(dataSpec));
}
}
......@@ -49,6 +49,22 @@ public final class ParsingLoadable<T> implements Loadable {
}
/**
* Loads a single parsable object.
*
* @param dataSource The {@link DataSource} through which the object should be read.
* @param uri The {@link Uri} of the object to read.
* @return The parsed object
* @throws IOException Thrown if there is an error while loading or parsing.
*/
public static <T> T load(DataSource dataSource, Parser<? extends T> parser, Uri uri)
throws IOException {
ParsingLoadable<T> loadable =
new ParsingLoadable<>(dataSource, uri, C.DATA_TYPE_UNKNOWN, parser);
loadable.load();
return loadable.getResult();
}
/**
* The {@link DataSpec} that defines the data to be loaded.
*/
public final DataSpec dataSpec;
......
......@@ -663,11 +663,6 @@ public class DownloadManagerTest {
}
@Override
public void init() throws InterruptedException, IOException {
// do nothing.
}
@Override
public void download() throws InterruptedException, IOException {
assertThat(isRemoveAction).isFalse();
started.countDown();
......
......@@ -53,10 +53,7 @@ public final class DashUtil {
*/
public static DashManifest loadManifest(DataSource dataSource, Uri uri)
throws IOException {
ParsingLoadable<DashManifest> loadable =
new ParsingLoadable<>(dataSource, uri, C.DATA_TYPE_MANIFEST, new DashManifestParser());
loadable.load();
return loadable.getResult();
return ParsingLoadable.load(dataSource, new DashManifestParser(), uri);
}
/**
......
......@@ -60,9 +60,7 @@ public final class DashDownloadAction extends SegmentDownloadAction<Representati
@Override
protected DashDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
DashDownloader downloader = new DashDownloader(manifestUri, constructorHelper);
downloader.selectRepresentations(keys);
return downloader;
return new DashDownloader(manifestUri, constructorHelper, keys);
}
@Override
......
......@@ -16,7 +16,7 @@
package com.google.android.exoplayer2.source.dash.offline;
import android.net.Uri;
import android.util.Pair;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.ChunkIndex;
import com.google.android.exoplayer2.offline.DownloadException;
......@@ -38,7 +38,7 @@ import java.util.ArrayList;
import java.util.List;
/**
* Helper class to download DASH streams.
* A downloader for DASH streams.
*
* <p>Example usage:
*
......@@ -47,9 +47,11 @@ import java.util.List;
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
* DashDownloader dashDownloader = new DashDownloader(manifestUrl, constructorHelper);
* // Select the first representation of the first adaptation set of the first period
* dashDownloader.selectRepresentations(new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
* // Create a downloader for the first representation of the first adaptation set of the first
* // period.
* DashDownloader dashDownloader = new DashDownloader(
* manifestUrl, constructorHelper, new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
* // Perform the download.
* dashDownloader.download();
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
......@@ -58,27 +60,12 @@ import java.util.List;
*/
public final class DashDownloader extends SegmentDownloader<DashManifest, RepresentationKey> {
/**
* @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper)
*/
public DashDownloader(Uri manifestUri, DownloaderConstructorHelper constructorHelper) {
super(manifestUri, constructorHelper);
}
@Override
public RepresentationKey[] getAllRepresentationKeys() throws IOException {
ArrayList<RepresentationKey> keys = new ArrayList<>();
DashManifest manifest = getManifest();
for (int periodIndex = 0; periodIndex < manifest.getPeriodCount(); periodIndex++) {
List<AdaptationSet> adaptationSets = manifest.getPeriod(periodIndex).adaptationSets;
for (int adaptationIndex = 0; adaptationIndex < adaptationSets.size(); adaptationIndex++) {
int representationsCount = adaptationSets.get(adaptationIndex).representations.size();
for (int i = 0; i < representationsCount; i++) {
keys.add(new RepresentationKey(periodIndex, adaptationIndex, i));
}
}
}
return keys.toArray(new RepresentationKey[keys.size()]);
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, Object[]) */
public DashDownloader(
Uri manifestUri,
DownloaderConstructorHelper constructorHelper,
@Nullable RepresentationKey[] trackKeys) {
super(manifestUri, constructorHelper, trackKeys);
}
@Override
......@@ -87,40 +74,36 @@ public final class DashDownloader extends SegmentDownloader<DashManifest, Repres
}
@Override
protected Pair<List<Segment>, Boolean> getSegments(
DataSource dataSource, DashManifest manifest, boolean allowIndexLoadErrors)
protected List<Segment> getSegments(
DataSource dataSource, DashManifest manifest, boolean allowIncompleteList)
throws InterruptedException, IOException {
ArrayList<Segment> segments = new ArrayList<>();
boolean segmentListComplete = true;
for (int i = 0; i < manifest.getPeriodCount(); i++) {
Period period = manifest.getPeriod(i);
long periodStartUs = C.msToUs(period.startMs);
long periodDurationUs = manifest.getPeriodDurationUs(i);
List<AdaptationSet> adaptationSets = period.adaptationSets;
for (int j = 0; j < adaptationSets.size(); j++) {
if (!addSegmentsForAdaptationSet(
addSegmentsForAdaptationSet(
dataSource,
adaptationSets.get(j),
periodStartUs,
periodDurationUs,
allowIndexLoadErrors,
segments)) {
segmentListComplete = false;
}
allowIncompleteList,
segments);
}
}
return Pair.<List<Segment>, Boolean>create(segments, segmentListComplete);
return segments;
}
private static boolean addSegmentsForAdaptationSet(
private static void addSegmentsForAdaptationSet(
DataSource dataSource,
AdaptationSet adaptationSet,
long periodStartUs,
long periodDurationUs,
boolean allowIndexLoadErrors,
boolean allowIncompleteList,
ArrayList<Segment> out)
throws IOException, InterruptedException {
boolean segmentListComplete = true;
for (int i = 0; i < adaptationSet.representations.size(); i++) {
Representation representation = adaptationSet.representations.get(i);
DashSegmentIndex index;
......@@ -131,11 +114,11 @@ public final class DashDownloader extends SegmentDownloader<DashManifest, Repres
throw new DownloadException("Missing segment index");
}
} catch (IOException e) {
if (!allowIndexLoadErrors) {
if (!allowIncompleteList) {
throw e;
}
// Loading failed, but load errors are allowed. Advance to the next representation.
segmentListComplete = false;
// Loading failed, but generating an incomplete segment list is allowed. Advance to the next
// representation.
continue;
}
......@@ -159,8 +142,6 @@ public final class DashDownloader extends SegmentDownloader<DashManifest, Repres
addSegment(periodStartUs + index.getTimeUs(j), baseUrl, index.getSegmentUrl(j), out);
}
}
return segmentListComplete;
}
private static void addSegment(
......
......@@ -60,9 +60,7 @@ public final class HlsDownloadAction extends SegmentDownloadAction<RenditionKey>
@Override
protected HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
HlsDownloader downloader = new HlsDownloader(manifestUri, constructorHelper);
downloader.selectRepresentations(keys);
return downloader;
return new HlsDownloader(manifestUri, constructorHelper, keys);
}
@Override
......
......@@ -16,7 +16,6 @@
package com.google.android.exoplayer2.source.hls.offline;
import android.net.Uri;
import android.util.Pair;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.SegmentDownloader;
......@@ -35,29 +34,13 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
/**
* Helper class to download HLS streams.
*
* <p>A subset of renditions can be downloaded by selecting them using {@link
* #selectRepresentations(Object[])}.
*/
/** A downloader for HLS streams. */
public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, RenditionKey> {
/**
* @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper)
*/
public HlsDownloader(Uri manifestUri, DownloaderConstructorHelper constructorHelper) {
super(manifestUri, constructorHelper);
}
@Override
public RenditionKey[] getAllRepresentationKeys() throws IOException {
ArrayList<RenditionKey> renditionKeys = new ArrayList<>();
HlsMasterPlaylist manifest = getManifest();
extractUrls(manifest.variants, renditionKeys);
extractUrls(manifest.audios, renditionKeys);
extractUrls(manifest.subtitles, renditionKeys);
return renditionKeys.toArray(new RenditionKey[renditionKeys.size()]);
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, Object[]) */
public HlsDownloader(
Uri manifestUri, DownloaderConstructorHelper constructorHelper, RenditionKey[] trackKeys) {
super(manifestUri, constructorHelper, trackKeys);
}
@Override
......@@ -71,8 +54,8 @@ public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, Re
}
@Override
protected Pair<List<Segment>, Boolean> getSegments(
DataSource dataSource, HlsMasterPlaylist manifest, boolean allowIndexLoadErrors)
protected List<Segment> getSegments(
DataSource dataSource, HlsMasterPlaylist manifest, boolean allowIncompleteList)
throws IOException {
HashSet<Uri> encryptionKeyUris = new HashSet<>();
ArrayList<HlsUrl> renditionUrls = new ArrayList<>();
......@@ -81,17 +64,15 @@ public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, Re
renditionUrls.addAll(manifest.subtitles);
ArrayList<Segment> segments = new ArrayList<>();
boolean segmentListComplete = true;
for (HlsUrl renditionUrl : renditionUrls) {
HlsMediaPlaylist mediaPlaylist = null;
Uri uri = UriUtil.resolveToUri(manifest.baseUri, renditionUrl.url);
try {
mediaPlaylist = (HlsMediaPlaylist) loadManifest(dataSource, uri);
} catch (IOException e) {
if (!allowIndexLoadErrors) {
if (!allowIncompleteList) {
throw e;
}
segmentListComplete = false;
}
segments.add(new Segment(mediaPlaylist != null ? mediaPlaylist.startTimeUs : Long.MIN_VALUE,
new DataSpec(uri)));
......@@ -111,7 +92,7 @@ public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, Re
addSegment(segments, mediaPlaylist, segment, encryptionKeyUris);
}
}
return Pair.<List<Segment>, Boolean>create(segments, segmentListComplete);
return segments;
}
private static HlsPlaylist loadManifest(DataSource dataSource, Uri uri) throws IOException {
......@@ -139,10 +120,4 @@ public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, Re
new DataSpec(resolvedUri, hlsSegment.byterangeOffset, hlsSegment.byterangeLength, null)));
}
private static void extractUrls(List<HlsUrl> hlsUrls, ArrayList<RenditionKey> renditionKeys) {
for (int i = 0; i < hlsUrls.size(); i++) {
renditionKeys.add(new RenditionKey(hlsUrls.get(i).url));
}
}
}
......@@ -33,8 +33,8 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
import com.google.android.exoplayer2.source.hls.playlist.RenditionKey;
import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource.Factory;
......@@ -56,7 +56,6 @@ public class HlsDownloaderTest {
private SimpleCache cache;
private File tempFolder;
private FakeDataSet fakeDataSet;
private HlsDownloader hlsDownloader;
@Before
public void setUp() throws Exception {
......@@ -74,7 +73,6 @@ public class HlsDownloaderTest {
.setRandomData(MEDIA_PLAYLIST_2_DIR + "fileSequence0.ts", 13)
.setRandomData(MEDIA_PLAYLIST_2_DIR + "fileSequence1.ts", 14)
.setRandomData(MEDIA_PLAYLIST_2_DIR + "fileSequence2.ts", 15);
hlsDownloader = getHlsDownloader(MASTER_PLAYLIST_URI);
}
@After
......@@ -83,55 +81,18 @@ public class HlsDownloaderTest {
}
@Test
public void testDownloadManifest() throws Exception {
HlsMasterPlaylist manifest = hlsDownloader.getManifest();
assertThat(manifest).isNotNull();
assertCachedData(cache, fakeDataSet, MASTER_PLAYLIST_URI);
}
@Test
public void testSelectRepresentationsClearsPreviousSelection() throws Exception {
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI));
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_2_URI));
hlsDownloader.download();
assertCachedData(
cache,
fakeDataSet,
MASTER_PLAYLIST_URI,
MEDIA_PLAYLIST_2_URI,
MEDIA_PLAYLIST_2_DIR + "fileSequence0.ts",
MEDIA_PLAYLIST_2_DIR + "fileSequence1.ts",
MEDIA_PLAYLIST_2_DIR + "fileSequence2.ts");
}
@Test
public void testCounterMethods() throws Exception {
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI));
hlsDownloader.download();
HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, getKeys(MEDIA_PLAYLIST_1_URI));
downloader.download();
assertThat(hlsDownloader.getDownloadedBytes())
.isEqualTo(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12);
}
@Test
public void testInitStatus() throws Exception {
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI));
hlsDownloader.download();
HlsDownloader newHlsDownloader = getHlsDownloader(MASTER_PLAYLIST_URI);
newHlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI));
newHlsDownloader.init();
assertThat(newHlsDownloader.getDownloadedBytes())
assertThat(downloader.getDownloadedBytes())
.isEqualTo(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12);
}
@Test
public void testDownloadRepresentation() throws Exception {
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI));
hlsDownloader.download();
HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, getKeys(MEDIA_PLAYLIST_1_URI));
downloader.download();
assertCachedData(
cache,
......@@ -145,8 +106,9 @@ public class HlsDownloaderTest {
@Test
public void testDownloadMultipleRepresentations() throws Exception {
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_2_URI));
hlsDownloader.download();
HlsDownloader downloader =
getHlsDownloader(MASTER_PLAYLIST_URI, getKeys(MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_2_URI));
downloader.download();
assertCachedData(cache, fakeDataSet);
}
......@@ -163,36 +125,28 @@ public class HlsDownloaderTest {
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence0.ts", 13)
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence1.ts", 14)
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence2.ts", 15);
hlsDownloader = getHlsDownloader(MASTER_PLAYLIST_URI);
// hlsDownloader.selectRepresentations() isn't called
hlsDownloader.download();
assertCachedData(cache, fakeDataSet);
hlsDownloader.remove();
HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, null);
downloader.download();
// select something random
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI));
// clear selection
hlsDownloader.selectRepresentations(getKeys());
hlsDownloader.download();
assertCachedData(cache, fakeDataSet);
hlsDownloader.remove();
}
@Test
public void testRemoveAll() throws Exception {
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_2_URI));
hlsDownloader.download();
hlsDownloader.remove();
public void testRemove() throws Exception {
HlsDownloader downloader =
getHlsDownloader(MASTER_PLAYLIST_URI, getKeys(MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_2_URI));
downloader.download();
downloader.remove();
assertCacheEmpty(cache);
}
@Test
public void testDownloadMediaPlaylist() throws Exception {
hlsDownloader = getHlsDownloader(MEDIA_PLAYLIST_1_URI);
hlsDownloader.selectRepresentations(getKeys(MEDIA_PLAYLIST_1_URI));
hlsDownloader.download();
HlsDownloader downloader =
getHlsDownloader(MEDIA_PLAYLIST_1_URI, getKeys(MEDIA_PLAYLIST_1_URI));
downloader.download();
assertCachedData(
cache,
......@@ -213,17 +167,17 @@ public class HlsDownloaderTest {
.setRandomData("fileSequence0.ts", 10)
.setRandomData("fileSequence1.ts", 11)
.setRandomData("fileSequence2.ts", 12);
hlsDownloader = getHlsDownloader(ENC_MEDIA_PLAYLIST_URI);
hlsDownloader.selectRepresentations(getKeys(ENC_MEDIA_PLAYLIST_URI));
hlsDownloader.download();
HlsDownloader downloader =
getHlsDownloader(ENC_MEDIA_PLAYLIST_URI, getKeys(ENC_MEDIA_PLAYLIST_URI));
downloader.download();
assertCachedData(cache, fakeDataSet);
}
private HlsDownloader getHlsDownloader(String mediaPlaylistUri) {
private HlsDownloader getHlsDownloader(String mediaPlaylistUri, @Nullable RenditionKey[] keys) {
Factory factory = new Factory(null).setFakeDataSet(fakeDataSet);
return new HlsDownloader(
Uri.parse(mediaPlaylistUri), new DownloaderConstructorHelper(cache, factory));
Uri.parse(mediaPlaylistUri), new DownloaderConstructorHelper(cache, factory), keys);
}
private static RenditionKey[] getKeys(String... urls) {
......
......@@ -60,9 +60,7 @@ public final class SsDownloadAction extends SegmentDownloadAction<TrackKey> {
@Override
protected SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
SsDownloader downloader = new SsDownloader(manifestUri, constructorHelper);
downloader.selectRepresentations(keys);
return downloader;
return new SsDownloader(manifestUri, constructorHelper, keys);
}
@Override
......
......@@ -16,7 +16,6 @@
package com.google.android.exoplayer2.source.smoothstreaming.offline;
import android.net.Uri;
import android.util.Pair;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.SegmentDownloader;
......@@ -33,7 +32,7 @@ import java.util.ArrayList;
import java.util.List;
/**
* Helper class to download SmoothStreaming streams.
* A downloader for SmoothStreaming streams.
*
* <p>Example usage:
*
......@@ -42,9 +41,10 @@ import java.util.List;
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
* SsDownloader ssDownloader = new SsDownloader(manifestUrl, constructorHelper);
* // Select the first track of the first stream element
* ssDownloader.selectRepresentations(new TrackKey[] {new TrackKey(0, 0)});
* // Create a downloader for the first track of the first stream element.
* SsDownloader ssDownloader = new SsDownloader(
* manifestUrl, constructorHelper, new TrackKey[] {new TrackKey(0, 0)});
* // Perform the download.
* ssDownloader.download();
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
......@@ -53,24 +53,10 @@ import java.util.List;
*/
public final class SsDownloader extends SegmentDownloader<SsManifest, TrackKey> {
/**
* @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper)
*/
public SsDownloader(Uri manifestUri, DownloaderConstructorHelper constructorHelper) {
super(SsUtil.fixManifestUri(manifestUri), constructorHelper);
}
@Override
public TrackKey[] getAllRepresentationKeys() throws IOException {
ArrayList<TrackKey> keys = new ArrayList<>();
SsManifest manifest = getManifest();
for (int i = 0; i < manifest.streamElements.length; i++) {
StreamElement streamElement = manifest.streamElements[i];
for (int j = 0; j < streamElement.formats.length; j++) {
keys.add(new TrackKey(i, j));
}
}
return keys.toArray(new TrackKey[keys.size()]);
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, Object[]) */
public SsDownloader(
Uri manifestUri, DownloaderConstructorHelper constructorHelper, TrackKey[] trackKeys) {
super(SsUtil.fixManifestUri(manifestUri), constructorHelper, trackKeys);
}
@Override
......@@ -82,8 +68,8 @@ public final class SsDownloader extends SegmentDownloader<SsManifest, TrackKey>
}
@Override
protected Pair<List<Segment>, Boolean> getSegments(
DataSource dataSource, SsManifest manifest, boolean allowIndexLoadErrors) throws IOException {
protected List<Segment> getSegments(
DataSource dataSource, SsManifest manifest, boolean allowIncompleteList) throws IOException {
ArrayList<Segment> segments = new ArrayList<>();
for (StreamElement streamElement : manifest.streamElements) {
for (int i = 0; i < streamElement.formats.length; i++) {
......@@ -95,7 +81,7 @@ public final class SsDownloader extends SegmentDownloader<SsManifest, TrackKey>
}
}
}
return Pair.<List<Segment>, Boolean>create(segments, true);
return segments;
}
}
......@@ -15,12 +15,12 @@
*/
package com.google.android.exoplayer2.playbacktests.gts;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.source.dash.DashUtil;
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.Representation;
......@@ -35,8 +35,6 @@ import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.ArrayList;
import java.util.List;
......@@ -47,9 +45,13 @@ public final class DashDownloadTest extends ActivityInstrumentationTestCase2<Hos
private static final String TAG = "DashDownloadTest";
private static final Uri MANIFEST_URI = Uri.parse(DashTestData.H264_MANIFEST);
private DashTestRunner testRunner;
private File tempFolder;
private SimpleCache cache;
private DefaultHttpDataSourceFactory httpDataSourceFactory;
private CacheDataSourceFactory offlineDataSourceFactory;
public DashDownloadTest() {
super(HostActivity.class);
......@@ -66,6 +68,10 @@ public final class DashDownloadTest extends ActivityInstrumentationTestCase2<Hos
DashTestData.H264_CDD_FIXED);
tempFolder = Util.createTempDirectory(getActivity(), "ExoPlayerTest");
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
httpDataSourceFactory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
offlineDataSourceFactory =
new CacheDataSourceFactory(
cache, DummyDataSource.FACTORY, CacheDataSource.FLAG_BLOCK_ON_CACHE);
}
@Override
......@@ -83,17 +89,13 @@ public final class DashDownloadTest extends ActivityInstrumentationTestCase2<Hos
return; // Pass.
}
// Download manifest only
createDashDownloader().getManifest();
long manifestLength = cache.getCacheSpace();
// Download representations
DashDownloader dashDownloader = downloadContent();
assertThat(dashDownloader.getDownloadedBytes())
.isEqualTo(cache.getCacheSpace() - manifestLength);
dashDownloader.download();
testRunner.setStreamName("test_h264_fixed_download").
setDataSourceFactory(newOfflineCacheDataSourceFactory()).run();
testRunner
.setStreamName("test_h264_fixed_download")
.setDataSourceFactory(offlineDataSourceFactory)
.run();
dashDownloader.remove();
......@@ -102,50 +104,27 @@ public final class DashDownloadTest extends ActivityInstrumentationTestCase2<Hos
}
private DashDownloader downloadContent() throws Exception {
DashDownloader dashDownloader = createDashDownloader();
DashManifest dashManifest = dashDownloader.getManifest();
try {
ArrayList<RepresentationKey> keys = new ArrayList<>();
for (int pIndex = 0; pIndex < dashManifest.getPeriodCount(); pIndex++) {
List<AdaptationSet> adaptationSets = dashManifest.getPeriod(pIndex).adaptationSets;
for (int aIndex = 0; aIndex < adaptationSets.size(); aIndex++) {
AdaptationSet adaptationSet = adaptationSets.get(aIndex);
List<Representation> representations = adaptationSet.representations;
for (int rIndex = 0; rIndex < representations.size(); rIndex++) {
String id = representations.get(rIndex).format.id;
if (DashTestData.AAC_AUDIO_REPRESENTATION_ID.equals(id)
|| DashTestData.H264_CDD_FIXED.equals(id)) {
keys.add(new RepresentationKey(pIndex, aIndex, rIndex));
}
DashManifest dashManifest =
DashUtil.loadManifest(httpDataSourceFactory.createDataSource(), MANIFEST_URI);
ArrayList<RepresentationKey> keys = new ArrayList<>();
for (int pIndex = 0; pIndex < dashManifest.getPeriodCount(); pIndex++) {
List<AdaptationSet> adaptationSets = dashManifest.getPeriod(pIndex).adaptationSets;
for (int aIndex = 0; aIndex < adaptationSets.size(); aIndex++) {
AdaptationSet adaptationSet = adaptationSets.get(aIndex);
List<Representation> representations = adaptationSet.representations;
for (int rIndex = 0; rIndex < representations.size(); rIndex++) {
String id = representations.get(rIndex).format.id;
if (DashTestData.AAC_AUDIO_REPRESENTATION_ID.equals(id)
|| DashTestData.H264_CDD_FIXED.equals(id)) {
keys.add(new RepresentationKey(pIndex, aIndex, rIndex));
}
}
dashDownloader.selectRepresentations(keys.toArray(new RepresentationKey[keys.size()]));
dashDownloader.download();
}
} catch (InterruptedException e) {
// do nothing
} catch (IOException e) {
Throwable exception = e;
while (!(exception instanceof InterruptedIOException)) {
if (exception == null) {
throw e;
}
exception = exception.getCause();
}
// else do nothing
}
return dashDownloader;
}
private DashDownloader createDashDownloader() {
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(cache, new DefaultHttpDataSourceFactory("ExoPlayer", null));
return new DashDownloader(Uri.parse(DashTestData.H264_MANIFEST), constructorHelper);
}
private CacheDataSourceFactory newOfflineCacheDataSourceFactory() {
return new CacheDataSourceFactory(cache, DummyDataSource.FACTORY,
CacheDataSource.FLAG_BLOCK_ON_CACHE);
new DownloaderConstructorHelper(cache, httpDataSourceFactory);
return new DashDownloader(
MANIFEST_URI, constructorHelper, keys.toArray(new RepresentationKey[keys.size()]));
}
}
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