diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
index 2de117e9d7..2f8d0045d3 100644
--- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
+++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
@@ -394,8 +394,7 @@ public class PlayerActivity extends AppCompatActivity
if (haveStartPosition) {
player.seekTo(startWindow, startPosition);
}
- player.setMediaItem(mediaSource);
- player.prepare();
+ player.prepare(mediaSource, !haveStartPosition, false);
updateButtonVisibility();
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
index 99089a2afc..7c8a454191 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
@@ -331,51 +331,26 @@ public interface ExoPlayer extends Player {
*/
void retry();
- /** Prepares the player. */
- void prepare();
-
/**
- * @deprecated Use {@code setMediaItem(mediaSource, C.TIME_UNSET)} and {@link #prepare()} instead.
+ * Prepares the player to play the provided {@link MediaSource}. Equivalent to {@code
+ * prepare(mediaSource, true, true)}.
*/
- @Deprecated
void prepare(MediaSource mediaSource);
- /** @deprecated Use {@link #setMediaItem(MediaSource, long)} and {@link #prepare()} instead. */
- @Deprecated
+ /**
+ * Prepares the player to play the provided {@link MediaSource}, optionally resetting the playback
+ * position the default position in the first {@link Timeline.Window}.
+ *
+ * @param mediaSource The {@link MediaSource} to play.
+ * @param resetPosition Whether the playback position should be reset to the default position in
+ * the first {@link Timeline.Window}. If false, playback will start from the position defined
+ * by {@link #getCurrentWindowIndex()} and {@link #getCurrentPosition()}.
+ * @param resetState Whether the timeline, manifest, tracks and track selections should be reset.
+ * Should be true unless the player is being prepared to play the same media as it was playing
+ * previously (e.g. if playback failed and is being retried).
+ */
void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState);
- /**
- * Sets the specified {@link MediaSource}.
- *
- *
Note: This is an intermediate implementation towards a larger change. Until then {@link
- * #prepare()} has to be called immediately after calling this method.
- *
- * @param mediaItem The new {@link MediaSource}.
- */
- void setMediaItem(MediaSource mediaItem);
-
- /**
- * Sets the specified {@link MediaSource}.
- *
- *
Note: This is an intermediate implementation towards a larger change. Until then {@link
- * #prepare()} has to be called immediately after calling this method.
- *
- *
This intermediate implementation calls {@code stop(true)} before seeking to avoid seeking in
- * a media item that has been set previously. It is equivalent with calling
- *
- *
- * if (!getCurrentTimeline().isEmpty()) {
- * player.stop(true);
- * }
- * player.seekTo(0, startPositionMs);
- * player.setMediaItem(mediaItem);
- *
- *
- * @param mediaItem The new {@link MediaSource}.
- * @param startPositionMs The position in milliseconds to start playback from.
- */
- void setMediaItem(MediaSource mediaItem, long startPositionMs);
-
/**
* Creates a message that can be sent to a {@link PlayerMessage.Target}. By default, the message
* will be delivered immediately without blocking on the playback thread. The default {@link
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
index 97658d2906..dd8fbee53c 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
@@ -62,7 +62,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
private final Timeline.Period period;
private final ArrayDeque pendingListenerNotifications;
- @Nullable private MediaSource mediaSource;
+ private MediaSource mediaSource;
private boolean playWhenReady;
@PlaybackSuppressionReason private int playbackSuppressionReason;
@RepeatMode private int repeatMode;
@@ -219,38 +219,34 @@ import java.util.concurrent.CopyOnWriteArrayList;
}
@Override
- @Deprecated
public void prepare(MediaSource mediaSource) {
- setMediaItem(mediaSource);
- prepareInternal(/* resetPosition= */ true, /* resetState= */ true);
+ prepare(mediaSource, /* resetPosition= */ true, /* resetState= */ true);
}
@Override
- @Deprecated
public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) {
- setMediaItem(mediaSource);
- prepareInternal(resetPosition, resetState);
+ this.mediaSource = mediaSource;
+ PlaybackInfo playbackInfo =
+ getResetPlaybackInfo(
+ resetPosition,
+ resetState,
+ /* resetError= */ true,
+ /* playbackState= */ Player.STATE_BUFFERING);
+ // Trigger internal prepare first before updating the playback info and notifying external
+ // listeners to ensure that new operations issued in the listener notifications reach the
+ // player after this prepare. The internal player can't change the playback info immediately
+ // because it uses a callback.
+ hasPendingPrepare = true;
+ pendingOperationAcks++;
+ internalPlayer.prepare(mediaSource, resetPosition, resetState);
+ updatePlaybackInfo(
+ playbackInfo,
+ /* positionDiscontinuity= */ false,
+ /* ignored */ DISCONTINUITY_REASON_INTERNAL,
+ TIMELINE_CHANGE_REASON_RESET,
+ /* seekProcessed= */ false);
}
- @Override
- public void prepare() {
- Assertions.checkNotNull(mediaSource);
- prepareInternal(/* resetPosition= */ false, /* resetState= */ true);
- }
-
- @Override
- public void setMediaItem(MediaSource mediaItem, long startPositionMs) {
- if (!getCurrentTimeline().isEmpty()) {
- stop(/* reset= */ true);
- }
- seekTo(/* windowIndex= */ 0, startPositionMs);
- setMediaItem(mediaItem);
- }
-
- @Override
- public void setMediaItem(MediaSource mediaItem) {
- mediaSource = mediaItem;
- }
@Override
public void setPlayWhenReady(boolean playWhenReady) {
@@ -610,29 +606,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
}
}
- /* package */ void prepareInternal(boolean resetPosition, boolean resetState) {
- Assertions.checkNotNull(mediaSource);
- PlaybackInfo playbackInfo =
- getResetPlaybackInfo(
- resetPosition,
- resetState,
- /* resetError= */ true,
- /* playbackState= */ Player.STATE_BUFFERING);
- // Trigger internal prepare first before updating the playback info and notifying external
- // listeners to ensure that new operations issued in the listener notifications reach the
- // player after this prepare. The internal player can't change the playback info immediately
- // because it uses a callback.
- hasPendingPrepare = true;
- pendingOperationAcks++;
- internalPlayer.prepare(mediaSource, resetPosition, resetState);
- updatePlaybackInfo(
- playbackInfo,
- /* positionDiscontinuity= */ false,
- /* ignored */ DISCONTINUITY_REASON_INTERNAL,
- TIMELINE_CHANGE_REASON_RESET,
- /* seekProcessed= */ false);
- }
-
private void handlePlaybackParameters(
PlaybackParameters playbackParameters, boolean operationAck) {
if (operationAck) {
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
index f1d01a114f..729dd150ae 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
@@ -1162,7 +1162,6 @@ public class SimpleExoPlayer extends BasePlayer
}
@Override
- @SuppressWarnings("deprecation")
public void retry() {
verifyApplicationThread();
if (mediaSource != null
@@ -1172,38 +1171,23 @@ public class SimpleExoPlayer extends BasePlayer
}
@Override
- @Deprecated
- @SuppressWarnings("deprecation")
public void prepare(MediaSource mediaSource) {
prepare(mediaSource, /* resetPosition= */ true, /* resetState= */ true);
}
@Override
- @Deprecated
public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) {
verifyApplicationThread();
- setMediaItem(mediaSource);
- prepareInternal(resetPosition, resetState);
- }
-
- @Override
- public void prepare() {
- verifyApplicationThread();
- prepareInternal(/* resetPosition= */ false, /* resetState= */ true);
- }
-
- @Override
- public void setMediaItem(MediaSource mediaItem, long startPositionMs) {
- verifyApplicationThread();
- setMediaItemInternal(mediaItem);
- player.setMediaItem(mediaItem, startPositionMs);
- }
-
- @Override
- public void setMediaItem(MediaSource mediaItem) {
- verifyApplicationThread();
- setMediaItemInternal(mediaItem);
- player.setMediaItem(mediaItem);
+ if (this.mediaSource != null) {
+ this.mediaSource.removeEventListener(analyticsCollector);
+ analyticsCollector.resetForNewMediaSource();
+ }
+ this.mediaSource = mediaSource;
+ mediaSource.addEventListener(eventHandler, analyticsCollector);
+ @AudioFocusManager.PlayerCommand
+ int playerCommand = audioFocusManager.handlePrepare(getPlayWhenReady());
+ updatePlayWhenReady(getPlayWhenReady(), playerCommand);
+ player.prepare(mediaSource, resetPosition, resetState);
}
@Override
@@ -1448,23 +1432,6 @@ public class SimpleExoPlayer extends BasePlayer
// Internal methods.
- private void prepareInternal(boolean resetPosition, boolean resetState) {
- Assertions.checkNotNull(mediaSource);
- @AudioFocusManager.PlayerCommand
- int playerCommand = audioFocusManager.handlePrepare(getPlayWhenReady());
- updatePlayWhenReady(getPlayWhenReady(), playerCommand);
- player.prepareInternal(resetPosition, resetState);
- }
-
- private void setMediaItemInternal(MediaSource mediaItem) {
- if (mediaSource != null) {
- mediaSource.removeEventListener(analyticsCollector);
- analyticsCollector.resetForNewMediaSource();
- }
- mediaSource = mediaItem;
- mediaSource.addEventListener(eventHandler, analyticsCollector);
- }
-
private void removeSurfaceCallbacks() {
if (textureView != null) {
if (textureView.getSurfaceTextureListener() != componentListener) {
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
index 8bd6b1ba09..8ec8cca06c 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
@@ -16,7 +16,6 @@
package com.google.android.exoplayer2;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.fail;
import static org.robolectric.Shadows.shadowOf;
@@ -36,10 +35,7 @@ import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.source.ClippingMediaSource;
-import com.google.android.exoplayer2.source.CompositeMediaSource;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
-import com.google.android.exoplayer2.source.LoopingMediaSource;
-import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
@@ -1588,7 +1584,6 @@ public final class ExoPlayerTest {
AtomicInteger counter = new AtomicInteger();
ActionSchedule actionSchedule =
new ActionSchedule.Builder("testSendMessagesFromStartPositionOnlyOnce")
- .waitForTimelineChanged()
.pause()
.sendMessage(
(messageType, payload) -> {
@@ -2931,218 +2926,6 @@ public final class ExoPlayerTest {
assertThat(seenPlaybackSuppression.get()).isFalse();
}
- @Test
- public void testDelegatingMediaSourceApproach() throws Exception {
- Timeline fakeTimeline =
- new FakeTimeline(
- new TimelineWindowDefinition(
- /* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000));
- final ConcatenatingMediaSource underlyingSource = new ConcatenatingMediaSource();
- CompositeMediaSource delegatingMediaSource =
- new CompositeMediaSource() {
- @Override
- public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
- super.prepareSourceInternal(mediaTransferListener);
- underlyingSource.addMediaSource(
- new FakeMediaSource(fakeTimeline, Builder.VIDEO_FORMAT));
- underlyingSource.addMediaSource(
- new FakeMediaSource(fakeTimeline, Builder.VIDEO_FORMAT));
- prepareChildSource(null, underlyingSource);
- }
-
- @Override
- public MediaPeriod createPeriod(
- MediaPeriodId id, Allocator allocator, long startPositionUs) {
- return underlyingSource.createPeriod(id, allocator, startPositionUs);
- }
-
- @Override
- public void releasePeriod(MediaPeriod mediaPeriod) {
- underlyingSource.releasePeriod(mediaPeriod);
- }
-
- @Override
- protected void onChildSourceInfoRefreshed(
- Void id, MediaSource mediaSource, Timeline timeline) {
- refreshSourceInfo(timeline);
- }
- };
- int[] currentWindowIndices = new int[1];
- long[] currentPlaybackPositions = new long[1];
- long[] windowCounts = new long[1];
- int seekToWindowIndex = 1;
- ActionSchedule actionSchedule =
- new ActionSchedule.Builder("testDelegatingMediaSourceApproach")
- .seek(/* windowIndex= */ 1, /* positionMs= */ 5000)
- .waitForSeekProcessed()
- .executeRunnable(
- new PlayerRunnable() {
- @Override
- public void run(SimpleExoPlayer player) {
- currentWindowIndices[0] = player.getCurrentWindowIndex();
- currentPlaybackPositions[0] = player.getCurrentPosition();
- windowCounts[0] = player.getCurrentTimeline().getWindowCount();
- }
- })
- .build();
- ExoPlayerTestRunner exoPlayerTestRunner =
- new Builder()
- .setMediaSource(delegatingMediaSource)
- .setActionSchedule(actionSchedule)
- .build(context)
- .start()
- .blockUntilActionScheduleFinished(TIMEOUT_MS)
- .blockUntilEnded(TIMEOUT_MS);
- exoPlayerTestRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PREPARED);
- assertArrayEquals(new long[] {2}, windowCounts);
- assertArrayEquals(new int[] {seekToWindowIndex}, currentWindowIndices);
- assertArrayEquals(new long[] {5_000}, currentPlaybackPositions);
- }
-
- @Test
- public void testSeekTo_windowIndexIsReset_deprecated() throws Exception {
- FakeTimeline fakeTimeline = new FakeTimeline(/* windowCount= */ 1);
- FakeMediaSource mediaSource = new FakeMediaSource(fakeTimeline);
- LoopingMediaSource loopingMediaSource = new LoopingMediaSource(mediaSource, 2);
- final int[] windowIndex = {C.INDEX_UNSET};
- final long[] positionMs = {C.TIME_UNSET};
- ActionSchedule actionSchedule =
- new ActionSchedule.Builder("testSeekTo_windowIndexIsReset_deprecated")
- .seek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET)
- .waitForSeekProcessed()
- .playUntilPosition(/* windowIndex= */ 1, /* positionMs= */ 5000)
- .executeRunnable(
- new PlayerRunnable() {
- @Override
- public void run(SimpleExoPlayer player) {
- //noinspection deprecation
- player.prepare(mediaSource);
- player.seekTo(/* positionMs= */ 5000);
- }
- })
- .executeRunnable(
- new PlayerRunnable() {
- @Override
- public void run(SimpleExoPlayer player) {
- windowIndex[0] = player.getCurrentWindowIndex();
- positionMs[0] = player.getCurrentPosition();
- }
- })
- .build();
- new ExoPlayerTestRunner.Builder()
- .setMediaSource(loopingMediaSource)
- .setActionSchedule(actionSchedule)
- .build(context)
- .start()
- .blockUntilActionScheduleFinished(TIMEOUT_MS);
-
- assertThat(windowIndex[0]).isEqualTo(0);
- assertThat(positionMs[0]).isAtLeast(5000L);
- }
-
- @Test
- public void testSeekTo_windowIndexIsReset() throws Exception {
- FakeTimeline fakeTimeline = new FakeTimeline(/* windowCount= */ 1);
- FakeMediaSource mediaSource = new FakeMediaSource(fakeTimeline);
- LoopingMediaSource loopingMediaSource = new LoopingMediaSource(mediaSource, 2);
- final int[] windowIndex = {C.INDEX_UNSET};
- final long[] positionMs = {C.TIME_UNSET};
- ActionSchedule actionSchedule =
- new ActionSchedule.Builder("testSeekTo_windowIndexIsReset")
- .seek(/* windowIndex= */ 1, /* positionMs= */ C.TIME_UNSET)
- .waitForSeekProcessed()
- .playUntilPosition(/* windowIndex= */ 1, /* positionMs= */ 5000)
- .executeRunnable(
- new PlayerRunnable() {
- @Override
- public void run(SimpleExoPlayer player) {
- player.setMediaItem(mediaSource, /* startPositionMs= */ 5000);
- player.prepare();
- }
- })
- .executeRunnable(
- new PlayerRunnable() {
- @Override
- public void run(SimpleExoPlayer player) {
- windowIndex[0] = player.getCurrentWindowIndex();
- positionMs[0] = player.getCurrentPosition();
- }
- })
- .build();
- new ExoPlayerTestRunner.Builder()
- .setMediaSource(loopingMediaSource)
- .setActionSchedule(actionSchedule)
- .build(context)
- .start()
- .blockUntilActionScheduleFinished(TIMEOUT_MS);
-
- assertThat(windowIndex[0]).isEqualTo(0);
- assertThat(positionMs[0]).isAtLeast(5000L);
- }
-
- @Test
- public void becomingNoisyIgnoredIfBecomingNoisyHandlingIsDisabled() throws Exception {
- CountDownLatch becomingNoisyHandlingDisabled = new CountDownLatch(1);
- CountDownLatch becomingNoisyDelivered = new CountDownLatch(1);
- PlayerStateGrabber playerStateGrabber = new PlayerStateGrabber();
- ActionSchedule actionSchedule =
- new ActionSchedule.Builder("becomingNoisyIgnoredIfBecomingNoisyHandlingIsDisabled")
- .executeRunnable(
- new PlayerRunnable() {
- @Override
- public void run(SimpleExoPlayer player) {
- player.setHandleAudioBecomingNoisy(false);
- becomingNoisyHandlingDisabled.countDown();
-
- // Wait for the broadcast to be delivered from the main thread.
- try {
- becomingNoisyDelivered.await();
- } catch (InterruptedException e) {
- throw new IllegalStateException(e);
- }
- }
- })
- .delay(1) // Handle pending messages on the playback thread.
- .executeRunnable(playerStateGrabber)
- .build();
-
- ExoPlayerTestRunner testRunner =
- new ExoPlayerTestRunner.Builder().setActionSchedule(actionSchedule).build(context).start();
- becomingNoisyHandlingDisabled.await();
- deliverBroadcast(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
- becomingNoisyDelivered.countDown();
-
- testRunner.blockUntilActionScheduleFinished(TIMEOUT_MS).blockUntilEnded(TIMEOUT_MS);
- assertThat(playerStateGrabber.playWhenReady).isTrue();
- }
-
- @Test
- public void pausesWhenBecomingNoisyIfBecomingNoisyHandlingIsEnabled() throws Exception {
- CountDownLatch becomingNoisyHandlingEnabled = new CountDownLatch(1);
- ActionSchedule actionSchedule =
- new ActionSchedule.Builder("pausesWhenBecomingNoisyIfBecomingNoisyHandlingIsEnabled")
- .executeRunnable(
- new PlayerRunnable() {
- @Override
- public void run(SimpleExoPlayer player) {
- player.setHandleAudioBecomingNoisy(true);
- becomingNoisyHandlingEnabled.countDown();
- }
- })
- .waitForPlayWhenReady(false) // Becoming noisy should set playWhenReady = false
- .play()
- .build();
-
- ExoPlayerTestRunner testRunner =
- new ExoPlayerTestRunner.Builder().setActionSchedule(actionSchedule).build(context).start();
- becomingNoisyHandlingEnabled.await();
- deliverBroadcast(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
-
- // If the player fails to handle becoming noisy, blockUntilActionScheduleFinished will time out
- // and throw, causing the test to fail.
- testRunner.blockUntilActionScheduleFinished(TIMEOUT_MS).blockUntilEnded(TIMEOUT_MS);
- }
-
// Internal methods.
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {
diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java
index bf3cc90a78..d64a44ac04 100644
--- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java
+++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java
@@ -431,8 +431,7 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc
if (actionSchedule != null) {
actionSchedule.start(player, trackSelector, null, handler, ExoPlayerTestRunner.this);
}
- player.setMediaItem(mediaSource);
- player.prepare();
+ player.prepare(mediaSource, /* resetPosition= */ false, /* resetState= */ false);
} catch (Exception e) {
handleException(e);
}
diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
index 47f34712b9..18eaec2cd7 100644
--- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
+++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
@@ -96,11 +96,6 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
throw new UnsupportedOperationException();
}
- @Override
- public void prepare() {
- throw new UnsupportedOperationException();
- }
-
@Override
public void prepare(MediaSource mediaSource) {
throw new UnsupportedOperationException();
@@ -111,16 +106,6 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer {
throw new UnsupportedOperationException();
}
- @Override
- public void setMediaItem(MediaSource mediaItem) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setMediaItem(MediaSource mediaItem, long startPositionMs) {
- throw new UnsupportedOperationException();
- }
-
@Override
public void setPlayWhenReady(boolean playWhenReady) {
throw new UnsupportedOperationException();