Skip to content

Commit

Permalink
Plumb an ExecutorService into Downloader implementations
Browse files Browse the repository at this point in the history
Issue: #5978
PiperOrigin-RevId: 307819608
  • Loading branch information
ojw28 authored and icbaker committed Apr 27, 2020
1 parent 37f0ff9 commit cd828e5
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 10 deletions.
6 changes: 3 additions & 3 deletions library/core/proguard-rules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.upstream.cache.CacheDataSource.Factory);
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.upstream.cache.CacheDataSource.Factory, java.util.concurrent.ExecutorService);
}
-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.upstream.cache.CacheDataSource.Factory);
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.upstream.cache.CacheDataSource.Factory, java.util.concurrent.ExecutorService);
}
-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.upstream.cache.CacheDataSource.Factory);
<init>(android.net.Uri, java.util.List, com.google.android.exoplayer2.upstream.cache.CacheDataSource.Factory, java.util.concurrent.ExecutorService);
}

# Constructors accessed via reflection in DefaultMediaSourceFactory and DownloadHelper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
* Default {@link DownloaderFactory}, supporting creation of progressive, DASH, HLS and
Expand Down Expand Up @@ -70,6 +71,7 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
}

private final CacheDataSource.Factory cacheDataSourceFactory;
@Nullable private final ExecutorService executorService;

/**
* Creates an instance.
Expand All @@ -78,15 +80,32 @@ public class DefaultDownloaderFactory implements DownloaderFactory {
* downloads will be written.
*/
public DefaultDownloaderFactory(CacheDataSource.Factory cacheDataSourceFactory) {
this(cacheDataSourceFactory, /* executorService= */ null);
}

/**
* Creates an instance.
*
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which
* downloads will be written.
* @param executorService An {@link ExecutorService} used to make requests for media being
* downloaded. Must not be a direct executor, but may be {@code null} if each download should
* make its requests directly on its own thread. Providing an {@link ExecutorService} that
* uses multiple threads will speed up download tasks that can be split into smaller parts for
* parallel execution.
*/
public DefaultDownloaderFactory(
CacheDataSource.Factory cacheDataSourceFactory, @Nullable ExecutorService executorService) {
this.cacheDataSourceFactory = cacheDataSourceFactory;
this.executorService = executorService;
}

@Override
public Downloader createDownloader(DownloadRequest request) {
switch (request.type) {
case DownloadRequest.TYPE_PROGRESSIVE:
return new ProgressiveDownloader(
request.uri, request.customCacheKey, cacheDataSourceFactory);
request.uri, request.customCacheKey, cacheDataSourceFactory, executorService);
case DownloadRequest.TYPE_DASH:
return createDownloader(request, DASH_DOWNLOADER_CONSTRUCTOR);
case DownloadRequest.TYPE_HLS:
Expand All @@ -98,13 +117,18 @@ public Downloader createDownloader(DownloadRequest request) {
}
}

