mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Mask ExoPlayer.isLoading when it transitions to IDLE or ENDED states
In some cases, the ExoPlayer immediately transitions to `STATE_IDLE` or `STATE_ENDED` on application thread, while `isLoading` can still remain as `true` before it is finally updated from playback thread. Issue: androidx/media#2133 #cherrypick PiperOrigin-RevId: 728724157
This commit is contained in:
parent
ae3eed2343
commit
daf8f9ff58
@ -7,6 +7,9 @@
|
||||
it easier to handle updates in other classes
|
||||
([#2128](https://github.com/androidx/media/issues/2128)).
|
||||
* ExoPlayer:
|
||||
* Fix a bug where `ExoPlayer.isLoading()` remains `true` while it has
|
||||
transitioned to `STATE_IDLE` or `STATE_ENDED`
|
||||
([#2133](https://github.com/androidx/media/issues/2133)).
|
||||
* Transformer:
|
||||
* Track Selection:
|
||||
* Extractors:
|
||||
|
@ -531,8 +531,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
}
|
||||
PlaybackInfo playbackInfo = this.playbackInfo.copyWithPlaybackError(null);
|
||||
playbackInfo =
|
||||
playbackInfo.copyWithPlaybackState(
|
||||
playbackInfo.timeline.isEmpty() ? STATE_ENDED : STATE_BUFFERING);
|
||||
maskPlaybackState(
|
||||
playbackInfo, playbackInfo.timeline.isEmpty() ? STATE_ENDED : 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
|
||||
@ -905,7 +905,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
PlaybackInfo newPlaybackInfo = playbackInfo;
|
||||
if (playbackInfo.playbackState == Player.STATE_READY
|
||||
|| (playbackInfo.playbackState == Player.STATE_ENDED && !timeline.isEmpty())) {
|
||||
newPlaybackInfo = playbackInfo.copyWithPlaybackState(Player.STATE_BUFFERING);
|
||||
newPlaybackInfo = maskPlaybackState(playbackInfo, Player.STATE_BUFFERING);
|
||||
}
|
||||
int oldMaskingMediaItemIndex = getCurrentMediaItemIndex();
|
||||
newPlaybackInfo =
|
||||
@ -1051,7 +1051,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
if (playbackInfo.sleepingForOffload) {
|
||||
playbackInfo = playbackInfo.copyWithEstimatedPosition();
|
||||
}
|
||||
playbackInfo = playbackInfo.copyWithPlaybackState(Player.STATE_IDLE);
|
||||
playbackInfo = maskPlaybackState(playbackInfo, Player.STATE_IDLE);
|
||||
playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(playbackInfo.periodId);
|
||||
playbackInfo.bufferedPositionUs = playbackInfo.positionUs;
|
||||
playbackInfo.totalBufferedDurationUs = 0;
|
||||
@ -1882,7 +1882,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
this.playbackInfo.copyWithLoadingMediaPeriodId(this.playbackInfo.periodId);
|
||||
playbackInfo.bufferedPositionUs = playbackInfo.positionUs;
|
||||
playbackInfo.totalBufferedDurationUs = 0;
|
||||
playbackInfo = playbackInfo.copyWithPlaybackState(Player.STATE_IDLE);
|
||||
playbackInfo = maskPlaybackState(playbackInfo, Player.STATE_IDLE);
|
||||
if (error != null) {
|
||||
playbackInfo = playbackInfo.copyWithPlaybackError(error);
|
||||
}
|
||||
@ -2360,7 +2360,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
maskingPlaybackState = STATE_BUFFERING;
|
||||
}
|
||||
}
|
||||
newPlaybackInfo = newPlaybackInfo.copyWithPlaybackState(maskingPlaybackState);
|
||||
newPlaybackInfo = maskPlaybackState(newPlaybackInfo, maskingPlaybackState);
|
||||
internalPlayer.setMediaSources(
|
||||
holders, startWindowIndex, Util.msToUs(startPositionMs), shuffleOrder);
|
||||
boolean positionDiscontinuity =
|
||||
@ -2434,7 +2434,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
&& toIndex == currentMediaSourceCount
|
||||
&& currentIndex >= newPlaybackInfo.timeline.getWindowCount();
|
||||
if (transitionsToEnded) {
|
||||
newPlaybackInfo = newPlaybackInfo.copyWithPlaybackState(STATE_ENDED);
|
||||
newPlaybackInfo = maskPlaybackState(newPlaybackInfo, STATE_ENDED);
|
||||
}
|
||||
internalPlayer.removeMediaSources(fromIndex, toIndex, shuffleOrder);
|
||||
return newPlaybackInfo;
|
||||
@ -2558,6 +2558,14 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
return playbackInfo;
|
||||
}
|
||||
|
||||
private static PlaybackInfo maskPlaybackState(PlaybackInfo playbackInfo, int playbackState) {
|
||||
playbackInfo = playbackInfo.copyWithPlaybackState(playbackState);
|
||||
if (playbackState == STATE_IDLE || playbackState == STATE_ENDED) {
|
||||
playbackInfo = playbackInfo.copyWithIsLoading(false);
|
||||
}
|
||||
return playbackInfo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<Object, Long> getPeriodPositionUsAfterTimelineChanged(
|
||||
Timeline oldTimeline,
|
||||
|
@ -1891,6 +1891,20 @@ public class ExoPlayerTest {
|
||||
assertThat(totalBufferedDuration[2]).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stopWhileLoading_correctMaskingIsLoading() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
player.setMediaSource(new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1)));
|
||||
player.prepare();
|
||||
advance(player).untilLoadingIs(true);
|
||||
|
||||
assertThat(player.isLoading()).isTrue();
|
||||
player.stop();
|
||||
assertThat(player.isLoading()).isFalse();
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stop_releasesMediaSource() throws Exception {
|
||||
Timeline timeline = new FakeTimeline();
|
||||
@ -2089,6 +2103,18 @@ public class ExoPlayerTest {
|
||||
assertThat(totalBufferedDuration[2]).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void releaseWhileLoading_correctMaskingIsLoading() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
player.setMediaSource(new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1)));
|
||||
player.prepare();
|
||||
advance(player).untilLoadingIs(true);
|
||||
|
||||
assertThat(player.isLoading()).isTrue();
|
||||
player.release();
|
||||
assertThat(player.isLoading()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingNewStartPositionPossibleAfterStopAndClearMediaItems() throws Exception {
|
||||
Timeline timeline = new FakeTimeline();
|
||||
@ -8810,6 +8836,29 @@ public class ExoPlayerTest {
|
||||
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setMediaSourcesWhileLoading_noSeekEmpty_correctMaskingIsLoading() throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
player.setMediaSource(new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1)));
|
||||
player.prepare();
|
||||
advance(player).untilLoadingIs(true);
|
||||
|
||||
assertThat(player.isLoading()).isTrue();
|
||||
// Set a media item with empty timeline.
|
||||
FakeMediaSource fakeMediaSource =
|
||||
new FakeMediaSource(Timeline.EMPTY) {
|
||||
@Override
|
||||
@Nullable
|
||||
public Timeline getInitialTimeline() {
|
||||
return getTimeline();
|
||||
}
|
||||
};
|
||||
player.setMediaSource(fakeMediaSource, /* resetPosition= */ false);
|
||||
assertThat(player.isLoading()).isFalse();
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMediaSources_whenEmptyInitialSeek_correctPeriodMasking() throws Exception {
|
||||
final long[] positions = new long[2];
|
||||
@ -9269,6 +9318,27 @@ public class ExoPlayerTest {
|
||||
assertThat(bufferedPositions[2]).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeMediaItemsWhileLoading_currentItemRemovedThatIsTheLast_correctMaskingIsLoading()
|
||||
throws Exception {
|
||||
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||
MediaSource firstMediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1));
|
||||
MediaSource secondMediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1));
|
||||
MediaSource thirdMediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1));
|
||||
player.setMediaSources(
|
||||
ImmutableList.of(firstMediaSource, secondMediaSource, thirdMediaSource),
|
||||
/* startMediaItemIndex= */ 2,
|
||||
/* startPositionMs= */ C.TIME_UNSET);
|
||||
player.prepare();
|
||||
advance(player).untilLoadingIs(true);
|
||||
|
||||
assertThat(player.isLoading()).isTrue();
|
||||
player.removeMediaItem(/* index= */ 2);
|
||||
assertThat(player.isLoading()).isFalse();
|
||||
|
||||
player.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeMediaItems_removeTailWithCurrentWindow_whenIdle_finishesPlayback()
|
||||
throws Exception {
|
||||
|
Loading…
x
Reference in New Issue
Block a user