use of com.google.android.exoplayer2.offline.Download in project ExoPlayer by google.
the class DefaultDownloadIndexTest method setSingleDownloadStopReason_setReasonToNone.
@Test
public void setSingleDownloadStopReason_setReasonToNone() throws Exception {
String id = "id";
DownloadBuilder downloadBuilder = new DownloadBuilder(id).setState(Download.STATE_COMPLETED).setStopReason(0x12345678);
Download download = downloadBuilder.build();
downloadIndex.putDownload(download);
downloadIndex.setStopReason(id, STOP_REASON_NONE);
Download readDownload = downloadIndex.getDownload(id);
Download expectedDownload = downloadBuilder.setStopReason(STOP_REASON_NONE).build();
assertEqual(readDownload, expectedDownload);
}
use of com.google.android.exoplayer2.offline.Download in project ExoPlayer by google.
the class DownloadNotificationHelper method buildProgressNotification.
/**
* Returns a progress notification for the given downloads.
*
* @param context A context.
* @param smallIcon A small icon for the notification.
* @param contentIntent An optional content intent to send when the notification is clicked.
* @param message An optional message to display on the notification.
* @param downloads The downloads.
* @param notMetRequirements Any requirements for downloads that are not currently met.
* @return The notification.
*/
public Notification buildProgressNotification(Context context, @DrawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message, List<Download> downloads, @Requirements.RequirementFlags int notMetRequirements) {
float totalPercentage = 0;
int downloadTaskCount = 0;
boolean allDownloadPercentagesUnknown = true;
boolean haveDownloadedBytes = false;
boolean haveDownloadingTasks = false;
boolean haveQueuedTasks = false;
boolean haveRemovingTasks = false;
for (int i = 0; i < downloads.size(); i++) {
Download download = downloads.get(i);
switch(download.state) {
case Download.STATE_REMOVING:
haveRemovingTasks = true;
break;
case Download.STATE_QUEUED:
haveQueuedTasks = true;
break;
case Download.STATE_RESTARTING:
case Download.STATE_DOWNLOADING:
haveDownloadingTasks = true;
float downloadPercentage = download.getPercentDownloaded();
if (downloadPercentage != C.PERCENTAGE_UNSET) {
allDownloadPercentagesUnknown = false;
totalPercentage += downloadPercentage;
}
haveDownloadedBytes |= download.getBytesDownloaded() > 0;
downloadTaskCount++;
break;
// Terminal states aren't expected, but if we encounter them we do nothing.
case Download.STATE_STOPPED:
case Download.STATE_COMPLETED:
case Download.STATE_FAILED:
default:
break;
}
}
int titleStringId;
boolean showProgress = true;
if (haveDownloadingTasks) {
titleStringId = R.string.exo_download_downloading;
} else if (haveQueuedTasks && notMetRequirements != 0) {
showProgress = false;
if ((notMetRequirements & Requirements.NETWORK_UNMETERED) != 0) {
// Note: This assumes that "unmetered" == "WiFi", since it provides a clearer message that's
// correct in the majority of cases.
titleStringId = R.string.exo_download_paused_for_wifi;
} else if ((notMetRequirements & Requirements.NETWORK) != 0) {
titleStringId = R.string.exo_download_paused_for_network;
} else {
titleStringId = R.string.exo_download_paused;
}
} else if (haveRemovingTasks) {
titleStringId = R.string.exo_download_removing;
} else {
// There are either no downloads, or all downloads are in terminal states.
titleStringId = NULL_STRING_ID;
}
int maxProgress = 0;
int currentProgress = 0;
boolean indeterminateProgress = false;
if (showProgress) {
maxProgress = 100;
if (haveDownloadingTasks) {
currentProgress = (int) (totalPercentage / downloadTaskCount);
indeterminateProgress = allDownloadPercentagesUnknown && haveDownloadedBytes;
} else {
indeterminateProgress = true;
}
}
return buildNotification(context, smallIcon, contentIntent, message, titleStringId, maxProgress, currentProgress, indeterminateProgress, /* ongoing= */
true, /* showWhen= */
false);
}
use of com.google.android.exoplayer2.offline.Download in project ExoPlayer by google.
the class SsDownloaderTest method createWithDefaultDownloaderFactory.
@Test
public void createWithDefaultDownloaderFactory() throws Exception {
CacheDataSource.Factory cacheDataSourceFactory = new CacheDataSource.Factory().setCache(Mockito.mock(Cache.class)).setUpstreamDataSourceFactory(DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(cacheDataSourceFactory, /* executor= */
Runnable::run);
Downloader downloader = factory.createDownloader(new DownloadRequest.Builder(/* id= */
"id", Uri.parse("https://www.test.com/download")).setMimeType(MimeTypes.APPLICATION_SS).setStreamKeys(Collections.singletonList(new StreamKey(/* groupIndex= */
0, /* trackIndex= */
0))).build());
assertThat(downloader).isInstanceOf(SsDownloader.class);
}
use of com.google.android.exoplayer2.offline.Download in project ExoPlayer by google.
the class SegmentDownloader method download.
@Override
public final void download(@Nullable ProgressListener progressListener) throws IOException, InterruptedException {
ArrayDeque<Segment> pendingSegments = new ArrayDeque<>();
ArrayDeque<SegmentDownloadRunnable> recycledRunnables = new ArrayDeque<>();
if (priorityTaskManager != null) {
priorityTaskManager.add(C.PRIORITY_DOWNLOAD);
}
try {
CacheDataSource dataSource = cacheDataSourceFactory.createDataSourceForDownloading();
// Get the manifest and all of the segments.
M manifest = getManifest(dataSource, manifestDataSpec, /* removing= */
false);
if (!streamKeys.isEmpty()) {
manifest = manifest.copy(streamKeys);
}
List<Segment> segments = getSegments(dataSource, manifest, /* removing= */
false);
// Sort the segments so that we download media in the right order from the start of the
// content, and merge segments where possible to minimize the number of server round trips.
Collections.sort(segments);
mergeSegments(segments, cacheKeyFactory);
// Scan the segments, removing any that are fully downloaded.
int totalSegments = segments.size();
int segmentsDownloaded = 0;
long contentLength = 0;
long bytesDownloaded = 0;
for (int i = segments.size() - 1; i >= 0; i--) {
DataSpec dataSpec = segments.get(i).dataSpec;
String cacheKey = cacheKeyFactory.buildCacheKey(dataSpec);
long segmentLength = dataSpec.length;
if (segmentLength == C.LENGTH_UNSET) {
long resourceLength = ContentMetadata.getContentLength(cache.getContentMetadata(cacheKey));
if (resourceLength != C.LENGTH_UNSET) {
segmentLength = resourceLength - dataSpec.position;
}
}
long segmentBytesDownloaded = cache.getCachedBytes(cacheKey, dataSpec.position, segmentLength);
bytesDownloaded += segmentBytesDownloaded;
if (segmentLength != C.LENGTH_UNSET) {
if (segmentLength == segmentBytesDownloaded) {
// The segment is fully downloaded.
segmentsDownloaded++;
segments.remove(i);
}
if (contentLength != C.LENGTH_UNSET) {
contentLength += segmentLength;
}
} else {
contentLength = C.LENGTH_UNSET;
}
}
// Download the segments.
@Nullable ProgressNotifier progressNotifier = progressListener != null ? new ProgressNotifier(progressListener, contentLength, totalSegments, bytesDownloaded, segmentsDownloaded) : null;
pendingSegments.addAll(segments);
while (!isCanceled && !pendingSegments.isEmpty()) {
// Block until there aren't any higher priority tasks.
if (priorityTaskManager != null) {
priorityTaskManager.proceed(C.PRIORITY_DOWNLOAD);
}
// Create and execute a runnable to download the next segment.
CacheDataSource segmentDataSource;
byte[] temporaryBuffer;
if (!recycledRunnables.isEmpty()) {
SegmentDownloadRunnable recycledRunnable = recycledRunnables.removeFirst();
segmentDataSource = recycledRunnable.dataSource;
temporaryBuffer = recycledRunnable.temporaryBuffer;
} else {
segmentDataSource = cacheDataSourceFactory.createDataSourceForDownloading();
temporaryBuffer = new byte[BUFFER_SIZE_BYTES];
}
Segment segment = pendingSegments.removeFirst();
SegmentDownloadRunnable downloadRunnable = new SegmentDownloadRunnable(segment, segmentDataSource, progressNotifier, temporaryBuffer);
addActiveRunnable(downloadRunnable);
executor.execute(downloadRunnable);
// Clean up runnables that have finished.
for (int j = activeRunnables.size() - 1; j >= 0; j--) {
SegmentDownloadRunnable activeRunnable = (SegmentDownloadRunnable) activeRunnables.get(j);
// it's already finished.
if (pendingSegments.isEmpty() || activeRunnable.isDone()) {
try {
activeRunnable.get();
removeActiveRunnable(j);
recycledRunnables.addLast(activeRunnable);
} catch (ExecutionException e) {
Throwable cause = Assertions.checkNotNull(e.getCause());
if (cause instanceof PriorityTooLowException) {
// We need to schedule this segment again in a future loop iteration.
pendingSegments.addFirst(activeRunnable.segment);
removeActiveRunnable(j);
recycledRunnables.addLast(activeRunnable);
} else if (cause instanceof IOException) {
throw (IOException) cause;
} else {
// The cause must be an uncaught Throwable type.
Util.sneakyThrow(cause);
}
}
}
}
// Don't move on to the next segment until the runnable for this segment has started. This
// drip feeds runnables to the executor, rather than providing them all up front.
downloadRunnable.blockUntilStarted();
}
} finally {
// Cancel them to speed this up.
for (int i = 0; i < activeRunnables.size(); i++) {
activeRunnables.get(i).cancel(/* interruptIfRunning= */
true);
}
// do this for the case where the main download thread was interrupted as part of cancelation.
for (int i = activeRunnables.size() - 1; i >= 0; i--) {
activeRunnables.get(i).blockUntilFinished();
removeActiveRunnable(i);
}
if (priorityTaskManager != null) {
priorityTaskManager.remove(C.PRIORITY_DOWNLOAD);
}
}
}
use of com.google.android.exoplayer2.offline.Download in project ExoPlayer by google.
the class DownloadHelper method addTextLanguagesToSelection.
/**
* Convenience method to add selections of tracks for all specified text languages. Must not be
* called until after preparation completes.
*
* @param selectUndeterminedTextLanguage Whether a text track with undetermined language should be
* selected for downloading if no track with one of the specified {@code languages} is
* available.
* @param languages A list of text languages for which tracks should be added to the download
* selection, as IETF BCP 47 conformant tags.
*/
public void addTextLanguagesToSelection(boolean selectUndeterminedTextLanguage, String... languages) {
assertPreparedWithMedia();
for (int periodIndex = 0; periodIndex < mappedTrackInfos.length; periodIndex++) {
DefaultTrackSelector.ParametersBuilder parametersBuilder = DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_CONTEXT.buildUpon();
MappedTrackInfo mappedTrackInfo = mappedTrackInfos[periodIndex];
int rendererCount = mappedTrackInfo.getRendererCount();
for (int rendererIndex = 0; rendererIndex < rendererCount; rendererIndex++) {
if (mappedTrackInfo.getRendererType(rendererIndex) != C.TRACK_TYPE_TEXT) {
parametersBuilder.setRendererDisabled(rendererIndex, /* disabled= */
true);
}
}
parametersBuilder.setSelectUndeterminedTextLanguage(selectUndeterminedTextLanguage);
for (String language : languages) {
parametersBuilder.setPreferredTextLanguage(language);
addTrackSelection(periodIndex, parametersBuilder.build());
}
}
}
Aggregations