Remove DownloadConstructorHelper

Something that helps a constructor always seemed a bit strange.
It's now possible to use CacheDataSource.Factory directly instead.

PiperOrigin-RevId: 307661930
This commit is contained in:
olly 2020-04-21 20:48:04 +01:00 committed by Ian Baker
parent 722a5b2279
commit 4abaaf138c
19 changed files with 198 additions and 266 deletions

View file

@ -60,8 +60,6 @@
`DecoderVideoRenderer` and `DecoderAudioRenderer` respectively, and
generalized to work with `Decoder` rather than `SimpleDecoder`.
* Add media item based playlist API to Player.
* Update `CachedContentIndex` to use `SecureRandom` for generating the
initialization vector used to encrypt the cache contents.
* Remove deprecated members in `DefaultTrackSelector`.
* Add `Player.DeviceComponent` and implement it for `SimpleExoPlayer` so
that the device volume can be controlled by player.
@ -108,8 +106,15 @@
`OfflineLicenseHelper`
([#7078](https://github.com/google/ExoPlayer/issues/7078)).
* Remove generics from DRM components.
* Downloads: Merge downloads in `SegmentDownloader` to improve overall
download speed ([#5978](https://github.com/google/ExoPlayer/issues/5978)).
* Downloads and caching:
* Merge downloads in `SegmentDownloader` to improve overall download
speed ([#5978](https://github.com/google/ExoPlayer/issues/5978)).
* Replace `CacheDataSinkFactory` and `CacheDataSourceFactory` with
`CacheDataSink.Factory` and `CacheDataSource.Factory` respectively.
* Remove `DownloadConstructorHelper` and use `CacheDataSource.Factory`
directly instead.
* Update `CachedContentIndex` to use `SecureRandom` for generating the
initialization vector used to encrypt the cache contents.
* DASH:
* Merge trick play adaptation sets (i.e., adaptation sets marked with
`http://dashif.org/guidelines/trickmode`) into the same `TrackGroup` as

View file

@ -22,18 +22,14 @@ import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.offline.ActionFileUpgradeUtil;
import com.google.android.exoplayer2.offline.DefaultDownloadIndex;
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.ui.DownloadNotificationHelper;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Log;
@ -131,11 +127,9 @@ public class DemoApplication extends Application {
DOWNLOAD_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ false);
upgradeActionFile(
DOWNLOAD_TRACKER_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ true);
DownloaderConstructorHelper downloaderConstructorHelper =
new DownloaderConstructorHelper(getDownloadCache(), buildHttpDataSourceFactory());
downloadManager =
new DownloadManager(
this, downloadIndex, new DefaultDownloaderFactory(downloaderConstructorHelper));
this, getDatabaseProvider(), getDownloadCache(), buildHttpDataSourceFactory());
downloadTracker =
new DownloadTracker(/* context= */ this, buildDataSourceFactory(), downloadManager);
}
@ -172,14 +166,12 @@ public class DemoApplication extends Application {
return downloadDirectory;
}
protected static CacheDataSourceFactory buildReadOnlyCacheDataSource(
protected static CacheDataSource.Factory buildReadOnlyCacheDataSource(
DataSource.Factory upstreamFactory, Cache cache) {
return new CacheDataSourceFactory(
cache,
upstreamFactory,
new FileDataSource.Factory(),
/* cacheWriteDataSinkFactory= */ null,
CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR,
/* eventListener= */ null);
return new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(upstreamFactory)
.setCacheWriteDataSinkFactory(null)
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
}
}

View file

@ -51,15 +51,15 @@
# Constructors accessed via reflection in DefaultDownloaderFactory
-dontnote com.google.android.exoplayer2.source.dash.offline.DashDownloader
-keepclassmembers class com.google.android.exoplayer2.source.dash.offline.DashDownloader {
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.offline.DownloaderConstructorHelper);
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.upstream.cache.CacheDataSource.Factory);
}
-dontnote com.google.android.exoplayer2.source.hls.offline.HlsDownloader
-keepclassmembers class com.google.android.exoplayer2.source.hls.offline.HlsDownloader {
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.offline.DownloaderConstructorHelper);
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.upstream.cache.CacheDataSource.Factory);
}
-dontnote com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloader
-keepclassmembers class com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloader {
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.offline.DownloaderConstructorHelper);
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.upstream.cache.CacheDataSource.Factory);
}
# Constructors accessed via reflection in DefaultMediaSourceFactory and DownloadHelper

