mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2026-08-18 02:53:10 +00:00
Enable media3 disk cache in new playback service (#8552)
### Description Enable media3 disk cache in new playback service Closes #8487 ### Checklist <!-- To help us keep the issue tracker clean and work as efficient as possible, please make sure that you have done all of the following. You can tick the boxes below by placing an x inside the brackets like this: [x] --> - [x] I have read the contribution guidelines: https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md#submit-a-pull-request - [x] I have performed a self-review of my code, going through my changes line by line and carefully considering why this line change is necessary - [x] I have run the automated code checks using `./gradlew checkstyle lint` - [x] My code follows the style guidelines of the AntennaPod project: https://antennapod.org/contribute/develop/app/code-style - [x] I have mentioned the corresponding issue and the relevant keyword (e.g., "Closes: #xy") in the description (see https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) - [x] If it is a core feature, I have added automated tests
This commit is contained in:
committed by
GitHub
parent
5442a66573
commit
e977dad7fc
@ -357,6 +357,7 @@ public class Media3PlaybackService extends MediaLibraryService {
|
||||
player.removeListener(playerListener);
|
||||
player.release();
|
||||
}
|
||||
ExoPlayerUtils.releaseCache();
|
||||
if (mediaSession != null) {
|
||||
mediaSession.release();
|
||||
}
|
||||
|
||||
@ -9,11 +9,15 @@ import androidx.media3.common.C;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.PlaybackException;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.database.StandaloneDatabaseProvider;
|
||||
import androidx.media3.datasource.DataSource;
|
||||
import androidx.media3.datasource.DefaultDataSource;
|
||||
import androidx.media3.datasource.DefaultHttpDataSource;
|
||||
import androidx.media3.datasource.HttpDataSource;
|
||||
import androidx.media3.datasource.ResolvingDataSource;
|
||||
import androidx.media3.datasource.cache.CacheDataSource;
|
||||
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor;
|
||||
import androidx.media3.datasource.cache.SimpleCache;
|
||||
import de.danoeh.antennapod.net.common.RedirectChecker;
|
||||
import androidx.media3.exoplayer.DefaultLoadControl;
|
||||
import androidx.media3.exoplayer.ExoPlayer;
|
||||
@ -30,32 +34,48 @@ import de.danoeh.antennapod.playback.base.MediaItemAdapter;
|
||||
import de.danoeh.antennapod.playback.service.R;
|
||||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class ExoPlayerUtils {
|
||||
private static volatile SimpleCache simpleCache;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public static ExoPlayer buildPlayer(Context context) {
|
||||
if (simpleCache == null) {
|
||||
simpleCache = new SimpleCache(new File(context.getCacheDir(), "streaming"),
|
||||
new LeastRecentlyUsedCacheEvictor(100 * 1024 * 1024),
|
||||
new StandaloneDatabaseProvider(context));
|
||||
}
|
||||
return new ExoPlayer.Builder(context)
|
||||
.setLoadControl(new DefaultLoadControl.Builder()
|
||||
.setBufferDurationsMs(
|
||||
(int) (UserPreferences.getFastForwardSecs() * 1000L),
|
||||
Math.max(DefaultLoadControl.DEFAULT_MAX_BUFFER_MS,
|
||||
(int) (UserPreferences.getFastForwardSecs() * 1000L)),
|
||||
(int) TimeUnit.HOURS.toMillis(1),
|
||||
(int) TimeUnit.HOURS.toMillis(3),
|
||||
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
|
||||
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)
|
||||
.setBackBuffer((int) (3 * UserPreferences.getRewindSecs() * 1000L), true)
|
||||
.setBackBuffer((int) TimeUnit.MINUTES.toMillis(5), true)
|
||||
.build())
|
||||
.setAudioAttributes(new AudioAttributes.Builder()
|
||||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.AUDIO_CONTENT_TYPE_SPEECH)
|
||||
.build(), true)
|
||||
.setMediaSourceFactory(new ApMediaSourceFactory(context))
|
||||
.setMediaSourceFactory(new ApMediaSourceFactory(context, simpleCache))
|
||||
.setSeekParameters(SeekParameters.EXACT)
|
||||
.setHandleAudioBecomingNoisy(UserPreferences.isPauseOnHeadsetDisconnect())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void releaseCache() {
|
||||
if (simpleCache != null) {
|
||||
simpleCache.release();
|
||||
simpleCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String translateErrorReason(@NonNull PlaybackException error, Context context) {
|
||||
if (NetworkUtils.wasDownloadBlocked(error)) {
|
||||
return context.getString(R.string.download_error_blocked);
|
||||
@ -86,11 +106,13 @@ public class ExoPlayerUtils {
|
||||
private final DefaultExtractorsFactory extractorsFactory;
|
||||
private final DefaultMediaSourceFactory defaultFactory;
|
||||
private final Context context;
|
||||
private final SimpleCache simpleCache;
|
||||
private final ConcurrentHashMap<String, String> redirectCache = new ConcurrentHashMap<>();
|
||||
|
||||
public ApMediaSourceFactory(Context context) {
|
||||
public ApMediaSourceFactory(Context context, SimpleCache simpleCache) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.simpleCache = simpleCache;
|
||||
this.extractorsFactory = new DefaultExtractorsFactory();
|
||||
this.extractorsFactory.setConstantBitrateSeekingEnabled(true);
|
||||
this.extractorsFactory.setMp3ExtractorFlags(Mp3Extractor.FLAG_DISABLE_ID3_METADATA);
|
||||
@ -140,7 +162,7 @@ public class ExoPlayerUtils {
|
||||
Collections.singletonMap("Authorization", authHeader));
|
||||
}
|
||||
DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(context, httpDataSourceFactory);
|
||||
return new ResolvingDataSource.Factory(dataSourceFactory, dataSpec -> {
|
||||
DataSource.Factory resolvingFactory = new ResolvingDataSource.Factory(dataSourceFactory, dataSpec -> {
|
||||
String originalUrl = dataSpec.uri.toString();
|
||||
if (!originalUrl.startsWith("http")) {
|
||||
return dataSpec;
|
||||
@ -155,6 +177,14 @@ public class ExoPlayerUtils {
|
||||
}
|
||||
return dataSpec.withUri(Uri.parse(resolvedUrl));
|
||||
});
|
||||
String uri = mediaItem.localConfiguration != null
|
||||
? mediaItem.localConfiguration.uri.toString() : "";
|
||||
if (uri.startsWith("http")) {
|
||||
return new CacheDataSource.Factory()
|
||||
.setCache(simpleCache)
|
||||
.setUpstreamDataSourceFactory(resolvingFactory);
|
||||
}
|
||||
return resolvingFactory;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
Reference in New Issue
Block a user