// Checker framework has no way of knowing whether arguments to newInstance can be null or not,
// and so opts to be conservative and assumes they cannot. In this case executorService can be
// nullable, so we suppress the warning.
@SuppressWarnings("nullness:argument.type.incompatible")
private Downloader createDownloader(
DownloadRequest request, @Nullable Constructor<? extends Downloader> constructor) {
if (constructor == null) {
throw new IllegalStateException("Module missing for: " + request.type);
}
try {
return constructor.newInstance(request.uri, request.streamKeys, cacheDataSourceFactory);
return constructor.newInstance(
request.uri, request.streamKeys, cacheDataSourceFactory, executorService);
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate downloader for: " + request.type, e);
}
Expand All @@ -115,7 +139,8 @@ private static Constructor<? extends Downloader> getDownloaderConstructor(Class<
try {
return clazz
.asSubclass(Downloader.class)
.getConstructor(Uri.class, List.class, CacheDataSource.Factory.class);
.getConstructor(
Uri.class, List.class, CacheDataSource.Factory.class, ExecutorService.class);
} catch (NoSuchMethodException e) {
// The downloader is present, but the expected constructor is missing.
throw new RuntimeException("Downloader constructor missing", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.android.exoplayer2.upstream.cache.CacheUtil;
import com.google.android.exoplayer2.util.PriorityTaskManager;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;

/** A downloader for progressive media streams. */
Expand All @@ -43,6 +44,26 @@ public final class ProgressiveDownloader implements Downloader {
*/
public ProgressiveDownloader(
Uri uri, @Nullable String customCacheKey, CacheDataSource.Factory cacheDataSourceFactory) {
this(uri, customCacheKey, cacheDataSourceFactory, /* executorService= */ null);
}

/**
* @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 cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
* @param executorService An {@link ExecutorService} used to make requests for the media being
* downloaded. Must not be a direct executor, but may be {@code null} if the requests should
* be made directly from the thread that calls {@link #download(ProgressListener)}. In the
* future, providing an {@link ExecutorService} that uses multiple threads may speed up the
* download by allowing parts of it to be executed in parallel.
*/
public ProgressiveDownloader(
Uri uri,
@Nullable String customCacheKey,
CacheDataSource.Factory cacheDataSourceFactory,
@Nullable ExecutorService executorService) {
dataSpec =
new DataSpec.Builder()
.setUri(uri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;

/**
Expand Down Expand Up @@ -77,9 +78,17 @@ public int compareTo(Segment other) {
* If empty, all streams are downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
* @param executorService An {@link ExecutorService} used to make requests for the media being
* downloaded. Must not be a direct executor, but may be {@code null} if the requests should
* be made directly from the thread that calls {@link #download(ProgressListener)}. Providing
* an {@link ExecutorService} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel.
*/
public SegmentDownloader(
Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
Uri manifestUri,
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory,
@Nullable ExecutorService executorService) {
this.manifestDataSpec = getCompressibleDataSpec(manifestUri);
this.streamKeys = new ArrayList<>(streamKeys);
this.dataSource = cacheDataSourceFactory.createDataSourceForDownloading();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
* A downloader for DASH streams.
Expand Down Expand Up @@ -73,7 +74,27 @@ public final class DashDownloader extends SegmentDownloader<DashManifest> {
*/
public DashDownloader(
Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
super(manifestUri, streamKeys, cacheDataSourceFactory);
this(manifestUri, streamKeys, cacheDataSourceFactory, /* executorService= */ null);
}

/**
* @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 cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
* @param executorService An {@link ExecutorService} used to make requests for the media being
* downloaded. Must not be a direct executor, but may be {@code null} if the requests should
* be made directly from the thread that calls {@link #download(ProgressListener)}. Providing
* an {@link ExecutorService} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel.
*/
public DashDownloader(
Uri manifestUri,
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory,
@Nullable ExecutorService executorService) {
super(manifestUri, streamKeys, cacheDataSourceFactory, executorService);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.hls.offline;

import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.offline.StreamKey;
Expand All @@ -32,6 +33,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
* A downloader for HLS streams.
Expand Down Expand Up @@ -67,7 +69,27 @@ public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
*/
public HlsDownloader(
Uri playlistUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
super(playlistUri, streamKeys, cacheDataSourceFactory);
this(playlistUri, streamKeys, cacheDataSourceFactory, /* executorService= */ null);
}

/**
* @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 cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
* @param executorService An {@link ExecutorService} used to make requests for the media being
* downloaded. Must not be a direct executor, but may be {@code null} if the requests should
* be made directly from the thread that calls {@link #download(ProgressListener)}. Providing
* an {@link ExecutorService} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel.
*/
public HlsDownloader(
Uri playlistUri,
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory,
@Nullable ExecutorService executorService) {
super(playlistUri, streamKeys, cacheDataSourceFactory, executorService);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.google.android.exoplayer2.source.smoothstreaming.offline;

import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.offline.StreamKey;
Expand All @@ -30,6 +31,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
* A downloader for SmoothStreaming streams.
Expand Down Expand Up @@ -66,7 +68,27 @@ public final class SsDownloader extends SegmentDownloader<SsManifest> {
*/
public SsDownloader(
Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
super(SsUtil.fixManifestUri(manifestUri), streamKeys, cacheDataSourceFactory);
this(manifestUri, streamKeys, cacheDataSourceFactory, /* executorService= */ null);
}

/**
* @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 cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
* @param executorService An {@link ExecutorService} used to make requests for the media being
* downloaded. Must not be a direct executor, but may be {@code null} if the requests should
* be made directly from the thread that calls {@link #download(ProgressListener)}. Providing
* an {@link ExecutorService} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel.
*/
public SsDownloader(
Uri manifestUri,
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory,
@Nullable ExecutorService executorService) {
super(SsUtil.fixManifestUri(manifestUri), streamKeys, cacheDataSourceFactory, executorService);
}

@Override
Expand Down

0 comments on commit cd828e5

Please sign in to comment.