Some restructing to make ExoPlayerImplInternal clearer.

- Update playbackInfo duration/position/bufferedPosition in a
  single place.
- Remove sampleSource variable, and remove side effects from
  getSampleSource. There was actually a subtle bug where
  getSampleSource wasn't called by anything where no renderers
  where enabled (meaning the source never transitioned).
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=125676540
This commit is contained in:
olly 2016-06-23 07:50:58 -07:00 committed by Oliver Woodman
parent 8eb1f3f57c
commit 5055a4aa91

View File

@ -95,8 +95,6 @@ import java.util.ArrayList;
private TrackRenderer rendererMediaClockSource; private TrackRenderer rendererMediaClockSource;
private MediaClock rendererMediaClock; private MediaClock rendererMediaClock;
private SampleSourceProvider sampleSourceProvider; private SampleSourceProvider sampleSourceProvider;
// TODO[playlists]: Use timeline.playingSource.sampleSource instead.
private SampleSource sampleSource;
private TrackRenderer[] enabledRenderers; private TrackRenderer[] enabledRenderers;
private boolean released; private boolean released;
private boolean playWhenReady; private boolean playWhenReady;
@ -300,7 +298,7 @@ import java.util.ArrayList;
this.playWhenReady = playWhenReady; this.playWhenReady = playWhenReady;
if (!playWhenReady) { if (!playWhenReady) {
stopRenderers(); stopRenderers();
updatePositionUs(); updatePlaybackPositions();
} else { } else {
if (state == ExoPlayer.STATE_READY) { if (state == ExoPlayer.STATE_READY) {
startRenderers(); startRenderers();
@ -329,51 +327,59 @@ import java.util.ArrayList;
} }
} }
private void updatePositionUs() { private void updatePlaybackPositions() throws ExoPlaybackException {
if (rendererMediaClockSource != null && !rendererMediaClockSource.isEnded()) { SampleSource sampleSource = timeline.getSampleSource();
internalPositionUs = rendererMediaClock.getPositionUs(); if (sampleSource == null) {
standaloneMediaClock.setPositionUs(internalPositionUs); return;
} else {
internalPositionUs = standaloneMediaClock.getPositionUs();
} }
playbackInfo.positionUs = internalPositionUs - sourceOffsetUs;
elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
}
private void updateBufferedPositionUs() { // Update the duration.
long sourceBufferedPositionUs = enabledRenderers.length > 0 if (playbackInfo.durationUs == C.UNSET_TIME_US) {
? timeline.playingSource.sampleSource.getBufferedPositionUs() : C.END_OF_SOURCE_US; playbackInfo.durationUs = sampleSource.getDurationUs();
long durationUs = playbackInfo.durationUs; }
playbackInfo.bufferedPositionUs = sourceBufferedPositionUs == C.END_OF_SOURCE_US
&& durationUs != C.UNSET_TIME_US ? durationUs : sourceBufferedPositionUs; // Update the playback position.
long positionUs = sampleSource.readDiscontinuity();
if (positionUs != C.UNSET_TIME_US) {
resetInternalPosition(positionUs);
} else {
if (rendererMediaClockSource != null && !rendererMediaClockSource.isEnded()) {
internalPositionUs = rendererMediaClock.getPositionUs();
standaloneMediaClock.setPositionUs(internalPositionUs);
} else {
internalPositionUs = standaloneMediaClock.getPositionUs();
}
positionUs = internalPositionUs - sourceOffsetUs;
}
playbackInfo.positionUs = positionUs;
elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
// Update the buffered position.
long bufferedPositionUs;
if (enabledRenderers.length == 0) {
bufferedPositionUs = C.END_OF_SOURCE_US;
} else {
bufferedPositionUs = sampleSource.getBufferedPositionUs();
if (bufferedPositionUs == C.END_OF_SOURCE_US && playbackInfo.durationUs != C.UNSET_TIME_US) {
bufferedPositionUs = playbackInfo.durationUs;
}
}
playbackInfo.bufferedPositionUs = bufferedPositionUs;
} }
private void doSomeWork() throws ExoPlaybackException, IOException { private void doSomeWork() throws ExoPlaybackException, IOException {
long operationStartTimeMs = SystemClock.elapsedRealtime(); long operationStartTimeMs = SystemClock.elapsedRealtime();
if (sampleSource == null) {
timeline.updateSources(); timeline.updateSources();
sampleSource = timeline.getSampleSource(); if (timeline.getSampleSource() == null) {
if (sampleSource == null) { // We're still waiting for the source to be prepared.
// We're still waiting for the source to be prepared. scheduleNextOperation(MSG_DO_SOME_WORK, operationStartTimeMs, PREPARING_SOURCE_INTERVAL_MS);
scheduleNextOperation(MSG_DO_SOME_WORK, operationStartTimeMs, PREPARING_SOURCE_INTERVAL_MS); return;
return;
}
} }
TraceUtil.beginSection("doSomeWork"); TraceUtil.beginSection("doSomeWork");
if (enabledRenderers.length > 0) { updatePlaybackPositions();
// Process a source discontinuity if there is one, else update the position.
if (!checkForSourceDiscontinuityInternal()) {
updatePositionUs();
sampleSource = timeline.getSampleSource();
}
updateBufferedPositionUs();
timeline.updateSources();
} else {
updatePositionUs();
}
boolean allRenderersEnded = true; boolean allRenderersEnded = true;
boolean allRenderersReadyOrEnded = true; boolean allRenderersReadyOrEnded = true;
for (TrackRenderer renderer : enabledRenderers) { for (TrackRenderer renderer : enabledRenderers) {
@ -441,34 +447,29 @@ import java.util.ArrayList;
stopRenderers(); stopRenderers();
rebuffering = false; rebuffering = false;
if (sourceIndex != playbackInfo.sourceIndex) { timeline.seekToSource(sourceIndex);
playbackInfo = new PlaybackInfo(sourceIndex); SampleSource sampleSource = timeline.getSampleSource();
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
}
sampleSource = timeline.seekToSource(sourceIndex);
if (sampleSource != null && enabledRenderers.length > 0) { if (sampleSource != null && enabledRenderers.length > 0) {
seekPositionUs = sampleSource.seekToUs(seekPositionUs); seekPositionUs = sampleSource.seekToUs(seekPositionUs);
} }
resetInternalPosition(seekPositionUs);
setNewSourcePositionInternal(seekPositionUs); if (sourceIndex != playbackInfo.sourceIndex) {
handler.sendEmptyMessage(MSG_DO_SOME_WORK); playbackInfo = new PlaybackInfo(sourceIndex);
playbackInfo.positionUs = seekPositionUs;
updatePlaybackPositions();
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
}
if (sampleSourceProvider != null) {
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
}
} finally { } finally {
eventHandler.sendEmptyMessage(MSG_SEEK_ACK); eventHandler.sendEmptyMessage(MSG_SEEK_ACK);
} }
} }
private boolean checkForSourceDiscontinuityInternal() throws ExoPlaybackException { private void resetInternalPosition(long sourcePositionUs) throws ExoPlaybackException {
long newSourcePositionUs = sampleSource.readDiscontinuity();
if (newSourcePositionUs == C.UNSET_TIME_US) {
return false;
}
setNewSourcePositionInternal(newSourcePositionUs);
return true;
}
private void setNewSourcePositionInternal(long sourcePositionUs) throws ExoPlaybackException {
playbackInfo.positionUs = sourcePositionUs;
internalPositionUs = sourceOffsetUs + sourcePositionUs; internalPositionUs = sourceOffsetUs + sourcePositionUs;
standaloneMediaClock.setPositionUs(internalPositionUs); standaloneMediaClock.setPositionUs(internalPositionUs);
for (TrackRenderer renderer : enabledRenderers) { for (TrackRenderer renderer : enabledRenderers) {
@ -506,7 +507,7 @@ import java.util.ArrayList;
} }
} }
enabledRenderers = new TrackRenderer[0]; enabledRenderers = new TrackRenderer[0];
sampleSource = null; sampleSourceProvider = null;
timeline.reset(); timeline.reset();
} }
@ -515,7 +516,7 @@ import java.util.ArrayList;
for (ExoPlayerMessage message : messages) { for (ExoPlayerMessage message : messages) {
message.target.handleMessage(message.messageType, message.message); message.target.handleMessage(message.messageType, message.message);
} }
if (sampleSource != null) { if (sampleSourceProvider != null) {
// The message may have caused something to change that now requires us to do work. // The message may have caused something to change that now requires us to do work.
handler.sendEmptyMessage(MSG_DO_SOME_WORK); handler.sendEmptyMessage(MSG_DO_SOME_WORK);
} }
@ -534,12 +535,12 @@ import java.util.ArrayList;
} }
private void reselectTracksInternal() throws ExoPlaybackException { private void reselectTracksInternal() throws ExoPlaybackException {
if (sampleSource == null) { if (timeline.getSampleSource() == null) {
// We don't have tracks yet, so we don't care. // We don't have tracks yet, so we don't care.
return; return;
} }
timeline.reselectTracks(); timeline.reselectTracks();
updateBufferedPositionUs(); updatePlaybackPositions();
handler.sendEmptyMessage(MSG_DO_SOME_WORK); handler.sendEmptyMessage(MSG_DO_SOME_WORK);
} }
@ -571,6 +572,10 @@ import java.util.ArrayList;
playingSourceEndPositionUs = C.UNSET_TIME_US; playingSourceEndPositionUs = C.UNSET_TIME_US;
} }
public SampleSource getSampleSource() throws ExoPlaybackException {
return playingSource == null ? null : playingSource.sampleSource;
}
public void updateSources() throws ExoPlaybackException, IOException { public void updateSources() throws ExoPlaybackException, IOException {
// TODO[playlists]: Let sample source providers invalidate sources that are already buffering. // TODO[playlists]: Let sample source providers invalidate sources that are already buffering.
@ -617,17 +622,31 @@ import java.util.ArrayList;
} }
} }
if (playingSource == null || readingSource != playingSource) { if (playingSource == null) {
// We are either waiting for preparation to complete, or already reading ahead.
return; return;
} }
if (readingSource != playingSource) {
if (playingSourceEndPositionUs != C.UNSET_TIME_US
&& internalPositionUs >= playingSourceEndPositionUs) {
playingSource.release();
setPlayingSource(readingSource, playingSourceEndPositionUs);
playbackInfo = new PlaybackInfo(playingSource.index);
updatePlaybackPositions();
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
} else {
// We're reading ahead, but it's not time to update the playing source yet.
return;
}
}
// Check whether all enabled renderers have read to the end of their TrackStreams. // Check whether all enabled renderers have read to the end of their TrackStreams.
for (TrackRenderer renderer : enabledRenderers) { for (TrackRenderer renderer : enabledRenderers) {
if (!renderer.hasReadStreamToEnd()) { if (!renderer.hasReadStreamToEnd()) {
return; return;
} }
} }
// TODO: Is playingSourceEndPositionUs equivalent to playbackInfo.durationUs?
if (playingSourceEndPositionUs == C.UNSET_TIME_US) { if (playingSourceEndPositionUs == C.UNSET_TIME_US) {
playingSourceEndPositionUs = sourceOffsetUs + playingSource.sampleSource.getDurationUs(); playingSourceEndPositionUs = sourceOffsetUs + playingSource.sampleSource.getDurationUs();
} }
@ -666,21 +685,7 @@ import java.util.ArrayList;
|| internalPositionUs < playingSourceEndPositionUs || playingSource.nextSource != null; || internalPositionUs < playingSourceEndPositionUs || playingSource.nextSource != null;
} }
public SampleSource getSampleSource() throws ExoPlaybackException { public void seekToSource(int sourceIndex) throws ExoPlaybackException {
if (playingSource == null) {
return null;
}
if (readingSource != playingSource && playingSourceEndPositionUs != C.UNSET_TIME_US
&& internalPositionUs >= playingSourceEndPositionUs) {
playingSource.release();
playbackInfo = new PlaybackInfo(readingSource.index);
setPlayingSource(readingSource, playingSourceEndPositionUs);
eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget();
}
return playingSource.sampleSource;
}
public SampleSource seekToSource(int sourceIndex) throws ExoPlaybackException {
// Clear the timeline, but keep the requested source if it is already prepared. // Clear the timeline, but keep the requested source if it is already prepared.
Source source = playingSource; Source source = playingSource;
Source newPlayingSource = null; Source newPlayingSource = null;
@ -699,16 +704,13 @@ import java.util.ArrayList;
bufferingSource = playingSource; bufferingSource = playingSource;
bufferingSourceOffsetUs = sourceOffsetUs; bufferingSourceOffsetUs = sourceOffsetUs;
} else { } else {
// TODO[REFACTOR]: Presumably we need to disable the renderers somewhere in here? // TODO[REFACTOR]: We need to disable the renderers somewhere in here?
playingSource = null; playingSource = null;
readingSource = null; readingSource = null;
bufferingSource = null; bufferingSource = null;
bufferingSourceOffsetUs = 0; bufferingSourceOffsetUs = 0;
sampleSource = null;
pendingSourceIndex = sourceIndex; pendingSourceIndex = sourceIndex;
} }
return sampleSource;
} }
public void reselectTracks() throws ExoPlaybackException { public void reselectTracks() throws ExoPlaybackException {
@ -756,7 +758,7 @@ import java.util.ArrayList;
} }
int enabledRendererCount = disableRenderers(false, newTrackSelections); int enabledRendererCount = disableRenderers(false, newTrackSelections);
TrackStream[] newStreams = sampleSource.selectTracks(oldStreams, newSelections, TrackStream[] newStreams = playingSource.sampleSource.selectTracks(oldStreams, newSelections,
playbackInfo.positionUs); playbackInfo.positionUs);
playingSource.updateTrackStreams(newTrackSelections, newSelections, newStreams); playingSource.updateTrackStreams(newTrackSelections, newSelections, newStreams);
trackSelector.onSelectionActivated(trackSelectionData); trackSelector.onSelectionActivated(trackSelectionData);
@ -793,7 +795,6 @@ import java.util.ArrayList;
private void setPlayingSource(Source source, long offsetUs) throws ExoPlaybackException { private void setPlayingSource(Source source, long offsetUs) throws ExoPlaybackException {
sourceOffsetUs = offsetUs; sourceOffsetUs = offsetUs;
// Disable/enable renderers for the new source. // Disable/enable renderers for the new source.
int enabledRendererCount = disableRenderers(true, source.trackSelections); int enabledRendererCount = disableRenderers(true, source.trackSelections);
if (playingSource != source) { if (playingSource != source) {
@ -803,11 +804,6 @@ import java.util.ArrayList;
playingSource = source; playingSource = source;
playingSourceEndPositionUs = C.UNSET_TIME_US; playingSourceEndPositionUs = C.UNSET_TIME_US;
enableRenderers(source.trackSelections, enabledRendererCount); enableRenderers(source.trackSelections, enabledRendererCount);
// Update playback information.
playbackInfo.durationUs = source.sampleSource.getDurationUs();
updateBufferedPositionUs();
updatePositionUs();
} }
private int disableRenderers(boolean sourceTransition, TrackSelectionArray newTrackSelections) private int disableRenderers(boolean sourceTransition, TrackSelectionArray newTrackSelections)