mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix masking step 1
1. Move Timeline/Manifest into PlaybackInfo 2. Don't update externally visible Timeline/Manifest during preparation 3. Ignore MSG_POSITION_DISCONTINUITY during preparation 4. Correctly set masking variables at start of preparation, and use them Once this change goes in, PlaybackInfo will contain timeline, manifest and position, which should always be self-consistent with one another. The next step would then be to move a bunch of logic in ExoPlayerImpl that derives state from timeline and position into PlaybackInfo, and split that into its own top level class that can be easily tested to make sure it never IndexOutOfBounds. I think we could also replace the masking variables and instead just assign a new PlaybackInfo to the playbackInfo variable whenever we're doing something that requires masking. This should be possible because we no longer update playbackInfo whenever we have pending acks. It would require allowing PlaybackInfo to mask the window position internally when the timeline is empty, but I think this is ok, and again is something we could test pretty easily. Issue: #3362 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=173909791
This commit is contained in:
parent
9b9a294fd8
commit
f150856567
3 changed files with 157 additions and 137 deletions
|
|
@ -56,7 +56,7 @@ public final class ExoPlayerTest extends TestCase {
|
||||||
.setTimeline(timeline).setRenderers(renderer)
|
.setTimeline(timeline).setRenderers(renderer)
|
||||||
.build().start().blockUntilEnded(TIMEOUT_MS);
|
.build().start().blockUntilEnded(TIMEOUT_MS);
|
||||||
testRunner.assertPositionDiscontinuityCount(0);
|
testRunner.assertPositionDiscontinuityCount(0);
|
||||||
testRunner.assertTimelinesEqual(timeline);
|
testRunner.assertTimelinesEqual();
|
||||||
assertEquals(0, renderer.formatReadCount);
|
assertEquals(0, renderer.formatReadCount);
|
||||||
assertEquals(0, renderer.bufferReadCount);
|
assertEquals(0, renderer.bufferReadCount);
|
||||||
assertFalse(renderer.isEnded);
|
assertFalse(renderer.isEnded);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import android.os.Message;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo;
|
import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo;
|
||||||
import com.google.android.exoplayer2.ExoPlayerImplInternal.SourceInfo;
|
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
|
|
@ -105,9 +104,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
ExoPlayerImpl.this.handleEvent(msg);
|
ExoPlayerImpl.this.handleEvent(msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
playbackInfo = new ExoPlayerImplInternal.PlaybackInfo(0, 0);
|
playbackInfo = new ExoPlayerImplInternal.PlaybackInfo(timeline, manifest, 0, 0);
|
||||||
internalPlayer = new ExoPlayerImplInternal(renderers, trackSelector, loadControl, playWhenReady,
|
internalPlayer = new ExoPlayerImplInternal(renderers, trackSelector, loadControl, playWhenReady,
|
||||||
repeatMode, shuffleModeEnabled, eventHandler, playbackInfo, this);
|
repeatMode, shuffleModeEnabled, eventHandler, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -137,6 +136,15 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) {
|
public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) {
|
||||||
|
if (!resetPosition) {
|
||||||
|
maskingWindowIndex = getCurrentWindowIndex();
|
||||||
|
maskingPeriodIndex = getCurrentPeriodIndex();
|
||||||
|
maskingWindowPositionMs = getCurrentPosition();
|
||||||
|
} else {
|
||||||
|
maskingWindowIndex = 0;
|
||||||
|
maskingPeriodIndex = 0;
|
||||||
|
maskingWindowPositionMs = 0;
|
||||||
|
}
|
||||||
if (resetState) {
|
if (resetState) {
|
||||||
if (!timeline.isEmpty() || manifest != null) {
|
if (!timeline.isEmpty() || manifest != null) {
|
||||||
timeline = Timeline.EMPTY;
|
timeline = Timeline.EMPTY;
|
||||||
|
|
@ -263,6 +271,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
maskingPeriodIndex = periodIndex;
|
maskingPeriodIndex = periodIndex;
|
||||||
}
|
}
|
||||||
if (positionMs == C.TIME_UNSET) {
|
if (positionMs == C.TIME_UNSET) {
|
||||||
|
// TODO: Work out when to call onPositionDiscontinuity on listeners for this case.
|
||||||
maskingWindowPositionMs = 0;
|
maskingWindowPositionMs = 0;
|
||||||
internalPlayer.seekTo(timeline, windowIndex, C.TIME_UNSET);
|
internalPlayer.seekTo(timeline, windowIndex, C.TIME_UNSET);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -313,7 +322,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCurrentPeriodIndex() {
|
public int getCurrentPeriodIndex() {
|
||||||
if (timeline.isEmpty() || pendingSeekAcks > 0) {
|
if (shouldMaskPosition()) {
|
||||||
return maskingPeriodIndex;
|
return maskingPeriodIndex;
|
||||||
} else {
|
} else {
|
||||||
return playbackInfo.periodId.periodIndex;
|
return playbackInfo.periodId.periodIndex;
|
||||||
|
|
@ -322,7 +331,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCurrentWindowIndex() {
|
public int getCurrentWindowIndex() {
|
||||||
if (timeline.isEmpty() || pendingSeekAcks > 0) {
|
if (shouldMaskPosition()) {
|
||||||
return maskingWindowIndex;
|
return maskingWindowIndex;
|
||||||
} else {
|
} else {
|
||||||
return timeline.getPeriod(playbackInfo.periodId.periodIndex, period).windowIndex;
|
return timeline.getPeriod(playbackInfo.periodId.periodIndex, period).windowIndex;
|
||||||
|
|
@ -358,7 +367,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getCurrentPosition() {
|
public long getCurrentPosition() {
|
||||||
if (timeline.isEmpty() || pendingSeekAcks > 0) {
|
if (shouldMaskPosition()) {
|
||||||
return maskingWindowPositionMs;
|
return maskingWindowPositionMs;
|
||||||
} else {
|
} else {
|
||||||
return playbackInfoPositionUsToWindowPositionMs(playbackInfo.positionUs);
|
return playbackInfoPositionUsToWindowPositionMs(playbackInfo.positionUs);
|
||||||
|
|
@ -368,7 +377,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
@Override
|
@Override
|
||||||
public long getBufferedPosition() {
|
public long getBufferedPosition() {
|
||||||
// TODO - Implement this properly.
|
// TODO - Implement this properly.
|
||||||
if (timeline.isEmpty() || pendingSeekAcks > 0) {
|
if (shouldMaskPosition()) {
|
||||||
return maskingWindowPositionMs;
|
return maskingWindowPositionMs;
|
||||||
} else {
|
} else {
|
||||||
return playbackInfoPositionUsToWindowPositionMs(playbackInfo.bufferedPositionUs);
|
return playbackInfoPositionUsToWindowPositionMs(playbackInfo.bufferedPositionUs);
|
||||||
|
|
@ -398,7 +407,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPlayingAd() {
|
public boolean isPlayingAd() {
|
||||||
return !timeline.isEmpty() && pendingSeekAcks == 0 && playbackInfo.periodId.isAd();
|
return !shouldMaskPosition() && playbackInfo.periodId.isAd();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -469,28 +478,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExoPlayerImplInternal.MSG_SOURCE_INFO_REFRESHED: {
|
case ExoPlayerImplInternal.MSG_SOURCE_INFO_REFRESHED: {
|
||||||
SourceInfo sourceInfo = (SourceInfo) msg.obj;
|
int prepareAcks = msg.arg1;
|
||||||
pendingPrepareAcks -= sourceInfo.prepareAcks;
|
int seekAcks = msg.arg2;
|
||||||
pendingSeekAcks -= sourceInfo.seekAcks;
|
handlePlaybackInfo((PlaybackInfo) msg.obj, prepareAcks, seekAcks, false);
|
||||||
if (pendingPrepareAcks == 0) {
|
|
||||||
timeline = sourceInfo.timeline;
|
|
||||||
manifest = sourceInfo.manifest;
|
|
||||||
playbackInfo = sourceInfo.playbackInfo;
|
|
||||||
if (pendingSeekAcks == 0 && timeline.isEmpty()) {
|
|
||||||
// Update the masking variables, which are used when the timeline is empty.
|
|
||||||
maskingPeriodIndex = 0;
|
|
||||||
maskingWindowIndex = 0;
|
|
||||||
maskingWindowPositionMs = 0;
|
|
||||||
}
|
|
||||||
for (Player.EventListener listener : listeners) {
|
|
||||||
listener.onTimelineChanged(timeline, manifest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pendingSeekAcks == 0 && sourceInfo.seekAcks > 0) {
|
|
||||||
for (Player.EventListener listener : listeners) {
|
|
||||||
listener.onSeekProcessed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExoPlayerImplInternal.MSG_TRACKS_CHANGED: {
|
case ExoPlayerImplInternal.MSG_TRACKS_CHANGED: {
|
||||||
|
|
@ -507,30 +497,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExoPlayerImplInternal.MSG_SEEK_ACK: {
|
case ExoPlayerImplInternal.MSG_SEEK_ACK: {
|
||||||
if (--pendingSeekAcks == 0) {
|
boolean seekPositionAdjusted = msg.arg1 != 0;
|
||||||
playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj;
|
handlePlaybackInfo((PlaybackInfo) msg.obj, 0, 1, seekPositionAdjusted);
|
||||||
if (timeline.isEmpty()) {
|
|
||||||
// Update the masking variables, which are used when the timeline is empty.
|
|
||||||
maskingPeriodIndex = 0;
|
|
||||||
maskingWindowIndex = 0;
|
|
||||||
maskingWindowPositionMs = 0;
|
|
||||||
}
|
|
||||||
for (Player.EventListener listener : listeners) {
|
|
||||||
if (msg.arg1 != 0) {
|
|
||||||
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_INTERNAL);
|
|
||||||
}
|
|
||||||
listener.onSeekProcessed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExoPlayerImplInternal.MSG_POSITION_DISCONTINUITY: {
|
case ExoPlayerImplInternal.MSG_POSITION_DISCONTINUITY: {
|
||||||
if (pendingSeekAcks == 0) {
|
handlePlaybackInfo((PlaybackInfo) msg.obj, 0, 0, true);
|
||||||
playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj;
|
|
||||||
for (Player.EventListener listener : listeners) {
|
|
||||||
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_PERIOD_TRANSITION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExoPlayerImplInternal.MSG_PLAYBACK_PARAMETERS_CHANGED: {
|
case ExoPlayerImplInternal.MSG_PLAYBACK_PARAMETERS_CHANGED: {
|
||||||
|
|
@ -555,6 +527,43 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handlePlaybackInfo(PlaybackInfo playbackInfo, int prepareAcks, int seekAcks,
|
||||||
|
boolean positionDiscontinuity) {
|
||||||
|
Assertions.checkNotNull(playbackInfo.timeline);
|
||||||
|
pendingPrepareAcks -= prepareAcks;
|
||||||
|
pendingSeekAcks -= seekAcks;
|
||||||
|
if (pendingPrepareAcks == 0 && pendingSeekAcks == 0) {
|
||||||
|
this.playbackInfo = playbackInfo;
|
||||||
|
boolean timelineOrManifestChanged = timeline != playbackInfo.timeline
|
||||||
|
|| manifest != playbackInfo.manifest;
|
||||||
|
timeline = playbackInfo.timeline;
|
||||||
|
manifest = playbackInfo.manifest;
|
||||||
|
if (timeline.isEmpty()) {
|
||||||
|
// Update the masking variables, which are used when the timeline is empty.
|
||||||
|
maskingPeriodIndex = 0;
|
||||||
|
maskingWindowIndex = 0;
|
||||||
|
maskingWindowPositionMs = 0;
|
||||||
|
}
|
||||||
|
if (timelineOrManifestChanged) {
|
||||||
|
for (Player.EventListener listener : listeners) {
|
||||||
|
listener.onTimelineChanged(timeline, manifest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (positionDiscontinuity) {
|
||||||
|
for (Player.EventListener listener : listeners) {
|
||||||
|
listener.onPositionDiscontinuity(
|
||||||
|
seekAcks > 0 ? DISCONTINUITY_REASON_INTERNAL : DISCONTINUITY_REASON_PERIOD_TRANSITION
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pendingSeekAcks == 0 && seekAcks > 0) {
|
||||||
|
for (Player.EventListener listener : listeners) {
|
||||||
|
listener.onSeekProcessed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private long playbackInfoPositionUsToWindowPositionMs(long positionUs) {
|
private long playbackInfoPositionUsToWindowPositionMs(long positionUs) {
|
||||||
long positionMs = C.usToMs(positionUs);
|
long positionMs = C.usToMs(positionUs);
|
||||||
if (!playbackInfo.periodId.isAd()) {
|
if (!playbackInfo.periodId.isAd()) {
|
||||||
|
|
@ -564,4 +573,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
return positionMs;
|
return positionMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean shouldMaskPosition() {
|
||||||
|
return timeline.isEmpty() || pendingSeekAcks > 0 || pendingPrepareAcks > 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ import java.io.IOException;
|
||||||
*/
|
*/
|
||||||
public static final class PlaybackInfo {
|
public static final class PlaybackInfo {
|
||||||
|
|
||||||
|
public final Timeline timeline;
|
||||||
|
public final Object manifest;
|
||||||
public final MediaPeriodId periodId;
|
public final MediaPeriodId periodId;
|
||||||
public final long startPositionUs;
|
public final long startPositionUs;
|
||||||
public final long contentPositionUs;
|
public final long contentPositionUs;
|
||||||
|
|
@ -61,15 +63,14 @@ import java.io.IOException;
|
||||||
public volatile long positionUs;
|
public volatile long positionUs;
|
||||||
public volatile long bufferedPositionUs;
|
public volatile long bufferedPositionUs;
|
||||||
|
|
||||||
public PlaybackInfo(int periodIndex, long startPositionUs) {
|
public PlaybackInfo(Timeline timeline, Object manifest, int periodIndex, long startPositionUs) {
|
||||||
this(new MediaPeriodId(periodIndex), startPositionUs);
|
this(timeline, manifest, new MediaPeriodId(periodIndex), startPositionUs, C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlaybackInfo(MediaPeriodId periodId, long startPositionUs) {
|
public PlaybackInfo(Timeline timeline, Object manifest, MediaPeriodId periodId,
|
||||||
this(periodId, startPositionUs, C.TIME_UNSET);
|
long startPositionUs, long contentPositionUs) {
|
||||||
}
|
this.timeline = timeline;
|
||||||
|
this.manifest = manifest;
|
||||||
public PlaybackInfo(MediaPeriodId periodId, long startPositionUs, long contentPositionUs) {
|
|
||||||
this.periodId = periodId;
|
this.periodId = periodId;
|
||||||
this.startPositionUs = startPositionUs;
|
this.startPositionUs = startPositionUs;
|
||||||
this.contentPositionUs = contentPositionUs;
|
this.contentPositionUs = contentPositionUs;
|
||||||
|
|
@ -77,31 +78,33 @@ import java.io.IOException;
|
||||||
bufferedPositionUs = startPositionUs;
|
bufferedPositionUs = startPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PlaybackInfo fromNewPosition(int periodIndex, long startPositionUs,
|
||||||
|
long contentPositionUs) {
|
||||||
|
return fromNewPosition(new MediaPeriodId(periodIndex), startPositionUs, contentPositionUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaybackInfo fromNewPosition(MediaPeriodId periodId, long startPositionUs,
|
||||||
|
long contentPositionUs) {
|
||||||
|
return new PlaybackInfo(timeline, manifest, periodId, startPositionUs, contentPositionUs);
|
||||||
|
}
|
||||||
|
|
||||||
public PlaybackInfo copyWithPeriodIndex(int periodIndex) {
|
public PlaybackInfo copyWithPeriodIndex(int periodIndex) {
|
||||||
PlaybackInfo playbackInfo = new PlaybackInfo(periodId.copyWithPeriodIndex(periodIndex),
|
PlaybackInfo playbackInfo = new PlaybackInfo(timeline, manifest,
|
||||||
startPositionUs, contentPositionUs);
|
periodId.copyWithPeriodIndex(periodIndex), startPositionUs, contentPositionUs);
|
||||||
playbackInfo.positionUs = positionUs;
|
copyMutablePositions(this, playbackInfo);
|
||||||
playbackInfo.bufferedPositionUs = bufferedPositionUs;
|
|
||||||
return playbackInfo;
|
return playbackInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
public PlaybackInfo copyWithTimeline(Timeline timeline, Object manifest) {
|
||||||
|
PlaybackInfo playbackInfo = new PlaybackInfo(timeline, manifest, periodId, startPositionUs,
|
||||||
|
contentPositionUs);
|
||||||
|
copyMutablePositions(this, playbackInfo);
|
||||||
|
return playbackInfo;
|
||||||
|
}
|
||||||
|
|
||||||
public static final class SourceInfo {
|
private static void copyMutablePositions(PlaybackInfo from, PlaybackInfo to) {
|
||||||
|
to.positionUs = from.positionUs;
|
||||||
public final Timeline timeline;
|
to.bufferedPositionUs = from.bufferedPositionUs;
|
||||||
public final Object manifest;
|
|
||||||
public final PlaybackInfo playbackInfo;
|
|
||||||
public final int prepareAcks;
|
|
||||||
public final int seekAcks;
|
|
||||||
|
|
||||||
public SourceInfo(Timeline timeline, Object manifest, PlaybackInfo playbackInfo,
|
|
||||||
int prepareAcks, int seekAcks) {
|
|
||||||
this.timeline = timeline;
|
|
||||||
this.manifest = manifest;
|
|
||||||
this.playbackInfo = playbackInfo;
|
|
||||||
this.prepareAcks = prepareAcks;
|
|
||||||
this.seekAcks = seekAcks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -192,12 +195,9 @@ import java.io.IOException;
|
||||||
private MediaPeriodHolder readingPeriodHolder;
|
private MediaPeriodHolder readingPeriodHolder;
|
||||||
private MediaPeriodHolder playingPeriodHolder;
|
private MediaPeriodHolder playingPeriodHolder;
|
||||||
|
|
||||||
private Timeline timeline;
|
|
||||||
|
|
||||||
public ExoPlayerImplInternal(Renderer[] renderers, TrackSelector trackSelector,
|
public ExoPlayerImplInternal(Renderer[] renderers, TrackSelector trackSelector,
|
||||||
LoadControl loadControl, boolean playWhenReady, @Player.RepeatMode int repeatMode,
|
LoadControl loadControl, boolean playWhenReady, @Player.RepeatMode int repeatMode,
|
||||||
boolean shuffleModeEnabled, Handler eventHandler, PlaybackInfo playbackInfo,
|
boolean shuffleModeEnabled, Handler eventHandler, ExoPlayer player) {
|
||||||
ExoPlayer player) {
|
|
||||||
this.renderers = renderers;
|
this.renderers = renderers;
|
||||||
this.trackSelector = trackSelector;
|
this.trackSelector = trackSelector;
|
||||||
this.loadControl = loadControl;
|
this.loadControl = loadControl;
|
||||||
|
|
@ -206,9 +206,9 @@ import java.io.IOException;
|
||||||
this.shuffleModeEnabled = shuffleModeEnabled;
|
this.shuffleModeEnabled = shuffleModeEnabled;
|
||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.state = Player.STATE_IDLE;
|
this.state = Player.STATE_IDLE;
|
||||||
this.playbackInfo = playbackInfo;
|
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
|
||||||
|
playbackInfo = new PlaybackInfo(null, null, 0, C.TIME_UNSET);
|
||||||
rendererCapabilities = new RendererCapabilities[renderers.length];
|
rendererCapabilities = new RendererCapabilities[renderers.length];
|
||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
renderers[i].setIndex(i);
|
renderers[i].setIndex(i);
|
||||||
|
|
@ -446,10 +446,10 @@ import java.io.IOException;
|
||||||
resetInternal(true);
|
resetInternal(true);
|
||||||
loadControl.onPrepared();
|
loadControl.onPrepared();
|
||||||
if (resetPosition) {
|
if (resetPosition) {
|
||||||
playbackInfo = new PlaybackInfo(0, C.TIME_UNSET);
|
playbackInfo = new PlaybackInfo(null, null, 0, C.TIME_UNSET);
|
||||||
} else {
|
} else {
|
||||||
// The new start position is the current playback position.
|
// The new start position is the current playback position.
|
||||||
playbackInfo = new PlaybackInfo(playbackInfo.periodId, playbackInfo.positionUs,
|
playbackInfo = new PlaybackInfo(null, null, playbackInfo.periodId, playbackInfo.positionUs,
|
||||||
playbackInfo.contentPositionUs);
|
playbackInfo.contentPositionUs);
|
||||||
}
|
}
|
||||||
this.mediaSource = mediaSource;
|
this.mediaSource = mediaSource;
|
||||||
|
|
@ -496,8 +496,9 @@ import java.io.IOException;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
int nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.info.id.periodIndex,
|
int nextPeriodIndex = playbackInfo.timeline.getNextPeriodIndex(
|
||||||
period, window, repeatMode, shuffleModeEnabled);
|
lastValidPeriodHolder.info.id.periodIndex, period, window, repeatMode,
|
||||||
|
shuffleModeEnabled);
|
||||||
while (lastValidPeriodHolder.next != null
|
while (lastValidPeriodHolder.next != null
|
||||||
&& !lastValidPeriodHolder.info.isLastInTimelinePeriod) {
|
&& !lastValidPeriodHolder.info.isLastInTimelinePeriod) {
|
||||||
lastValidPeriodHolder = lastValidPeriodHolder.next;
|
lastValidPeriodHolder = lastValidPeriodHolder.next;
|
||||||
|
|
@ -534,7 +535,8 @@ import java.io.IOException;
|
||||||
// position of the playing period to make sure none of the removed period is played.
|
// position of the playing period to make sure none of the removed period is played.
|
||||||
MediaPeriodId periodId = playingPeriodHolder.info.id;
|
MediaPeriodId periodId = playingPeriodHolder.info.id;
|
||||||
long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.positionUs);
|
long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.positionUs);
|
||||||
playbackInfo = new PlaybackInfo(periodId, newPositionUs, playbackInfo.contentPositionUs);
|
playbackInfo = playbackInfo.fromNewPosition(periodId, newPositionUs,
|
||||||
|
playbackInfo.contentPositionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -696,6 +698,7 @@ import java.io.IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void seekToInternal(SeekPosition seekPosition) throws ExoPlaybackException {
|
private void seekToInternal(SeekPosition seekPosition) throws ExoPlaybackException {
|
||||||
|
Timeline timeline = playbackInfo.timeline;
|
||||||
if (timeline == null) {
|
if (timeline == null) {
|
||||||
pendingInitialSeekCount++;
|
pendingInitialSeekCount++;
|
||||||
pendingSeekPosition = seekPosition;
|
pendingSeekPosition = seekPosition;
|
||||||
|
|
@ -710,10 +713,10 @@ import java.io.IOException;
|
||||||
// timeline has changed and a suitable seek position could not be resolved in the new one.
|
// 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
|
// Set the internal position to (firstPeriodIndex,TIME_UNSET) so that a subsequent seek to
|
||||||
// (firstPeriodIndex,0) isn't ignored.
|
// (firstPeriodIndex,0) isn't ignored.
|
||||||
playbackInfo = new PlaybackInfo(firstPeriodIndex, C.TIME_UNSET);
|
playbackInfo = playbackInfo.fromNewPosition(firstPeriodIndex, C.TIME_UNSET, C.TIME_UNSET);
|
||||||
setState(Player.STATE_ENDED);
|
setState(Player.STATE_ENDED);
|
||||||
eventHandler.obtainMessage(MSG_SEEK_ACK, 1, 0, new PlaybackInfo(firstPeriodIndex, 0))
|
eventHandler.obtainMessage(MSG_SEEK_ACK, 1, 0,
|
||||||
.sendToTarget();
|
playbackInfo.fromNewPosition(firstPeriodIndex, 0, C.TIME_UNSET)).sendToTarget();
|
||||||
// Reset, but retain the source so that it can still be used should a seek occur.
|
// Reset, but retain the source so that it can still be used should a seek occur.
|
||||||
resetInternal(false);
|
resetInternal(false);
|
||||||
return;
|
return;
|
||||||
|
|
@ -739,7 +742,7 @@ import java.io.IOException;
|
||||||
seekPositionAdjusted |= periodPositionUs != newPeriodPositionUs;
|
seekPositionAdjusted |= periodPositionUs != newPeriodPositionUs;
|
||||||
periodPositionUs = newPeriodPositionUs;
|
periodPositionUs = newPeriodPositionUs;
|
||||||
} finally {
|
} finally {
|
||||||
playbackInfo = new PlaybackInfo(periodId, periodPositionUs, contentPositionUs);
|
playbackInfo = playbackInfo.fromNewPosition(periodId, periodPositionUs, contentPositionUs);
|
||||||
eventHandler.obtainMessage(MSG_SEEK_ACK, seekPositionAdjusted ? 1 : 0, 0, playbackInfo)
|
eventHandler.obtainMessage(MSG_SEEK_ACK, seekPositionAdjusted ? 1 : 0, 0, playbackInfo)
|
||||||
.sendToTarget();
|
.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
@ -809,7 +812,7 @@ import java.io.IOException;
|
||||||
private boolean shouldKeepPeriodHolder(MediaPeriodId seekPeriodId, long positionUs,
|
private boolean shouldKeepPeriodHolder(MediaPeriodId seekPeriodId, long positionUs,
|
||||||
MediaPeriodHolder holder) {
|
MediaPeriodHolder holder) {
|
||||||
if (seekPeriodId.equals(holder.info.id) && holder.prepared) {
|
if (seekPeriodId.equals(holder.info.id) && holder.prepared) {
|
||||||
timeline.getPeriod(holder.info.id.periodIndex, period);
|
playbackInfo.timeline.getPeriod(holder.info.id.periodIndex, period);
|
||||||
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs);
|
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs);
|
||||||
if (nextAdGroupIndex == C.INDEX_UNSET
|
if (nextAdGroupIndex == C.INDEX_UNSET
|
||||||
|| period.getAdGroupTimeUs(nextAdGroupIndex) == holder.info.endPositionUs) {
|
|| period.getAdGroupTimeUs(nextAdGroupIndex) == holder.info.endPositionUs) {
|
||||||
|
|
@ -884,7 +887,7 @@ import java.io.IOException;
|
||||||
mediaSource = null;
|
mediaSource = null;
|
||||||
}
|
}
|
||||||
mediaPeriodInfoSequence.setTimeline(null);
|
mediaPeriodInfoSequence.setTimeline(null);
|
||||||
timeline = null;
|
playbackInfo = playbackInfo.copyWithTimeline(null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1024,10 +1027,11 @@ import java.io.IOException;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timeline oldTimeline = timeline;
|
Timeline oldTimeline = playbackInfo.timeline;
|
||||||
timeline = sourceRefreshInfo.timeline;
|
Timeline timeline = sourceRefreshInfo.timeline;
|
||||||
mediaPeriodInfoSequence.setTimeline(timeline);
|
|
||||||
Object manifest = sourceRefreshInfo.manifest;
|
Object manifest = sourceRefreshInfo.manifest;
|
||||||
|
mediaPeriodInfoSequence.setTimeline(timeline);
|
||||||
|
playbackInfo = playbackInfo.copyWithTimeline(timeline, manifest);
|
||||||
|
|
||||||
if (oldTimeline == null) {
|
if (oldTimeline == null) {
|
||||||
int processedPrepareAcks = pendingPrepareCount;
|
int processedPrepareAcks = pendingPrepareCount;
|
||||||
|
|
@ -1040,32 +1044,32 @@ import java.io.IOException;
|
||||||
if (periodPosition == null) {
|
if (periodPosition == null) {
|
||||||
// The seek position was valid for the timeline that it was performed into, but the
|
// 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.
|
// timeline has changed and a suitable seek position could not be resolved in the new one.
|
||||||
handleSourceInfoRefreshEndedPlayback(manifest, processedPrepareAcks,
|
handleSourceInfoRefreshEndedPlayback(processedPrepareAcks, processedInitialSeekCount);
|
||||||
processedInitialSeekCount);
|
|
||||||
} else {
|
} else {
|
||||||
int periodIndex = periodPosition.first;
|
int periodIndex = periodPosition.first;
|
||||||
long positionUs = periodPosition.second;
|
long positionUs = periodPosition.second;
|
||||||
MediaPeriodId periodId =
|
MediaPeriodId periodId =
|
||||||
mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, positionUs);
|
mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, positionUs);
|
||||||
playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : positionUs, positionUs);
|
playbackInfo = playbackInfo.fromNewPosition(periodId, periodId.isAd() ? 0 : positionUs,
|
||||||
notifySourceInfoRefresh(manifest, processedPrepareAcks, processedInitialSeekCount);
|
positionUs);
|
||||||
|
notifySourceInfoRefresh(processedPrepareAcks, processedInitialSeekCount);
|
||||||
}
|
}
|
||||||
} else if (playbackInfo.startPositionUs == C.TIME_UNSET) {
|
} else if (playbackInfo.startPositionUs == C.TIME_UNSET) {
|
||||||
if (timeline.isEmpty()) {
|
if (timeline.isEmpty()) {
|
||||||
handleSourceInfoRefreshEndedPlayback(manifest, processedPrepareAcks, 0);
|
handleSourceInfoRefreshEndedPlayback(processedPrepareAcks, 0);
|
||||||
} else {
|
} else {
|
||||||
Pair<Integer, Long> defaultPosition = getPeriodPosition(
|
Pair<Integer, Long> defaultPosition = getPeriodPosition(timeline,
|
||||||
timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET);
|
timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET);
|
||||||
int periodIndex = defaultPosition.first;
|
int periodIndex = defaultPosition.first;
|
||||||
long startPositionUs = defaultPosition.second;
|
long startPositionUs = defaultPosition.second;
|
||||||
MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex,
|
MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex,
|
||||||
startPositionUs);
|
startPositionUs);
|
||||||
playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : startPositionUs,
|
playbackInfo = playbackInfo.fromNewPosition(periodId,
|
||||||
startPositionUs);
|
periodId.isAd() ? 0 : startPositionUs, startPositionUs);
|
||||||
notifySourceInfoRefresh(manifest, processedPrepareAcks, 0);
|
notifySourceInfoRefresh(processedPrepareAcks, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notifySourceInfoRefresh(manifest, processedPrepareAcks, 0);
|
notifySourceInfoRefresh(processedPrepareAcks, 0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1074,7 +1078,7 @@ import java.io.IOException;
|
||||||
MediaPeriodHolder periodHolder = playingPeriodHolder != null ? playingPeriodHolder
|
MediaPeriodHolder periodHolder = playingPeriodHolder != null ? playingPeriodHolder
|
||||||
: loadingPeriodHolder;
|
: loadingPeriodHolder;
|
||||||
if (periodHolder == null && playingPeriodIndex >= oldTimeline.getPeriodCount()) {
|
if (periodHolder == null && playingPeriodIndex >= oldTimeline.getPeriodCount()) {
|
||||||
notifySourceInfoRefresh(manifest);
|
notifySourceInfoRefresh();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Object playingPeriodUid = periodHolder == null
|
Object playingPeriodUid = periodHolder == null
|
||||||
|
|
@ -1086,11 +1090,11 @@ import java.io.IOException;
|
||||||
int newPeriodIndex = resolveSubsequentPeriod(playingPeriodIndex, oldTimeline, timeline);
|
int newPeriodIndex = resolveSubsequentPeriod(playingPeriodIndex, oldTimeline, timeline);
|
||||||
if (newPeriodIndex == C.INDEX_UNSET) {
|
if (newPeriodIndex == C.INDEX_UNSET) {
|
||||||
// We failed to resolve a suitable restart position.
|
// We failed to resolve a suitable restart position.
|
||||||
handleSourceInfoRefreshEndedPlayback(manifest);
|
handleSourceInfoRefreshEndedPlayback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// We resolved a subsequent period. Seek to the default position in the corresponding window.
|
// We resolved a subsequent period. Seek to the default position in the corresponding window.
|
||||||
Pair<Integer, Long> defaultPosition = getPeriodPosition(
|
Pair<Integer, Long> defaultPosition = getPeriodPosition(timeline,
|
||||||
timeline.getPeriod(newPeriodIndex, period).windowIndex, C.TIME_UNSET);
|
timeline.getPeriod(newPeriodIndex, period).windowIndex, C.TIME_UNSET);
|
||||||
newPeriodIndex = defaultPosition.first;
|
newPeriodIndex = defaultPosition.first;
|
||||||
long newPositionUs = defaultPosition.second;
|
long newPositionUs = defaultPosition.second;
|
||||||
|
|
@ -1113,8 +1117,8 @@ import java.io.IOException;
|
||||||
// Actually do the seek.
|
// Actually do the seek.
|
||||||
MediaPeriodId periodId = new MediaPeriodId(newPeriodIndex);
|
MediaPeriodId periodId = new MediaPeriodId(newPeriodIndex);
|
||||||
newPositionUs = seekToPeriodPosition(periodId, newPositionUs);
|
newPositionUs = seekToPeriodPosition(periodId, newPositionUs);
|
||||||
playbackInfo = new PlaybackInfo(periodId, newPositionUs);
|
playbackInfo = playbackInfo.fromNewPosition(periodId, newPositionUs, C.TIME_UNSET);
|
||||||
notifySourceInfoRefresh(manifest);
|
notifySourceInfoRefresh();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1130,15 +1134,15 @@ import java.io.IOException;
|
||||||
if (!periodId.isAd() || periodId.adIndexInAdGroup != playbackInfo.periodId.adIndexInAdGroup) {
|
if (!periodId.isAd() || periodId.adIndexInAdGroup != playbackInfo.periodId.adIndexInAdGroup) {
|
||||||
long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.contentPositionUs);
|
long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.contentPositionUs);
|
||||||
long contentPositionUs = periodId.isAd() ? playbackInfo.contentPositionUs : C.TIME_UNSET;
|
long contentPositionUs = periodId.isAd() ? playbackInfo.contentPositionUs : C.TIME_UNSET;
|
||||||
playbackInfo = new PlaybackInfo(periodId, newPositionUs, contentPositionUs);
|
playbackInfo = playbackInfo.fromNewPosition(periodId, newPositionUs, contentPositionUs);
|
||||||
notifySourceInfoRefresh(manifest);
|
notifySourceInfoRefresh();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (periodHolder == null) {
|
if (periodHolder == null) {
|
||||||
// We don't have any period holders, so we're done.
|
// We don't have any period holders, so we're done.
|
||||||
notifySourceInfoRefresh(manifest);
|
notifySourceInfoRefresh();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1163,7 +1167,7 @@ import java.io.IOException;
|
||||||
// position of the playing period to make sure none of the removed period is played.
|
// position of the playing period to make sure none of the removed period is played.
|
||||||
long newPositionUs =
|
long newPositionUs =
|
||||||
seekToPeriodPosition(playingPeriodHolder.info.id, playbackInfo.positionUs);
|
seekToPeriodPosition(playingPeriodHolder.info.id, playbackInfo.positionUs);
|
||||||
playbackInfo = new PlaybackInfo(playingPeriodHolder.info.id, newPositionUs,
|
playbackInfo = playbackInfo.fromNewPosition(playingPeriodHolder.info.id, newPositionUs,
|
||||||
playbackInfo.contentPositionUs);
|
playbackInfo.contentPositionUs);
|
||||||
} else {
|
} else {
|
||||||
// Update the loading period to be the last period that's still valid, and release all
|
// Update the loading period to be the last period that's still valid, and release all
|
||||||
|
|
@ -1177,7 +1181,7 @@ import java.io.IOException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notifySourceInfoRefresh(manifest);
|
notifySourceInfoRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaPeriodHolder updatePeriodInfo(MediaPeriodHolder periodHolder, int periodIndex) {
|
private MediaPeriodHolder updatePeriodInfo(MediaPeriodHolder periodHolder, int periodIndex) {
|
||||||
|
|
@ -1191,36 +1195,36 @@ import java.io.IOException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSourceInfoRefreshEndedPlayback(Object manifest) {
|
private void handleSourceInfoRefreshEndedPlayback() {
|
||||||
handleSourceInfoRefreshEndedPlayback(manifest, 0, 0);
|
handleSourceInfoRefreshEndedPlayback(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSourceInfoRefreshEndedPlayback(Object manifest, int prepareAcks,
|
private void handleSourceInfoRefreshEndedPlayback(int prepareAcks, int seekAcks) {
|
||||||
int seekAcks) {
|
Timeline timeline = playbackInfo.timeline;
|
||||||
int firstPeriodIndex = timeline.isEmpty() ? 0 : timeline.getWindow(
|
int firstPeriodIndex = timeline.isEmpty() ? 0 : timeline.getWindow(
|
||||||
timeline.getFirstWindowIndex(shuffleModeEnabled), window).firstPeriodIndex;
|
timeline.getFirstWindowIndex(shuffleModeEnabled), window).firstPeriodIndex;
|
||||||
// Set the internal position to (firstPeriodIndex,TIME_UNSET) so that a subsequent seek to
|
// Set the internal position to (firstPeriodIndex,TIME_UNSET) so that a subsequent seek to
|
||||||
// (firstPeriodIndex,0) isn't ignored.
|
// (firstPeriodIndex,0) isn't ignored.
|
||||||
playbackInfo = new PlaybackInfo(firstPeriodIndex, C.TIME_UNSET);
|
playbackInfo = playbackInfo.fromNewPosition(firstPeriodIndex, C.TIME_UNSET, C.TIME_UNSET);
|
||||||
setState(Player.STATE_ENDED);
|
setState(Player.STATE_ENDED);
|
||||||
// Set the playback position to (firstPeriodIndex,0) for notifying the eventHandler.
|
// Set the playback position to (firstPeriodIndex,0) for notifying the eventHandler.
|
||||||
notifySourceInfoRefresh(manifest, prepareAcks, seekAcks, new PlaybackInfo(firstPeriodIndex, 0));
|
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.
|
// Reset, but retain the source so that it can still be used should a seek occur.
|
||||||
resetInternal(false);
|
resetInternal(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifySourceInfoRefresh(Object manifest) {
|
private void notifySourceInfoRefresh() {
|
||||||
notifySourceInfoRefresh(manifest, 0, 0);
|
notifySourceInfoRefresh(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifySourceInfoRefresh(Object manifest, int prepareAcks, int seekAcks) {
|
private void notifySourceInfoRefresh(int prepareAcks, int seekAcks) {
|
||||||
notifySourceInfoRefresh(manifest, prepareAcks, seekAcks, playbackInfo);
|
notifySourceInfoRefresh(prepareAcks, seekAcks, playbackInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifySourceInfoRefresh(Object manifest, int prepareAcks, int seekAcks,
|
private void notifySourceInfoRefresh(int prepareAcks, int seekAcks, PlaybackInfo playbackInfo) {
|
||||||
PlaybackInfo playbackInfo) {
|
eventHandler.obtainMessage(MSG_SOURCE_INFO_REFRESHED, prepareAcks, seekAcks, playbackInfo)
|
||||||
eventHandler.obtainMessage(MSG_SOURCE_INFO_REFRESHED,
|
.sendToTarget();
|
||||||
new SourceInfo(timeline, manifest, playbackInfo, prepareAcks, seekAcks)).sendToTarget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1260,6 +1264,7 @@ import java.io.IOException;
|
||||||
* bounds of the timeline.
|
* bounds of the timeline.
|
||||||
*/
|
*/
|
||||||
private Pair<Integer, Long> resolveSeekPosition(SeekPosition seekPosition) {
|
private Pair<Integer, Long> resolveSeekPosition(SeekPosition seekPosition) {
|
||||||
|
Timeline timeline = playbackInfo.timeline;
|
||||||
Timeline seekTimeline = seekPosition.timeline;
|
Timeline seekTimeline = seekPosition.timeline;
|
||||||
if (seekTimeline.isEmpty()) {
|
if (seekTimeline.isEmpty()) {
|
||||||
// The application performed a blind seek without a non-empty timeline (most likely based on
|
// The application performed a blind seek without a non-empty timeline (most likely based on
|
||||||
|
|
@ -1291,7 +1296,8 @@ import java.io.IOException;
|
||||||
periodIndex = resolveSubsequentPeriod(periodPosition.first, seekTimeline, timeline);
|
periodIndex = resolveSubsequentPeriod(periodPosition.first, seekTimeline, timeline);
|
||||||
if (periodIndex != C.INDEX_UNSET) {
|
if (periodIndex != C.INDEX_UNSET) {
|
||||||
// We found one. Map the SeekPosition onto the corresponding default position.
|
// We found one. Map the SeekPosition onto the corresponding default position.
|
||||||
return getPeriodPosition(timeline.getPeriod(periodIndex, period).windowIndex, C.TIME_UNSET);
|
return getPeriodPosition(timeline, timeline.getPeriod(periodIndex, period).windowIndex,
|
||||||
|
C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
// We didn't find one. Give up.
|
// We didn't find one. Give up.
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -1301,12 +1307,13 @@ import java.io.IOException;
|
||||||
* Calls {@link Timeline#getPeriodPosition(Timeline.Window, Timeline.Period, int, long)} using the
|
* Calls {@link Timeline#getPeriodPosition(Timeline.Window, Timeline.Period, int, long)} using the
|
||||||
* current timeline.
|
* current timeline.
|
||||||
*/
|
*/
|
||||||
private Pair<Integer, Long> getPeriodPosition(int windowIndex, long windowPositionUs) {
|
private Pair<Integer, Long> getPeriodPosition(Timeline timeline, int windowIndex,
|
||||||
|
long windowPositionUs) {
|
||||||
return timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
|
return timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePeriods() throws ExoPlaybackException, IOException {
|
private void updatePeriods() throws ExoPlaybackException, IOException {
|
||||||
if (timeline == null) {
|
if (playbackInfo.timeline == null) {
|
||||||
// We're waiting to get information about periods.
|
// We're waiting to get information about periods.
|
||||||
mediaSource.maybeThrowSourceInfoRefreshError();
|
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1332,7 +1339,7 @@ import java.io.IOException;
|
||||||
// the end of the playing period, so advance playback to the next period.
|
// the end of the playing period, so advance playback to the next period.
|
||||||
playingPeriodHolder.release();
|
playingPeriodHolder.release();
|
||||||
setPlayingPeriodHolder(playingPeriodHolder.next);
|
setPlayingPeriodHolder(playingPeriodHolder.next);
|
||||||
playbackInfo = new PlaybackInfo(playingPeriodHolder.info.id,
|
playbackInfo = playbackInfo.fromNewPosition(playingPeriodHolder.info.id,
|
||||||
playingPeriodHolder.info.startPositionUs, playingPeriodHolder.info.contentPositionUs);
|
playingPeriodHolder.info.startPositionUs, playingPeriodHolder.info.contentPositionUs);
|
||||||
updatePlaybackPositions();
|
updatePlaybackPositions();
|
||||||
eventHandler.obtainMessage(MSG_POSITION_DISCONTINUITY, playbackInfo).sendToTarget();
|
eventHandler.obtainMessage(MSG_POSITION_DISCONTINUITY, playbackInfo).sendToTarget();
|
||||||
|
|
@ -1439,7 +1446,7 @@ import java.io.IOException;
|
||||||
? RENDERER_TIMESTAMP_OFFSET_US
|
? RENDERER_TIMESTAMP_OFFSET_US
|
||||||
: (loadingPeriodHolder.getRendererOffset() + loadingPeriodHolder.info.durationUs);
|
: (loadingPeriodHolder.getRendererOffset() + loadingPeriodHolder.info.durationUs);
|
||||||
int holderIndex = loadingPeriodHolder == null ? 0 : loadingPeriodHolder.index + 1;
|
int holderIndex = loadingPeriodHolder == null ? 0 : loadingPeriodHolder.index + 1;
|
||||||
Object uid = timeline.getPeriod(info.id.periodIndex, period, true).uid;
|
Object uid = playbackInfo.timeline.getPeriod(info.id.periodIndex, period, true).uid;
|
||||||
MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder(renderers, rendererCapabilities,
|
MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder(renderers, rendererCapabilities,
|
||||||
rendererPositionOffsetUs, trackSelector, loadControl, mediaSource, uid, holderIndex, info);
|
rendererPositionOffsetUs, trackSelector, loadControl, mediaSource, uid, holderIndex, info);
|
||||||
if (loadingPeriodHolder != null) {
|
if (loadingPeriodHolder != null) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue