Search in sources :

Example 1 with STATE_ENDED

use of androidx.media3.common.Player.STATE_ENDED in project media by androidx.

the class MediaControllerStateMaskingTest method removeMediaItems_removedTailIncludesCurrentItem_callsOnPlaybackStateChanged.

@Test
public void removeMediaItems_removedTailIncludesCurrentItem_callsOnPlaybackStateChanged() throws Exception {
    int initialMediaItemIndex = 1;
    int initialPlaybackState = STATE_READY;
    int testFromIndex = 1;
    int testToIndex = 3;
    int testPlaybackState = STATE_ENDED;
    Timeline testTimeline = createTimeline(createMediaItems(/* size= */
    3));
    Bundle playerConfig = new RemoteMediaSession.MockPlayerConfigBuilder().setTimeline(testTimeline).setCurrentMediaItemIndex(initialMediaItemIndex).setCurrentPeriodIndex(initialMediaItemIndex).setPlaybackState(initialPlaybackState).build();
    remoteSession.setPlayer(playerConfig);
    MediaController controller = controllerTestRule.createController(remoteSession.getToken());
    CountDownLatch latch = new CountDownLatch(1);
    AtomicInteger newPlaybackStateRef = new AtomicInteger();
    Player.Listener listener = new Player.Listener() {

        @Override
        public void onPlaybackStateChanged(int playbackState) {
            newPlaybackStateRef.set(playbackState);
            latch.countDown();
        }
    };
    threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener));
    threadTestRule.getHandler().postAndSync(() -> {
        controller.removeMediaItems(/* fromIndex= */
        testFromIndex, /* toIndex= */
        testToIndex);
    });
    assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
    assertThat(newPlaybackStateRef.get()).isEqualTo(testPlaybackState);
}
Also used : MediaTestUtils.createTimeline(androidx.media3.session.MediaTestUtils.createTimeline) Timeline(androidx.media3.common.Timeline) Player(androidx.media3.common.Player) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Bundle(android.os.Bundle) CountDownLatch(java.util.concurrent.CountDownLatch) LargeTest(androidx.test.filters.LargeTest) Test(org.junit.Test)

Example 2 with STATE_ENDED

use of androidx.media3.common.Player.STATE_ENDED in project media by androidx.

the class MediaControllerStateMaskingTest method removeMediaItems_removeAllItems.

@Test
public void removeMediaItems_removeAllItems() throws Exception {
    int initialMediaItemIndex = 1;
    int initialPlaybackState = STATE_READY;
    long initialCurrentPosition = 3_000;
    String firstMediaId = "firstMediaId";
    String secondMediaId = "secondMediaId";
    String thirdMediaId = "thirdMediaId";
    int testFromIndex = 0;
    int testToIndex = 3;
    int testMediaItemCount = 0;
    int testCurrentMediaItemIndex = 0;
    int testNextMediaItemIndex = C.INDEX_UNSET;
    int testPreviousMediaItemIndex = C.INDEX_UNSET;
    int testPlaybackState = STATE_ENDED;
    long testCurrentPosition = 0;
    Bundle playerConfig = new RemoteMediaSession.MockPlayerConfigBuilder().setTimeline(MediaTestUtils.createTimeline(createMediaItems(firstMediaId, secondMediaId, thirdMediaId))).setCurrentMediaItemIndex(initialMediaItemIndex).setCurrentPeriodIndex(initialMediaItemIndex).setCurrentPosition(initialCurrentPosition).setPlaybackState(initialPlaybackState).build();
    remoteSession.setPlayer(playerConfig);
    MediaController controller = controllerTestRule.createController(remoteSession.getToken());
    CountDownLatch latch = new CountDownLatch(4);
    AtomicReference<Timeline> newTimelineRef = new AtomicReference<>();
    AtomicReference<MediaItem> newMediaItemRef = new AtomicReference<>();
    AtomicInteger newPlaybackStateRef = new AtomicInteger();
    AtomicReference<Player.Events> onEventsRef = new AtomicReference<>();
    Player.Listener listener = new Player.Listener() {

        @Override
        public void onTimelineChanged(Timeline timeline, int reason) {
            newTimelineRef.set(timeline);
            latch.countDown();
        }

        @Override
        public void onMediaItemTransition(@Nullable MediaItem mediaItem, int reason) {
            newMediaItemRef.set(mediaItem);
            latch.countDown();
        }

        @Override
        public void onPlaybackStateChanged(int playbackState) {
            newPlaybackStateRef.set(playbackState);
            latch.countDown();
        }

        @Override
        public void onEvents(Player player, Player.Events events) {
            onEventsRef.set(events);
            latch.countDown();
        }
    };
    threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener));
    AtomicInteger currentMediaItemIndexRef = new AtomicInteger();
    AtomicInteger nextMediaItemIndexRef = new AtomicInteger();
    AtomicInteger previousMediaItemIndexRef = new AtomicInteger();
    AtomicLong newCurrentPositionRef = new AtomicLong();
    threadTestRule.getHandler().postAndSync(() -> {
        controller.removeMediaItems(/* fromIndex= */
        testFromIndex, /* toIndex= */
        testToIndex);
        currentMediaItemIndexRef.set(controller.getCurrentMediaItemIndex());
        nextMediaItemIndexRef.set(controller.getNextMediaItemIndex());
        previousMediaItemIndexRef.set(controller.getPreviousMediaItemIndex());
        newCurrentPositionRef.set(controller.getCurrentPosition());
    });
    assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
    assertTimeline(newTimelineRef.get(), testMediaItemCount, /* ignored= */
    C.INDEX_UNSET, /* ignored= */
    C.INDEX_UNSET, /* ignored= */
    C.INDEX_UNSET);
    assertThat(newMediaItemRef.get()).isNull();
    assertThat(newPlaybackStateRef.get()).isEqualTo(testPlaybackState);
    assertThat(onEventsRef.get().contains(Player.EVENT_TIMELINE_CHANGED)).isTrue();
    assertThat(onEventsRef.get().contains(Player.EVENT_MEDIA_ITEM_TRANSITION)).isTrue();
    assertThat(onEventsRef.get().contains(Player.EVENT_PLAYBACK_STATE_CHANGED)).isTrue();
    assertThat(currentMediaItemIndexRef.get()).isEqualTo(testCurrentMediaItemIndex);
    assertThat(nextMediaItemIndexRef.get()).isEqualTo(testNextMediaItemIndex);
    assertThat(previousMediaItemIndexRef.get()).isEqualTo(testPreviousMediaItemIndex);
    assertThat(newCurrentPositionRef.get()).isEqualTo(testCurrentPosition);
}
Also used : Player(androidx.media3.common.Player) Bundle(android.os.Bundle) AtomicReference(java.util.concurrent.atomic.AtomicReference) CountDownLatch(java.util.concurrent.CountDownLatch) MediaTestUtils.createTimeline(androidx.media3.session.MediaTestUtils.createTimeline) Timeline(androidx.media3.common.Timeline) AtomicLong(java.util.concurrent.atomic.AtomicLong) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) MediaItem(androidx.media3.common.MediaItem) Nullable(androidx.annotation.Nullable) LargeTest(androidx.test.filters.LargeTest) Test(org.junit.Test)

Example 3 with STATE_ENDED

use of androidx.media3.common.Player.STATE_ENDED in project media by androidx.

the class ExoPlayerImpl method setMediaSourcesInternal.

private void setMediaSourcesInternal(List<MediaSource> mediaSources, int startWindowIndex, long startPositionMs, boolean resetToDefaultPosition) {
    int currentWindowIndex = getCurrentWindowIndexInternal();
    long currentPositionMs = getCurrentPosition();
    pendingOperationAcks++;
    if (!mediaSourceHolderSnapshots.isEmpty()) {
        removeMediaSourceHolders(/* fromIndex= */
        0, /* toIndexExclusive= */
        mediaSourceHolderSnapshots.size());
    }
    List<MediaSourceList.MediaSourceHolder> holders = addMediaSourceHolders(/* index= */
    0, mediaSources);
    Timeline timeline = createMaskingTimeline();
    if (!timeline.isEmpty() && startWindowIndex >= timeline.getWindowCount()) {
        throw new IllegalSeekPositionException(timeline, startWindowIndex, startPositionMs);
    }
    // Evaluate the actual start position.
    if (resetToDefaultPosition) {
        startWindowIndex = timeline.getFirstWindowIndex(shuffleModeEnabled);
        startPositionMs = C.TIME_UNSET;
    } else if (startWindowIndex == C.INDEX_UNSET) {
        startWindowIndex = currentWindowIndex;
        startPositionMs = currentPositionMs;
    }
    PlaybackInfo newPlaybackInfo = maskTimelineAndPosition(playbackInfo, timeline, maskWindowPositionMsOrGetPeriodPositionUs(timeline, startWindowIndex, startPositionMs));
    // Mask the playback state.
    int maskingPlaybackState = newPlaybackInfo.playbackState;
    if (startWindowIndex != C.INDEX_UNSET && newPlaybackInfo.playbackState != STATE_IDLE) {
        // Position reset to startWindowIndex (results in pending initial seek).
        if (timeline.isEmpty() || startWindowIndex >= timeline.getWindowCount()) {
            // Setting an empty timeline or invalid seek transitions to ended.
            maskingPlaybackState = STATE_ENDED;
        } else {
            maskingPlaybackState = STATE_BUFFERING;
        }
    }
    newPlaybackInfo = newPlaybackInfo.copyWithPlaybackState(maskingPlaybackState);
    internalPlayer.setMediaSources(holders, startWindowIndex, Util.msToUs(startPositionMs), shuffleOrder);
    boolean positionDiscontinuity = !playbackInfo.periodId.periodUid.equals(newPlaybackInfo.periodId.periodUid) && !playbackInfo.timeline.isEmpty();
    updatePlaybackInfo(newPlaybackInfo, /* timelineChangeReason= */
    TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, /* ignored */
    PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, /* seekProcessed= */
    false, /* positionDiscontinuity= */
    positionDiscontinuity, DISCONTINUITY_REASON_REMOVE, /* discontinuityWindowStartPositionUs= */
    getCurrentPositionUsInternal(newPlaybackInfo), /* ignored */
    C.INDEX_UNSET);
}
Also used : Timeline(androidx.media3.common.Timeline) SuppressLint(android.annotation.SuppressLint) IllegalSeekPositionException(androidx.media3.common.IllegalSeekPositionException)

Example 4 with STATE_ENDED

use of androidx.media3.common.Player.STATE_ENDED in project media by androidx.

the class ExoPlayerTest method onPlayerErrorChanged_isNotifiedForNullError.

@Test
public void onPlayerErrorChanged_isNotifiedForNullError() throws Exception {
    ExoPlayer player = new TestExoPlayerBuilder(context).build();
    player.addMediaSource(new FakeMediaSource(/* timeline= */
    null) {

        @Override
        public void maybeThrowSourceInfoRefreshError() throws IOException {
            throw new IOException();
        }
    });
    Player.Listener mockListener = mock(Player.Listener.class);
    player.addListener(mockListener);
    player.prepare();
    player.play();
    ExoPlaybackException error = TestPlayerRunHelper.runUntilError(player);
    // The media source fails preparation, so we expect both methods to be called.
    verify(mockListener).onPlayerErrorChanged(error);
    verify(mockListener).onPlayerError(error);
    reset(mockListener);
    player.setMediaSource(new FakeMediaSource());
    player.prepare();
    player.play();
    TestPlayerRunHelper.runUntilPlaybackState(player, STATE_ENDED);
    // Now the player, which had a playback error, was re-prepared causing the error to be cleared.
    // We expect the change to null to be notified, but not onPlayerError.
    verify(mockListener).onPlayerErrorChanged(ArgumentMatchers.isNull());
    verify(mockListener, never()).onPlayerError(any());
}
Also used : Listener(androidx.media3.common.Player.Listener) Player(androidx.media3.common.Player) FakeMediaSource(androidx.media3.test.utils.FakeMediaSource) IOException(java.io.IOException) TestExoPlayerBuilder(androidx.media3.test.utils.TestExoPlayerBuilder) Test(org.junit.Test)

Example 5 with STATE_ENDED

use of androidx.media3.common.Player.STATE_ENDED in project media by androidx.

the class ExoPlayerImpl method removeMediaItemsInternal.

private PlaybackInfo removeMediaItemsInternal(int fromIndex, int toIndex) {
    Assertions.checkArgument(fromIndex >= 0 && toIndex >= fromIndex && toIndex <= mediaSourceHolderSnapshots.size());
    int currentIndex = getCurrentMediaItemIndex();
    Timeline oldTimeline = getCurrentTimeline();
    int currentMediaSourceCount = mediaSourceHolderSnapshots.size();
    pendingOperationAcks++;
    removeMediaSourceHolders(fromIndex, /* toIndexExclusive= */
    toIndex);
    Timeline newTimeline = createMaskingTimeline();
    PlaybackInfo newPlaybackInfo = maskTimelineAndPosition(playbackInfo, newTimeline, getPeriodPositionUsAfterTimelineChanged(oldTimeline, newTimeline));
    // Player transitions to STATE_ENDED if the current index is part of the removed tail.
    final boolean transitionsToEnded = newPlaybackInfo.playbackState != STATE_IDLE && newPlaybackInfo.playbackState != STATE_ENDED && fromIndex < toIndex && toIndex == currentMediaSourceCount && currentIndex >= newPlaybackInfo.timeline.getWindowCount();
    if (transitionsToEnded) {
        newPlaybackInfo = newPlaybackInfo.copyWithPlaybackState(STATE_ENDED);
    }
    internalPlayer.removeMediaSources(fromIndex, toIndex, shuffleOrder);
    return newPlaybackInfo;
}
Also used : Timeline(androidx.media3.common.Timeline) SuppressLint(android.annotation.SuppressLint)

Aggregations

Timeline (androidx.media3.common.Timeline)6 Player (androidx.media3.common.Player)3 Test (org.junit.Test)3 SuppressLint (android.annotation.SuppressLint)2 Bundle (android.os.Bundle)2 Nullable (androidx.annotation.Nullable)2 IllegalSeekPositionException (androidx.media3.common.IllegalSeekPositionException)2 PositionInfo (androidx.media3.common.Player.PositionInfo)2 Period (androidx.media3.common.Timeline.Period)2 RemotableTimeline (androidx.media3.common.Timeline.RemotableTimeline)2 Window (androidx.media3.common.Timeline.Window)2 MediaTestUtils.createTimeline (androidx.media3.session.MediaTestUtils.createTimeline)2 LargeTest (androidx.test.filters.LargeTest)2 ArrayList (java.util.ArrayList)2 CountDownLatch (java.util.concurrent.CountDownLatch)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 MediaItem (androidx.media3.common.MediaItem)1 Listener (androidx.media3.common.Player.Listener)1 FakeMediaSource (androidx.media3.test.utils.FakeMediaSource)1 TestExoPlayerBuilder (androidx.media3.test.utils.TestExoPlayerBuilder)1