View file

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import java.lang.reflect.Constructor;
import java.util.List;
@ -32,7 +33,7 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
@Nullable private static final Constructor<? extends Downloader> SS_DOWNLOADER_CONSTRUCTOR;
static {
Constructor<? extends Downloader> dashDownloaderConstructor = null;
@Nullable Constructor<? extends Downloader> dashDownloaderConstructor = null;
try {
// LINT.IfChange
dashDownloaderConstructor =
@ -43,7 +44,7 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
// Expected if the app was built without the DASH module.
}
DASH_DOWNLOADER_CONSTRUCTOR = dashDownloaderConstructor;
Constructor<? extends Downloader> hlsDownloaderConstructor = null;
@Nullable Constructor<? extends Downloader> hlsDownloaderConstructor = null;
try {
// LINT.IfChange
hlsDownloaderConstructor =
@ -54,7 +55,7 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
// Expected if the app was built without the HLS module.
}
HLS_DOWNLOADER_CONSTRUCTOR = hlsDownloaderConstructor;
Constructor<? extends Downloader> ssDownloaderConstructor = null;
@Nullable Constructor<? extends Downloader> ssDownloaderConstructor = null;
try {
// LINT.IfChange
ssDownloaderConstructor =
@ -68,11 +69,16 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
SS_DOWNLOADER_CONSTRUCTOR = ssDownloaderConstructor;
}
private final DownloaderConstructorHelper downloaderConstructorHelper;
private final CacheDataSource.Factory cacheDataSourceFactory;
/** @param downloaderConstructorHelper A helper for instantiating downloaders. */
public DefaultDownloaderFactory(DownloaderConstructorHelper downloaderConstructorHelper) {
this.downloaderConstructorHelper = downloaderConstructorHelper;
/**
* Creates an instance.
*
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which
* downloads will be written.
*/
public DefaultDownloaderFactory(CacheDataSource.Factory cacheDataSourceFactory) {
this.cacheDataSourceFactory = cacheDataSourceFactory;
}
@Override
@ -80,7 +86,7 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
switch (request.type) {
case DownloadRequest.TYPE_PROGRESSIVE:
return new ProgressiveDownloader(
request.uri, request.customCacheKey, downloaderConstructorHelper);
request.uri, request.customCacheKey, cacheDataSourceFactory);
case DownloadRequest.TYPE_DASH:
return createDownloader(request, DASH_DOWNLOADER_CONSTRUCTOR);
case DownloadRequest.TYPE_HLS:
@ -98,7 +104,7 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
throw new IllegalStateException("Module missing for: " + request.type);
}
try {
return constructor.newInstance(request.uri, request.streamKeys, downloaderConstructorHelper);
return constructor.newInstance(request.uri, request.streamKeys, cacheDataSourceFactory);
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate downloader for: " + request.type, e);
}
@ -109,7 +115,7 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
try {
return clazz
.asSubclass(Downloader.class)
.getConstructor(Uri.class, List.class, DownloaderConstructorHelper.class);
.getConstructor(Uri.class, List.class, CacheDataSource.Factory.class);
} catch (NoSuchMethodException e) {
// The downloader is present, but the expected constructor is missing.
throw new RuntimeException("Downloader constructor missing", e);

View file

@ -40,6 +40,7 @@ import com.google.android.exoplayer2.scheduler.RequirementsWatcher;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSource.Factory;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.CacheEvictor;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.util.Assertions;
@ -197,7 +198,10 @@ public final class DownloadManager {
this(
context,
new DefaultDownloadIndex(databaseProvider),
new DefaultDownloaderFactory(new DownloaderConstructorHelper(cache, upstreamFactory)));
new DefaultDownloaderFactory(
new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(upstreamFactory)));
}
/**

View file

@ -1,135 +0,0 @@
/*
* Copyright (C) 2017 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.exoplayer2.offline;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSink;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSinkFactory;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.CacheKeyFactory;
import com.google.android.exoplayer2.util.PriorityTaskManager;
/** A helper class that holds necessary parameters for {@link Downloader} construction. */
public final class DownloaderConstructorHelper {
private final CacheDataSource.Factory onlineCacheDataSourceFactory;
private final CacheDataSource.Factory offlineCacheDataSourceFactory;
/**
* @param cache Cache instance to be used to store downloaded data.
* @param upstreamFactory A {@link DataSource.Factory} for creating {@link DataSource}s for
* downloading data.
*/
public DownloaderConstructorHelper(Cache cache, DataSource.Factory upstreamFactory) {
this(
cache,
upstreamFactory,
/* cacheReadDataSourceFactory= */ null,
/* cacheWriteDataSinkFactory= */ null,
/* priorityTaskManager= */ null);
}
/**
* @param cache Cache instance to be used to store downloaded data.
* @param upstreamFactory A {@link DataSource.Factory} for creating {@link DataSource}s for
* downloading data.
* @param cacheReadDataSourceFactory A {@link DataSource.Factory} for creating {@link DataSource}s
* for reading data from the cache. If null then a {@link FileDataSource.Factory} will be
* used.
* @param cacheWriteDataSinkFactory A {@link DataSink.Factory} for creating {@link DataSource}s
* for writing data to the cache. If null then a {@link CacheDataSinkFactory} will be used.
* @param priorityTaskManager A {@link PriorityTaskManager} to use when downloading. If non-null,
* downloaders will register as tasks with priority {@link C#PRIORITY_DOWNLOAD} whilst
* downloading.
*/
public DownloaderConstructorHelper(
Cache cache,
DataSource.Factory upstreamFactory,
@Nullable DataSource.Factory cacheReadDataSourceFactory,
@Nullable DataSink.Factory cacheWriteDataSinkFactory,
@Nullable PriorityTaskManager priorityTaskManager) {
this(
cache,
upstreamFactory,
cacheReadDataSourceFactory,
cacheWriteDataSinkFactory,
priorityTaskManager,
/* cacheKeyFactory= */ null);
}
/**
* @param cache Cache instance to be used to store downloaded data.
* @param upstreamFactory A {@link DataSource.Factory} for creating {@link DataSource}s for
* downloading data.
* @param cacheReadDataSourceFactory A {@link DataSource.Factory} for creating {@link DataSource}s
* for reading data from the cache. If null then a {@link FileDataSource.Factory} will be
* used.
* @param cacheWriteDataSinkFactory A {@link DataSink.Factory} for creating {@link DataSource}s
* for writing data to the cache. If null then a {@link CacheDataSinkFactory} will be used.
* @param priorityTaskManager A {@link PriorityTaskManager} to use when downloading. If non-null,
* downloaders will register as tasks with priority {@link C#PRIORITY_DOWNLOAD} whilst
* downloading.
* @param cacheKeyFactory An optional factory for cache keys.
*/
public DownloaderConstructorHelper(
Cache cache,
DataSource.Factory upstreamFactory,
@Nullable DataSource.Factory cacheReadDataSourceFactory,
@Nullable DataSink.Factory cacheWriteDataSinkFactory,
@Nullable PriorityTaskManager priorityTaskManager,
@Nullable CacheKeyFactory cacheKeyFactory) {
onlineCacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(upstreamFactory)
.setUpstreamPriorityTaskManager(priorityTaskManager)
.setUpstreamPriority(C.PRIORITY_DOWNLOAD)
.setFlags(CacheDataSource.FLAG_BLOCK_ON_CACHE);
offlineCacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(cache)
.setCacheWriteDataSinkFactory(null)
.setFlags(CacheDataSource.FLAG_BLOCK_ON_CACHE);
if (cacheKeyFactory != null) {
onlineCacheDataSourceFactory.setCacheKeyFactory(cacheKeyFactory);
offlineCacheDataSourceFactory.setCacheKeyFactory(cacheKeyFactory);
}
if (cacheReadDataSourceFactory != null) {
onlineCacheDataSourceFactory.setCacheReadDataSourceFactory(cacheReadDataSourceFactory);
offlineCacheDataSourceFactory.setCacheReadDataSourceFactory(cacheReadDataSourceFactory);
}
if (cacheWriteDataSinkFactory != null) {
onlineCacheDataSourceFactory.setCacheWriteDataSinkFactory(cacheWriteDataSinkFactory);
}
}
/** Returns a new {@link CacheDataSource} instance. */
public CacheDataSource createCacheDataSource() {
return onlineCacheDataSourceFactory.createDataSource();
}
/**
* Returns a new {@link CacheDataSource} instance which accesses cache read-only and throws an
* exception on cache miss.
*/
public CacheDataSource createOfflineCacheDataSource() {
return offlineCacheDataSourceFactory.createDataSource();
}
}

View file

@ -25,15 +25,7 @@ import com.google.android.exoplayer2.util.PriorityTaskManager;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* A downloader for progressive media streams.
*
* <p>The downloader attempts to download the entire media bytes referenced by a {@link Uri} into a
* cache as defined by {@link DownloaderConstructorHelper}. Callers can use the constructor to
* specify a custom cache key for the downloaded bytes.
*
* <p>The downloader will avoid downloading already-downloaded media bytes.
*/
/** A downloader for progressive media streams. */
public final class ProgressiveDownloader implements Downloader {
private static final int BUFFER_SIZE_BYTES = 128 * 1024;
@ -46,17 +38,18 @@ public final class ProgressiveDownloader implements Downloader {
* @param uri Uri of the data to be downloaded.
* @param customCacheKey A custom key that uniquely identifies the original stream. Used for cache
* indexing. May be null.
* @param constructorHelper A {@link DownloaderConstructorHelper} instance.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public ProgressiveDownloader(
Uri uri, @Nullable String customCacheKey, DownloaderConstructorHelper constructorHelper) {
this.dataSpec =
Uri uri, @Nullable String customCacheKey, CacheDataSource.Factory cacheDataSourceFactory) {
dataSpec =
new DataSpec.Builder()
.setUri(uri)
.setKey(customCacheKey)
.setFlags(DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION)
.build();
this.dataSource = constructorHelper.createCacheDataSource();
dataSource = cacheDataSourceFactory.createDataSourceForDownloading();
isCanceled = new AtomicBoolean();
}

View file

@ -67,7 +67,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
private final DataSpec manifestDataSpec;
private final CacheDataSource dataSource;
private final CacheDataSource offlineDataSource;
private final CacheDataSource removingDataSource;
private final ArrayList<StreamKey> streamKeys;
private final AtomicBoolean isCanceled;
@ -75,14 +75,15 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
* @param manifestUri The {@link Uri} of the manifest to be downloaded.
* @param streamKeys Keys defining which streams in the manifest should be selected for download.
* If empty, all streams are downloaded.
* @param constructorHelper A {@link DownloaderConstructorHelper} instance.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public SegmentDownloader(
Uri manifestUri, List<StreamKey> streamKeys, DownloaderConstructorHelper constructorHelper) {
Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
this.manifestDataSpec = getCompressibleDataSpec(manifestUri);
this.streamKeys = new ArrayList<>(streamKeys);
this.dataSource = constructorHelper.createCacheDataSource();
this.offlineDataSource = constructorHelper.createOfflineCacheDataSource();
this.dataSource = cacheDataSourceFactory.createDataSourceForDownloading();
this.removingDataSource = cacheDataSourceFactory.createDataSourceForRemovingDownload();
isCanceled = new AtomicBoolean();
}
@ -176,8 +177,8 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
@Override
public final void remove() throws InterruptedException {
try {
M manifest = getManifest(offlineDataSource, manifestDataSpec);
List<Segment> segments = getSegments(offlineDataSource, manifest, true);
M manifest = getManifest(removingDataSource, manifestDataSpec);
List<Segment> segments = getSegments(removingDataSource, manifest, true);
for (int i = 0; i < segments.size(); i++) {
removeDataSpec(segments.get(i).dataSpec);
}

View file

@ -207,12 +207,54 @@ public final class CacheDataSource implements DataSource {
@Override
public CacheDataSource createDataSource() {
return createDataSourceInternal(
upstreamDataSourceFactory != null ? upstreamDataSourceFactory.createDataSource() : null,
flags,
upstreamPriority);
}
/**
* Returns an instance suitable for downloading content. The created instance is equivalent to
* one that would be created by {@link #createDataSource()}, except:
*
* <ul>
* <li>The {@link #FLAG_BLOCK_ON_CACHE} is always set.
* <li>The task priority is overridden to be {@link C#PRIORITY_DOWNLOAD}.
* </ul>
*
* @return An instance suitable for downloading content.
*/
public CacheDataSource createDataSourceForDownloading() {
return createDataSourceInternal(
upstreamDataSourceFactory != null ? upstreamDataSourceFactory.createDataSource() : null,
flags | FLAG_BLOCK_ON_CACHE,
C.PRIORITY_DOWNLOAD);
}
/**
* Returns an instance suitable for reading cached content as part of removing a download. The
* created instance is equivalent to one that would be created by {@link #createDataSource()},
* except:
*
* <ul>
* <li>The upstream is overridden to be {@code null}, since when removing content we don't
* want to request anything that's not already cached.
* <li>The {@link #FLAG_BLOCK_ON_CACHE} is always set.
* <li>The task priority is overridden to be {@link C#PRIORITY_DOWNLOAD}.
* </ul>
*
* @return An instance suitable for reading cached content as part of removing a download.
*/
public CacheDataSource createDataSourceForRemovingDownload() {
return createDataSourceInternal(
/* upstreamDataSource= */ null, flags | FLAG_BLOCK_ON_CACHE, C.PRIORITY_DOWNLOAD);
}
private CacheDataSource createDataSourceInternal(
@Nullable DataSource upstreamDataSource, @Flags int flags, int upstreamPriority) {
Cache cache = Assertions.checkNotNull(this.cache);
@Nullable
DataSource upstreamDataSource =
upstreamDataSourceFactory != null ? upstreamDataSourceFactory.createDataSource() : null;
@Nullable DataSink cacheWriteDataSink;
if (cacheIsReadOnly) {
if (cacheIsReadOnly || upstreamDataSource == null) {
cacheWriteDataSink = null;
} else if (cacheWriteDataSinkFactory != null) {
cacheWriteDataSink = cacheWriteDataSinkFactory.createDataSink();

View file

@ -21,6 +21,7 @@ import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.upstream.DummyDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -32,9 +33,11 @@ public final class DefaultDownloaderFactoryTest {
@Test
public void createProgressiveDownloader() throws Exception {
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(constructorHelper);
CacheDataSource.Factory cacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(Mockito.mock(Cache.class))
.setUpstreamDataSourceFactory(DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(cacheDataSourceFactory);
Downloader downloader =
factory.createDownloader(

View file

@ -20,7 +20,6 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.ChunkIndex;
import com.google.android.exoplayer2.offline.DownloadException;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
@ -35,6 +34,7 @@ import com.google.android.exoplayer2.source.dash.manifest.Representation;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.ParsingLoadable;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -46,19 +46,20 @@ import java.util.List;
*
* <pre>{@code
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor(), databaseProvider);
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
* CacheDataSource.Factory cacheDataSourceFactory =
* new CacheDataSource.Factory()
* .setCache(cache)
* .setUpstreamDataSourceFactory(new DefaultHttpDataSourceFactory(userAgent));
* // Create a downloader for the first representation of the first adaptation set of the first
* // period.
* DashDownloader dashDownloader =
* new DashDownloader(
* manifestUrl, Collections.singletonList(new StreamKey(0, 0, 0)), constructorHelper);
* manifestUrl, Collections.singletonList(new StreamKey(0, 0, 0)), cacheDataSourceFactory);
* // Perform the download.
* dashDownloader.download(progressListener);
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
* // Use the downloaded data for playback.
* DashMediaSource mediaSource =
* new DashMediaSource.Factory(cacheDataSourceFactory).createMediaSource(mediaItem);
* }</pre>
*/
public final class DashDownloader extends SegmentDownloader<DashManifest> {
@ -67,11 +68,12 @@ public final class DashDownloader extends SegmentDownloader<DashManifest> {
* @param manifestUri The {@link Uri} of the manifest to be downloaded.
* @param streamKeys Keys defining which representations in the manifest should be selected for
* download. If empty, all representations are downloaded.
* @param constructorHelper A {@link DownloaderConstructorHelper} instance.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public DashDownloader(
Uri manifestUri, List<StreamKey> streamKeys, DownloaderConstructorHelper constructorHelper) {
super(manifestUri, streamKeys, constructorHelper);
Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
super(manifestUri, streamKeys, cacheDataSourceFactory);
}
@Override

View file

@ -32,17 +32,16 @@ import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadException;
import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.Downloader;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.DownloaderFactory;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.testutil.CacheAsserts.RequestSet;
import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.FakeDataSource.Factory;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DummyDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
@ -81,9 +80,11 @@ public class DashDownloaderTest {
@Test
public void createWithDefaultDownloaderFactory() {
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(constructorHelper);
CacheDataSource.Factory cacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(Mockito.mock(Cache.class))
.setUpstreamDataSourceFactory(DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(cacheDataSourceFactory);
Downloader downloader =
factory.createDownloader(
@ -184,7 +185,7 @@ public class DashDownloaderTest {
.setRandomData("text_segment_2", 2)
.setRandomData("text_segment_3", 3);
FakeDataSource fakeDataSource = new FakeDataSource(fakeDataSet);
Factory factory = mock(Factory.class);
FakeDataSource.Factory factory = mock(FakeDataSource.Factory.class);
when(factory.createDataSource()).thenReturn(fakeDataSource);
DashDownloader dashDownloader =
@ -216,7 +217,7 @@ public class DashDownloaderTest {
.setRandomData("period_2_segment_2", 2)
.setRandomData("period_2_segment_3", 3);
FakeDataSource fakeDataSource = new FakeDataSource(fakeDataSet);
Factory factory = mock(Factory.class);
FakeDataSource.Factory factory = mock(FakeDataSource.Factory.class);
when(factory.createDataSource()).thenReturn(fakeDataSource);
DashDownloader dashDownloader =
@ -327,12 +328,16 @@ public class DashDownloaderTest {
}
private DashDownloader getDashDownloader(FakeDataSet fakeDataSet, StreamKey... keys) {
return getDashDownloader(new Factory().setFakeDataSet(fakeDataSet), keys);
return getDashDownloader(new FakeDataSource.Factory().setFakeDataSet(fakeDataSet), keys);
}
private DashDownloader getDashDownloader(Factory factory, StreamKey... keys) {
return new DashDownloader(
TEST_MPD_URI, keysList(keys), new DownloaderConstructorHelper(cache, factory));
private DashDownloader getDashDownloader(
FakeDataSource.Factory upstreamDataSourceFactory, StreamKey... keys) {
CacheDataSource.Factory cacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(upstreamDataSourceFactory);
return new DashDownloader(TEST_MPD_URI, keysList(keys), cacheDataSourceFactory);
}
private static ArrayList<StreamKey> keysList(StreamKey... keys) {

View file

@ -29,7 +29,6 @@ import com.google.android.exoplayer2.offline.DefaultDownloadIndex;
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.testutil.CacheAsserts.RequestSet;
@ -40,6 +39,7 @@ import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSource.Factory;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
@ -253,12 +253,14 @@ public class DownloadManagerDashTest {
runOnMainThread(
() -> {
Factory fakeDataSourceFactory = new FakeDataSource.Factory().setFakeDataSet(fakeDataSet);
DefaultDownloaderFactory downloaderFactory =
new DefaultDownloaderFactory(
new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(fakeDataSourceFactory));
downloadManager =
new DownloadManager(
ApplicationProvider.getApplicationContext(),
downloadIndex,
new DefaultDownloaderFactory(
new DownloaderConstructorHelper(cache, fakeDataSourceFactory)));
ApplicationProvider.getApplicationContext(), downloadIndex, downloaderFactory);
downloadManager.setRequirements(new Requirements(0));
downloadManagerListener =

View file

@ -33,7 +33,6 @@ import com.google.android.exoplayer2.offline.Download;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.DownloadService;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.scheduler.Scheduler;
import com.google.android.exoplayer2.testutil.DummyMainThread;
@ -42,6 +41,7 @@ import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.ConditionVariable;
@ -113,12 +113,14 @@ public class DownloadServiceDashTest {
() -> {
DefaultDownloadIndex downloadIndex =
new DefaultDownloadIndex(TestUtil.getInMemoryDatabaseProvider());
DefaultDownloaderFactory downloaderFactory =
new DefaultDownloaderFactory(
new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(fakeDataSourceFactory));
final DownloadManager dashDownloadManager =
new DownloadManager(
ApplicationProvider.getApplicationContext(),
downloadIndex,
new DefaultDownloaderFactory(
new DownloaderConstructorHelper(cache, fakeDataSourceFactory)));
ApplicationProvider.getApplicationContext(), downloadIndex, downloaderFactory);
downloadManagerListener =
new TestDownloadManagerListener(dashDownloadManager, dummyMainThread);
dashDownloadManager.resumeDownloads();

View file

@ -17,7 +17,6 @@ package com.google.android.exoplayer2.source.hls.offline;
import android.net.Uri;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
@ -27,6 +26,7 @@ import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.ParsingLoadable;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.util.UriUtil;
import java.io.IOException;
import java.util.ArrayList;
@ -40,20 +40,20 @@ import java.util.List;
*
* <pre>{@code
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor(), databaseProvider);
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
* CacheDataSource.Factory cacheDataSourceFactory =
* new CacheDataSource.Factory()
* .setCache(cache)
* .setUpstreamDataSourceFactory(new DefaultHttpDataSourceFactory(userAgent));
* // Create a downloader for the first variant in a master playlist.
* HlsDownloader hlsDownloader =
* new HlsDownloader(
* playlistUri,
* Collections.singletonList(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, 0)),
* constructorHelper);
* Collections.singletonList(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, 0));
* // Perform the download.
* hlsDownloader.download(progressListener);
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
* // Use the downloaded data for playback.
* HlsMediaSource mediaSource =
* new HlsMediaSource.Factory(cacheDataSourceFactory).createMediaSource(mediaItem);
* }</pre>
*/
public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
@ -62,11 +62,12 @@ public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
* @param playlistUri The {@link Uri} of the playlist to be downloaded.
* @param streamKeys Keys defining which renditions in the playlist should be selected for
* download. If empty, all renditions are downloaded.
* @param constructorHelper A {@link DownloaderConstructorHelper} instance.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public HlsDownloader(
Uri playlistUri, List<StreamKey> streamKeys, DownloaderConstructorHelper constructorHelper) {
super(playlistUri, streamKeys, constructorHelper);
Uri playlistUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
super(playlistUri, streamKeys, cacheDataSourceFactory);
}
@Override

View file

@ -40,15 +40,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.Downloader;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.DownloaderFactory;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
import com.google.android.exoplayer2.testutil.CacheAsserts.RequestSet;
import com.google.android.exoplayer2.testutil.FakeDataSet;
import com.google.android.exoplayer2.testutil.FakeDataSource.Factory;
import com.google.android.exoplayer2.testutil.FakeDataSource;
import com.google.android.exoplayer2.upstream.DummyDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
@ -97,9 +97,11 @@ public class HlsDownloaderTest {
@Test
public void createWithDefaultDownloaderFactory() {
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(constructorHelper);
CacheDataSource.Factory cacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(Mockito.mock(Cache.class))
.setUpstreamDataSourceFactory(DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(cacheDataSourceFactory);
Downloader downloader =
factory.createDownloader(
@ -213,9 +215,11 @@ public class HlsDownloaderTest {
}
private HlsDownloader getHlsDownloader(String mediaPlaylistUri, List<StreamKey> keys) {
Factory factory = new Factory().setFakeDataSet(fakeDataSet);
return new HlsDownloader(
Uri.parse(mediaPlaylistUri), keys, new DownloaderConstructorHelper(cache, factory));
CacheDataSource.Factory cacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(new FakeDataSource.Factory().setFakeDataSet(fakeDataSet));
return new HlsDownloader(Uri.parse(mediaPlaylistUri), keys, cacheDataSourceFactory);
}
private static ArrayList<StreamKey> getKeys(int... variantIndices) {

View file

@ -17,7 +17,6 @@ package com.google.android.exoplayer2.source.smoothstreaming.offline;
import android.net.Uri;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
@ -27,6 +26,7 @@ import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsUtil;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.ParsingLoadable;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -38,20 +38,21 @@ import java.util.List;
*
* <pre>{@code
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor(), databaseProvider);
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
* CacheDataSource.Factory cacheDataSourceFactory =
* new CacheDataSource.Factory()
* .setCache(cache)
* .setUpstreamDataSourceFactory(new DefaultHttpDataSourceFactory(userAgent));
* // Create a downloader for the first track of the first stream element.
* SsDownloader ssDownloader =
* new SsDownloader(
* manifestUrl,
* Collections.singletonList(new StreamKey(0, 0)),
* constructorHelper);
* cacheDataSourceFactory);
* // Perform the download.
* ssDownloader.download(progressListener);
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
* // Use the downloaded data for playback.
* SsMediaSource mediaSource =
* new SsMediaSource.Factory(cacheDataSourceFactory).createMediaSource(mediaItem);
* }</pre>
*/
public final class SsDownloader extends SegmentDownloader<SsManifest> {
@ -60,11 +61,12 @@ public final class SsDownloader extends SegmentDownloader<SsManifest> {
* @param manifestUri The {@link Uri} of the manifest to be downloaded.
* @param streamKeys Keys defining which streams in the manifest should be selected for download.
* If empty, all streams are downloaded.
* @param constructorHelper A {@link DownloaderConstructorHelper} instance.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public SsDownloader(
Uri manifestUri, List<StreamKey> streamKeys, DownloaderConstructorHelper constructorHelper) {
super(SsUtil.fixManifestUri(manifestUri), streamKeys, constructorHelper);
Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
super(SsUtil.fixManifestUri(manifestUri), streamKeys, cacheDataSourceFactory);
}
@Override

View file

@ -22,11 +22,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.Downloader;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.DownloaderFactory;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.upstream.DummyDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -38,9 +38,11 @@ public final class SsDownloaderTest {
@Test
public void createWithDefaultDownloaderFactory() throws Exception {
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(constructorHelper);
CacheDataSource.Factory cacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(Mockito.mock(Cache.class))
.setUpstreamDataSourceFactory(DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(cacheDataSourceFactory);
Downloader downloader =
factory.createDownloader(

View file

@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertWithMessage;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.rule.ActivityTestRule;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.dash.DashUtil;
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
@ -120,9 +119,11 @@ public final class DashDownloadTest {
}
}
}
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(cache, httpDataSourceFactory);
return new DashDownloader(MANIFEST_URI, keys, constructorHelper);
CacheDataSource.Factory cacheDataSourceFactory =
new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(httpDataSourceFactory);
return new DashDownloader(MANIFEST_URI, keys, cacheDataSourceFactory);
}
}