Update AndroidX Media and ExoPlayer (#5371)
This commit is contained in:
parent
add003c06b
commit
434cd2b79f
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 + ")");
|
||||
|
|
Loading…
Reference in New Issue