From 5055a4aa9173aeae14114aee7fe7d4629d3430a0 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 23 Jun 2016 07:50:58 -0700 Subject: [PATCH] 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 --- .../exoplayer/ExoPlayerImplInternal.java | 174 +++++++++--------- 1 file changed, 85 insertions(+), 89 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java index ef71696008..c3c414097f 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java @@ -95,8 +95,6 @@ import java.util.ArrayList; private TrackRenderer rendererMediaClockSource; private MediaClock rendererMediaClock; private SampleSourceProvider sampleSourceProvider; - // TODO[playlists]: Use timeline.playingSource.sampleSource instead. - private SampleSource sampleSource; private TrackRenderer[] enabledRenderers; private boolean released; private boolean playWhenReady; @@ -300,7 +298,7 @@ import java.util.ArrayList; this.playWhenReady = playWhenReady; if (!playWhenReady) { stopRenderers(); - updatePositionUs(); + updatePlaybackPositions(); } else { if (state == ExoPlayer.STATE_READY) { startRenderers(); @@ -329,51 +327,59 @@ import java.util.ArrayList; } } - private void updatePositionUs() { - if (rendererMediaClockSource != null && !rendererMediaClockSource.isEnded()) { - internalPositionUs = rendererMediaClock.getPositionUs(); - standaloneMediaClock.setPositionUs(internalPositionUs); - } else { - internalPositionUs = standaloneMediaClock.getPositionUs(); + private void updatePlaybackPositions() throws ExoPlaybackException { + SampleSource sampleSource = timeline.getSampleSource(); + if (sampleSource == null) { + return; } - playbackInfo.positionUs = internalPositionUs - sourceOffsetUs; - elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000; - } - private void updateBufferedPositionUs() { - long sourceBufferedPositionUs = enabledRenderers.length > 0 - ? timeline.playingSource.sampleSource.getBufferedPositionUs() : C.END_OF_SOURCE_US; - long durationUs = playbackInfo.durationUs; - playbackInfo.bufferedPositionUs = sourceBufferedPositionUs == C.END_OF_SOURCE_US - && durationUs != C.UNSET_TIME_US ? durationUs : sourceBufferedPositionUs; + // Update the duration. + if (playbackInfo.durationUs == C.UNSET_TIME_US) { + playbackInfo.durationUs = sampleSource.getDurationUs(); + } + + // 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 { long operationStartTimeMs = SystemClock.elapsedRealtime(); - if (sampleSource == null) { - timeline.updateSources(); - sampleSource = timeline.getSampleSource(); - if (sampleSource == null) { - // We're still waiting for the source to be prepared. - scheduleNextOperation(MSG_DO_SOME_WORK, operationStartTimeMs, PREPARING_SOURCE_INTERVAL_MS); - return; - } + + timeline.updateSources(); + if (timeline.getSampleSource() == null) { + // We're still waiting for the source to be prepared. + scheduleNextOperation(MSG_DO_SOME_WORK, operationStartTimeMs, PREPARING_SOURCE_INTERVAL_MS); + return; } TraceUtil.beginSection("doSomeWork"); - if (enabledRenderers.length > 0) { - // Process a source discontinuity if there is one, else update the position. - if (!checkForSourceDiscontinuityInternal()) { - updatePositionUs(); - sampleSource = timeline.getSampleSource(); - } - updateBufferedPositionUs(); - timeline.updateSources(); - } else { - updatePositionUs(); - } - + updatePlaybackPositions(); boolean allRenderersEnded = true; boolean allRenderersReadyOrEnded = true; for (TrackRenderer renderer : enabledRenderers) { @@ -441,34 +447,29 @@ import java.util.ArrayList; stopRenderers(); rebuffering = false; - if (sourceIndex != playbackInfo.sourceIndex) { - playbackInfo = new PlaybackInfo(sourceIndex); - eventHandler.obtainMessage(MSG_SOURCE_CHANGED, playbackInfo).sendToTarget(); - } - - sampleSource = timeline.seekToSource(sourceIndex); + timeline.seekToSource(sourceIndex); + SampleSource sampleSource = timeline.getSampleSource(); if (sampleSource != null && enabledRenderers.length > 0) { seekPositionUs = sampleSource.seekToUs(seekPositionUs); } + resetInternalPosition(seekPositionUs); - setNewSourcePositionInternal(seekPositionUs); - handler.sendEmptyMessage(MSG_DO_SOME_WORK); + if (sourceIndex != playbackInfo.sourceIndex) { + 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 { eventHandler.sendEmptyMessage(MSG_SEEK_ACK); } } - private boolean checkForSourceDiscontinuityInternal() 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; + private void resetInternalPosition(long sourcePositionUs) throws ExoPlaybackException { internalPositionUs = sourceOffsetUs + sourcePositionUs; standaloneMediaClock.setPositionUs(internalPositionUs); for (TrackRenderer renderer : enabledRenderers) { @@ -506,7 +507,7 @@ import java.util.ArrayList; } } enabledRenderers = new TrackRenderer[0]; - sampleSource = null; + sampleSourceProvider = null; timeline.reset(); } @@ -515,7 +516,7 @@ import java.util.ArrayList; for (ExoPlayerMessage message : messages) { 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. handler.sendEmptyMessage(MSG_DO_SOME_WORK); } @@ -534,12 +535,12 @@ import java.util.ArrayList; } private void reselectTracksInternal() throws ExoPlaybackException { - if (sampleSource == null) { + if (timeline.getSampleSource() == null) { // We don't have tracks yet, so we don't care. return; } timeline.reselectTracks(); - updateBufferedPositionUs(); + updatePlaybackPositions(); handler.sendEmptyMessage(MSG_DO_SOME_WORK); } @@ -571,6 +572,10 @@ import java.util.ArrayList; playingSourceEndPositionUs = C.UNSET_TIME_US; } + public SampleSource getSampleSource() throws ExoPlaybackException { + return playingSource == null ? null : playingSource.sampleSource; + } + public void updateSources() throws ExoPlaybackException, IOException { // 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) { - // We are either waiting for preparation to complete, or already reading ahead. + if (playingSource == null) { 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. for (TrackRenderer renderer : enabledRenderers) { if (!renderer.hasReadStreamToEnd()) { return; } } + // TODO: Is playingSourceEndPositionUs equivalent to playbackInfo.durationUs? if (playingSourceEndPositionUs == C.UNSET_TIME_US) { playingSourceEndPositionUs = sourceOffsetUs + playingSource.sampleSource.getDurationUs(); } @@ -666,21 +685,7 @@ import java.util.ArrayList; || internalPositionUs < playingSourceEndPositionUs || playingSource.nextSource != null; } - public SampleSource getSampleSource() 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 { + public void seekToSource(int sourceIndex) throws ExoPlaybackException { // Clear the timeline, but keep the requested source if it is already prepared. Source source = playingSource; Source newPlayingSource = null; @@ -699,16 +704,13 @@ import java.util.ArrayList; bufferingSource = playingSource; bufferingSourceOffsetUs = sourceOffsetUs; } 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; readingSource = null; bufferingSource = null; bufferingSourceOffsetUs = 0; - sampleSource = null; pendingSourceIndex = sourceIndex; } - - return sampleSource; } public void reselectTracks() throws ExoPlaybackException { @@ -756,7 +758,7 @@ import java.util.ArrayList; } int enabledRendererCount = disableRenderers(false, newTrackSelections); - TrackStream[] newStreams = sampleSource.selectTracks(oldStreams, newSelections, + TrackStream[] newStreams = playingSource.sampleSource.selectTracks(oldStreams, newSelections, playbackInfo.positionUs); playingSource.updateTrackStreams(newTrackSelections, newSelections, newStreams); trackSelector.onSelectionActivated(trackSelectionData); @@ -793,7 +795,6 @@ import java.util.ArrayList; private void setPlayingSource(Source source, long offsetUs) throws ExoPlaybackException { sourceOffsetUs = offsetUs; - // Disable/enable renderers for the new source. int enabledRendererCount = disableRenderers(true, source.trackSelections); if (playingSource != source) { @@ -803,11 +804,6 @@ import java.util.ArrayList; playingSource = source; playingSourceEndPositionUs = C.UNSET_TIME_US; enableRenderers(source.trackSelections, enabledRendererCount); - - // Update playback information. - playbackInfo.durationUs = source.sampleSource.getDurationUs(); - updateBufferedPositionUs(); - updatePositionUs(); } private int disableRenderers(boolean sourceTransition, TrackSelectionArray newTrackSelections)