Update AndroidX Media and ExoPlayer (#5371)

This commit is contained in:
Taco 2021-12-10 15:28:09 -05:00 committed by GitHub
parent add003c06b
commit 434cd2b79f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 23 deletions

View File

@ -2,6 +2,7 @@ package de.test.antennapod.service.playback;
import android.content.Context;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.MediumTest;
import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting;
@ -56,12 +57,14 @@ public class PlaybackServiceMediaPlayerTest {
private volatile AssertionFailedError assertionError;
@After
@UiThreadTest
public void tearDown() throws Exception {
PodDBAdapter.deleteDatabase();
httpServer.stop();
}
@Before
@UiThreadTest
public void setUp() throws Exception {
assertionError = null;
EspressoTestUtils.clearPreferences();
@ -117,6 +120,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testInit() {
final Context c = getInstrumentation().getTargetContext();
PlaybackServiceMediaPlayer psmp = new LocalPSMP(c, new DefaultPSMPCallback());
@ -141,6 +145,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPlayMediaObjectStreamNoStartNoPrepare() throws InterruptedException {
final Context c = getInstrumentation().getTargetContext();
final CountDownLatch countDownLatch = new CountDownLatch(2);
@ -181,6 +186,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPlayMediaObjectStreamStartNoPrepare() throws InterruptedException {
final Context c = getInstrumentation().getTargetContext();
final CountDownLatch countDownLatch = new CountDownLatch(2);
@ -222,6 +228,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPlayMediaObjectStreamNoStartPrepare() throws InterruptedException {
final Context c = getInstrumentation().getTargetContext();
final CountDownLatch countDownLatch = new CountDownLatch(4);
@ -264,6 +271,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPlayMediaObjectStreamStartPrepare() throws InterruptedException {
final Context c = getInstrumentation().getTargetContext();
final CountDownLatch countDownLatch = new CountDownLatch(5);
@ -308,6 +316,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPlayMediaObjectLocalNoStartNoPrepare() throws InterruptedException {
final Context c = getInstrumentation().getTargetContext();
final CountDownLatch countDownLatch = new CountDownLatch(2);
@ -347,6 +356,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPlayMediaObjectLocalStartNoPrepare() throws InterruptedException {
final Context c = getInstrumentation().getTargetContext();
final CountDownLatch countDownLatch = new CountDownLatch(2);
@ -386,6 +396,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPlayMediaObjectLocalNoStartPrepare() throws InterruptedException {
final Context c = getInstrumentation().getTargetContext();
final CountDownLatch countDownLatch = new CountDownLatch(4);
@ -427,6 +438,7 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPlayMediaObjectLocalStartPrepare() throws InterruptedException {
final Context c = getInstrumentation().getTargetContext();
final CountDownLatch countDownLatch = new CountDownLatch(5);
@ -530,46 +542,55 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPauseDefaultState() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.STOPPED, false, false, false, 1);
}
@Test
@UiThreadTest
public void testPausePlayingStateNoAbandonNoReinitNoStream() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.PLAYING, false, false, false, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPausePlayingStateNoAbandonNoReinitStream() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.PLAYING, true, false, false, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPausePlayingStateAbandonNoReinitNoStream() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.PLAYING, false, true, false, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPausePlayingStateAbandonNoReinitStream() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.PLAYING, true, true, false, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPausePlayingStateNoAbandonReinitNoStream() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.PLAYING, false, false, true, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPausePlayingStateNoAbandonReinitStream() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.PLAYING, true, false, true, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPausePlayingStateAbandonReinitNoStream() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.PLAYING, false, true, true, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPausePlayingStateAbandonReinitStream() throws InterruptedException {
pauseTestSkeleton(PlayerStatus.PLAYING, true, true, true, LATCH_TIMEOUT_SECONDS);
}
@ -616,16 +637,19 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testResumePausedState() throws InterruptedException {
resumeTestSkeleton(PlayerStatus.PAUSED, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testResumePreparedState() throws InterruptedException {
resumeTestSkeleton(PlayerStatus.PREPARED, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testResumePlayingState() throws InterruptedException {
resumeTestSkeleton(PlayerStatus.PLAYING, 1);
}
@ -678,21 +702,25 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testPrepareInitializedState() throws InterruptedException {
prepareTestSkeleton(PlayerStatus.INITIALIZED, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPreparePlayingState() throws InterruptedException {
prepareTestSkeleton(PlayerStatus.PLAYING, 1);
}
@Test
@UiThreadTest
public void testPreparePausedState() throws InterruptedException {
prepareTestSkeleton(PlayerStatus.PAUSED, 1);
}
@Test
@UiThreadTest
public void testPreparePreparedState() throws InterruptedException {
prepareTestSkeleton(PlayerStatus.PREPARED, 1);
}
@ -735,21 +763,25 @@ public class PlaybackServiceMediaPlayerTest {
}
@Test
@UiThreadTest
public void testReinitPlayingState() throws InterruptedException {
reinitTestSkeleton(PlayerStatus.PLAYING, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testReinitPausedState() throws InterruptedException {
reinitTestSkeleton(PlayerStatus.PAUSED, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testPreparedPlayingState() throws InterruptedException {
reinitTestSkeleton(PlayerStatus.PREPARED, LATCH_TIMEOUT_SECONDS);
}
@Test
@UiThreadTest
public void testReinitInitializedState() throws InterruptedException {
reinitTestSkeleton(PlayerStatus.INITIALIZED, LATCH_TIMEOUT_SECONDS);
}

View File

@ -43,7 +43,7 @@ project.ext {
appcompatVersion = "1.3.1"
coreVersion = "1.5.0"
fragmentVersion = "1.3.6"
mediaVersion = "1.1.0"
mediaVersion = "1.4.3"
paletteVersion = "1.0.0"
preferenceVersion = "1.1.1"
recyclerViewVersion = "1.2.1"
@ -62,7 +62,7 @@ project.ext {
rxAndroidVersion = "2.1.1"
rxJavaVersion = "2.2.2"
iconifyVersion = "2.2.2"
exoPlayerVersion = "2.11.8"
exoPlayerVersion = "2.14.2"
audioPlayerVersion = "v2.0.0"
// Only used for free builds. This version should be updated regularly.

View File

@ -3,12 +3,13 @@ package de.danoeh.antennapod.core.glide;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.bumptech.glide.Priority;
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import com.google.android.exoplayer2.util.Log;
import okhttp3.Call;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@ -22,7 +23,7 @@ import java.io.InputStream;
import java.io.OutputStream;
public class ResizingOkHttpStreamFetcher extends OkHttpStreamFetcher {
private static final String TAG = "ResizingOkHttpStreamFetcher";
private static final String TAG = "ResizingOkHttpStreamFet";
private static final int MAX_DIMENSIONS = 1500;
private static final int MAX_FILE_SIZE = 1024 * 1024; // 1 MB

View File

@ -12,20 +12,21 @@ import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory;
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.DefaultTrackNameProvider;
import com.google.android.exoplayer2.ui.TrackNameProvider;
@ -48,6 +49,7 @@ import org.antennapod.audio.MediaPlayer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -88,12 +90,12 @@ public class ExoPlayerWrapper implements IPlayer {
trackSelector = new DefaultTrackSelector(context);
exoPlayer = new SimpleExoPlayer.Builder(context, new DefaultRenderersFactory(context))
.setTrackSelector(trackSelector)
.setLoadControl(loadControl.createDefaultLoadControl())
.setLoadControl(loadControl.build())
.build();
exoPlayer.setSeekParameters(SeekParameters.EXACT);
exoPlayer.addListener(new Player.EventListener() {
exoPlayer.addListener(new Player.Listener() {
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
public void onPlaybackStateChanged(@Player.State int playbackState) {
if (audioCompletionListener != null && playbackState == Player.STATE_ENDED) {
audioCompletionListener.onCompletion(null);
} else if (infoListener != null && playbackState == Player.STATE_BUFFERING) {
@ -119,8 +121,10 @@ public class ExoPlayerWrapper implements IPlayer {
}
@Override
public void onSeekProcessed() {
if (audioSeekCompleteListener != null) {
public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition,
@NonNull Player.PositionInfo newPosition,
@Player.DiscontinuityReason int reason) {
if (audioSeekCompleteListener != null && reason == Player.DISCONTINUITY_REASON_SEEK) {
audioSeekCompleteListener.onSeekComplete(null);
}
}
@ -157,12 +161,13 @@ public class ExoPlayerWrapper implements IPlayer {
@Override
public void pause() {
exoPlayer.setPlayWhenReady(false);
exoPlayer.pause();
}
@Override
public void prepare() throws IllegalStateException {
exoPlayer.prepare(mediaSource, false, true);
exoPlayer.setMediaSource(mediaSource, false);
exoPlayer.prepare();
}
@Override
@ -198,25 +203,31 @@ public class ExoPlayerWrapper implements IPlayer {
b.setContentType(i);
b.setFlags(a.flags);
b.setUsage(a.usage);
exoPlayer.setAudioAttributes(b.build());
exoPlayer.setAudioAttributes(b.build(), false);
}
public void setDataSource(String s, String user, String password)
throws IllegalArgumentException, IllegalStateException {
Log.d(TAG, "setDataSource: " + s);
OkHttpDataSourceFactory httpDataSourceFactory = new OkHttpDataSourceFactory(
AntennapodHttpClient.getHttpClient(), ClientConfig.USER_AGENT);
final OkHttpDataSource.Factory httpDataSourceFactory =
new OkHttpDataSource.Factory(AntennapodHttpClient.getHttpClient())
.setUserAgent(ClientConfig.USER_AGENT);
if (!TextUtils.isEmpty(user) && !TextUtils.isEmpty(password)) {
httpDataSourceFactory.getDefaultRequestProperties().set("Authorization",
HttpDownloader.encodeCredentials(user, password, "ISO-8859-1"));
final HashMap<String, String> requestProperties = new HashMap<>();
requestProperties.put(
"Authorization",
HttpDownloader.encodeCredentials(user, password, "ISO-8859-1")
);
httpDataSourceFactory.setDefaultRequestProperties(requestProperties);
}
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, null, httpDataSourceFactory);
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
extractorsFactory.setConstantBitrateSeekingEnabled(true);
extractorsFactory.setMp3ExtractorFlags(Mp3Extractor.FLAG_DISABLE_ID3_METADATA);
ProgressiveMediaSource.Factory f = new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory);
mediaSource = f.createMediaSource(Uri.parse(s));
final MediaItem mediaItem = MediaItem.fromUri(Uri.parse(s));
mediaSource = f.createMediaSource(mediaItem);
}
@Override
@ -231,7 +242,8 @@ public class ExoPlayerWrapper implements IPlayer {
@Override
public void setPlaybackParams(float speed, boolean skipSilence) {
playbackParameters = new PlaybackParameters(speed, playbackParameters.pitch, skipSilence);
playbackParameters = new PlaybackParameters(speed, playbackParameters.pitch);
exoPlayer.setSkipSilenceEnabled(skipSilence);
exoPlayer.setPlaybackParameters(playbackParameters);
}
@ -252,7 +264,7 @@ public class ExoPlayerWrapper implements IPlayer {
@Override
public void start() {
exoPlayer.setPlayWhenReady(true);
exoPlayer.play();
// Can't set params when paused - so always set it on start in case they changed
exoPlayer.setPlaybackParameters(playbackParameters);
}
@ -312,7 +324,7 @@ public class ExoPlayerWrapper implements IPlayer {
TrackSelectionArray trackSelections = exoPlayer.getCurrentTrackSelections();
List<Format> availableFormats = getFormats();
for (int i = 0; i < trackSelections.length; i++) {
TrackSelection track = trackSelections.get(i);
ExoTrackSelection track = (ExoTrackSelection) trackSelections.get(i);
if (track == null) {
continue;
}

View File

@ -1231,7 +1231,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
| PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_FAST_FORWARD
| PlaybackStateCompat.ACTION_SKIP_TO_NEXT
| PlaybackStateCompat.ACTION_SEEK_TO;
| PlaybackStateCompat.ACTION_SEEK_TO
| PlaybackStateCompat.ACTION_SET_PLAYBACK_SPEED;
if (useSkipToPreviousForRewindInLockscreen()) {
// Workaround to fool Android so that Lockscreen will expose a skip-to-previous button,
@ -1887,6 +1888,12 @@ public class PlaybackService extends MediaBrowserServiceCompat {
seekTo((int) pos);
}
@Override
public void onSetPlaybackSpeed(float speed) {
Log.d(TAG, "onSetPlaybackSpeed()");
setSpeed(speed);
}
@Override
public boolean onMediaButtonEvent(final Intent mediaButton) {
Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");