mirror of
https://github.com/samsonjs/media.git
synced 2026-04-02 10:45:51 +00:00
Unify internal reset method to support state and position resets.
The ExoPlayerImplInternal.reset method now takes the same set of options as the ExoPlayer.prepare method. This also allows to - Remove some code duplication within ExoPlayerImplInternal - Fix calls to prepare(sameSource, resetPosition=true, resetState=false) with enabled shuffle mode where the position was not correctly reset to the first period index. - Keep the current timeline when calling stop (in line with ExoPlayerImpl). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=176481878
This commit is contained in:
parent
fdb53ac8d1
commit
e1d960db68
2 changed files with 55 additions and 31 deletions
|
|
@ -17,7 +17,6 @@ package com.google.android.exoplayer2;
|
|||
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource.Listener;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.testutil.ActionSchedule;
|
||||
|
|
@ -541,4 +540,30 @@ public final class ExoPlayerTest extends TestCase {
|
|||
Player.TIMELINE_CHANGE_REASON_DYNAMIC);
|
||||
}
|
||||
|
||||
public void testRepreparationWithPositionResetAndShufflingUsesFirstPeriod() throws Exception {
|
||||
Timeline fakeTimeline = new FakeTimeline(new TimelineWindowDefinition(/* isSeekable= */ true,
|
||||
/* isDynamic= */ false, /* durationUs= */ 100000));
|
||||
ConcatenatingMediaSource firstMediaSource = new ConcatenatingMediaSource(/* isAtomic= */ false,
|
||||
new FakeShuffleOrder(/* length= */ 2),
|
||||
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT),
|
||||
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT)
|
||||
);
|
||||
ConcatenatingMediaSource secondMediaSource = new ConcatenatingMediaSource(/* isAtomic= */ false,
|
||||
new FakeShuffleOrder(/* length= */ 2),
|
||||
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT),
|
||||
new FakeMediaSource(fakeTimeline, null, Builder.VIDEO_FORMAT)
|
||||
);
|
||||
ActionSchedule actionSchedule = new ActionSchedule.Builder("testRepreparationWithShuffle")
|
||||
// Wait for first preparation and enable shuffling. Plays period 0.
|
||||
.waitForPlaybackState(Player.STATE_READY).setShuffleModeEnabled(true)
|
||||
// Reprepare with second media source (keeping state, but with position reset).
|
||||
// Plays period 1 and 0 because of the reversed fake shuffle order.
|
||||
.prepareSource(secondMediaSource, /* resetPosition= */ true, /* resetState= */ false)
|
||||
.build();
|
||||
ExoPlayerTestRunner testRunner = new ExoPlayerTestRunner.Builder()
|
||||
.setMediaSource(firstMediaSource).setActionSchedule(actionSchedule)
|
||||
.build().start().blockUntilEnded(TIMEOUT_MS);
|
||||
testRunner.assertPlayedPeriodIndices(0, 1, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -393,17 +393,10 @@ import java.io.IOException;
|
|||
|
||||
private void prepareInternal(MediaSource mediaSource, boolean resetPosition) {
|
||||
pendingPrepareCount++;
|
||||
resetInternal(true);
|
||||
resetInternal(/* releaseMediaSource= */ true, resetPosition);
|
||||
loadControl.onPrepared();
|
||||
if (resetPosition) {
|
||||
playbackInfo = new PlaybackInfo(null, null, 0, C.TIME_UNSET);
|
||||
} else {
|
||||
// The new start position is the current playback position.
|
||||
playbackInfo = new PlaybackInfo(null, null, playbackInfo.periodId, playbackInfo.positionUs,
|
||||
playbackInfo.contentPositionUs);
|
||||
}
|
||||
this.mediaSource = mediaSource;
|
||||
mediaSource.prepareSource(player, true, this);
|
||||
mediaSource.prepareSource(player, /* isTopLevelSource= */ true, /* listener = */ this);
|
||||
setState(Player.STATE_BUFFERING);
|
||||
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
|
||||
}
|
||||
|
|
@ -638,18 +631,16 @@ import java.io.IOException;
|
|||
|
||||
Pair<Integer, Long> periodPosition = resolveSeekPosition(seekPosition);
|
||||
if (periodPosition == null) {
|
||||
int firstPeriodIndex = timeline.isEmpty() ? 0 : timeline.getWindow(
|
||||
timeline.getFirstWindowIndex(shuffleModeEnabled), window).firstPeriodIndex;
|
||||
// The seek position was valid for the timeline that it was performed into, but the
|
||||
// timeline has changed and a suitable seek position could not be resolved in the new one.
|
||||
// Set the internal position to (firstPeriodIndex,TIME_UNSET) so that a subsequent seek to
|
||||
// (firstPeriodIndex,0) isn't ignored.
|
||||
playbackInfo = playbackInfo.fromNewPosition(firstPeriodIndex, C.TIME_UNSET, C.TIME_UNSET);
|
||||
setState(Player.STATE_ENDED);
|
||||
eventHandler.obtainMessage(MSG_SEEK_ACK, 1, 0,
|
||||
playbackInfo.fromNewPosition(firstPeriodIndex, 0, C.TIME_UNSET)).sendToTarget();
|
||||
// Reset, but retain the source so that it can still be used should a seek occur.
|
||||
resetInternal(false);
|
||||
resetInternal(false, true);
|
||||
// Set the playback position to 0 for notifying the eventHandler (instead of C.TIME_UNSET).
|
||||
eventHandler.obtainMessage(MSG_SEEK_ACK, /* seekAdjusted = */ 1, 0,
|
||||
playbackInfo.fromNewPosition(playbackInfo.periodId.periodIndex, /* startPositionUs = */ 0,
|
||||
/* contentPositionUs= */ C.TIME_UNSET))
|
||||
.sendToTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -768,13 +759,13 @@ import java.io.IOException;
|
|||
}
|
||||
|
||||
private void stopInternal() {
|
||||
resetInternal(true);
|
||||
resetInternal(/* releaseMediaSource= */ false, /* resetPosition= */ false);
|
||||
loadControl.onStopped();
|
||||
setState(Player.STATE_IDLE);
|
||||
}
|
||||
|
||||
private void releaseInternal() {
|
||||
resetInternal(true);
|
||||
resetInternal(/* releaseMediaSource= */ true, /* resetPosition= */ true);
|
||||
loadControl.onReleased();
|
||||
setState(Player.STATE_IDLE);
|
||||
internalPlaybackThread.quit();
|
||||
|
|
@ -784,7 +775,7 @@ import java.io.IOException;
|
|||
}
|
||||
}
|
||||
|
||||
private void resetInternal(boolean releaseMediaSource) {
|
||||
private void resetInternal(boolean releaseMediaSource, boolean resetPosition) {
|
||||
handler.removeMessages(MSG_DO_SOME_WORK);
|
||||
rebuffering = false;
|
||||
mediaClock.stop();
|
||||
|
|
@ -804,6 +795,20 @@ import java.io.IOException;
|
|||
readingPeriodHolder = null;
|
||||
playingPeriodHolder = null;
|
||||
setIsLoading(false);
|
||||
if (resetPosition) {
|
||||
// Set the internal position to (firstPeriodIndex,TIME_UNSET) so that a subsequent seek to
|
||||
// (firstPeriodIndex,0) isn't ignored.
|
||||
Timeline timeline = playbackInfo.timeline;
|
||||
int firstPeriodIndex = timeline == null || timeline.isEmpty()
|
||||
? 0
|
||||
: timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window)
|
||||
.firstPeriodIndex;
|
||||
playbackInfo = playbackInfo.fromNewPosition(firstPeriodIndex, C.TIME_UNSET, C.TIME_UNSET);
|
||||
} else {
|
||||
// The new start position is the current playback position.
|
||||
playbackInfo = playbackInfo.fromNewPosition(playbackInfo.periodId, playbackInfo.positionUs,
|
||||
playbackInfo.contentPositionUs);
|
||||
}
|
||||
if (releaseMediaSource) {
|
||||
if (mediaSource != null) {
|
||||
mediaSource.releaseSource();
|
||||
|
|
@ -1129,18 +1134,12 @@ import java.io.IOException;
|
|||
}
|
||||
|
||||
private void handleSourceInfoRefreshEndedPlayback(int prepareAcks, int seekAcks) {
|
||||
Timeline timeline = playbackInfo.timeline;
|
||||
int firstPeriodIndex = timeline.isEmpty() ? 0 : timeline.getWindow(
|
||||
timeline.getFirstWindowIndex(shuffleModeEnabled), window).firstPeriodIndex;
|
||||
// Set the internal position to (firstPeriodIndex,TIME_UNSET) so that a subsequent seek to
|
||||
// (firstPeriodIndex,0) isn't ignored.
|
||||
playbackInfo = playbackInfo.fromNewPosition(firstPeriodIndex, C.TIME_UNSET, C.TIME_UNSET);
|
||||
setState(Player.STATE_ENDED);
|
||||
// Set the playback position to (firstPeriodIndex,0) for notifying the eventHandler.
|
||||
notifySourceInfoRefresh(prepareAcks, seekAcks,
|
||||
playbackInfo.fromNewPosition(firstPeriodIndex, 0, C.TIME_UNSET));
|
||||
// Reset, but retain the source so that it can still be used should a seek occur.
|
||||
resetInternal(false);
|
||||
resetInternal(false, true);
|
||||
// Set the playback position to 0 for notifying the eventHandler (instead of C.TIME_UNSET).
|
||||
notifySourceInfoRefresh(prepareAcks, seekAcks,
|
||||
playbackInfo.fromNewPosition(playbackInfo.periodId.periodIndex, 0, C.TIME_UNSET));
|
||||
}
|
||||
|
||||
private void notifySourceInfoRefresh() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue