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.
+ *
*
+ *
*
- * - When the player is created it will initialize the track selector by calling
- * {@link #init(InvalidationListener)}.
- * - When the player needs to make a track selection it will call
- * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)}. This typically occurs at the
- * start of playback, when the player starts to buffer a new period of the media being played,
- * and when the track selector invalidates its previous selections.
- * - The player may perform a track selection well in advance of the selected tracks becoming
- * active, where active is defined to mean that the renderers are actually consuming media
- * corresponding to the selection that was made. For example when playing media containing
- * multiple periods, the track selection for a period is made when the player starts to buffer
- * that period. Hence if the player's buffering policy is to maintain a 30 second buffer, the
- * selection will occur approximately 30 seconds in advance of it becoming active. In fact the
- * selection may never become active, for example if the user seeks to some other period of the
- * media during the 30 second gap. The player indicates to the track selector when a selection
- * it has previously made becomes active by calling {@link #onSelectionActivated(Object)}.
- * - If the track selector wishes to indicate to the player that selections it has previously
- * made are invalid, it can do so by calling
- * {@link InvalidationListener#onTrackSelectionsInvalidated()} on the
- * {@link InvalidationListener} that was passed to {@link #init(InvalidationListener)}. A
- * track selector may wish to do this if its configuration has changed, for example if it now
- * wishes to prefer audio tracks in a particular language. This will trigger the player to make
- * new track selections. Note that the player will have to re-buffer in the case that the new
- * track selection for the currently playing period differs from the one that was invalidated.
- *
+ * - When the player is created it will initialize the track selector by calling {@link
+ * #init(InvalidationListener, BandwidthMeter)}.
+ *
- When the player needs to make a track selection it will call {@link
+ * #selectTracks(RendererCapabilities[], TrackGroupArray)}. This typically occurs at the start
+ * of playback, when the player starts to buffer a new period of the media being played, and
+ * when the track selector invalidates its previous selections.
+ *
- The player may perform a track selection well in advance of the selected tracks becoming
+ * active, where active is defined to mean that the renderers are actually consuming media
+ * corresponding to the selection that was made. For example when playing media containing
+ * multiple periods, the track selection for a period is made when the player starts to buffer
+ * that period. Hence if the player's buffering policy is to maintain a 30 second buffer, the
+ * selection will occur approximately 30 seconds in advance of it becoming active. In fact the
+ * selection may never become active, for example if the user seeks to some other period of
+ * the media during the 30 second gap. The player indicates to the track selector when a
+ * selection it has previously made becomes active by calling {@link
+ * #onSelectionActivated(Object)}.
+ *
- If the track selector wishes to indicate to the player that selections it has previously
+ * made are invalid, it can do so by calling {@link
+ * InvalidationListener#onTrackSelectionsInvalidated()} on the {@link InvalidationListener}
+ * that was passed to {@link #init(InvalidationListener, BandwidthMeter)}. A track selector
+ * may wish to do this if its configuration has changed, for example if it now wishes to
+ * prefer audio tracks in a particular language. This will trigger the player to make new
+ * track selections. Note that the player will have to re-buffer in the case that the new
+ * track selection for the currently playing period differs from the one that was invalidated.
*
*
* 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);
+ }
+}