Search in sources :

Example 26 with Download

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);
}
Also used : DownloadBuilder(com.google.android.exoplayer2.testutil.DownloadBuilder) Test(org.junit.Test)

Example 27 with Download

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);
}
Also used : Download(com.google.android.exoplayer2.offline.Download)

Example 28 with Download

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);
}
Also used : CacheDataSource(com.google.android.exoplayer2.upstream.cache.CacheDataSource) DefaultDownloaderFactory(com.google.android.exoplayer2.offline.DefaultDownloaderFactory) DefaultDownloaderFactory(com.google.android.exoplayer2.offline.DefaultDownloaderFactory) DownloaderFactory(com.google.android.exoplayer2.offline.DownloaderFactory) Downloader(com.google.android.exoplayer2.offline.Downloader) DefaultDownloaderFactory(com.google.android.exoplayer2.offline.DefaultDownloaderFactory) DownloaderFactory(com.google.android.exoplayer2.offline.DownloaderFactory) StreamKey(com.google.android.exoplayer2.offline.StreamKey) Test(org.junit.Test)

Example 29 with Download

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);
        }
    }
}
Also used : IOException(java.io.IOException) ArrayDeque(java.util.ArrayDeque) PriorityTooLowException(com.google.android.exoplayer2.util.PriorityTaskManager.PriorityTooLowException) CacheDataSource(com.google.android.exoplayer2.upstream.cache.CacheDataSource) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) ExecutionException(java.util.concurrent.ExecutionException) Nullable(androidx.annotation.Nullable)

Example 30 with 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());
        }
    }
}
Also used : DefaultTrackSelector(com.google.android.exoplayer2.trackselection.DefaultTrackSelector) MappedTrackInfo(com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo)

Aggregations

Test (org.junit.Test)22 DownloadBuilder (com.google.android.exoplayer2.testutil.DownloadBuilder)17 CacheDataSource (com.google.android.exoplayer2.upstream.cache.CacheDataSource)5 DefaultDownloaderFactory (com.google.android.exoplayer2.offline.DefaultDownloaderFactory)4 StreamKey (com.google.android.exoplayer2.offline.StreamKey)4 SQLiteDatabase (android.database.sqlite.SQLiteDatabase)3 Download (com.google.android.exoplayer2.offline.Download)3 Downloader (com.google.android.exoplayer2.offline.Downloader)3 DownloaderFactory (com.google.android.exoplayer2.offline.DownloaderFactory)3 Nullable (androidx.annotation.Nullable)2 DatabaseIOException (com.google.android.exoplayer2.database.DatabaseIOException)2 DefaultTrackSelector (com.google.android.exoplayer2.trackselection.DefaultTrackSelector)2 MappedTrackInfo (com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo)2 IOException (java.io.IOException)2 Notification (android.app.Notification)1 Context (android.content.Context)1 SQLException (android.database.SQLException)1 SQLiteException (android.database.sqlite.SQLiteException)1 Format (com.google.android.exoplayer2.Format)1 StandaloneDatabaseProvider (com.google.android.exoplayer2.database.StandaloneDatabaseProvider)1