diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 46ba143a5a..01afb5773f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -15,6 +15,8 @@ * Add support for lazy preparation of playlist media sources in `ConcatenatingMediaSource` ([#3972](https://github.com/google/ExoPlayer/issues/3972)). +* Pass `BandwidthMeter` to `TrackSelection.Factory` which can be used to obtain + bandwidth estimates in the future. Always null at the moment. * HLS: * Allow injection of custom playlist trackers. * Add method to `BandwidthMeter` to return the `TransferListener` used to gather diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index fc946804f4..8080a41b57 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -162,7 +162,7 @@ import java.util.Collections; enabledRenderers = new Renderer[0]; window = new Timeline.Window(); period = new Timeline.Period(); - trackSelector.init(this); + trackSelector.init(/* listener= */ this, /* bandwidthMeter= */ null); // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can // not normally change to this priority" is incorrect. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java index 0aa6dcffaa..d13596d2d7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java @@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.chunk.MediaChunk; import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Util; import java.util.List; @@ -137,11 +138,15 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { } @Override - public AdaptiveTrackSelection createTrackSelection(TrackGroup group, int... tracks) { + public AdaptiveTrackSelection createTrackSelection( + TrackGroup group, @Nullable BandwidthMeter bandwidthMeter, int... tracks) { + if (this.bandwidthMeter != null) { + bandwidthMeter = this.bandwidthMeter; + } return new AdaptiveTrackSelection( group, tracks, - bandwidthMeter, + Assertions.checkNotNull(bandwidthMeter), minDurationForQualityIncreaseMs, maxDurationForQualityDecreaseMs, minDurationToRetainAfterDiscardMs, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 10b11044d3..66f0c605f8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -1206,7 +1206,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { rendererTrackSelections[i] = Assertions.checkNotNull(adaptiveTrackSelectionFactory) .createTrackSelection( - rendererTrackGroups.get(override.groupIndex), override.tracks); + rendererTrackGroups.get(override.groupIndex), + getBandwidthMeter(), + override.tracks); } } } @@ -1352,7 +1354,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { formatSupports, mixedMimeTypeAdaptationSupports, params, - adaptiveTrackSelectionFactory); + adaptiveTrackSelectionFactory, + getBandwidthMeter()); } if (selection == null) { selection = selectFixedVideoTrack(groups, formatSupports, params); @@ -1365,7 +1368,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { int[][] formatSupport, int mixedMimeTypeAdaptationSupports, Parameters params, - TrackSelection.Factory adaptiveTrackSelectionFactory) + TrackSelection.Factory adaptiveTrackSelectionFactory, + @Nullable BandwidthMeter bandwidthMeter) throws ExoPlaybackException { int requiredAdaptiveSupport = params.allowNonSeamlessAdaptiveness ? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS) @@ -1381,7 +1385,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { params.viewportOrientationMayChange); if (adaptiveTracks.length > 0) { return Assertions.checkNotNull(adaptiveTrackSelectionFactory) - .createTrackSelection(group, adaptiveTracks); + .createTrackSelection(group, bandwidthMeter, adaptiveTracks); } } return null; @@ -1600,8 +1604,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { getAdaptiveAudioTracks( selectedGroup, formatSupports[selectedGroupIndex], params.allowMixedMimeAdaptiveness); if (adaptiveTracks.length > 0) { - return adaptiveTrackSelectionFactory.createTrackSelection(selectedGroup, - adaptiveTracks); + return adaptiveTrackSelectionFactory + .createTrackSelection(selectedGroup, getBandwidthMeter(), adaptiveTracks); } } return new FixedTrackSelection(selectedGroup, selectedTrackIndex); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/FixedTrackSelection.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/FixedTrackSelection.java index 2aecf624da..e378b4fcf5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/FixedTrackSelection.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/FixedTrackSelection.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.trackselection; import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.util.Assertions; /** @@ -48,7 +49,8 @@ public final class FixedTrackSelection extends BaseTrackSelection { } @Override - public FixedTrackSelection createTrackSelection(TrackGroup group, int... tracks) { + public FixedTrackSelection createTrackSelection( + TrackGroup group, @Nullable BandwidthMeter bandwidthMeter, int... tracks) { Assertions.checkArgument(tracks.length == 1); return new FixedTrackSelection(group, tracks[0], reason, data); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/RandomTrackSelection.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/RandomTrackSelection.java index e1bdc73986..4c908f3a7f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/RandomTrackSelection.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/RandomTrackSelection.java @@ -19,6 +19,7 @@ import android.os.SystemClock; import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import java.util.Random; /** @@ -45,7 +46,8 @@ public final class RandomTrackSelection extends BaseTrackSelection { } @Override - public RandomTrackSelection createTrackSelection(TrackGroup group, int... tracks) { + public RandomTrackSelection createTrackSelection( + TrackGroup group, @Nullable BandwidthMeter bandwidthMeter, int... tracks) { return new RandomTrackSelection(group, tracks, random); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelection.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelection.java index 58616996ff..5ad3e37ab3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelection.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelection.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.chunk.MediaChunk; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import java.util.List; /** @@ -36,16 +37,29 @@ public interface TrackSelection { */ interface Factory { + /** + * @deprecated Use and implement {@link + * #createTrackSelection(TrackGroup, BandwidthMeter, int...)} instead. + */ + @Deprecated + default TrackSelection createTrackSelection(TrackGroup group, int... tracks) { + return createTrackSelection(group, /* bandwidthMeter= */ null, tracks); + } + /** * Creates a new selection. * * @param group The {@link TrackGroup}. Must not be null. + * @param bandwidthMeter A {@link BandwidthMeter} which can be used to select tracks, or null if + * no such bandwidth meter is available. * @param tracks The indices of the selected tracks within the {@link TrackGroup}. Must not be * null or empty. May be in any order. * @return The created selection. */ - TrackSelection createTrackSelection(TrackGroup group, int... tracks); - + default TrackSelection createTrackSelection( + TrackGroup group, @Nullable BandwidthMeter bandwidthMeter, int... tracks) { + return createTrackSelection(group, tracks); + } } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java index 0c229527a0..e2ac7fff2a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java @@ -22,6 +22,7 @@ import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.upstream.BandwidthMeter; /** * The component of an {@link ExoPlayer} responsible for selecting tracks to be consumed by each of @@ -29,48 +30,52 @@ import com.google.android.exoplayer2.source.TrackGroupArray; * suitable for most use cases. * *

Interactions with the player

+ * * The following interactions occur between the player and its track selector during playback. + * *

+ * *

* *

Renderer configuration

- * The {@link TrackSelectorResult} returned by - * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)} contains not only - * {@link TrackSelection}s for each renderer, but also {@link RendererConfiguration}s defining - * configuration parameters that the renderers should apply when consuming the corresponding media. - * Whilst it may seem counter-intuitive for a track selector to also specify renderer configuration - * information, in practice the two are tightly bound together. It may only be possible to play a - * certain combination tracks if the renderers are configured in a particular way. Equally, it may - * only be possible to configure renderers in a particular way if certain tracks are selected. Hence - * it makes sense to determined the track selection and corresponding renderer configurations in a - * single step. + * + * The {@link TrackSelectorResult} returned by {@link #selectTracks(RendererCapabilities[], + * TrackGroupArray)} contains not only {@link TrackSelection}s for each renderer, but also {@link + * RendererConfiguration}s defining configuration parameters that the renderers should apply when + * consuming the corresponding media. Whilst it may seem counter-intuitive for a track selector to + * also specify renderer configuration information, in practice the two are tightly bound together. + * It may only be possible to play a certain combination tracks if the renderers are configured in a + * particular way. Equally, it may only be possible to configure renderers in a particular way if + * certain tracks are selected. Hence it makes sense to determined the track selection and + * corresponding renderer configurations in a single step. * *

Threading model

+ * * All calls made by the player into the track selector are on the player's internal playback * thread. The track selector may call {@link InvalidationListener#onTrackSelectionsInvalidated()} * from any thread. @@ -91,15 +96,19 @@ public abstract class TrackSelector { } private @Nullable InvalidationListener listener; + private @Nullable BandwidthMeter bandwidthMeter; /** * Called by the player to initialize the selector. * * @param listener An invalidation listener that the selector can call to indicate that selections * it has previously made are no longer valid. + * @param bandwidthMeter A bandwidth meter which can be used by track selections to select tracks, + * or null if no such bandwidth meter is available. */ - public final void init(InvalidationListener listener) { + public final void init(InvalidationListener listener, @Nullable BandwidthMeter bandwidthMeter) { this.listener = listener; + this.bandwidthMeter = bandwidthMeter; } /** @@ -132,4 +141,11 @@ public abstract class TrackSelector { } } + /** + * Returns a bandwidth meter which can be used by track selections to select tracks, or null if no + * such bandwidth meter is available. + */ + protected final @Nullable BandwidthMeter getBandwidthMeter() { + return bandwidthMeter; + } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java index f9ebee78d6..06c34a379d 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java @@ -16,6 +16,10 @@ package com.google.android.exoplayer2.trackselection; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -54,6 +58,23 @@ public final class AdaptiveTrackSelectionTest { fakeClock = new FakeClock(0); } + @Test + public void testFactoryUsesInitiallyProvidedBandwidthMeter() { + BandwidthMeter initialBandwidthMeter = mock(BandwidthMeter.class); + BandwidthMeter injectedBandwidthMeter = mock(BandwidthMeter.class); + Format format = videoFormat(/* bitrate= */ 500, /* width= */ 320, /* height= */ 240); + AdaptiveTrackSelection adaptiveTrackSelection = + new AdaptiveTrackSelection.Factory(initialBandwidthMeter) + .createTrackSelection(new TrackGroup(format), injectedBandwidthMeter, /* tracks= */ 0); + adaptiveTrackSelection.updateSelectedTrack( + /* playbackPositionUs= */ 0, + /* bufferedDurationUs= */ 0, + /* availableDurationUs= */ C.TIME_UNSET); + + verify(initialBandwidthMeter, atLeastOnce()).getBitrateEstimate(); + verifyZeroInteractions(injectedBandwidthMeter); + } + @Test public void testSelectInitialIndexUseMaxInitialBitrateIfNoBandwidthEstimate() { Format format1 = videoFormat(/* bitrate= */ 500, /* width= */ 320, /* height= */ 240); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java index 2ba63d6773..780d703fe6 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java @@ -19,9 +19,13 @@ import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_EXCEEDS_ import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_HANDLED; import static com.google.android.exoplayer2.RendererConfiguration.DEFAULT; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyVararg; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; import android.os.Parcel; @@ -38,6 +42,7 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Paramet import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.util.MimeTypes; import java.util.HashMap; import java.util.Map; @@ -71,33 +76,33 @@ public final class DefaultTrackSelectorTest { private static final RendererCapabilities[] RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER = new RendererCapabilities[] {VIDEO_CAPABILITIES, NO_SAMPLE_CAPABILITIES}; - private static final TrackGroup VIDEO_TRACK_GROUP = - new TrackGroup( - Format.createVideoSampleFormat( - "video", - MimeTypes.VIDEO_H264, - null, - Format.NO_VALUE, - Format.NO_VALUE, - 1024, - 768, - Format.NO_VALUE, - null, - null)); - private static final TrackGroup AUDIO_TRACK_GROUP = - new TrackGroup( - Format.createAudioSampleFormat( - "audio", - MimeTypes.AUDIO_AAC, - null, - Format.NO_VALUE, - Format.NO_VALUE, - 2, - 44100, - null, - null, - 0, - null)); + private static final Format VIDEO_FORMAT = + Format.createVideoSampleFormat( + "video", + MimeTypes.VIDEO_H264, + null, + Format.NO_VALUE, + Format.NO_VALUE, + 1024, + 768, + Format.NO_VALUE, + null, + null); + private static final Format AUDIO_FORMAT = + Format.createAudioSampleFormat( + "audio", + MimeTypes.AUDIO_AAC, + null, + Format.NO_VALUE, + Format.NO_VALUE, + 2, + 44100, + null, + null, + 0, + null); + private static final TrackGroup VIDEO_TRACK_GROUP = new TrackGroup(VIDEO_FORMAT); + private static final TrackGroup AUDIO_TRACK_GROUP = new TrackGroup(AUDIO_FORMAT); private static final TrackGroupArray TRACK_GROUPS = new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP); @@ -282,7 +287,7 @@ public final class DefaultTrackSelectorTest { @Test public void testSetParameterWithDefaultParametersDoesNotNotifyInvalidationListener() throws Exception { - trackSelector.init(invalidationListener); + trackSelector.init(invalidationListener, /* bandwidthMeter= */ null); verify(invalidationListener, never()).onTrackSelectionsInvalidated(); } @@ -295,7 +300,7 @@ public final class DefaultTrackSelectorTest { public void testSetParameterWithNonDefaultParameterNotifyInvalidationListener() throws Exception { Parameters parameters = new ParametersBuilder().setPreferredAudioLanguage("eng").build(); - trackSelector.init(invalidationListener); + trackSelector.init(invalidationListener, /* bandwidthMeter= */ null); trackSelector.setParameters(parameters); verify(invalidationListener).onTrackSelectionsInvalidated(); @@ -310,7 +315,7 @@ public final class DefaultTrackSelectorTest { public void testSetParameterWithSameParametersDoesNotNotifyInvalidationListenerAgain() throws Exception { ParametersBuilder builder = new ParametersBuilder().setPreferredAudioLanguage("eng"); - trackSelector.init(invalidationListener); + trackSelector.init(invalidationListener, /* bandwidthMeter= */ null); trackSelector.setParameters(builder.build()); trackSelector.setParameters(builder.build()); @@ -956,6 +961,116 @@ public final class DefaultTrackSelectorTest { assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(lowerBitrateFormat); } + @Test + public void testSelectTracksWithMultipleAudioTracksReturnsAdaptiveTrackSelection() + throws Exception { + TrackSelection adaptiveTrackSelection = mock(TrackSelection.class); + TrackSelection.Factory adaptiveTrackSelectionFactory = mock(TrackSelection.Factory.class); + when(adaptiveTrackSelectionFactory.createTrackSelection(any(), any(), anyVararg())) + .thenReturn(adaptiveTrackSelection); + + trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory); + + BandwidthMeter bandwidthMeter = mock(BandwidthMeter.class); + trackSelector.init(invalidationListener, bandwidthMeter); + + TrackGroupArray trackGroupArray = singleTrackGroup(AUDIO_FORMAT, AUDIO_FORMAT); + TrackSelectorResult result = + trackSelector.selectTracks( + new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroupArray); + + assertThat(result.length).isEqualTo(1); + assertThat(result.selections.get(0)).isEqualTo(adaptiveTrackSelection); + verify(adaptiveTrackSelectionFactory) + .createTrackSelection(trackGroupArray.get(0), bandwidthMeter, 0, 1); + } + + @Test + public void testSelectTracksWithMultipleAudioTracksOverrideReturnsAdaptiveTrackSelection() + throws Exception { + TrackSelection adaptiveTrackSelection = mock(TrackSelection.class); + TrackSelection.Factory adaptiveTrackSelectionFactory = mock(TrackSelection.Factory.class); + when(adaptiveTrackSelectionFactory.createTrackSelection(any(), any(), anyVararg())) + .thenReturn(adaptiveTrackSelection); + + trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory); + + BandwidthMeter bandwidthMeter = mock(BandwidthMeter.class); + trackSelector.init(invalidationListener, bandwidthMeter); + + TrackGroupArray trackGroupArray = singleTrackGroup(AUDIO_FORMAT, AUDIO_FORMAT, AUDIO_FORMAT); + trackSelector.setParameters( + trackSelector + .buildUponParameters() + .setSelectionOverride( + /* rendererIndex= */ 0, + trackGroupArray, + new SelectionOverride(/* groupIndex= */ 0, /* tracks= */ 1, 2))); + TrackSelectorResult result = + trackSelector.selectTracks( + new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroupArray); + + assertThat(result.length).isEqualTo(1); + assertThat(result.selections.get(0)).isEqualTo(adaptiveTrackSelection); + verify(adaptiveTrackSelectionFactory) + .createTrackSelection(trackGroupArray.get(0), bandwidthMeter, 1, 2); + } + + @Test + public void testSelectTracksWithMultipleVideoTracksReturnsAdaptiveTrackSelection() + throws Exception { + TrackSelection adaptiveTrackSelection = mock(TrackSelection.class); + TrackSelection.Factory adaptiveTrackSelectionFactory = mock(TrackSelection.Factory.class); + when(adaptiveTrackSelectionFactory.createTrackSelection(any(), any(), anyVararg())) + .thenReturn(adaptiveTrackSelection); + + trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory); + + BandwidthMeter bandwidthMeter = mock(BandwidthMeter.class); + trackSelector.init(invalidationListener, bandwidthMeter); + + TrackGroupArray trackGroupArray = singleTrackGroup(VIDEO_FORMAT, VIDEO_FORMAT); + TrackSelectorResult result = + trackSelector.selectTracks( + new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroupArray); + + assertThat(result.length).isEqualTo(1); + assertThat(result.selections.get(0)).isEqualTo(adaptiveTrackSelection); + verify(adaptiveTrackSelectionFactory) + .createTrackSelection(trackGroupArray.get(0), bandwidthMeter, 0, 1); + } + + @Test + public void testSelectTracksWithMultipleVideoTracksOverrideReturnsAdaptiveTrackSelection() + throws Exception { + TrackSelection adaptiveTrackSelection = mock(TrackSelection.class); + TrackSelection.Factory adaptiveTrackSelectionFactory = mock(TrackSelection.Factory.class); + when(adaptiveTrackSelectionFactory.createTrackSelection(any(), any(), anyVararg())) + .thenReturn(adaptiveTrackSelection); + + trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory); + + BandwidthMeter bandwidthMeter = mock(BandwidthMeter.class); + trackSelector.init(invalidationListener, bandwidthMeter); + + TrackGroupArray trackGroupArray = singleTrackGroup(VIDEO_FORMAT, VIDEO_FORMAT, VIDEO_FORMAT); + trackSelector.setParameters( + trackSelector + .buildUponParameters() + .setSelectionOverride( + /* rendererIndex= */ 0, + trackGroupArray, + new SelectionOverride(/* groupIndex= */ 0, /* tracks= */ 1, 2))); + TrackSelectorResult result = + trackSelector.selectTracks( + new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroupArray); + + assertThat(result.length).isEqualTo(1); + assertThat(result.selections.get(0)).isEqualTo(adaptiveTrackSelection); + verify(adaptiveTrackSelectionFactory) + .createTrackSelection(trackGroupArray.get(0), bandwidthMeter, 1, 2); + } + private static void assertTrackSelections(TrackSelectorResult result, TrackSelection[] expected) { assertThat(result.length).isEqualTo(expected.length); for (int i = 0; i < expected.length; i++) { diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectorTest.java new file mode 100644 index 0000000000..7fb910e18a --- /dev/null +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectorTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.trackselection; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.RendererCapabilities; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener; +import com.google.android.exoplayer2.upstream.BandwidthMeter; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.robolectric.RobolectricTestRunner; + +/** Unit test for {@link TrackSelector}. */ +@RunWith(RobolectricTestRunner.class) +public class TrackSelectorTest { + + private TrackSelector trackSelector; + + @Before + public void setUp() { + trackSelector = new TrackSelector() { + @Override + public TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities, + TrackGroupArray trackGroups) throws ExoPlaybackException { + throw new UnsupportedOperationException(); + } + + @Override + public void onSelectionActivated(Object info) {} + }; + } + + @Test + public void getBandwidthMeter_beforeInitialization_returnsNull() { + assertThat(trackSelector.getBandwidthMeter()).isNull(); + } + + @Test + public void getBandwidthMeter_afterInitialization_returnsProvidedBandwidthMeter() { + InvalidationListener invalidationListener = Mockito.mock(InvalidationListener.class); + BandwidthMeter bandwidthMeter = Mockito.mock(BandwidthMeter.class); + trackSelector.init(invalidationListener, bandwidthMeter); + + assertThat(trackSelector.getBandwidthMeter()).isEqualTo(bandwidthMeter); + } +}