diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java b/demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java index 1482657e44..47f02e5634 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/player/DemoPlayer.java @@ -245,6 +245,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi pushSurface(true); } + @SuppressWarnings("deprecation") public int getTrackCount(int type) { return !player.getRendererHasMedia(type) ? 0 : trackNames[type].length; } @@ -330,7 +331,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi if (trackNames[rendererIndex] == null) { // Convert a null trackNames to an array of suitable length. int trackCount = multiTrackSources[rendererIndex] != null - ? multiTrackSources[rendererIndex].getTrackCount() : 1; + ? multiTrackSources[rendererIndex].getMultiTrackCount() : 1; trackNames[rendererIndex] = new String[trackCount]; } } @@ -619,6 +620,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi } } + @SuppressWarnings("deprecation") private void pushTrackSelection(int type, boolean allowRendererEnable) { if (multiTrackSources == null) { return; diff --git a/library/src/androidTest/java/com/google/android/exoplayer/dash/DashChunkSourceTest.java b/library/src/androidTest/java/com/google/android/exoplayer/dash/DashChunkSourceTest.java index 0c7d7c5e29..d2744a8fc5 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/dash/DashChunkSourceTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/dash/DashChunkSourceTest.java @@ -101,7 +101,7 @@ public class DashChunkSourceTest extends InstrumentationTestCase { public void testGetSeekRangeOnVod() { DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO, null, null, mock(FormatEvaluator.class)); - chunkSource.enable(); + chunkSource.enable(0); TimeRange seekRange = chunkSource.getSeekRange(); checkSeekRange(seekRange, 0, VOD_DURATION_MS * 1000); @@ -394,7 +394,7 @@ public class DashChunkSourceTest extends InstrumentationTestCase { AdaptationSet.TYPE_VIDEO, null, mockDataSource, EVALUATOR, new FakeClock(AVAILABILITY_CURRENT_TIME_MS + periodStartMs), liveEdgeLatencyMs * 1000, AVAILABILITY_REALTIME_OFFSET_MS * 1000, false, null, null); - chunkSource.enable(); + chunkSource.enable(0); return chunkSource; } diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java index e54645e095..0cbbfcd093 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java @@ -74,7 +74,7 @@ import android.os.Looper; *

Player state

* *

The components of an {@link ExoPlayer}'s state can be divided into two distinct groups. State - * accessed by {@link #getRendererEnabled(int)} and {@link #getPlayWhenReady()} are only ever + * accessed by {@link #getSelectedTrack(int)} and {@link #getPlayWhenReady()} is only ever * changed by invoking the player's methods, and are never changed as a result of operations that * have been performed asynchronously by the playback thread. In contrast, the playback state * accessed by {@link #getPlaybackState()} is only ever changed as a result of operations @@ -219,6 +219,18 @@ public interface ExoPlayer { * The player has finished playing the media. */ public static final int STATE_ENDED = 5; + + /** + * A value that can be passed as the second argument to {@link #setSelectedTrack(int, int)} to + * disable the renderer. + */ + public static final int TRACK_DISABLED = -1; + /** + * A value that can be passed as the second argument to {@link #setSelectedTrack(int, int)} to + * select the default track. + */ + public static final int TRACK_DEFAULT = 0; + /** * Represents an unknown time or duration. */ @@ -266,27 +278,73 @@ public interface ExoPlayer { *

* Always returns false whilst the player is in the {@link #STATE_PREPARING} state. * + * @deprecated Use {@code getTrackCount(rendererIndex) > 0}. * @param rendererIndex The index of the renderer. * @return True if the renderer has media to play, false otherwise. */ + @Deprecated public boolean getRendererHasMedia(int rendererIndex); /** * Sets whether the renderer at the given index is enabled. * + * @deprecated Use {@code setSelectedTrack(rendererIndex, trackIndex)}. Passing + * {@link #TRACK_DEFAULT} as {@code trackIndex} is equivalent to enabling the renderer with + * this method. Passing {@link #TRACK_DISABLED} is equivalent to disabling the renderer. * @param rendererIndex The index of the renderer. * @param enabled Whether the renderer at the given index should be enabled. */ + @Deprecated public void setRendererEnabled(int rendererIndex, boolean enabled); /** * Whether the renderer at the given index is enabled. * + * @deprecated Use {@code getSelectedTrack(rendererIndex)}. A return value between 0 (inclusive) + * and {@code getTrackCount(rendererIndex)} (exclusive) indicate the renderer is enabled. A + * value outside of this range (e.g. {@link #TRACK_DISABLED}) indicates that the renderer is + * disabled. * @param rendererIndex The index of the renderer. * @return Whether the renderer is enabled. */ + @Deprecated public boolean getRendererEnabled(int rendererIndex); + /** + * Returns the number of tracks exposed by the specified renderer. + * + * @param rendererIndex The index of the renderer. + * @return The number of tracks. + */ + public int getTrackCount(int rendererIndex); + + /** + * Returns the format of a track. + * + * @param rendererIndex The index of the renderer. + * @param trackIndex The index of the track. + * @return The format of the track. + */ + public MediaFormat getTrackFormat(int rendererIndex, int trackIndex); + + /** + * Selects a track for the specified renderer. + * + * @param rendererIndex The index of the renderer. + * @param trackIndex The index of the track. A negative value or a value greater than or equal to + * the renderer's track count will disable the renderer. + */ + public void setSelectedTrack(int rendererIndex, int trackIndex); + + /** + * Returns the index of the currently selected track for the specified renderer. + * + * @param rendererIndex The index of the renderer. + * @return The selected track. A negative value or a value greater than or equal to the renderer's + * track count indicates that the renderer is disabled. + */ + public int getSelectedTrack(int rendererIndex); + /** * Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}. * If the player is already in this state, then this method can be used to pause and resume diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java index 7cac863dfa..67a8af7acc 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java @@ -96,44 +96,45 @@ import java.util.concurrent.CopyOnWriteArraySet; internalPlayer.prepare(renderers); } + @Deprecated @Override - // TODO: Deprecate in ExoPlayer. public boolean getRendererHasMedia(int rendererIndex) { - return getRendererTrackCount(rendererIndex) > 0; + return getTrackCount(rendererIndex) > 0; } + @Deprecated @Override - // TODO: Deprecate in ExoPlayer. public void setRendererEnabled(int rendererIndex, boolean enabled) { - setRendererSelectedTrack(rendererIndex, enabled ? 0 : -1); + setSelectedTrack(rendererIndex, enabled ? ExoPlayer.TRACK_DEFAULT : ExoPlayer.TRACK_DISABLED); + } + + @Deprecated + @Override + public boolean getRendererEnabled(int rendererIndex) { + int selectedTrack = getSelectedTrack(rendererIndex); + return 0 <= selectedTrack && selectedTrack < getTrackCount(rendererIndex); } @Override - // TODO: Deprecate in ExoPlayer. - public boolean getRendererEnabled(int rendererIndex) { - return getRendererSelectedTrack(rendererIndex) == 0; - } - - // TODO: Expose in ExoPlayer. - public int getRendererTrackCount(int rendererIndex) { + public int getTrackCount(int rendererIndex) { return trackFormats[rendererIndex] != null ? trackFormats[rendererIndex].length : 0; } - // TODO: Expose in ExoPlayer. - public MediaFormat getRendererTrackInfo(int rendererIndex, int trackIndex) { + @Override + public MediaFormat getTrackFormat(int rendererIndex, int trackIndex) { return trackFormats[rendererIndex][trackIndex]; } - // TODO: Expose in ExoPlayer. - public void setRendererSelectedTrack(int rendererIndex, int trackIndex) { + @Override + public void setSelectedTrack(int rendererIndex, int trackIndex) { if (selectedTrackIndices[rendererIndex] != trackIndex) { selectedTrackIndices[rendererIndex] = trackIndex; internalPlayer.setRendererSelectedTrack(rendererIndex, trackIndex); } } - // TODO: Expose in ExoPlayer. - public int getRendererSelectedTrack(int rendererIndex) { + @Override + public int getSelectedTrack(int rendererIndex) { return selectedTrackIndices[rendererIndex]; } diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java index 6835b6aeb9..95e8e5ac0d 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java @@ -81,6 +81,7 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load private Loader loader; private boolean loadingFinished; private IOException currentLoadableException; + private int enabledTrackCount; private int currentLoadableExceptionCount; private long currentLoadableExceptionTimestamp; private long currentLoadStartTimeMs; @@ -131,7 +132,7 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load if (state == STATE_PREPARED) { return true; } - loader = new Loader("Loader:" + chunkSource.getFormat().mimeType); + loader = new Loader("Loader:" + chunkSource.getFormat(0).mimeType); state = STATE_PREPARED; return true; } @@ -139,22 +140,21 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load @Override public int getTrackCount() { Assertions.checkState(state == STATE_PREPARED || state == STATE_ENABLED); - return 1; + return chunkSource.getTrackCount(); } @Override public MediaFormat getFormat(int track) { Assertions.checkState(state == STATE_PREPARED || state == STATE_ENABLED); - Assertions.checkState(track == 0); - return chunkSource.getFormat(); + return chunkSource.getFormat(track); } @Override public void enable(int track, long positionUs) { Assertions.checkState(state == STATE_PREPARED); - Assertions.checkState(track == 0); + Assertions.checkState(enabledTrackCount++ == 0); state = STATE_ENABLED; - chunkSource.enable(); + chunkSource.enable(track); loadControl.register(this, bufferSizeContribution); downstreamFormat = null; downstreamMediaFormat = null; @@ -167,7 +167,7 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load @Override public void disable(int track) { Assertions.checkState(state == STATE_ENABLED); - Assertions.checkState(track == 0); + Assertions.checkState(--enabledTrackCount == 0); state = STATE_PREPARED; try { chunkSource.disable(mediaChunks); @@ -187,7 +187,6 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load @Override public boolean continueBuffering(int track, long positionUs) { Assertions.checkState(state == STATE_ENABLED); - Assertions.checkState(track == 0); downstreamPositionUs = positionUs; chunkSource.continueBuffering(positionUs); updateLoadControl(); @@ -198,7 +197,6 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load public int readData(int track, long positionUs, MediaFormatHolder formatHolder, SampleHolder sampleHolder, boolean onlyReadDiscontinuity) { Assertions.checkState(state == STATE_ENABLED); - Assertions.checkState(track == 0); downstreamPositionUs = positionUs; if (pendingDiscontinuity) { diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSource.java b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSource.java index 80509f30aa..7d46af3d70 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSource.java @@ -31,13 +31,21 @@ import java.util.List; public interface ChunkSource { /** - * Gets the format. + * Returns the number of tracks exposed by the source. + * + * @return The number of tracks. + */ + int getTrackCount(); + + /** + * Gets the format of the specified track. *

* May be called when the source is disabled or enabled. * - * @return The format. + * @param track The track index. + * @return The format of the track. */ - MediaFormat getFormat(); + MediaFormat getFormat(int track); /** * Adaptive video {@link ChunkSource} implementations must return a copy of the provided @@ -52,8 +60,10 @@ public interface ChunkSource { /** * Called when the source is enabled. + * + * @param track The track index. */ - void enable(); + void enable(int track); /** * Called when the source is disabled. diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/MultiTrackChunkSource.java b/library/src/main/java/com/google/android/exoplayer/chunk/MultiTrackChunkSource.java index 194529735b..5e8dc638ee 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/MultiTrackChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/MultiTrackChunkSource.java @@ -27,6 +27,8 @@ import java.util.List; * A {@link ChunkSource} providing the ability to switch between multiple other {@link ChunkSource} * instances. */ +// TODO: Expose multiple tracks directly in DashChunkSource and SmoothStreamingChunkSource, and +// delete this class. public final class MultiTrackChunkSource implements ChunkSource, ExoPlayerComponent { /** @@ -55,18 +57,23 @@ public final class MultiTrackChunkSource implements ChunkSource, ExoPlayerCompon * * @return The number of tracks. */ - public int getTrackCount() { + public int getMultiTrackCount() { return allSources.length; } @Override - public MediaFormat getFormat() { - return selectedSource.getFormat(); + public int getTrackCount() { + return selectedSource.getTrackCount(); } @Override - public void enable() { - selectedSource.enable(); + public MediaFormat getFormat(int track) { + return selectedSource.getFormat(track); + } + + @Override + public void enable(int track) { + selectedSource.enable(track); enabled = true; } diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/SingleSampleChunkSource.java b/library/src/main/java/com/google/android/exoplayer/chunk/SingleSampleChunkSource.java index 5584741460..53ae76fe34 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/SingleSampleChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/SingleSampleChunkSource.java @@ -55,7 +55,12 @@ public final class SingleSampleChunkSource implements ChunkSource { } @Override - public MediaFormat getFormat() { + public int getTrackCount() { + return 1; + } + + @Override + public MediaFormat getFormat(int track) { return mediaFormat; } @@ -65,7 +70,7 @@ public final class SingleSampleChunkSource implements ChunkSource { } @Override - public void enable() { + public void enable(int track) { // Do nothing. } diff --git a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java index f3e20ac602..551aa79e1d 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java @@ -291,7 +291,12 @@ public class DashChunkSource implements ChunkSource { } @Override - public final MediaFormat getFormat() { + public int getTrackCount() { + return 1; + } + + @Override + public final MediaFormat getFormat(int track) { return mediaFormat; } @@ -301,7 +306,7 @@ public class DashChunkSource implements ChunkSource { } @Override - public void enable() { + public void enable(int track) { fatalError = null; formatEvaluator.enable(); if (manifestFetcher != null) { diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java index fc9c62d117..5f182b0a35 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java @@ -187,12 +187,17 @@ public class SmoothStreamingChunkSource implements ChunkSource { } @Override - public final MediaFormat getFormat() { + public int getTrackCount() { + return 1; + } + + @Override + public final MediaFormat getFormat(int track) { return mediaFormat; } @Override - public void enable() { + public void enable(int track) { fatalError = null; formatEvaluator.enable(); if (manifestFetcher != null) {