Allow passing BandwidthMeter to TrackSelector and TrackSelection.Factory.

This enabled the player to specify the bandwidth meter after the track
selector and the track selection factory have been created.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=199286400
This commit is contained in:
tonihei 2018-06-05 06:20:30 -07:00 committed by Oliver Woodman
parent 23afdd6f66
commit 1773708fe4
11 changed files with 323 additions and 78 deletions

View File

@ -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

View File

@ -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.

View File

@ -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,

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}
/**

View File

@ -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.
*
* <h3>Interactions with the player</h3>
*
* The following interactions occur between the player and its track selector during playback.
*
* <p>
*
* <ul>
* <li>When the player is created it will initialize the track selector by calling
* {@link #init(InvalidationListener)}.</li>
* <li>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.</li>
* <li>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)}.</li>
* <li>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.
* </li>
* <li>When the player is created it will initialize the track selector by calling {@link
* #init(InvalidationListener, BandwidthMeter)}.
* <li>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.
* <li>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)}.
* <li>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.
* </ul>
*
* <h3>Renderer configuration</h3>
* 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.
*
* <h3>Threading model</h3>
*
* 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;
}
}

View File

@ -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);

View File

@ -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++) {

View File

@ -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);
}
}