I am trying to stream videos from URLs and save them in cache during the same time.
I am using the DataBaseInspector of Android Studio to check the cache and it seems to work but not all the time.
Sometimes i have this error when i try to play a video :
2021-01-21 10:27:12.956 26648-28069/test.com.test E/ExoPlayerImplInternal: Playback error
com.google.android.exoplayer2.ExoPlaybackException: Source error
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:554)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:238)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.io.IOException: DummyDataSource cannot be opened
at com.google.android.exoplayer2.upstream.DummyDataSource.open(DummyDataSource.java:39)
at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:764)
at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:579)
at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:84)
at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1017)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:415)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Reading the error we can see an IOException, so i have checked the path in cache and again it's working sometimes... The keys i register in the exoplayer internal db are the URLs (i let the exoplayer do all the job but i checked myself after).
Here is my code :
@Inject
public VideoCacheManager(@NonNull SimpleCache simpleCache, @ActivityContext Context context) {
this.simpleCache = simpleCache;
this.context = context;
cacheDataSource = new CacheDataSource.Factory();
cacheDataSource.setCache(simpleCache);
Log.d(TAG, "VideoCacheManager: cache size left : " + simpleCache.getCacheSpace());
cacheDataSource.setEventListener(new CacheDataSource.EventListener() {
@Override
public void onCachedBytesRead(long cacheSizeBytes, long cachedBytesRead) {
Log.d(TAG, "onCachedBytesRead: cached bytes read : " + cachedBytesRead);
}
@Override
public void onCacheIgnored(int reason) {
Log.d(TAG, "onCacheIgnored: cache ignored : " + reason);
}
});
}
public MediaSource buildMediaSource(MediaItem mediaItem) {
return new ProgressiveMediaSource.Factory(cacheDataSource).createMediaSource(mediaItem);
}
And SimpleCache is a Singleton injected with Hilt :
@Provides
@Singleton
public static SimpleCache simpleCache(@ApplicationContext Context context) {
return new SimpleCache(context.getApplicationContext().getCacheDir(), leastRecentlyUsedCacheEvictor(), exoDatabaseProvider(context));
}
@Provides
@Singleton
public static LeastRecentlyUsedCacheEvictor leastRecentlyUsedCacheEvictor() {
return new LeastRecentlyUsedCacheEvictor(exoPlayerCacheSize());
}
@Provides
@Singleton
public static Long exoPlayerCacheSize() {
return (long) (500 * 1024 * 1024);
}
@Provides
@Singleton
public static ExoDatabaseProvider exoDatabaseProvider(@ApplicationContext Context context) {
return new ExoDatabaseProvider(context);
}
And in my ExoPlayer class i have a simple method :
public void prepare(MediaItem mediaItem) {
lastMediaItem = mediaItem;
Log.d(TAG, "prepare: media item : " + mediaItem.playbackProperties);
MediaSource mediaSource = videoCacheManager.buildMediaSource(mediaItem);
Log.d(TAG, "prepare: source : " + mediaSource.getInitialTimeline());
simpleExoPlayer.prepare(mediaSource);
}
I have read enough about the exoplayer and it is supposed to do download to the cache the video if it does not exist, during the first streaming session... So what is this error and how to fix it ?
The first time i have used this code it worked, then i have cleared everything and retried without success.
Okay i simply must have removed the DefaultDataSourceFactory
by mistake and forgot to set back an UpstreamDataSource
to the CacheDataSource
instance.
Everything works fine now, hope this helps others.
In code we need to add this :
DefaultDataSourceFactory defaultDataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, context.getString(R.string.app_name)));
cacheDataSource.setUpstreamDataSourceFactory(defaultDataSourceFactory);
I have also learn a lot about ExoPlayer
watching this video, despite it was in 2018 with the exoplayer version 2.8.
I am using the latest at the moment, meaning 2.12.3.