Closed debz-eight closed 2 months ago
Thanks for your question.
I have implemented a download feature for my audio app
I assume this implies you have downloaded the media of a media item into a Cache
, namely into a SimpleCache
instance. I respond in the following assuming that your app is running in a single process which is the process architecture in which SimpleCache
is supported. Or more precisely I assume that downloading to and reading from a SimpleCache
singleton instance is feasible in the current architecture. See this line in the class level JavaDoc of SimpleCache
, saying 'only one instance of SimpleCache is allowed for a given directory at a given time'.
With a single cache instance, the player on the session side can create a media source factory that has a read only cache data source, that reads from the cache to which you've downloaded the media. When building your player in the service you'd do something like this to get a CacheDataSource
using the download Cache
singleton:
public static synchronized DataSource.Factory getDataSourceFactory(Context context) {
if (dataSourceFactory == null) {
context = context.getApplicationContext();
DefaultDataSource.Factory upstreamFactory =
new DefaultDataSource.Factory(context, getHttpDataSourceFactory(context));
Cache cache = getDownloadCacheSingleton(context);
dataSourceFactory = new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(upstreamFactory)
.setCacheWriteDataSinkFactory(null)
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
}
return dataSourceFactory;
}
The CacheDataSource
checks whether the requested media is in the cache, in case of a cache-miss the upstream datasource is used to load the data from the original source.
Then use the cache data source to create a media source factory with which to build the player:
DefaultMediaSourceFactory defaultMediaSourceFactory =
new DefaultMediaSourceFactorycontext)
.setDataSourceFactory(getDataSourceFactory(context));
ExoPlayer exoPlayer =
new ExoPlayer.Builder(context)
.setMediaSourceFactory(defaultMediaSourceFactory)
.build();
If you setup your player this way, it will read from the cache if media is in the cache, and asks the upstream data source if not and stream the data from the original source. So there is no need for a controller to know whether a media item is downloaded or not, the controller just tells the session to play the media item either way.
See general docs about 'Playing downloaded content'.
If you are having a multi-process architecture that separates downloading and playback in different processes, I think it's worth to try to move this into the same process. The alternative is writing a cross-process capable Cache
implementation.
Yes, this solution worked.
What I did was once I got the DownloadRequest
object, I converted it into a media item using DownloadRequest.toMediaItem()
. Then I added my necessary media MediaMetaData
by building upon the existing media items and then set the media items using controller.setMediaItems(updatedMediaItems)
.
After this, as you instructed, I used my existing download cache and create a cacheDataSourceFactory
and set it to Exoplayer with setMediaSourceFactory()
So, I have implemented a download feature for my audio app following the docs that uses a
DownloadUtil
andDownloadTracker
which in turn usesDownloadManager
to do so. Now the download is working fine. After a file is downloaded, I am getting themediaSource
properly.If
isFromDownloads
is true then I want to play the downloaded file. This code section is from a Fragment and I have access toMediaController
. As you can see, that if internet is present then media is being streamed and I am setting media items using the controller and seeking according to my needs which is being played from insideonAddMediaItems()
usingplayer.prepare()
andplayer.play()
. But I don't know how to do the same for downloaded content.I am not really sure where to post this. So, I posted this here. If you need any other info or context related to code, I'll be happy to explain.