Using https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.html is there a way to grab all the MediaSources that have been cached?
Asked
Active
Viewed 4,672 times
2 Answers
7
The Cache offers no convenient API to get all completely cached URIs or similar.
If you create your own CacheEvictor (for instance by wrapping a LeastRecentlyUsedCacheEvictor) you can do your own book keeping when spans are added or removed and then delegate to the LRUCacheEvictor. This way you can maintain a list of cached URLs.
You can check what portions for a given uri is cached:
// create the data spec of a given media file
Uri uri = Uri.parse("http://cool.stuff.com/song-123.mp3")
DataSpec dataSpec = new DataSpec(uri);
// get information about what is cached for the given data spec
CacheUtil.CachingCounters counters = new CacheUtil.CachingCounters();
CacheUtil.getCached(dataSpec, cache, counters);
if (counters.contentLength == counters.totalCachedBytes()) {
// all bytes cached
} else if (counters.totalCachedBytes() == 0){
// not cached at all
} else {
// partially cached
}
If the data for a given uri is only partially cached you can check what spans are available like this:
NavigableSet<CacheSpan> cachedSpans =
cache.getCachedSpans(CacheUtil.generateKey(uri));

marcbaechinger
- 2,759
- 18
- 21
-
This is incredibly helpful, thank you! I will definitely be using this, but it doesn't directly answer the question that I was originally trying to ask (I probably should have clarified it more). As far as each uri that is in cache, do I need to maintain a list of URIs as the enter and leave cache on my own, or is there a way to just grab every available URI in the cache? If I need to maintain it myself, what is the best way to do that. Thank you again for your insight! – Nic Capdevila Jan 04 '18 at 19:14
-
1What's the use case you are trying to implement? Actually, why do you need to know what is in the cache? If you are trying to achieve offline behaviour in a controlled way I recommend using a downloader: https://github.com/google/ExoPlayer/blob/release-v2/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java – marcbaechinger Jan 04 '18 at 20:04
-
The overarching goal is that my audio only player will be pulling down new tracks, and caching them as it goes, and if for some reason it fails to pull down a new track (bad connection or server issues), it should grab a track from cache to continue seamless playback, while continuing this process (get a new track from server if possible, if not, move to the next cached track). When grabbing cache, it should grab the oldest track (to prevent a repetition) and then mark it as recently used (so the next time it doesn't grab the same track). Does that all make sense? – Nic Capdevila Jan 04 '18 at 20:27
-
1I understand. Yes I think you need to maintain a map of uris/keys yourself. If you are using a SimpleCache you may want to create your own CacheEvictor. This can be based on eg. the LeastRecentlyCacheEvictor which in addition keeps track of which urls are completely cached (in onSpanAdded) and adds them to the list if so. As soon as a span for this uri/key is removed you need to remove the uri from that list again. In case of network loss you ask the evictor for the list of uris. – marcbaechinger Jan 04 '18 at 22:04
-
That makes perfect sense to me. I am also looking more into this ProgressiveDownloader as it may be useful for my use-case. Looking through the ExoPlayer repo, it seems that it's only being used in tests, do you happen to know offhand if there's any resources or real usages of it or any other downloader that you could point me to? Thank you so very much for your help. – Nic Capdevila Jan 04 '18 at 22:11
-
I can't give you references, but rest assured ExoPlayers Caches is used by significant apps in production. – marcbaechinger Jan 04 '18 at 22:29
2
CacheUtil no longer exists, https://github.com/google/ExoPlayer/blob/2a88f0fb295ff5b56e6fbcbe7e91bdf922cbae13/RELEASENOTES.md#2120-2020-09-11
there is another way to check cached content:
import com.google.android.exoplayer2.upstream.DataSpec
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
import com.google.android.exoplayer2.upstream.cache.ContentMetadata
import com.google.android.exoplayer2.upstream.cache.Cache
/* the same instance, used in player build pipeline */
lateinit var cacheDataSourceFactory: CacheDataSource.Factory
/* usually this is SimpleCache instance, also used in player build pipeline */
lateinit var cacheImpl: Cache
fun isCompletelyCached(urL :String) :Boolean {
val uri = Uri.parse(urL)
// factory which is used to generate "content key" for uri.
// content keys are not always equal to urL
// in complex cases the factory may be different from default implementation
val cacheKeyFactory = cacheDataSourceFactory.cacheKeyFactory
// content key used to retrieve metadata for cache entry
val contentKey = cacheKeyFactory.buildCacheKey(DataSpec(uri))
val contentMetadata = cache.getContentMetadata(contentKey)
val contentLength = ContentMetadata.getContentLength(contentMetadata)
if(contentLength < 0){
// this happens when player has never queried this urL over network
// or has no info about size of the source
return false
}
// this is summary for all cache spans, cached by exoplayer, which belongs to given urL.
// each span is a chunk of content, which may be randomly downloaded
val cachedLength = cache.getCachedBytes(contentKey, 0L, contentLength)
return contentLength == cachedLength
}

dmz9
- 163
- 1
- 7