Downloading Streams

Erdem Guven
AndroidX Media3
Published in
4 min readApr 17, 2018

There have been major changes since the writing of this post please see the new page on our developer site for the latest information on downloading.

Recently we have added support for downloading DASH, HLS and SmoothStreaming non-live streams in addition to progressive streams. This post is an introduction to this functionality.

Let’s begin with learning the main classes involved:

  • Cache is used to store the read data from network, locally. Normally, for caching purposes it’s configured to use a limited amount of disk space and delete least recently used data. When used for downloading it is configured without a disk space limit and not to delete anything.
  • DataSource is used to read streams of data. HttpDataSource is used to read HTTP resources.
  • Downloader downloads one certain type of stream. There are subclasses for DASH, HLS, SmoothStreaming and also progressive streams. One Downloader downloads only one stream.
  • DownloadManager manages multiple downloads and persists download tasks. Downloads can be done in parallel or sequentially.
  • DownloadAction is used to request downloading media or removing an already downloaded media by DownloadManager. It contains necessary parameters to initiate the download. There is one subclass for each stream type.
  • DownloadService executes downloads as a Android service so they can continue even if the app exits.
  • Scheduler is used to start and stop DownloadService depending on whether specified requirements are met. For example, it can be configured to start downloads when there is an unmetered network or while the device is charging, even while the app isn’t running.

Note, although the Downloaders can be used standalone, it’s recommended to use DownloadService and DownloadManager for full functionality.

Simplified interaction graph of the classes

Creating a DownloadService

DownloadService is an abstract class; to use it you need to subclass it and implement its abstract methods:

  • getDownloadManager() returns the DownloadManager to be used.
  • getScheduler() and getRequirements() return a optional Scheduler and requirements that control when downloads should be allowed to proceed. See for details: PlatformScheduler, JobDispatcherScheduler and Requirements.
  • getForegroundNotification() returns a notification to be displayed when the service running in the foreground. You can use buildProgressNotification method in DownloadNotificationUtil to create a notification in default style.

Creating a DownloadManager

There are three parameters you need to provide for the simplest constructor of DownloadManager:

DownloadManager(
// A helper class for creating
Downloaders
DownloaderConstructorHelper constructorHelper,
// File to save active actions
File actionFile,
// Used to deserialize DownloadActions
Deserializer... deserializers)
  • DownloaderConstructorHelper holds necessary parameters for constructing Downloaders.
  • actionFile is the file where DownloadActions are saved. So when the app restarts these actions can be continued. DON’T give a path in the folder you used for SimpleCache to store downloaded content. SimpleCache deletes any file it doesn’t know.
  • Deserializers are used to load actions from actionFile. There is one Deserializer implementation for each stream type. For example DashDownloadAction.DESERIALIZER for DASH content. You need to pass in the Deserializers associated with the stream types you want to download.

There is another constructor of DownloadManager by which you can set the maximum number of simultaneous downloads. It’s set to 1 by default.

Making a download request

The service is started with the first download request. To do a request you can call:

DownloadService.startWithAction(
Context context,
Class<? extends DownloadService> clazz, // your subclass
DownloadAction downloadAction,
boolean foreground)

You need to use the right subclass of DownloadAction for the stream you want to download. For example, to download a progressive stream, you need to create a ProgressiveDownloadAction:

ProgressiveDownloadAction(
Uri uri, // Uri of the data to be downloaded
boolean removeAction, // If true, removes downloaded data
String data, // Optional custom data for this action
String customCacheKey) // Optional custom cache key

You need to specify the uri of the content and whether you want to download it, or remove what has already been downloaded. There is also an optional data parameter which can be used to store application specific information.

Creating DownloadActions for DASH, HLS and SmoothStreaming is similar. Additionally you need to specify which representations you want to download. Details will be covered in a separate post.

Playing downloaded content

Playing the downloaded content is basically reading data from cache instead of network. Downloaded content is split into multiple small cache files so it isn’t possible to play content directly from the files. You need to use a CacheDataSource (or CacheDataSourceFactory) with the Cache you used for downloading while creating your MediaSource. And don’t forget you should use the original content url you used to download the content (not the local path to the cache folder or any file in it).

There are more details included while downloading DASH, HLS and SmoothStreaming which is covered in the follow up post.

I hope this post helps you easily start using DownloadService. For questions and bugs please go to ExoPlayer Github issue tracker.

--

--